> 技术文档 > JS逆向 - 滴滴(dd03、dd05)WSGSIG

JS逆向 - 滴滴(dd03、dd05)WSGSIG


文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 小结

概要

提示:仅供学习,不得用做商业交易,如有侵权请及时联系

逆向:JS逆向 - 滴滴(dd03、dd05)WSGSIG

URL(dd03): aHR0cHM6Ly9wYWdlLnVkYWNoZS5jb20vdXQtd2VieC91dC1yZWNoYXJnZS1waG9uZS9vdGhlcnMuaHRtbD9mdXNpb25fZW5hYmxlX29mZl9tb2RlPTEmaGlkZU5hdmlnYXRpb249MiZ4ZW52PWg1JmNmdD1jYXImY3N0PSZkY2huPWRkV3Bqa3gmb3BlbmlkPXVuZGVmaW5lZCZjaXR5SWQ9MCZsYXQ9MCZsbmc9MCZlbnRyYW5jZV9jaGFubmVsPTcyMjc4ODA1Mzcmd2VieF9jbHVzdGVyX2lkPTQzNiZ4X2FjdF9rZXk9dXQtcmVjaGFyZ2UtcGhvbmUtZGVmYXVsdCZ4Yml6PSZwcm9kX2tleT11dC1yZWNoYXJnZS1waG9uZSZ4cHNpZD0yNGFmODNkMTcxMmU0NjcxOTYwMTg2MDUwMzY3N2M4NSZ4b2lkPWU1YmQxMGExLTRmYTMtNGU1Yy04NWIyLTUzYmZmNGRjYzQ5OSZ4c3BtX2Zyb209Jnhwc2lkX3Jvb3Q9MjRhZjgzZDE3MTJlNDY3MTk2MDE4NjA1MDM2NzdjODUmeHBzaWRfZnJvbT0meHBzaWRfc2hhcmU9JmZfeHBzaWQ9MjRhZjgzZDE3MTJlNDY3MTk2MDE4NjA1MDM2NzdjODUmcm9vdF94cHNpZD0yNGFmODNkMTcxMmU0NjcxOTYwMTg2MDUwMzY3N2M4NSZjaGFubmVsX2lkPTcyJTJDMjc4JTJDODA1MzcjL2luZGV4P2hhc2hfcGFzc3BvcnRfbG9naW4=

JS逆向 - 滴滴(dd03、dd05)WSGSIG

URL(dd05):aHR0cHM6Ly9wYXNzcG9ydC5kaWRpY2h1eGluZy5jb20vY29tbW9uL3BjLWxvZ2luL3YzL2luZGV4Lmh0bWwjLw==

JS逆向 - 滴滴(dd03、dd05)WSGSIG

整体架构流程

提示:分析流程

一、dd03、关键字搜索或者堆栈断点都可以

  1. 搜索wsgsig
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
  2. 观察发现加密函数是一个s.getSign
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
  3. 单步进入发现是一个l()方法加密
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
  4. 最后发现它是一个拼接的处理的字符串,有进行md5和base64操作
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
  5. 比较简单,直接扣下来就可以了
    源码:
const CrytpJs = require(\'crypto-js\');function s(t) { for (var e = t.length, n = t.length - 1; n >= 0; n--) { var r = t.charCodeAt(n); r > 127 && r <= 2047 ? e++ : r > 2047 && r <= 65535 && (e += 2), r >= 56320 && r <= 57343 && n-- } return e}var b = Math.floor(new Date / 1e3);var E = \'q{自己去网页拿}\';E += Math.random();var k = CrytpJs.MD5(\"R4doMFFeMNlliIWM\"+E).toString(), T = [{k: \"ts\",v: b}, {k: \"v\",v: \"1\"}, {k: \"os\",v: \"web\"}, {k: \"av\",v: \"02\"}, {k: \"kv\",v: \"0000010001\"}, {k: \"vl\",v: s(E)}, {k: \"sig\",v: k}].map(function(t) {return t.k + \"=\" + t.v}).join(\"&\");function i(t, e) { for (var n = [], r = 0; r < e.length; r++) n[r] = t[r % 4] ^ e.charCodeAt(r); return n = Array.prototype.slice.apply(t).concat(n), String.fromCharCode.apply(null, n)}function r(t) { for (var e = \"ABCDEFG0123456789abcdefgHIJKLMN+/hijklmnOPQRSTopqrstUVWXYZuvwxyz\", n = \"\" + t, r = void 0, i = void 0, o = 0, a = \"\"; n.charAt(0 | o) || (e = \"=\", o % 1); a += e.charAt(63 & r >> 8 - o % 1 * 8)) { if ((i = n.charCodeAt(o += .75)) > 255) throw new Error(\"\'base64\' failed: The string to be encoded contains characters outside of the Latin1 range.\"); r = r << 8 | i } return a}dd03 = \"dd03-\" + r(i(new Uint8Array(new Uint32Array([Math.floor(4294967296 * Math.random())]).buffer), T)).replace(/=*$/, \"\")console.log(dd03)

JS逆向 - 滴滴(dd03、dd05)WSGSIG

二、dd05、一样的关键词搜索或者堆栈断点

  1. 搜索wsgsig断点
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
  2. 发现它是通过Object(it[‘a’])函数加密的,i是一个表单参数、r是表示sign值是否更新
Object(it[\"a\"])({ body: i, noDomainCheck: !0, signUpgrade: r, contentType: \"application/x-www-form-urlencoded\" })

JS逆向 - 滴滴(dd03、dd05)WSGSIG
3. 那我们进入先进入到这个it[‘a’]方法中去观察它是怎么实现的,发现是一个webpack
JS逆向 - 滴滴(dd03、dd05)WSGSIG
4. 往上翻一点点,你会发现它其实是一个jsvmp,那么我们有俩种选择:1、插装纯算。2、扣webpack补环境
JS逆向 - 滴滴(dd03、dd05)WSGSIG
5. 这里我选择补环境吧,纯算有点废时间,大佬可以去纯一下,会到刚刚那个**it[‘a’]**的位置,我们需要知道他是通过那个函数去加载的it,直接搜索it =会发现就在上面
JS逆向 - 滴滴(dd03、dd05)WSGSIG

  1. 到这里,我们就得去重新去刷新网页了,让浏览器去加载到这个地方
 var it = a(\"4bf1\"); wsgsign = Object(it[\"a\"])({ body: i, noDomainCheck: !0, signUpgrade: r, contentType: \"application/x-www-form-urlencoded\" })
  1. 进入到,a函数里面,发现导出加载函数是i函数
    JS逆向 - 滴滴(dd03、dd05)WSGSIG

这里说一个webpack的形式:

!function (所有加载对象) {// 导出函数 function r() { var n = []; // 本地存储,加载一次就不需要加载 if (n[r]) return n[r].exports; var t = n[r] = { i: r, l: !1, exports: {} }; // 加载器 return 所有加载对象[r].call(t.exports, t, t.exports, i), t.l = !0, t.exports } // 导出函数自定义的属性或者方法 r.e = ...; r.m = ....; r.c = ....;}({ // 所有加载对象 \"键名\": \"值函数\", .......});
  1. 所以我们首页需要把r这个导出函数定义到全局,然后去浏览器中拿到,‘4bf1’键名对应的函数
    JS逆向 - 滴滴(dd03、dd05)WSGSIG
window = globalThis;window.导出;}({ // 所有加载对象 \"键名\": \"值函数\", .......});这个上面加上 window.导出 = r这个导出函数
  1. 然后执行window.导出(‘4bf1’),注意导出的时候不只是导出了这一个对象,因为他里面会去加载其他的对象,所以还得去拿其他的对象,不然会报错e[r].call这个加载不起来

  2. 我这里直接就使用自吐了,把4bf1加载的对象全部收集起来,大概有个600多的对象函数

  3. 如果还是不太懂,网上有一堆的webpack自吐教程,自己可以看看,研究研究

  4. 当我们全部扣下来,补完环境发现它的值的位数与浏览器不一致
    JS逆向 - 滴滴(dd03、dd05)WSGSIG

  5. 继续观察浏览器,你会发现,它回去初始化加载其他包signinit

请求载荷:data = { \"diuu\": \"xxx\", \"bizId\": \"xxx\", \"sdkVer\": \"5.1.14\", \"os\": \"4\", \"appVer\": \"v3\" }

请求头:Sign

JS逆向 - 滴滴(dd03、dd05)WSGSIG
JS逆向 - 滴滴(dd03、dd05)WSGSIG
14. 最后你会发现它是从这里进行初始化的
JS逆向 - 滴滴(dd03、dd05)WSGSIG

Object(rt[\"a\"])(Object(y[\"a\"])(Object(y[\"a\"])({}, pt[ot] || pt.default), {}, {  os: \"4\",  appVer: \"v3\",  domainList: [ct],  byQuery: !0,  httpEnable: [\"development\", \"rdtest\", \"wycdev\", \"wycdev01\"].includes(ot) }))
  1. 还是一样的扣webpack

技术名词解释

提示:补环境

  • 挂代理,导包(webpack)
//set不需要打印的属性或者函数set_print = [];//get不需要打印的属性或者函数no_print = [];setProxyArr = function setProxyArr(proxyObjArr) { for (let i = 0; i < proxyObjArr.length; i++) { const handler = `{ get: function(target, property, receiver) { if(no_print.includes(property)){ return target[property]; } dtavm.log(\"方法:\", \"get \", \"对象:\", \"${proxyObjArr[i]}\", \" 属性:\", property, \" 属性类型:\", typeof property, \", 属性值:\", target[property], \", 属性值类型:\", typeof target[property]); return target[property]; }, set: function(target, property, value, receiver) { if(set_print.includes(property)){ return Reflect.set(...arguments); } dtavm.log(\"方法:\", \"set \", \"对象:\", \"${proxyObjArr[i]}\", \" 属性:\", property, \" 属性类型:\", typeof property, \", 属性值:\", value, \", 属性值类型:\", typeof target[property]); return Reflect.set(...arguments); } }`; eval(`try { ${proxyObjArr[i]}; ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler}); } catch (e) { ${proxyObjArr[i]} = {}; ${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler}); }`); }}
  • 保护函数,tostring检测
!(function () { \"use strict\"; const $toString = Function.toString; const myFunction_toString_symbol = Symbol(\'(\'.concat(\'\', \')_\', (Math.random() + \'\').toString(36))); const mytoString = function () { return typeof this == \'function\' && this[myFunction_toString_symbol] || $toString.call(this); }; function set_native(func, key, value) { Object.defineProperty(func, key, { \"enumerable\": false, \"configurable\": true, \"writable\": true, \"value\": value }) }; delete Function.prototype[\'toString\']; set_native(Function.prototype, \"toString\", mytoString); set_native(Function.prototype.toString, myFunction_toString_symbol, \"function toString() { [native code] }\"); this.func_set_native = function (func) { set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol, func.name || \'\'}() { [native code] }`) }}).call(globalThis);
  • 检测点document.all、navigator.plugins原型链和window函数
createTagProto(\'HTMLAllCollection\');const v8 = require_(\'v8\');const vm=require_(\'vm\');v8.setFlagsFromString(\'--allow-natives-syntax\');let undetectable = vm.runInThisContext(\"%GetUndetectable()\");v8.setFlagsFromString(\'--no-allow-natives-syntax\');all = undetectable;all.__proto__ = HTMLAllCollection.prototype;all.length = xx;createTagProto(\'PromiseRejectionEvent\');createTagProto(\'MutationObserver\');createTagProto(\'CSSStyleDeclaration\');createTagProto(\'CSSRuleList\');createTagProto(\'DOMRectList\');createTagProto(\'DOMStringList\');createTagProto(\'DataTransferItemList\');createTagProto(\'FileList\');createTagProto(\'HTMLCollection\');createTagProto(\'HTMLFormElement\');createTagProto(\'HTMLSelectElement\');createTagProto(\'MediaList\');createTagProto(\'MimeTypeArray\');createTagProto(\'NamedNodeMap\');createTagProto(\'NodeList\');createTagProto(\'SVGLengthList\');createTagProto(\'SVGNumberList\');createTagProto(\'SVGPointList\');createTagProto(\'SVGStringList\');createTagProto(\'SVGTransformList\');createTagProto(\'SourceBufferList\');createTagProto(\'StyleSheetList\');createTagProto(\'TextTrackCueList\');createTagProto(\'TextTrackList\');createTagProto(\'TouchList\');createTagProto(\'DOMTokenList\');DOMTokenList.prototype[Symbol.iterator] = function values() {}DOMTokenList.prototype[Symbol.iterator].toString = function toString() {}DOMTokenList.prototype.values = function values() {}DOMTokenList.prototype.keys = function keys() {}DOMTokenList.prototype.entries = function entries() {}DOMTokenList.prototype.forEach = function forEach() {}window.func_set_native(DOMTokenList.prototype.values);window.func_set_native(DOMTokenList.prototype.keys);window.func_set_native(DOMTokenList.prototype.entries);window.func_set_native(DOMTokenList.prototype.forEach);

JS逆向 - 滴滴(dd03、dd05)WSGSIG

小结

提示:学习交流主页,星球持续更新中:链接https://t.zsxq.com/AJTw2(+星球主页+v)