1. 程式人生 > >抖音介面簽名_signature的加密演算法破解

抖音介面簽名_signature的加密演算法破解

最近無聊想抓一抓抖音的資料玩玩,把整個過程大概的記錄給大家,分享一下。

一、尋找介面

    通過幾個小時的觀察,我發現可以從分享頁面入手,因為這裡包含了所有我們想要的資料。隨便挑一個分享出他的個人資訊頁面,這裡就以抖音上最火的“莉哥”為例。分享出來後拿到的分享連結是:https://www.douyin.com/share/user/57720812347/?share_type=link。利用Chrome的開發者工具,直接在XHR拿到通訊資料。


Respone裡面便是我們想要的莉哥所有的視訊資料,包含播放量,點贊,評論等等各種資訊。在讓我們看看Headers裡面請求的URL會需要哪些引數。

標出的URL:

https://www.douyin.com/aweme/v1/aweme/post/?user_id=57720812347&count=21&max_cursor=0&aid=1128&_signature=R8qxlhATHPXt5fEW4KBhFkfKsY

user_id : 這個在分享出來的連結裡面有,看引數名都知道是代表什麼了。

max_cursor :這個第一次是0,之後需要取剩餘列表的時候應該就要用上一次請求得到的JSON資料中的“max_cursor”了。

aid:不清楚用途,直接跟著用1128。

_signature:簽名,這次的目標。

二、尋找_signature

    既然要破解簽名,那麼肯定是要先找到是哪裡生成的。直接在NetWork搜尋就是了,馬上就發現了簽名生成的位置。再在這個js檔案搜尋一下signature是哪裡賦值的。



    這裡就看到簽名函式_bytedAcrawler.sign,nonce引數傳的就是user_id。繼續看看_bytedAcrawler是哪裡來的。




可以看到_bytedAcrawler應該就是這個混淆了的函式生成的。看到這裡大概心裡就知道該怎麼樣去拿到這個_signature了,我們只要把“_M”的define函式和require函式都拿到手,直接呼叫就可以了。那麼讓我們找找define函式和require函式在哪定義的吧。一樣繼續搜關鍵詞“_M”,如下。


_M整個都定義在base_327cc85的js檔案內,我們想要的define和require都在,而n和e都在上面定義了。


到這裡我們所要找的東西都找齊了。按猜想只要把define和require搬出來,然後“douyin_falcon:node_modules/byted-acrawler/dist/runtime”的定義也搬出來,我們就能夠自己生成自己的_bytedAcrawler.sign了。

三、驗證

    現在把關鍵處的幾塊程式碼copy出來。

    _M的define和require:

!function(t) {
    if (t.__M = t.__M || {},
    !t.__M.require) {
        var e, n, r = document.getElementsByTagName("head")[0], i = {}, o = {}, a = {}, u = {}, c = {}, s = {}, l = function(t, n) {
            if (!(t in u)) {
                u[t] = !0;
                var i = document.createElement("script");
                if (n) {
                    var o = setTimeout(n, e.timeout);
                    i.onerror = function() {
                        clearTimeout(o),
                        n()
                    }
                    ;
                    var a = function() {
                        clearTimeout(o)
                    };
                    "onload"in i ? i.onload = a : i.onreadystatechange = function() {
                        ("loaded" === this.readyState || "complete" === this.readyState) && a()
                    }
                }
                return i.type = "text/javascript",
                i.src = t,
                r.appendChild(i),
                i
            }
        }, f = function(t, e, n) {
            var r = i[t] || (i[t] = []);
            r.push(e);
            var o, a = c[t] || c[t + ".js"] || {}, u = a.pkg;
            o = u ? s[u].url || s[u].uri : a.url || a.uri || t,
            l(o, n && function() {
                n(t)
            }
            )
        };
        n = function(t, e) {
            "function" != typeof e && (e = arguments[2]),
            t = t.replace(/\.js$/i, ""),
            o[t] = e;
            var n = i[t];
            if (n) {
                for (var r = 0, a = n.length; a > r; r++)
                    n[r]();
                delete i[t]
            }
        }
        ,
        e = function(t) {
            if (t && t.splice)
                return e.async.apply(this, arguments);
            t = e.alias(t);
            var n = a[t];
            if (n)
                return n.exports;
            var r = o[t];
            if (!r)
                throw "[ModJS] Cannot find module `" + t + "`";
            n = a[t] = {
                exports: {}
            };
            var i = "function" == typeof r ? r.apply(n, [e, n.exports, n]) : r;
            return i && (n.exports = i),
            n.exports && !n.exports["default"] && Object.defineProperty && Object.isExtensible(n.exports) && Object.defineProperty(n.exports, "default", {
                value: n.exports
            }),
            n.exports
        }
        ,
        e.async = function(n, r, i) {
            function a(t) {
                for (var n, r = 0, h = t.length; h > r; r++) {
                    var p = e.alias(t[r]);
                    p in o ? (n = c[p] || c[p + ".js"],
                    n && "deps"in n && a(n.deps)) : p in s || (s[p] = !0,
                    l++,
                    f(p, u, i),
                    n = c[p] || c[p + ".js"],
                    n && "deps"in n && a(n.deps))
                }
            }
            function u() {
                if (0 === l--) {
                    for (var i = [], o = 0, a = n.length; a > o; o++)
                        i[o] = e(n[o]);
                    r && r.apply(t, i)
                }
            }
            "string" == typeof n && (n = [n]);
            var s = {}
              , l = 0;
            a(n),
            u()
        }
        ,
        e.resourceMap = function(t) {
            var e, n;
            n = t.res;
            for (e in n)
                n.hasOwnProperty(e) && (c[e] = n[e]);
            n = t.pkg;
            for (e in n)
                n.hasOwnProperty(e) && (s[e] = n[e])
        }
        ,
        e.loadJs = function(t) {
            l(t)
        }
        ,
        e.loadCss = function(t) {
            if (t.content) {
                var e = document.createElement("style");
                e.type = "text/css",
                e.styleSheet ? e.styleSheet.cssText = t.content : e.innerHTML = t.content,
                r.appendChild(e)
            } else if (t.url) {
                var n = document.createElement("link");
                n.href = t.url,
                n.rel = "stylesheet",
                n.type = "text/css",
                r.appendChild(n)
            }
        }
        ,
        e.alias = function(t) {
            return t.replace(/\.js$/i, "")
        }
        ,
        e.timeout = 5e3,
        t.__M.define = n,
        t.__M.require = e
    }
}(this);

    “douyin_falcon:node_modules/byted-acrawler/dist/runtime”模組:

