首頁>技術>

今天繼續跟蹤某招標網站的反扒流程,利用 JS 的單步除錯功能,成功定位到了 ajax 傳送請求前對 URL 偷樑換柱的地方,也是一大進展。

條件斷點和堆疊定位

之前可以斷定就是 ajax 請求中存在鉤子事件,導致請求 URL 引數變化的,但一直沒找到證據。偷學到一些 JS 逆向技巧之後,利用條件斷點和堆疊呼叫鏈,終於定位到了。

第一步,在 Sources 右側除錯面板中,開啟 Ajax 任意請求斷點:

利用堆疊鏈,倒推檢視呼叫方,是 ajax 的 send 方法:

這個 send 方法並沒有修改 URL 引數,所以繼續在前面 g.open 那裡打斷點,它解釋的函式最終完成了對 URL 引數的重置邏輯。

注意:open 和 send 之前呼叫的方法,是動態變動的,每一次請求後這個函式名稱也會變化,這裡是 _$zh ,後面就變成其他了套路如此深,讓我等小白只能望而卻步!

重寫 ajax 的 open

前面利用條件斷點後,再單步除錯跟蹤,最終找到了 ajax 傳送之前修改 URL 路徑的方法,繼續分析它的流程。

首先,網站的 send 方法存在鉤子,在 ajax 的傳送邏輯中,open 被解釋為另一個函式【網頁每次重新整理,該函式名稱都會變化】:

第二步,繼續定位到 _$eg 函式定義的地方:

第三步,檢視它的程式碼

function _$eg() {    _$6f();    var _$Rc = _$ep(arguments[1]);    arguments[1] = _$Rc._$s3;    this._$Wl = _$Rc._$Wl;    return _$UA[_$uT[43]](this, arguments);}

當心,這裡存在障眼法,所見的 _6f() 函式並不是真實的函式,它被解釋為:

在當前 JS 片段中搜索 _$CU 函式定義:

function _$CU() {    var _$lh = [65];    Array.prototype.push.apply(_$lh, arguments);    return _$wV.apply(this, _$lh);}

繼續追 _$wV 是一堆很長的混淆 JS ,它並沒有影響請求引數,暫時不管它。

修改 URL 的地方

後面那句 var _$Rc = _$ep(arguments[1]) 函式呼叫後,ajax 的請求的 URL 就變化了,增加了兩個額外引數:

定位到這個方法:

function _$ep(_$SZ, _$uA) {      var _$G_, _$uG = null;      var _$Rc = _$SZ;      function _$kw(_$Mj, _$jU) {          var _$Rc = [];          var _$fL = '';          var _$nC = _$Fm(_$Q5());          _$Rc = _$Rc[_$uT[4]](_$jU, _$Mj, _$uA || 0, _$nC);          var _$eg = _$5Z(743, 6, true, _$Rc);          var _$x$ = _$EJ + _$eg;          _$uG = _$hx(_$4T(_$x$), 2);          return _$aW[_$uT[9]](_$fL, _$3a, _$uT[3], _$x$);      }      function _$fL() {          try {              if (typeof _$SZ !== _$uT[6])                  _$SZ += '';              _$G_ = _$Vr(_$SZ);              if (_$O0) {                  _$SZ = _$RJ(_$SZ, _$G_);              }          } catch (_$Rc) {              return;          }          if (_$G_ === null || _$G_._$R9 >= 4) {              _$5Z(773, 6);              return;          }          if (_$8H(_$G_)) {              _$5Z(773, 6);              return;          }          _$SZ = _$G_._$Sy + _$G_._$lJ;          var _$fL = _$Rf(_$G_);          var _$nC = _$fL ? _$uT[7] + _$fL : '';          var _$eg = _$3f(_$91(_$nZ(_$G_._$$G + _$nC)));          var _$x$ = 0;          if (_$G_._$_B) {              _$x$ |= 1;          }          _$SZ += _$uT[7] + _$kw(_$x$, _$eg, _$uA);          if (_$fL.length > 0) {              if (_$HV && _$HV <= 8) {                  _$SZ = _$s9(_$SZ);              }              if (!(_$Zu & 1024)) {                  _$fL = _$s9(_$fL);              }              _$fL = _$uT[62] + _$E6(_$fL, _$uG, 4);          }          _$SZ += _$fL;      }      function _$nC(_$Mj) {          _$40(2, _$nP(5));          if (_$uG === null || _$hS(_$G_) === false) {              return _$Mj;          }          if (typeof _$Mj === _$uT[6] || typeof _$Mj === _$uT[615] || typeof _$Mj === _$uT[77]) {              _$Mj = _$E6(_$Mj, _$uG, 5);          }          return _$Mj;      }      function _$eg(_$Mj, _$jU) {          if ((_$Mj === 'get' || _$Mj === _$uT[247]) && (_$yA & 1) && (_$Zu & 8192) && !(_$G_ && (_$G_._$R9 >= 5 || _$G_._$_B))) {              if (_$jU === _$Xm || _$jU === null || _$jU === '')                  _$jU = _$uT[299];              if (_$jU === _$uT[299]) {                  return _$jU;              }          }          return '';      }      _$fL();      return {          _$7W: _$Rc,          _$s3: _$SZ,          _$Wl: _$nC,          _$Wm: _$eg      };}

跟到這裡真的是無能為力了,這一堆不明所以的 JS ,可能就是傳說中利用凱撒密碼混淆過的,下一步的研究方向就是用 AST 語法把它們還原。

可能這個邏輯中存在時間戳資訊。

第二,直接呼叫一下 open 之前那個修改 URL 的函式,可以拿到後面的引數:

理論上逆向解釋出上面這段 JS ,用 Java 實現這個 return 語句得到修正後的 URL ,就可以解決反扒問題了。難點在於怎麼用程式碼在模擬 ajax 請求之前定位到當前頁面返回的這個 open 鉤子函式呢?人家可是動態生成的啊,還是得解密上面那段鉤子函式所在的 JS 片段。

說實話,這個可比上一篇介紹的無限 debugger 手段高明多了,就算知道能除錯,但實際上卻是一本無字天書!神吶,救救我吧!

12
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 不會開發Maven外掛(plugin)?我來幫你梳理內容