文章目录
-
- 概要
- 整体架构流程
- 技术名词解释
- 小结
概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系
逆向:JS逆向 - 滴滴(dd03、dd05)WSGSIG
URL(dd03): aHR0cHM6Ly9wYWdlLnVkYWNoZS5jb20vdXQtd2VieC91dC1yZWNoYXJnZS1waG9uZS9vdGhlcnMuaHRtbD9mdXNpb25fZW5hYmxlX29mZl9tb2RlPTEmaGlkZU5hdmlnYXRpb249MiZ4ZW52PWg1JmNmdD1jYXImY3N0PSZkY2huPWRkV3Bqa3gmb3BlbmlkPXVuZGVmaW5lZCZjaXR5SWQ9MCZsYXQ9MCZsbmc9MCZlbnRyYW5jZV9jaGFubmVsPTcyMjc4ODA1Mzcmd2VieF9jbHVzdGVyX2lkPTQzNiZ4X2FjdF9rZXk9dXQtcmVjaGFyZ2UtcGhvbmUtZGVmYXVsdCZ4Yml6PSZwcm9kX2tleT11dC1yZWNoYXJnZS1waG9uZSZ4cHNpZD0yNGFmODNkMTcxMmU0NjcxOTYwMTg2MDUwMzY3N2M4NSZ4b2lkPWU1YmQxMGExLTRmYTMtNGU1Yy04NWIyLTUzYmZmNGRjYzQ5OSZ4c3BtX2Zyb209Jnhwc2lkX3Jvb3Q9MjRhZjgzZDE3MTJlNDY3MTk2MDE4NjA1MDM2NzdjODUmeHBzaWRfZnJvbT0meHBzaWRfc2hhcmU9JmZfeHBzaWQ9MjRhZjgzZDE3MTJlNDY3MTk2MDE4NjA1MDM2NzdjODUmcm9vdF94cHNpZD0yNGFmODNkMTcxMmU0NjcxOTYwMTg2MDUwMzY3N2M4NSZjaGFubmVsX2lkPTcyJTJDMjc4JTJDODA1MzcjL2luZGV4P2hhc2hfcGFzc3BvcnRfbG9naW4=

URL(dd05):aHR0cHM6Ly9wYXNzcG9ydC5kaWRpY2h1eGluZy5jb20vY29tbW9uL3BjLWxvZ2luL3YzL2luZGV4Lmh0bWwjLw==

整体架构流程
提示:分析流程
一、dd03、关键字搜索或者堆栈断点都可以
- 搜索wsgsig
- 观察发现加密函数是一个s.getSign
- 单步进入发现是一个l()方法加密
- 最后发现它是一个拼接的处理的字符串,有进行md5和base64操作
- 比较简单,直接扣下来就可以了
源码:
javascript
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)

二、dd05、一样的关键词搜索或者堆栈断点
- 搜索wsgsig断点
- 发现它是通过Object(it['a'])函数加密的,i是一个表单参数、r是表示sign值是否更新
javascript
Object(it["a"])({
body: i,
noDomainCheck: !0,
signUpgrade: r,
contentType: "application/x-www-form-urlencoded"
})

-
那我们进入先进入到这个it['a']方法中去观察它是怎么实现的,发现是一个webpack
-
往上翻一点点,你会发现它其实是一个jsvmp,那么我们有俩种选择:1、插装纯算。2、扣webpack补环境
-
这里我选择补环境吧,纯算有点废时间,大佬可以去纯一下,会到刚刚那个**it['a']**的位置,我们需要知道他是通过那个函数去加载的it,直接搜索it =会发现就在上面
-
到这里,我们就得去重新去刷新网页了,让浏览器去加载到这个地方
javascript
var it = a("4bf1");
wsgsign = Object(it["a"])({
body: i,
noDomainCheck: !0,
signUpgrade: r,
contentType: "application/x-www-form-urlencoded"
})
- 进入到,a函数里面,发现导出加载函数是i函数
这里说一个webpack的形式:
javascript
!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 = ....;
}({
// 所有加载对象
"键名": "值函数",
.......
});
- 所以我们首页需要把r这个导出函数定义到全局,然后去浏览器中拿到,'4bf1'键名对应的函数
javascript
window = globalThis;
window.导出;
}({
// 所有加载对象
"键名": "值函数",
.......
});这个上面加上 window.导出 = r这个导出函数
-
然后执行window.导出('4bf1'),注意导出的时候不只是导出了这一个对象,因为他里面会去加载其他的对象,所以还得去拿其他的对象,不然会报错e[r].call这个加载不起来
-
我这里直接就使用自吐了,把4bf1加载的对象全部收集起来,大概有个600多的对象函数
-
如果还是不太懂,网上有一堆的webpack自吐教程,自己可以看看,研究研究
-
当我们全部扣下来,补完环境发现它的值的位数与浏览器不一致
-
继续观察浏览器,你会发现,它回去初始化加载其他包signinit
请求载荷:
data = { "diuu": "xxx", "bizId": "xxx", "sdkVer": "5.1.14", "os": "4", "appVer": "v3" }
请求头:Sign
- 最后你会发现它是从这里进行初始化的
javascript
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)
}))
- 还是一样的扣webpack
技术名词解释
提示:补环境
- 挂代理,导包(webpack)
javascript
//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检测
javascript
!(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函数
javascript
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);

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