__M.define("douyin_falcon:node_modules/byted-acrawler/dist/runtime", function(l, e) {
    Function(function(l) {
        return 'e(e,a,r){(b[e]||(b[e]=t("x,y","x "+e+" y")(r,a)}a(e,a,r){(k[r]||(k[r]=t("x,y","new x[y]("+Array(r+1).join(",x[y]")(1)+")")(e,a)}r(e,a,r){n,t,s={},b=s.d=r?r.d+1:0;for(s["$"+b]=s,t=0;t<b;t)s[n="$"+t]=r[n];for(t=0,b=s=a;t<b;t)s[t]=a[t];c(e,0,s)}c(t,b,k){u(e){v[x]=e}f{g=,ting(bg)}l{try{y=c(t,b,k)}catch(e){h=e,y=l}}for(h,y,d,g,v=[],x=0;;)switch(g=){case 1:u(!)4:f5:u((e){a=0,r=e;{c=a<r;c&&u(e[a]),c}}(6:y=,u((y8:if(g=,lg,g=,y===c)b+=g;else if(y!==l)y9:c10:u(s(11:y=,u(+y)12:for(y=f,d=[],g=0;g<y;g)d[g]=y.charCodeAt(g)^g+y;u(String.fromCharCode.apply(null,d13:y=,h=delete [y]14:59:u((g=)?(y=x,v.slice(x-=g,y:[])61:u([])62:g=,k[0]=65599*k[0]+k[1].charCodeAt(g)>>>065:h=,y=,[y]=h66:u(e(t[b],,67:y=,d=,u((g=).x===c?r(g.y,y,k):g.apply(d,y68:u(e((g=t[b])<"<"?(b--,f):g+g,,70:u(!1)71:n72:+f73:u(parseInt(f,3675:if(){bcase 74:g=<<16>>16g76:u(k[])77:y=,u([y])78:g=,u(a(v,x-=g+1,g79:g=,u(k["$"+g])81:h=,[f]=h82:u([f])83:h=,k[]=h84:!085:void 086:u(v[x-1])88:h=,y=,h,y89:u({e{r(e.y,arguments,k)}e.y=f,e.x=c,e})90:null91:h93:h=0:;default:u((g<<16>>16)-16)}}n=this,t=n.Function,s=Object.keys||(e){a={},r=0;for(c in e)a[r]=c;a=r,a},b={},k={};r'.replace(/[-]/g, function(e) {
            return l[15 & e.charCodeAt(0)]
        })
    }("v[x++]=v[--x]t.charCodeAt(b++)-32function return ))++.substrvar .length(),b+=;break;case ;break}".split("")))()('gr$Daten Иb/s!l y͒yĹg,(lfi~ah`{mv,-n|jqewVxp{rvmmx,&effkx[!cs"l".Pq%widthl"@q&heightl"vr*getContextx$"2d[!cs#l#,*;?|u.|uc{uq$fontl#vr(fillTextx$$龘ฑภ경2<[#c}l#2q*shadowBlurl#1q-shadowOffsetXl#$$limeq+shadowColorl#vr#arcx88802[%c}l#vr&strokex[ c}l"v,)}eOmyoZB]mx[ cs!0s$l$Pb<k7l l!r&lengthb%^l$1+s$jl  s#i$1ek1s$gr#tack4)zgr#tac$! +0o![#cj?o ]!l$b%s"o ]!l"l$b*b^0d#>>>s!0s%yA0s"l"l!r&lengthb<k+l"^l"1+s"jl  s&l&z0l!$ +["cs\'(0l#i\'1ps9wxb&s() &{s)/s(gr&Stringr,fromCharCodes)0s*yWl ._b&s o!])l l Jb<k$.aj;l .Tb<k$.gj/l .^b<k&i"-4j!+& s+yPo!]+s!l!l Hd>&l!l Bd>&+l!l <d>&+l!l 6d>&+l!l &+ s,y=o!o!]/q"13o!l q"10o!],l 2d>& s.{s-yMo!o!]0q"13o!]*Ld<l 4d#>>>b|s!o!l q"10o!],l!& s/yIo!o!].q"13o!],o!]*Jd<l 6d#>>>b|&o!]+l &+ s0l-l!&l-l!i\'1z141z4b/@d<l"b|&+l-l(l!b^&+l-l&zl\'g,)gk}ejo{cm,)|yn~Lij~em["cl$b%@d<l&zl\'l $ +["cl$b%b|&+l-l%8d<@b|l!b^&+ q$sign ', [Object.defineProperty(e, "__esModule", {
        value: !0
    })])
});

    呼叫處:

dycs = __M.require("douyin_falcon:node_modules/byted-acrawler/dist/runtime") ;
signc = dycs.sign(57720812347);
document.write(signc);

    直接Chrome開啟就可以看到了,真的生成了。


    放入介面引數試試看能不能用?


可以看到裡面都是部分的視訊列表封面和視訊點贊資料等等資料。

四、結語

感覺有點標題黨,其實並沒有把整個演算法破解出來,不過既然都已經都到了這個地步了,把演算法破解出來看起來也不是很難而且也沒什麼意思,有點懶,能用就行吧。整個過程好像挺簡單,其實也花了一些時間並沒有寫的這麼順利,本想詳細過程都寫下來。不過都是些基礎操作,懶得寫了。“_M”的定義那塊程式碼,應該是有很多沒有用的。比如document相關的,f函式和n函式。想拿去用的話最好精簡一下吧。

有什麼問題再留言,有空的話回儘量回覆。不過抖音也真是重視反爬,昨天還能拿到視訊播放量,評論數以及各種個人資訊,今天寫Blog的時候突然發現很多資料都沒了,只留下了個點贊數等等對頁面有用的資料而已了,還以為我出了什麼問題。要是大家發現了其他什麼有好玩的資料介面,告訴我一聲。偷偷的~