某网站心跳包参数加密的wasm分析

11 篇文章 7 订阅

js层动态分析

网站地址:aHR0cHM6Ly9saXZlLmJpbGliaWxpLmNvbS8=

首先打开任意直播,然后进行抓包
在这里插入图片描述
这里可以看到,s参数就是加密的,不多说,直接下个XHR断点
在这里插入图片描述
这时s参数已经生成,发现有很多的异步,不要紧,一个一个调用堆栈往前找

在这里插入图片描述
在找到到这个调用堆栈的时候,这个函数名称引起了我的注意,在这行下一个断点,然后继续让代码执行

在这里插入图片描述
断点再次断下时,发现是调用的上面的函数,继续在关键的callbacks.sign处下断点
在这里插入图片描述
callbacks.sign来到这里继续在t.sign下断点

在这里插入图片描述

来到这里进行单步调试,可以发现r.spyder就是计算签名的函数,在控制台尝试运行一下,然后继续跟进去

在这里插入图片描述

在这里插入图片描述

这个名称,很明显就是调用了wasm,抓包中搜索wasm

在这里插入图片描述

搜索到有两个wasm,那么就在wasm的文本格式中继续搜索spyder这个关键词,因为这个是导出函数,一定会出现在wasm的文本格式中

在这里插入图片描述
其中一个可以搜索到结果,样品地址:aHR0cHM6Ly9pMC5oZHNsYi5jb20vYmZzL2xpdmUvZTc5MTU1NjcwNmY4OGQ4OGI0ODQ2YTYxYTU4M2IzMWRiMDA3ZjgzZC53YXNt

nodejs调用wasm与绕过dom环境检测

这篇文章将不直接分析算法,而是先尝试使用nodejs调用wasm的方式来获取结果

一般的加载顺序是先找到导入函数,然后加载wasm,最后获取导出函数

在这里插入图片描述

导入函数直接白给,那么就复制粘贴好了,初步代码如下


const fs = require('fs');
let wasmfilename = 'bilibili2.wasm';


var importObject = {
    env: {
        __cargo_web_snippet_0d39c013e2144171d64e2fac849140a7e54c939a: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.location)
        },
        __cargo_web_snippet_0f503de1d61309643e0e13a7871406891e3691c9: function (r) {
            e.STDWEB_PRIVATE.from_js(r, window)
        },
        __cargo_web_snippet_10f5aa3985855124ab83b21d4e9f7297eb496508: function (r) {
            return e.STDWEB_PRIVATE.acquire_js_reference(r) instanceof Array | 0
        },
        __cargo_web_snippet_2b0b92aee0d0de6a955f8e5540d7923636d951ae: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.origin,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_461d4581925d5b0bf583a3b445ed676af8701ca6: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.host,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_4c895ac2b754e5559c1415b6546d672c58e29da6: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.protocol,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_614a3dd2adb7e9eac4a0ec6e59d37f87e0521c3b: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.error)
        },
        __cargo_web_snippet_62ef43cf95b12a9b5cdec1639439c972d6373280: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.childNodes)
        },
        __cargo_web_snippet_6fcce0aae651e2d748e085ff1f800f87625ff8c8: function (r) {
            e.STDWEB_PRIVATE.from_js(r, document)
        },
        __cargo_web_snippet_7ba9f102925446c90affc984f921f414615e07dd: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.body)
        },
        __cargo_web_snippet_80d6d56760c65e49b7be8b6b01c1ea861b046bf0: function (r) {
            e.STDWEB_PRIVATE.decrement_refcount(r)
        },
        __cargo_web_snippet_897ff2d0160606ea98961935acb125d1ddbf4688: function (r) {
            var t = e.STDWEB_PRIVATE.acquire_js_reference(r);
            return t instanceof DOMException && "SecurityError" === t.name
        },
        __cargo_web_snippet_8c32019649bb581b1b742eeedfc410e2bedd56a6: function (r, t) {
            var n = e.STDWEB_PRIVATE.acquire_js_reference(r);
            e.STDWEB_PRIVATE.serialize_array(t, n)
        },
        __cargo_web_snippet_a466a2ab96cd77e1a77dcdb39f4f031701c195fc: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.pathname,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_ab05f53189dacccf2d365ad26daa407d4f7abea9: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.value)
        },
        __cargo_web_snippet_b06dde4acf09433b5190a4b001259fe5d4abcbc2: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.success)
        },
        __cargo_web_snippet_b33a39de4ca954888e26fe9caa277138e808eeba: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.length)
        },
        __cargo_web_snippet_cdf2859151791ce4cad80688b200564fb08a8613: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.href,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_e8ef87c41ded1c10f8de3c70dea31a053e19747c: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, function () {
                    try {
                        return {
                            value: t.hostname,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_e9638d6405ab65f78daf4a5af9c9de14ecf1e2ec: function (r) {
            r = e.STDWEB_PRIVATE.to_js(r),
                e.STDWEB_PRIVATE.unregister_raw_value(r)
        },
        __cargo_web_snippet_ff5103e6cc179d13b4c7a785bdce2708fd559fc0: function (r) {
            e.STDWEB_PRIVATE.tmp = e.STDWEB_PRIVATE.to_js(r)
        },
        __web_on_grow: A
    }
};

var wasmobject = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array(fs.readFileSync(wasmfilename))), importObject);
console.log(wasmobject);

