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

文章目录

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

概要

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

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

URL(dd05):aHR0cHM6Ly9wYXNzcG9ydC5kaWRpY2h1eGluZy5jb20vY29tbW9uL3BjLWxvZ2luL3YzL2luZGV4Lmh0bWwjLw==

整体架构流程

提示:分析流程

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

  1. 搜索wsgsig
  2. 观察发现加密函数是一个s.getSign
  3. 单步进入发现是一个l()方法加密
  4. 最后发现它是一个拼接的处理的字符串,有进行md5和base64操作
  5. 比较简单,直接扣下来就可以了
    源码:
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、一样的关键词搜索或者堆栈断点

  1. 搜索wsgsig断点
  2. 发现它是通过Object(it['a'])函数加密的,i是一个表单参数、r是表示sign值是否更新
javascript 复制代码
Object(it["a"])({
     body: i,
     noDomainCheck: !0,
     signUpgrade: r,
     contentType: "application/x-www-form-urlencoded"
 })
  1. 那我们进入先进入到这个it['a']方法中去观察它是怎么实现的,发现是一个webpack

  2. 往上翻一点点,你会发现它其实是一个jsvmp,那么我们有俩种选择:1、插装纯算。2、扣webpack补环境

  3. 这里我选择补环境吧,纯算有点废时间,大佬可以去纯一下,会到刚刚那个**it['a']**的位置,我们需要知道他是通过那个函数去加载的it,直接搜索it =会发现就在上面

  4. 到这里,我们就得去重新去刷新网页了,让浏览器去加载到这个地方

javascript 复制代码
 var it = a("4bf1");
 wsgsign = Object(it["a"])({
     body: i,
     noDomainCheck: !0,
     signUpgrade: r,
     contentType: "application/x-www-form-urlencoded"
 })
  1. 进入到,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 = ....;
}({
    // 所有加载对象
    "键名": "值函数",
    .......
});
  1. 所以我们首页需要把r这个导出函数定义到全局,然后去浏览器中拿到,'4bf1'键名对应的函数
javascript 复制代码
window = globalThis;
window.导出;
}({
    // 所有加载对象
    "键名": "值函数",
    .......
});这个上面加上 window.导出 = r这个导出函数
  1. 然后执行window.导出('4bf1'),注意导出的时候不只是导出了这一个对象,因为他里面会去加载其他的对象,所以还得去拿其他的对象,不然会报错e[r].call这个加载不起来

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

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

  4. 当我们全部扣下来,补完环境发现它的值的位数与浏览器不一致

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

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


  1. 最后你会发现它是从这里进行初始化的
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)
                }))
  1. 还是一样的扣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)

相关推荐
yume_sibai5 分钟前
Vue 生命周期
前端·javascript·vue.js
学习的学习者15 分钟前
CS课程项目设计4:支持AI人机对战的五子棋游戏
人工智能·python·深度学习·五子棋
讨厌吃蛋黄酥22 分钟前
🌟 React Router Dom 终极指南:二级路由与 Outlet 的魔法之旅
前端·javascript
LeoSpud28 分钟前
# 🚀 如何在公司正确配置 Miniconda + conda-forge(避免 Anaconda 商业限制)
python
是小崔啊1 小时前
【爬虫】06 - 自动化爬虫selenium
爬虫·selenium·自动化
一晌小贪欢1 小时前
Python100个库分享第38个—lxml(爬虫篇)
爬虫·python·python爬虫·lxml·python库分享
用户1437729245611 小时前
标题专项行动期恶意邮件泛滥?AiPy监测工具来帮忙,快速识别超省心!
人工智能·python
秋难降1 小时前
聊聊广度优先搜索~~~
python·算法
每天都能睁开眼1 小时前
从零开始用 Python 爬取网页:初学者的实践指南
python
alim20121 小时前
图论基本算法
python·算法·图论