直接运行发现报错
在这里插入图片描述

那就直接给个空函数


const fs = require('fs');
let wasmfilename = 'bilibili2.wasm';


var __fun = function(){};

var importObject = {
    env: {
        __cargo_web_snippet_0d39c013e2144171d64e2fac849140a7e54c939a: function (r, t) {
            t = e.STDWEB_PRIVATE.to_js(t),
                e.STDWEB_PRIVATE.from_js(r, t.location)
        },
        /*省略重复的代码*/
        __web_on_grow: __fun
    }
};

var wasmobject = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array(fs.readFileSync(wasmfilename))), importObject);
var wasmmemory = wasmobject.exports.memory;
console.log(wasmobject);
console.log(wasmmemory);

这时已经可以加载成功,并且成功获取内存

在这里插入图片描述

然后就是根据js的逻辑,来调用wasm即可。不过这个wasm有两个坑,一个是数据类型的处理,另一个是dom环境的检测

第一点:在prepare_any_arg函数里面有个from_js函数
在这里插入图片描述
这里可以看到对传进来的数据类型不同,会做不同的处理。例如字符串的类型是4,数值的类型是2或者3,null的类型为1,void 0 的类型为0,布尔值为5或者6,以及其他类型,所以要改写一下js处理数据的逻辑,同时修改倒数函数中的函数名,下面是数据处理的相关函数

var to_js = function (r) {
    var t = (new Uint8Array(wasmmemory.buffer))[r + 12];
    if (t !== 0){
        if(t === 1){
            return null;
        }else if(t === 2){
            return (new Int32Array(wasmmemory.buffer))[r / 4];
        }else if(t === 3){
            return (new Float64Array(wasmmemory.buffer))[r / 8];
        }else if(t === 4){
            var _ = (new Uint32Array(wasmmemory.buffer))[r / 4]
                , n = (new Uint32Array(wasmmemory.buffer))[(r + 4) / 4];
            return to_js_string(_, n)
        }else if(t === 5){
            return !1;
        }else if(t === 6){
            return !0;
        }else if(t === 7){
            console.log('返回数组。未实现')
        }else if(t === 8){
            console.log('返回对象。未实现')
        }else if(t === 9){
            return id_to_ref_map[(new Int32Array(wasmmemory.buffer))[r / 4]]
        }else {
            console.log('返回其他。未实现')
        }
    }

};

var to_js_string = function (r, _) {
    return (new Buffer.from((new Uint8Array(wasmmemory.buffer)).subarray(r, r + _))).toString()
};

var to_utf8_string = function (t, _) {
    var n = new Uint8Array(new Buffer.from(_, 'utf8'));
    var a = n.length;
    var c = wasmobject.exports.__web_malloc(a);
    var R = new Uint8Array(wasmmemory.buffer, c, a);
    R.set(n);
    (new Uint32Array(wasmmemory.buffer))[t / 4] = c;
    (new Uint32Array(wasmmemory.buffer))[(t + 4) / 4] = a;
};

var acquire_rust_reference = function (r) {
    var c = last_refid++;
    id_to_ref_map[c] = r;
    return c
};

var serialize_array = function (r, t) {
    var _ = t.length
        , n = wasmobject.exports.__web_malloc(16 * _);
    (new Uint8Array(wasmmemory.buffer))[r + 12] = 7;
    (new Uint32Array(wasmmemory.buffer))[r / 4] = n;
    (new Uint32Array(wasmmemory.buffer))[(r + 4) / 4] = _;
    for (var a = 0; a < _; ++a)
        from_js(n + 16 * a, t[a])
};


var from_js = function (r, t) {
    var _ = Object.prototype.toString.call(t);
    if ("[object String]" === _){
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 4;
        to_utf8_string(r, t);
    }
    else if ("[object Number]" === _)
        t === (0 | t) ? ((new Uint8Array(wasmmemory.buffer))[r + 12] = 2,
            (new Int32Array(wasmmemory.buffer))[r / 4] = t) : ((new Uint8Array(wasmmemory.buffer))[r + 12] = 3,
            (new Float64Array(wasmmemory.buffer))[r / 8] = t);
    else if (null === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 1;
    else if (void 0 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 0;
    else if (!1 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 5;
    else if (!0 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 6;
    else if ("[object Symbol]" === _) {
        var n = register_raw_value(t);
        e.HEAPU8[r + 12] = 15,
            e.HEAP32[r / 4] = n
    } else {
        var a = acquire_rust_reference(t);
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 9;
        (new Int32Array(wasmmemory.buffer))[r / 4] = a;
    }
};

var prepare_any_arg = function(r){
    var t = wasmobject.exports.__web_malloc(16);
    from_js(t, r);
    return t
};

第二点:然后设置参数尝试进行调用

var arge1 = '{"id":"[3,163,13,5887574]","device":"[\\"AUTO1716277899447614\\",\\"3fc2a589-9cb7-42bf-85c9-c2af590c2fad\\"]","ets":1627808068,"benchmark":"seacasdgyijfhofiuxoannn","time":60,"ts":1627808222759,"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4580.0 Safari/537.36"}';
var arge2 = new Array();
arge2.push(2);
arge2.push(5);
arge2.push(1);
arge2.push(4);

var wasmr = prepare_any_arg(arge1);
var wasmt = prepare_any_arg(arge2);
console.log(wasmr);
console.log(wasmt);
wasmobject.exports.spyder.apply(null, [wasmr, wasmt]);

在这里插入图片描述
此时可以发现其对bom和dom都有检测,这个问题不大,简单的补头就可以解决,报错什么就补什么

window = {
    location: {
        host: "live.bilibili.com",
        hostname: "live.bilibili.com",
        href: "https://live.bilibili.com/",
        origin: "https://live.bilibili.com",
        pathname: "/blanc/",
        protocol: "https:"
    }
};

document = {
    body: {
        childNodes: [0]
    }
};

加上上面的代码,就可以绕过检测,最终的完整代码


const fs = require('fs');
let wasmfilename = 'bilibili2.wasm';

window = {
    location: {
        host: "live.bilibili.com",
        hostname: "live.bilibili.com",
        href: "https://live.bilibili.com/",
        origin: "https://live.bilibili.com",
        pathname: "/blanc/",
        protocol: "https:"
    }
};

document = {
    body: {
        childNodes: [0]
    }
};


var tmp;
var id_to_ref_map = {};
var last_refid = 1;

var __fun = function(){};

var importObject = {
    env: {
        __cargo_web_snippet_0d39c013e2144171d64e2fac849140a7e54c939a: function(r, t) {
            t = to_js(t);
            from_js(r, t.location)
        },
        __cargo_web_snippet_0f503de1d61309643e0e13a7871406891e3691c9: function(r) {
            from_js(r, window)
        },
        __cargo_web_snippet_10f5aa3985855124ab83b21d4e9f7297eb496508: function(r) {
            return id_to_ref_map[r] instanceof Array | 0;
        },
        __cargo_web_snippet_2b0b92aee0d0de6a955f8e5540d7923636d951ae: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.origin,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_461d4581925d5b0bf583a3b445ed676af8701ca6: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.host,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_4c895ac2b754e5559c1415b6546d672c58e29da6: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.protocol,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_614a3dd2adb7e9eac4a0ec6e59d37f87e0521c3b: __fun,
        __cargo_web_snippet_62ef43cf95b12a9b5cdec1639439c972d6373280: function(r, t) {
            t = to_js(t),
                from_js(r, t.childNodes)
        },
        __cargo_web_snippet_6fcce0aae651e2d748e085ff1f800f87625ff8c8: function(r) {
            from_js(r, document)
        },
        __cargo_web_snippet_7ba9f102925446c90affc984f921f414615e07dd: function(r, t) {
            t = to_js(t),
                from_js(r, t.body)
        },
        __cargo_web_snippet_80d6d56760c65e49b7be8b6b01c1ea861b046bf0: __fun,
        __cargo_web_snippet_897ff2d0160606ea98961935acb125d1ddbf4688: __fun,
        __cargo_web_snippet_8c32019649bb581b1b742eeedfc410e2bedd56a6: function(r, t) {
            var _ = id_to_ref_map[r];
            serialize_array(t, _);
        },
        __cargo_web_snippet_a466a2ab96cd77e1a77dcdb39f4f031701c195fc: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.pathname,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_ab05f53189dacccf2d365ad26daa407d4f7abea9: function(r, t) {
            t = to_js(t),
                from_js(r, t.value)
        },
        __cargo_web_snippet_b06dde4acf09433b5190a4b001259fe5d4abcbc2: function(r, t) {
            t = to_js(t),
                from_js(r, t.success)
        },
        __cargo_web_snippet_b33a39de4ca954888e26fe9caa277138e808eeba: function(r, t) {
            t = to_js(t),
                from_js(r, t.length)
        },
        __cargo_web_snippet_cdf2859151791ce4cad80688b200564fb08a8613: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.href,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_e8ef87c41ded1c10f8de3c70dea31a053e19747c: function(r, t) {
            t = to_js(t),
                from_js(r, function() {
                    try {
                        return {
                            value: t.hostname,
                            success: !0
                        }
                    } catch (e) {
                        return {
                            error: e,
                            success: !1
                        }
                    }
                }())
        },
        __cargo_web_snippet_e9638d6405ab65f78daf4a5af9c9de14ecf1e2ec: __fun,
        __cargo_web_snippet_ff5103e6cc179d13b4c7a785bdce2708fd559fc0: function(r) {
            tmp = to_js(r)
        },
        __web_on_grow: __fun
    }
};

var wasmobject = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array(fs.readFileSync(wasmfilename))), importObject);
var wasmmemory = wasmobject.exports.memory;

var to_js = function (r) {
    var t = (new Uint8Array(wasmmemory.buffer))[r + 12];
    if (t !== 0){
        if(t === 1){
            return null;
        }else if(t === 2){
            return (new Int32Array(wasmmemory.buffer))[r / 4];
        }else if(t === 3){
            return (new Float64Array(wasmmemory.buffer))[r / 8];
        }else if(t === 4){
            var _ = (new Uint32Array(wasmmemory.buffer))[r / 4]
                , n = (new Uint32Array(wasmmemory.buffer))[(r + 4) / 4];
            return to_js_string(_, n)
        }else if(t === 5){
            return !1;
        }else if(t === 6){
            return !0;
        }else if(t === 7){
            console.log('返回数组。未实现')
        }else if(t === 8){
            console.log('返回对象。未实现')
        }else if(t === 9){
            return id_to_ref_map[(new Int32Array(wasmmemory.buffer))[r / 4]]
        }else {
            console.log('返回其他。未实现')
        }
    }

};

var to_js_string = function (r, _) {
    return (new Buffer.from((new Uint8Array(wasmmemory.buffer)).subarray(r, r + _))).toString()
};

var to_utf8_string = function (t, _) {
    var n = new Uint8Array(new Buffer.from(_, 'utf8'));
    var a = n.length;
    var c = wasmobject.exports.__web_malloc(a);
    var R = new Uint8Array(wasmmemory.buffer, c, a);
    R.set(n);
    (new Uint32Array(wasmmemory.buffer))[t / 4] = c;
    (new Uint32Array(wasmmemory.buffer))[(t + 4) / 4] = a;
};

var acquire_rust_reference = function (r) {
    var c = last_refid++;
    id_to_ref_map[c] = r;
    return c
};

var serialize_array = function (r, t) {
    var _ = t.length
        , n = wasmobject.exports.__web_malloc(16 * _);
    (new Uint8Array(wasmmemory.buffer))[r + 12] = 7;
    (new Uint32Array(wasmmemory.buffer))[r / 4] = n;
    (new Uint32Array(wasmmemory.buffer))[(r + 4) / 4] = _;
    for (var a = 0; a < _; ++a)
        from_js(n + 16 * a, t[a])
};


var from_js = function (r, t) {
    var _ = Object.prototype.toString.call(t);
    if ("[object String]" === _){
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 4;
        to_utf8_string(r, t);
    }
    else if ("[object Number]" === _)
        t === (0 | t) ? ((new Uint8Array(wasmmemory.buffer))[r + 12] = 2,
            (new Int32Array(wasmmemory.buffer))[r / 4] = t) : ((new Uint8Array(wasmmemory.buffer))[r + 12] = 3,
            (new Float64Array(wasmmemory.buffer))[r / 8] = t);
    else if (null === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 1;
    else if (void 0 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 0;
    else if (!1 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 5;
    else if (!0 === t)
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 6;
    else if ("[object Symbol]" === _) {
        var n = register_raw_value(t);
        e.HEAPU8[r + 12] = 15,
            e.HEAP32[r / 4] = n
    } else {
        var a = acquire_rust_reference(t);
        (new Uint8Array(wasmmemory.buffer))[r + 12] = 9;
        (new Int32Array(wasmmemory.buffer))[r / 4] = a;
    }
};

var prepare_any_arg = function(r){
    var t = wasmobject.exports.__web_malloc(16);
    from_js(t, r);
    return t
};


var arge1 = '{"id":"[3,163,13,5887574]","device":"[\\"AUTO1716277899447614\\",\\"3fc2a589-9cb7-42bf-85c9-c2af590c2fad\\"]","ets":1627808068,"benchmark":"seacasdgyijfhofiuxoannn","time":60,"ts":1627808222759,"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4580.0 Safari/537.36"}';
var arge2 = new Array();
arge2.push(2);
arge2.push(5);
arge2.push(1);
arge2.push(4);

var wasmr = prepare_any_arg(arge1);
var wasmt = prepare_any_arg(arge2);

wasmobject.exports.spyder.apply(null, [wasmr, wasmt]);

console.log(tmp);

在这里插入图片描述
这时已经可以得到结果,经测试与浏览器计算结果一致

IDA分析与python算法还原

关于wasm转o文件的操作在本篇就忽略了,详细内容参考上一篇:https://www.52pojie.cn/thread-1461335-1-1.html

在这里插入图片描述
IDA打开处理好的o文件,找到spyder方法,进入伪代码,函数的开头就出现了熟悉的case,没错,这个就是在js层设置的各种数据类型对应的数字。但是这个不太要管,根据前面nodejs调用wasm可知,前面会有一大段检测环境的代码,我们应该跳过这段检测的代码后再分析,进入图标概括,如下图

在这里插入图片描述
在这里插入图片描述
点击这一个块,然后再f5
在这里插入图片描述
在这里插入图片描述

一进去答案就出来了,连函数名都没有混淆,简直是白给
因为v160是小于等于5的,所以可以得出如下结论

数值算法
0hmac_md5
1hmac_sha1
2hmac_sha256
3hmac_sha224
4hmac_sha512
5hmac_sha384

既然都是hmac的算法,那么只要得到密钥的需要摘要的内容,那么就可以直接用python的库完成签名

动态调试我是用的是Google Chrome 94.0.4596.0(正式版本)canary (64 位)

从spyder函数的第二个参数可知,首先计算的哈希函数是hmac_sha256,先简单说一下hmac的算法,根据文章HMAC算法原理
在这里插入图片描述

hmac的算法实际上是计算了两次原本的哈希函数

1.首先将key填充至64字节,然后与i_pad进行异或,得到i key pad
2.还是将key填充至64字节,然后与o_pad进行异或,得到o key pad
3.将i key pad放在签名内容的前面,然后计算一次sha,得到hash sum 1
4.将步骤2中的o key pad放在步骤3的hash sum 1前面,再计算一次sha,得到hash sum 2

这时的hash sum 2就是最终hmac的结果,进入IDA中的hmac_sha256函数看一看
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可以看到创建了两个sha256函数,进行了4次input,两次digest,与上面的算法是一致的,那么只需要直到input的内容,那么就可以还原算法了,在wasm中的hmac_sha256下一个断点,断下后,在函数内所有的input下一个断点
在这里插入图片描述
断下来后右下角的小按钮很有用,可以直接查看内存视图
根据OpenSSL的源码https://github.com/openssl/openssl/blob/master/crypto/hmac/hmac.c中的函数定义
在这里插入图片描述

第一个参数是结构体,第二个参数是内容,第三个参数是内容的长度
在这里插入图片描述
直接跳转到地址,可以看到这个就是64字节长度的i key pad,全部与0x36进行异或,就可以得到密钥为【seacasdgyijfhofiuxoannn】,实际就是参数的benchmark的值,继续执行
在这里插入图片描述
这时可以看到o key pad,继续往下
在这里插入图片描述
这时就可以看到实际签名的内容了,长度是199字节,是一段json的字符串,尝试使用python还原

    def hmac_sha256(key, data):
        key = bytearray(key.encode())
        while len(key) < 64:
            key.append(0)
        i_key_pad = bytes([i ^ 54 for i in key])
        o_key_pad = bytes([i ^ 92 for i in key])
        sha256s = hashlib.sha256()
        sha256s.update(i_key_pad)
        sha256s.update(data.encode())
        hash_sum_1 = sha256s.digest()
        sha256s = hashlib.sha256()
        sha256s.update(o_key_pad)
        sha256s.update(hash_sum_1)
        return sha256s.hexdigest()
    
    data = {"platform":"web","parent_id":3,"area_id":163,"seq_id":13,"room_id":5887574,"buvid":"AUTO1716277899447614","uuid":"3fc2a589-9cb7-42bf-85c9-c2af590c2fad","ets":1627808068,"time":60,"ts":1627808222759}
    data = json.dumps(data, separators=(',', ':'))
    benchmark = 'seacasdgyijfhofiuxoannn'
    print(hmac_sha256(benchmark, data))
    print(HMAC.new(benchmark.encode(), data.encode(), SHA256).hexdigest())

运行发现,两个结果是一致的,都是【938e55c730b57bc3972ae88c1a45db62040a12d63e40d66d0ab8cbb09c121197】,如此类推,其他hmac函数都可以这样获取密钥和内容,最后可以得出签名的算法

    data = {"platform":"web","parent_id":3,"area_id":163,"seq_id":13,"room_id":5887574,"buvid":"AUTO1716277899447614","uuid":"3fc2a589-9cb7-42bf-85c9-c2af590c2fad","ets":1627808068,"time":60,"ts":1627808222759}
    data = json.dumps(data, separators=(',', ':'))
    benchmark = 'seacasdgyijfhofiuxoannn'
    data = HMAC.new(benchmark, data.encode(), SHA256).hexdigest()
    data = HMAC.new(benchmark, data.encode(), SHA384).hexdigest()
    data = HMAC.new(benchmark, data.encode(), SHA1).hexdigest()
    s = HMAC.new(benchmark, data.encode(), SHA512).hexdigest()
    print(s)

后面就没有做请求测试了。理论上是没有问题的了,完结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值