吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4178|回复: 82
上一主题 下一主题
收起左侧

[Web逆向] 某q音乐sign逆向-多角度

  [复制链接]
跳转到指定楼层
楼主
utf8 发表于 2025-4-8 16:39 回帖奖励

某q音乐sign逆向-多角度

目标网站:aHR0cHM6Ly95LnFxLmNvbS9uL3J5cXEvc29uZ0RldGFpbC8wMDJxVTVhWTNRdTI0eQ==

本文仅供学习交流,因使用本文内容而产生的任何风险及后果,作者不承担任何责任,一起学习吧

逆向分析

定位加密点

查看带有sign参数的接口,查看调用堆栈,你可以发现基本都是vendor.chunk...这个文件,那么直接进入这个文件。

还是一样的,先进行搜索,简单搜索sign:,很快就可以定位到,两处都打上断点。

这里我们还是简单分析一下 sign 的值就是 i 的值,那么我们简单去看一下 i 又是上面那个三元表达式生成的。那么目标就很明确了,在这里打上断点。刷新页面,确认唯一加密入口。

参数生成分析

逐行分析代码:

var i, o = n(350).default;
i = "GET" === t.type.toUpperCase() ? o(t.data.data) : o(t.data)
// "GET" === t.type.toUpperCase() --> false --> i = o(t.data)

既然找到了入口,那么让我们简单多次运行一下这个函数:

// o(t.data) --> 'zzc801bff23inniav1jfzf9nzjutynzqhlwaof7812674'

你会发现结果一致,那么这个就很方便我们进行后续的分析。我们先记录一组值,方便后续结果验证o('12345')='zzca873dd41zwq69wr8hrqun6rvk1b5srwqncdc4c4d03',。那么加密函数可以确定为这个 o函数 那么这个函数是什么呢,我们向上看看这个函数。很容易找到o = n(350).default。那么这个n又是上面呢,简单输出一下,你会发现:

n = function d(t) {
        if (a[t])
            return a[t].exports;
        var r = a[t] = {
            i: t,
            l: !1,
            exports: {}
        };
        return e[t].call(r.exports, r, r.exports, d),
        r.l = !0,
        r.exports
    }

很明显的一个webpack,如果你对这部分不是很熟悉你可以上网搜一下,我这边简单讲解一下

webpack技术

快速入门文章:https://blog.csdn.net/weixin_46714216/article/details/140741361

webpack 技术其实就是一个前端模块打包技术,它可以将多个模块按照依赖关系进行静态分析,并生成一个或多个打包后的文件。

核心概念: entry(入口)、output(输出)、loader(加载器)和plugin(插件)

逆向的关键点在于找到加载器,在此之前我们先了解一下几个核心的函数:

call 方法
  • callFunction 的方法,用来改变函数的 this 指向,并立即执行

  • 语法:func.call(thisArg, arg1, arg2, ...)

举例:

function greet(greeting, punctuation) {
  // this.name 来自于外部传入的对象
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = {
  name: 'Alice'
};

// 使用 call 调用 greet 函数,把 this 指向 person 对象
greet.call(person, 'Hello', '!');  // 输出:Hello, Alice!
apply 方法
  • apply 和 call 功能类似,也是改变函数的 this 指向并立即执行。

  • 区别在于:apply 接收参数是以数组形式传入的。

  • 语法:func.apply(thisArg, [arg1, arg2, ...])

举例:

function greet(greeting, punctuation) {
  // 与 call 示例相同,只是换用 apply
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = {
  name: 'Bob'
};

// 使用 apply 调用 greet 函数,参数作为数组传入
greet.apply(person, ['Hi', '.']);  // 输出:Hi, Bob.
webpack技术

在学习完上面的内容之后,我们来简单举几个例子,希望你有更深刻的理解:


// 1. 使用感叹号将函数声明转为表达式,立即执行该函数并传入一个对象参数
!function(e) { // 形参 e 接收传入的对象 {1:fn,5:fn}
    // 2. 初始化模块缓存对象 t
    t = {}; 

    // 3. 定义模块加载函数 n
    function n(r) { // r 是模块ID(此处调用时为 '1')
        // 4. 检查模块是否已加载
        if (t[r]) return t[r].exports; // 已缓存则直接返回exports

        // 5. 初始化新模块容器
        var i = t[r] = { // 同时写入缓存对象 t
            exports: {} // 模块的导出对象
        };

        // 6. 执行模块代码(核心步骤)
        // e[r] 获取模块函数(此处是 e['1'] 对应的函数)
        // 使用 call 方法,将模块函数的 this 指向 i.exports
        // 参数顺序:模块对象, exports对象, 加载函数
        e[r].call(i.exports, i, i.exports, n);

        // 7. 返回模块的导出结果
        return i.exports
    };

    // 8. 触发模块加载:加载ID为'1'的模块
    n('1') 
}({
    // 9. 传入的模块定义对象(模拟Webpack的模块集合)
    1: function(){console.log(1)}, // 模块ID为'1'的函数
    5: function(){console.log(5)}  // 模块ID为'5'的函数(未使用)
})

参数逆向分析--方法1--补环境

好,回到原来的代码,让我们逐行分析这个代码:

n = function d(t) {
        if (a[t])  // 如果模块 a[t] 已经被加载过了(缓存存在),直接返回它的 exports(模块导出内容)
            return a[t].exports;

        // 否则开始加载模块:创建模块对象 r
        var r = a[t] = {
            i: t,       // 模块 id
            l: !1,      // 模块是否已经加载,false 表示还没加载
            exports: {} // 用来存放模块导出的内容
        };

        return e[t].call(r.exports, r, r.exports, d),// 执行模块函数 e[t],绑定 this 为 r.exports,传入参数:模块对象 r、模块的 exports 和 require 函数 d(自己)
        r.l = !0,  // 标记模块为已加载
        r.exports  // 返回模块的 exports
    }

// ------------------------------------------------------------------------------------------------
// 简单改写一下,清晰结构

function d(t) {

    console.log('调用模块---> ',t)  // 如果你理解了上面的代码,那么我们就可以实现webpack自吐模块了
    var a = {};     // 初始化模块缓存对象
    // 如果模块 a[t] 已经被加载过了(缓存存在),直接返回它的 exports(模块导出内容)
    if (a[t])
        return a[t].exports;

    // 否则开始加载模块:创建模块对象 r
    var r = a[t] = {
        i: t,         // 模块 id
        l: !1,        // 模块是否已经加载,false 表示还没加载
        exports: {}   // 用来存放模块导出的内容
    };

    // 执行模块函数 e[t],绑定 this 为 r.exports --> 很明显模块是缺失的需要我们自己找
    // 传入参数:模块对象 r、模块的 exports 和 require 函数 d(自己)
    e[t].call(r.exports, r, r.exports, d);

    // 标记模块为已加载
    r.l = !0;

    // 返回模块的 exports
    return r.exports;
}
webpack_output = d //全局暴露 ps:这个导出变量名字最好特殊别被其他变量覆盖咯

先从简单的还原webpack开始吧(补环境),直接将一整个加载器完全扣下来

var n;

!function(e) {
    function t(t) {
        for (var a, n, d = t[0], c = t[1], i = t[2], l = 0, b = []; l < d.length; l++)
            n = d[l],
            Object.prototype.hasOwnProperty.call(o, n) && o[n] && b.push(o[n][0]),
            o[n] = 0;
        for (a in c)
            Object.prototype.hasOwnProperty.call(c, a) && (e[a] = c[a]);
        for (u && u(t); b.length; )
            b.shift()();
        return f.push.apply(f, i || []),
        r()
    }
    function r() {
        for (var e, t = 0; t < f.length; t++) {
            for (var r = f[t], a = !0, n = 1; n < r.length; n++) {
                var c = r[n];
                0 !== o[c] && (a = !1)
            }
            a && (f.splice(t--, 1),
            e = d(d.s = r[0]))
        }
        return e
    }
    var a = {}
      , n = {
        21: 0
    }
      , o = {
        21: 0
    }
      , f = [];
    function d(t) {

    console.log('调用模块---> ',t)  // 如果你理解了上面的代码,那么我们就可以实现webpack自吐模块了
    var a = {};     // 初始化模块缓存对象
    // 如果模块 a[t] 已经被加载过了(缓存存在),直接返回它的 exports(模块导出内容)
    if (a[t])
        return a[t].exports;

    // 否则开始加载模块:创建模块对象 r
    var r = a[t] = {
        i: t,         // 模块 id
        l: !1,        // 模块是否已经加载,false 表示还没加载
        exports: {}   // 用来存放模块导出的内容
    };

    // 执行模块函数 e[t],绑定 this 为 r.exports --> 很明显模块是缺失的需要我们自己找
    // 传入参数:模块对象 r、模块的 exports 和 require 函数 d(自己)
    e[t].call(r.exports, r, r.exports, d);

    // 标记模块为已加载
    r.l = !0;

    // 返回模块的 exports
    return r.exports;
    }
    webpack_output = d //全局暴露
    d.e = function(e) {
        var t = [];
        n[e] ? t.push(n[e]) : 0 !== n[e] && {
            1: 1,
            3: 1,
            4: 1,
            5: 1,
            6: 1,
            7: 1,
            8: 1,
            9: 1,
            10: 1,
            11: 1,
            12: 1,
            13: 1,
            14: 1,
            15: 1,
            16: 1,
            17: 1,
            18: 1,
            19: 1,
            20: 1,
            22: 1,
            23: 1,
            24: 1,
            25: 1,
            26: 1
        }[e] && t.push(n[e] = new Promise((function(t, r) {
            for (var a = "css/" + ({
                1: "common",
                3: "album",
                4: "albumDetail",
                5: "album_mall",
                6: "category",
                7: "cmtpage",
                8: "download_detail",
                9: "index",
                10: "msg_center",
                11: "mv",
                12: "mvList",
                13: "mv_toplist",
                14: "notfound",
                15: "player",
                16: "player_radio",
                17: "playlist",
                18: "playlist_edit",
                19: "profile",
                20: "radio",
                22: "search",
                23: "singer",
                24: "singer_list",
                25: "songDetail",
                26: "toplist"
            }[e] || e) + "." + {
                1: "092d215c4a601df90f9f",
                3: "5cf0d69eaf29bcab23d2",
                4: "798353db5b0eb05d5358",
                5: "df4c243f917604263e58",
                6: "20d532d798099a44bc88",
                7: "e3bedf2b5810f8db0684",
                8: "559f0a2e11f1f5800b13",
                9: "2573d208d34ff3d682f0",
                10: "020422608fe8bfb1719a",
                11: "8bdb1df6c5436b790baa",
                12: "47ce9300786df1b70584",
                13: "4aee33230ba2d6b81dce",
                14: "e6f63b0cf57dd029fbd6",
                15: "1d2dbefbea113438324a",
                16: "d893492de07ce97d8048",
                17: "9484fde660fe93d9f9f0",
                18: "67fb85e7f96455763c83",
                19: "5e8c651e74b13244f7cf",
                20: "3befd83c10b19893ec66",
                22: "b2d11f89ea6a512a2302",
                23: "c7a38353c5f4ebb47491",
                24: "df0961952a2d3f022894",
                25: "4c080567e394fd45608b",
                26: "8edb142553f97482e00f"
            }[e] + ".chunk.css?max_age=2592000", o = d.p + a, f = document.getElementsByTagName("link"), c = 0; c < f.length; c++) {
                var i = (u = f[c]).getAttribute("data-href") || u.getAttribute("href");
                if ("stylesheet" === u.rel && (i === a || i === o))
                    return t()
            }
            var l = document.getElementsByTagName("style");
            for (c = 0; c < l.length; c++) {
                var u;
                if ((i = (u = l[c]).getAttribute("data-href")) === a || i === o)
                    return t()
            }
            var b = document.createElement("link");
            b.rel = "stylesheet",
            b.type = "text/css",
            b.onload = t,
            b.onerror = function(t) {
                var a = t && t.target && t.target.src || o
                  , f = new Error("Loading CSS chunk " + e + " failed.\n(" + a + ")");
                f.code = "CSS_CHUNK_LOAD_FAILED",
                f.request = a,
                delete n[e],
                b.parentNode.removeChild(b),
                r(f)
            }
            ,
            b.href = o,
            0 !== b.href.indexOf(window.location.origin + "/") && (b.crossOrigin = "anonymous"),
            document.getElementsByTagName("head")[0].appendChild(b)
        }
        )).then((function() {
            n[e] = 0
        }
        )));
        var r = o[e];
        if (0 !== r)
            if (r)
                t.push(r[2]);
            else {
                var a = new Promise((function(t, a) {
                    r = o[e] = [t, a]
                }
                ));
                t.push(r[2] = a);
                var f, c = document.createElement("script");
                c.charset = "utf-8",
                c.timeout = 120,
                d.nc && c.setAttribute("nonce", d.nc),
                c.src = function(e) {
                    return d.p + "js/" + ({
                        1: "common",
                        3: "album",
                        4: "albumDetail",
                        5: "album_mall",
                        6: "category",
                        7: "cmtpage",
                        8: "download_detail",
                        9: "index",
                        10: "msg_center",
                        11: "mv",
                        12: "mvList",
                        13: "mv_toplist",
                        14: "notfound",
                        15: "player",
                        16: "player_radio",
                        17: "playlist",
                        18: "playlist_edit",
                        19: "profile",
                        20: "radio",
                        22: "search",
                        23: "singer",
                        24: "singer_list",
                        25: "songDetail",
                        26: "toplist"
                    }[e] || e) + ".chunk." + {
                        1: "071ff4c93a36213b8e52",
                        3: "62fa0b6e13bdae5565df",
                        4: "ac1634a6cb1398f5f52f",
                        5: "c165da78f8e281d22b0f",
                        6: "8fbd80e377e3e8e81d2a",
                        7: "d1c1a21bc6d2234edcfd",
                        8: "094e227aa4af23758b7f",
                        9: "25deb3bc649fea321e4e",
                        10: "53237e74c6bc8294affc",
                        11: "1741b53500e75aa199dd",
                        12: "ece15e2e69d60159285f",
                        13: "8bbf72e90588993598fc",
                        14: "6eb4f1aeb6ba0b64b608",
                        15: "f4cd83bb066b3fae0a82",
                        16: "c48f9e6437253f47aedd",
                        17: "b02b0c36e514eacc9804",
                        18: "279d53770728d6d8071f",
                        19: "e1cbac4bc67bc66f7505",
                        20: "07641382e662e56a4bd9",
                        22: "2037125a09567d65d8ac",
                        23: "9e448e13e293aa03a267",
                        24: "fd0f2c1dd1b1dc00ce3e",
                        25: "d340acd4929cab481128",
                        26: "b759d290f5c1376e403c"
                    }[e] + ".js?max_age=2592000"
                }(e),
                0 !== c.src.indexOf(window.location.origin + "/") && (c.crossOrigin = "anonymous");
                var i = new Error;
                f = function(t) {
                    c.onerror = c.onload = null,
                    clearTimeout(l);
                    var r = o[e];
                    if (0 !== r) {
                        if (r) {
                            var a = t && ("load" === t.type ? "missing" : t.type)
                              , n = t && t.target && t.target.src;
                            i.message = "Loading chunk " + e + " failed.\n(" + a + ": " + n + ")",
                            i.name = "ChunkLoadError",
                            i.type = a,
                            i.request = n,
                            r[1](i)
                        }
                        o[e] = void 0
                    }
                }
                ;
                var l = setTimeout((function() {
                    f({
                        type: "timeout",
                        target: c
                    })
                }
                ), 12e4);
                c.onerror = c.onload = f,
                document.head.appendChild(c)
            }
        return Promise.all(t)
    }
    ,
    d.m = e,
    d.c = a,
    d.d = function(e, t, r) {
        d.o(e, t) || Object.defineProperty(e, t, {
            enumerable: !0,
            get: r
        })
    }
    ,
    d.r = function(e) {
        "undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
            value: "Module"
        }),
        Object.defineProperty(e, "__esModule", {
            value: !0
        })
    }
    ,
    d.t = function(e, t) {
        if (1 & t && (e = d(e)),
        8 & t)
            return e;
        if (4 & t && "object" === typeof e && e && e.__esModule)
            return e;
        var r = Object.create(null);
        if (d.r(r),
        Object.defineProperty(r, "default", {
            enumerable: !0,
            value: e
        }),
        2 & t && "string" != typeof e)
            for (var a in e)
                d.d(r, a, function(t) {
                    return e[t]
                }
                .bind(null, a));
        return r
    }
    ,
    d.n = function(e) {
        var t = e && e.__esModule ? function() {
            return e.default
        }
        : function() {
            return e
        }
        ;
        return d.d(t, "a", t),
        t
    }
    ,
    d.o = function(e, t) {
        return Object.prototype.hasOwnProperty.call(e, t)
    }
    ,
    d.p = "/ryqq/",
    d.oe = function(e) {
        throw e
    }
    ;
    var c = window.webpackJsonp = window.webpackJsonp || []
      , i = c.push.bind(c);
    c.push = t,
    c = c.slice();
    for (var l = 0; l < c.length; l++)
        t(c[l]);
    var u = i;
    r()
}({});

运行看看缺啥,补环境就是缺啥补啥。

ok,缺少window。补上 window = globalThis和模块导出代码(自己好好想想,这个太简单了),再次运行。
缺少模块模块 350 ,那我们直接去导出看看,发现模块350是l()函数,但是记住,webpack模块要全扣,把这个一整个大函数(function(e, t, n))扣下来,补入我们的加载器中。这里代码我就不贴出来,自己去思考一下,才可以进步。继续执行,发现缺少模块 80,浏览器输出一下,一看是个window对象,那么我们只需要把这个模块函数返回值设为window即可(这里很坑,你需要注意作用域的问题,建议直接把n(80)该为window)。再次执行,发现如下报错:

throw c ? c(b, d, i) : b;
^
TypeError: Cannot set properties of undefined (setting '_getSecuritySign')

这种非模块报错,一般就是被检测环境了,你可以联调测试,一步步去补充缺少的值。这里快速分析,我们直接挂上代理。缺啥补啥。这里比较简单就直接跳过了,简单提一嘴,一般补环境最好把异常捕获给删了,不然有些网站很折磨人。

代理放在这里

function getEnvs(proxyObjs) {
    for (let i = 0; i < proxyObjs.length; i++) {
        const handler = `{
      get: function(target, property, receiver) {
        console.log("方法:", "get  ", "对象:", "${proxyObjs[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", target[property], ", 属性值类型:", typeof target[property]);
        return target[property];
      },
      set: function(target, property, value, receiver) {
        console.log("方法:", "set  ", "对象:", "${proxyObjs[i]}", "  属性:", property, "  属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]);
        return Reflect.set(...arguments);
      }
    }`;
        eval(`try {
            ${proxyObjs[i]};
            ${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler});
        } catch (e) {
            ${proxyObjs[i]} = {};
            ${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler});
        }`);
    }
}

proxyObjs = ['window', 'document', 'location', 'navigator', 'history', 'screen']
getEnvs(proxyObjs);

简单补上环境我们就成功拿到了结果,验证是正确的。

参数逆向分析--方法2--插桩

补环境确实简单,其实纯算也不难

单纯研究这个vmp,故直接修改补环境的代码。

既然我们找到了,参数生成的入口,函数o,那我们就去看看这个函数到底做了什么。

一般插装的方法的重点在于call,apply,和各种各样的运算符的位置。那么简单的在这些位置上插装吧(巨麻烦)。具体插装,我直接放到代码里面了。插桩不是一次就可以成功的,自己可以多试试,注意指针!!!

日志一般是倒着看(确定逆向目标,分布击破),我这边讲解就顺着讲了。看别人不如自己写一写

日志最开始就是一堆初始化,而且大头都是sha1的摘要计算。为什么是sha1,这个就需要你对这个算法比较熟悉了,这部分我基本上看到这几个魔法值就确定这个算法。

我贴出关键日志

[case 67] 准备调用: d[12].call(d[11], d[15])
    => 函数 theFunc =  [Function: l]
    => this = d[11] =  l {
  blocks: [
    0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0,
    0, 0, 0
  ],
  h0: 1732584193,
  h1: 4023233417,
  h2: 2562383102,
  h3: 271733878,
  h4: 3285377520,  --> sha1
  hBytes: 0,
  bytes: 0,
  start: 0,
  block: 0,
  hashed: false,
  finalized: false,
  first: true
}
    => 参数1 = d[15] =  12345  --> 入参

这里简单讲一下这个技巧

算法 状态变量数<br>(如:h0 ~ h3) 初始魔法值个数 魔法值(十六进制) 魔法值(十进制) 总长度(比特)
MD5 4 <br>(h0 ~ h3) 4 h0=0x67452301<br>h1=0xEFCDAB89<br>h2=0x98BADCFE<br>h3=0x10325476 h0=1732584193<br>h1=4023233417<br>h2=2562383102<br>h3=271733878 128 bits
SHA-1 5 <br>(h0 ~ h4) 5 同上 +<br>h4=0xC3D2E1F0 同上 +<br>h4=3285377520 160 bits

简单验证一下 12345 sha1 --> 8CB2237D0679CA88DB6464EAC60DA96345513964  完全没问题。那么接着看另一部分加密

日志如下:

[case 67] 准备调用: d[127].call(d[95], d[38])
    => 函数 theFunc =  [Function: map]
    => this = d[95] =  [
  23, 14, 6, 36,
  16, 40, 7, 19
]  --> 循环列表
    => 参数1 = d[38] =  [Function: l]
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964   sha1 字符串
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 23
[Hook] rightVal = d[16][23] => A
[Hook] d[18] now => A
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 14
[Hook] rightVal = d[16][14] => 8
[Hook] d[18] now => 8
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 6
[Hook] rightVal = d[16][6] => 7
[Hook] d[18] now => 7
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 36
[Hook] rightVal = d[16][36] => 3
[Hook] d[18] now => 3
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 16
[Hook] rightVal = d[16][16] => D
[Hook] d[18] now => D
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 40
[Hook] rightVal = d[16][40] => undefined
[Hook] d[18] now => undefined
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 7
[Hook] rightVal = d[16][7] => D
[Hook] d[18] now => D
[Hook] case 78 end
执行到--》 1
执行到--》 37
执行到--》 28
[Hook] case 28 start, g= 3498
[Hook] key1 = n[3499] = 16
[Hook] key2 = n[3500] = 14
[Hook] key3 = n[3501] = 0
[Hook] d[16] = d[14][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[16] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 28
[Hook] case 28 start, g= 3502
[Hook] key1 = n[3503] = 9
[Hook] key2 = n[3504] = 12
[Hook] key3 = n[3505] = 0
[Hook] d[9] = d[12][0] = true
[Hook] case 28 end, d[9] => true
执行到--》 47
执行到--》 77
执行到--》 78
[Hook] case 78 start, g = 257
[Hook] key1 = n[258] = 18
[Hook] key2 = n[259] = 16
[Hook] key3 = n[260] = 8
[Hook] subKey = d[8] => 19
[Hook] rightVal = d[16][19] => 4
[Hook] d[18] now => 4
[Hook] case 78 end
执行到--》 1
    => 调用结束,赋值 d[139] =  [ 'A', '8', '7', '3', 'D', undefined, 'D', '4' ]  --> A873DD4  DC4C4D03也是同理,但是前面的循环列表不一样,自己去找找吧

这部分日志很简单。就是循环列表在sha1串里面取字符

还原代码如下:

function extractByIndexArray(key_str, indexArray) {
  return indexArray.map(i => key_str[i]).join('');
}
const indices1 = [23, 14, 6, 36 ,16 , 40, 7, 19];
const result1 = extractByIndexArray(sha1, indices1);
console.log('result1:', result1);  // => A873DD4

接下来这部分这个核心加密点,需要你日志点输出准确,不然确实不太好看

核心日志如下:

[Hook]77 assignment start, g = 5037
[Hook] key1 = n[5038] = 87
[Hook] key2 = n[5039] = 38
[Hook] d[87] = d[38] => [
   89,  39, 179, 150, 218,  82,
   58, 252, 177,  52, 186, 123,
  120,  64, 242, 133, 143, 161,
  121, 179
]
[Hook]77 assignment end
执行到--》 28
[Hook] case 28 start, g= 5040
[Hook] key1 = n[5041] = 38
[Hook] key2 = n[5042] = 67
[Hook] key3 = n[5043] = 0
[Hook] d[38] = d[67][0] = true
[Hook] case 28 end, d[38] => true
执行到--》 47
执行到--》 56
执行到--》 27
执行到--》 77
[Hook]77 assignment start, g = 440
[Hook] key1 = n[441] = 48
[Hook] key2 = n[442] = 18
[Hook] d[48] = d[18] => []
[Hook]77 assignment end
执行到--》 27
执行到--》 77
[Hook]77 assignment start, g = 446
[Hook] key1 = n[447] = 181
[Hook] key2 = n[448] = 144
[Hook] d[181] = d[144] => 0
[Hook]77 assignment end
执行到--》 7
执行到--》 48
执行到--》 47
执行到--》 60
执行到--》 21
case21 乘法运算: 0 * 2 = 0,写入 d[186]
执行到--》 78
[Hook] case 78 start, g = 5210
[Hook] key1 = n[5211] = 95
[Hook] key2 = n[5212] = 38
[Hook] key3 = n[5213] = 186
[Hook] subKey = d[186] => 0
[Hook] rightVal = d[38][0] => 8
[Hook] d[38] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[95] now => 8
[Hook] case 78 end
执行到--》 78
[Hook] case 78 start, g = 5214
[Hook] key1 = n[5215] = 186
[Hook] key2 = n[5216] = 85
[Hook] key3 = n[5217] = 95
[Hook] subKey = d[95] => 8
[Hook] rightVal = d[85][8] => 8
[Hook] d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[186] now => 8
[Hook] case 78 end
执行到--》 27
执行到--》 21
case21 乘法运算: 8 * 16 = 128,写入 d[38]
执行到--》 28
[Hook] case 28 start, g= 5225
[Hook] key1 = n[5226] = 95
[Hook] key2 = n[5227] = 43
[Hook] key3 = n[5228] = 0
[Hook] d[95] = d[43][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[95] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 21
case21 乘法运算: 0 * 2 = 0,写入 d[186]
执行到--》 34 加法运算: 0 + 1 = 1,写入 d[134]
执行到--》 78
[Hook] case 78 start, g = 5237
[Hook] key1 = n[5238] = 186
[Hook] key2 = n[5239] = 95
[Hook] key3 = n[5240] = 134
[Hook] subKey = d[134] => 1
[Hook] rightVal = d[95][1] => C
[Hook] d[95] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[186] now => C
[Hook] case 78 end
执行到--》 69
[Hook] case 69 start, g = 5241
[Hook] s1_leftKey = n[5242] = 134
[Hook] s1_baseKey = n[5243] = 85
[Hook] s1_subKeyIndex = n[5244] = 186
[Hook] s1_subKey = d[186] => C
[Hook] s1_rightVal = d[85][C] => 12
[Hook] s1_rightVal = d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[134] = 12
[Hook] s2_leftKey = n[5245] = 186
[Hook] s2_rightKey1 = n[5246] = 38
[Hook] s2_rightKey2 = n[5247] = 134
[Hook] s2_val1 = d[38] => 128
[Hook] s2_val2 = d[134] => 12
[Hook] s2_result = 128 + 12 => 140
[Hook] d[186] = 140
[Hook] case 69 end
执行到--》 77
[Hook]77 assignment start, g = 5248
[Hook] key1 = n[5249] = 37
[Hook] key2 = n[5250] = 186
[Hook] d[37] = d[186] => 140
[Hook]77 assignment end
执行到--》 78
[Hook] case 78 start, g = 5251
[Hook] key1 = n[5252] = 186
[Hook] key2 = n[5253] = 87
[Hook] key3 = n[5254] = 181
[Hook] subKey = d[181] => 0
[Hook] rightVal = d[87][0] => 89
[Hook] d[87] = [89,39,179,150,218,82,58,252,177,52,186,123,120,64,242,133,143,161,121,179]
[Hook] d[186] now => 89
[Hook] case 78 end
执行到--》 77
[Hook]77 assignment start, g = 5255
[Hook] key1 = n[5256] = 140
[Hook] key2 = n[5257] = 186
[Hook] d[140] = d[186] => 89
[Hook]77 assignment end
执行到--》 38
执行到--》 4
执行到--》 51 异或运算: 140 ^ 89 = 213,写入 d[186]
执行到--》 67
case67
[case 67] 准备调用: d[134].call(d[48], d[186])
    => 函数 theFunc =  [Function: push]
    => this = d[48] =  []
    => 参数1 = d[186] =  213
    => 调用结束,赋值 d[28] =  1
执行到--》 47
执行到--》 77
[Hook]77 assignment start, g = 4053
[Hook] key1 = n[4054] = 38
[Hook] key2 = n[4055] = 181
[Hook] d[38] = d[181] => 0
[Hook]77 assignment end
执行到--》 66
执行到--》 22
执行到--》 7
执行到--》 47
执行到--》 60
执行到--》 21
case21 乘法运算: 1 * 2 = 2,写入 d[186]
执行到--》 78
[Hook] case 78 start, g = 5210
[Hook] key1 = n[5211] = 95
[Hook] key2 = n[5212] = 38
[Hook] key3 = n[5213] = 186
[Hook] subKey = d[186] => 2
[Hook] rightVal = d[38][2] => B
[Hook] d[38] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[95] now => B
[Hook] case 78 end
执行到--》 78
[Hook] case 78 start, g = 5214
[Hook] key1 = n[5215] = 186
[Hook] key2 = n[5216] = 85
[Hook] key3 = n[5217] = 95
[Hook] subKey = d[95] => B
[Hook] rightVal = d[85][B] => 11
[Hook] d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[186] now => 11
[Hook] case 78 end
执行到--》 27
执行到--》 21
case21 乘法运算: 11 * 16 = 176,写入 d[38]
执行到--》 28
[Hook] case 28 start, g= 5225
[Hook] key1 = n[5226] = 95
[Hook] key2 = n[5227] = 43
[Hook] key3 = n[5228] = 0
[Hook] d[95] = d[43][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[95] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 21
case21 乘法运算: 1 * 2 = 2,写入 d[186]
执行到--》 34 加法运算: 2 + 1 = 3,写入 d[134]
执行到--》 78
[Hook] case 78 start, g = 5237
[Hook] key1 = n[5238] = 186
[Hook] key2 = n[5239] = 95
[Hook] key3 = n[5240] = 134
[Hook] subKey = d[134] => 3
[Hook] rightVal = d[95][3] => 2
[Hook] d[95] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[186] now => 2
[Hook] case 78 end
执行到--》 69
[Hook] case 69 start, g = 5241
[Hook] s1_leftKey = n[5242] = 134
[Hook] s1_baseKey = n[5243] = 85
[Hook] s1_subKeyIndex = n[5244] = 186
[Hook] s1_subKey = d[186] => 2
[Hook] s1_rightVal = d[85][2] => 2
[Hook] s1_rightVal = d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[134] = 2
[Hook] s2_leftKey = n[5245] = 186
[Hook] s2_rightKey1 = n[5246] = 38
[Hook] s2_rightKey2 = n[5247] = 134
[Hook] s2_val1 = d[38] => 176
[Hook] s2_val2 = d[134] => 2
[Hook] s2_result = 176 + 2 => 178
[Hook] d[186] = 178
[Hook] case 69 end
执行到--》 77
[Hook]77 assignment start, g = 5248
[Hook] key1 = n[5249] = 37
[Hook] key2 = n[5250] = 186
[Hook] d[37] = d[186] => 178
[Hook]77 assignment end
执行到--》 78
[Hook] case 78 start, g = 5251
[Hook] key1 = n[5252] = 186
[Hook] key2 = n[5253] = 87
[Hook] key3 = n[5254] = 181
[Hook] subKey = d[181] => 1
[Hook] rightVal = d[87][1] => 39
[Hook] d[87] = [89,39,179,150,218,82,58,252,177,52,186,123,120,64,242,133,143,161,121,179]
[Hook] d[186] now => 39
[Hook] case 78 end
执行到--》 77
[Hook]77 assignment start, g = 5255
[Hook] key1 = n[5256] = 140
[Hook] key2 = n[5257] = 186
[Hook] d[140] = d[186] => 39
[Hook]77 assignment end
执行到--》 38
执行到--》 4
执行到--》 51 异或运算: 178 ^ 39 = 149,写入 d[186]
执行到--》 67
case67
[case 67] 准备调用: d[134].call(d[48], d[186])
    => 函数 theFunc =  [Function: push]
    => this = d[48] =  [ 213 ]
    => 参数1 = d[186] =  149
    => 调用结束,赋值 d[28] =  2
执行到--》 47
执行到--》 77
[Hook]77 assignment start, g = 4053
[Hook] key1 = n[4054] = 38
[Hook] key2 = n[4055] = 181
[Hook] d[38] = d[181] => 1
[Hook]77 assignment end
执行到--》 66
执行到--》 22
执行到--》 7
执行到--》 47
执行到--》 60
执行到--》 21
case21 乘法运算: 2 * 2 = 4,写入 d[186]
执行到--》 78
[Hook] case 78 start, g = 5210
[Hook] key1 = n[5211] = 95
[Hook] key2 = n[5212] = 38
[Hook] key3 = n[5213] = 186
[Hook] subKey = d[186] => 4
[Hook] rightVal = d[38][4] => 2
[Hook] d[38] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[95] now => 2
[Hook] case 78 end
执行到--》 78
[Hook] case 78 start, g = 5214
[Hook] key1 = n[5215] = 186
[Hook] key2 = n[5216] = 85
[Hook] key3 = n[5217] = 95
[Hook] subKey = d[95] => 2
[Hook] rightVal = d[85][2] => 2
[Hook] d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[186] now => 2
[Hook] case 78 end
执行到--》 27
执行到--》 21
case21 乘法运算: 2 * 16 = 32,写入 d[38]
执行到--》 28
[Hook] case 28 start, g= 5225
[Hook] key1 = n[5226] = 95
[Hook] key2 = n[5227] = 43
[Hook] key3 = n[5228] = 0
[Hook] d[95] = d[43][0] = 8CB2237D0679CA88DB6464EAC60DA96345513964
[Hook] case 28 end, d[95] => 8CB2237D0679CA88DB6464EAC60DA96345513964
执行到--》 21
case21 乘法运算: 2 * 2 = 4,写入 d[186]
执行到--》 34 加法运算: 4 + 1 = 5,写入 d[134]
执行到--》 78
[Hook] case 78 start, g = 5237
[Hook] key1 = n[5238] = 186
[Hook] key2 = n[5239] = 95
[Hook] key3 = n[5240] = 134
[Hook] subKey = d[134] => 5
[Hook] rightVal = d[95][5] => 3
[Hook] d[95] = "8CB2237D0679CA88DB6464EAC60DA96345513964"
[Hook] d[186] now => 3
[Hook] case 78 end
执行到--》 69
[Hook] case 69 start, g = 5241
[Hook] s1_leftKey = n[5242] = 134
[Hook] s1_baseKey = n[5243] = 85
[Hook] s1_subKeyIndex = n[5244] = 186
[Hook] s1_subKey = d[186] => 3
[Hook] s1_rightVal = d[85][3] => 3
[Hook] s1_rightVal = d[85] = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"A":10,"B":11,"C":12,"D":13,"E":14,"F":15}
[Hook] d[134] = 3
[Hook] s2_leftKey = n[5245] = 186
[Hook] s2_rightKey1 = n[5246] = 38
[Hook] s2_rightKey2 = n[5247] = 134
[Hook] s2_val1 = d[38] => 32
[Hook] s2_val2 = d[134] => 3
[Hook] s2_result = 32 + 3 => 35
[Hook] d[186] = 35
[Hook] case 69 end
执行到--》 77
[Hook]77 assignment start, g = 5248
[Hook] key1 = n[5249] = 37
[Hook] key2 = n[5250] = 186
[Hook] d[37] = d[186] => 35
[Hook]77 assignment end
执行到--》 78
[Hook] case 78 start, g = 5251
[Hook] key1 = n[5252] = 186
[Hook] key2 = n[5253] = 87
[Hook] key3 = n[5254] = 181
[Hook] subKey = d[181] => 2
[Hook] rightVal = d[87][2] => 179
[Hook] d[87] = [89,39,179,150,218,82,58,252,177,52,186,123,120,64,242,133,143,161,121,179]
[Hook] d[186] now => 179
[Hook] case 78 end
执行到--》 77
[Hook]77 assignment start, g = 5255
[Hook] key1 = n[5256] = 140
[Hook] key2 = n[5257] = 186
[Hook] d[140] = d[186] => 179
[Hook]77 assignment end
执行到--》 38
执行到--》 4
执行到--》 51 异或运算: 35 ^ 179 = 144,写入 d[186]

简单讲解如下:

// key_str = 8CB2237D0679CA88DB6464EAC60DA96345513964
// 乘法运算是:

// 一轮
// 乘法运算: 0 * 2 = 0,写入 d[186]  --> key_str[0]  --> 8
// dict['8'] --> 8
// 乘法运算: 8 * 16 = 128
// key_str[1]  --> C --> dict['C'] --> 12
// 128 + 12 = 140
// 140 ^ key_list[0] --> 140 ^ 89 = 213

// 二轮
// 乘法运算: 1 * 2 = 2,写入 d[186] --> key_str[2] --> B
// dict['B'] --> 11
// 乘法运算: 11 * 16 = 176,写入 d[38]
// key_str[3] --> 2 --> dict['2'] --> 2
// 176 + 2 = 178
// 178 ^ key_list[1] --> 178 ^ 39 = 149
function decodeKeyToNumberArray(key_str) {
    const dict = {
     看看日志你也可以做出来的
    };

    const key_list = [
      看看日志你也可以做出来的
    ];

    const numberArray = [];

    for (let i = 0; i < key_list.length; i++) {
      const highChar = key_str[2 * i];
      const lowChar  = key_str[2 * i + 1];

      const highVal = dict[highChar];
      const lowVal  = dict[lowChar];

      const byteVal = highVal * 16 + lowVal;
      const xored   = byteVal ^ key_list[i];

      numberArray.push(xored);

      // 可选日志输出
      console.log(
        `Pair #${i}: "${highChar}${lowChar}" => (${highVal}*16 + ${lowVal} = ${byteVal})` +
        ` ^ ${key_list[i]} = ${xored}`
      );
    }

    return numberArray;
  }

结果和日志一样,这里就不展示了[213,149,144,235,220,43,240,116,106,80,222,145,190,77,91,230,202,240,64,215]

后面一部分将这个数组转化为字符串,看到这个 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=,基本就可以猜一下base64

const byteArray = new Uint8Array([213,149,144,235,220,43,240,116,106,80,222,145,190,77,91,230,202,240,64,215]);
const base64 = btoa(String.fromCharCode(...byteArray));
console.log(base64); //--> 1ZWQ691L8HRqUN6Rvk1b5srwQNc=

果不其然就是这个,只不过是把最后结果 --> .replace(/[\/+=]/g, '')

那么这一部分算法也就完成了。

最后将前面的字符串拼接就是最后的结果:

zzc(定死) + A873DD4 + 1ZWQ691L8HRqUN6Rvk1b5srwQNc + DC4C4D03  --toLowerCase--> zzca873dd41zwq69wr8hrqun6rvk1b5srwqncdc4c4d03

纯算就完成了,完整代码就不写了,看着上面都是可以推出来的。

参数逆向分析--方法3--反汇编

你知道你很急,但是先别急。这部分我要想想怎么用通俗的语言讲画大饼。静待佳音吧。

免费评分

参与人数 33威望 +2 吾爱币 +132 热心值 +31 收起 理由
Night1918 + 1 + 1 谢谢@Thanks!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
xiiye + 1 + 1 用心讨论,共获提升!
imumu1239 + 1 + 1 谢谢@Thanks!
jk998 + 1 + 1 我很赞同!
lwGoodChinese + 1 热心回复!
sht281 + 1 + 1 谢谢@Thanks!
涛之雨 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
superboy8286 + 1 + 1 谢谢@Thanks!
dyyxqy2014 + 1 + 1 我很赞同!
tianyu925 + 1 我很赞同!
nanum + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
imfly + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
120305 + 1 + 1 谢谢@Thanks!
逍遥黑心 + 1 + 1 用心讨论,共获提升!
wzvideni + 1 + 1 我很赞同!
serious_snow + 1 + 1 我很赞同!
melooon + 1 + 1 我很赞同!
jjwandqyl + 1 热心回复!
731 + 1 + 1 谢谢@Thanks!
mobaixin + 1 + 1 谢谢@Thanks!
anning666 + 1 + 1 我很赞同!
beihai1314 + 1 + 1 我很赞同!
zaijianwukong + 1 + 1 谢谢@Thanks!
Victor365 + 1 + 1 我很赞同!
哔哔叽叽 + 1 + 1 我很赞同!
mxkgb + 1 + 1 谢谢@Thanks!
Issacclark1 + 1 谢谢@Thanks!
1959450071 + 1 + 1 谢谢@Thanks!
熊猫拍板砖 + 2 + 1 谢谢@Thanks!
l686 + 1 + 1 谢谢@Thanks!
helian147 + 1 + 1 热心回复!
fvv123456 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| utf8 发表于 2025-4-15 17:53 |楼主
ZeLin99 发表于 2025-4-15 17:06
大佬你们在哪儿找的学习逆向方法呢,我刚接触这方面,求指导

多逛论坛,先通篇看下来,如果觉得自己可以做,就复现一下。刚刚开始不要搞难的,去多看看js语法。这个玩意儿就是多练。视频的话你去网上一搜一大把。
推荐
 楼主| utf8 发表于 2025-4-8 21:03 |楼主
后面有空我会详细讲一下jsvmp,聊聊反编译的思考方向(不针对任何网站,只是思路),我也是个小萌新,希望各位大佬多多指点。
3#
stopforme 发表于 2025-4-8 17:53
4#
199122 发表于 2025-4-8 17:59
支持一下 谢谢啦
5#
dream1991 发表于 2025-4-8 19:38
支持一下 谢谢啦
6#
qingfeng66 发表于 2025-4-8 20:06
厉害啊
支持一下
7#
kegumingxin666 发表于 2025-4-8 20:10
感谢分享
8#
yzr820301 发表于 2025-4-8 20:18
谢谢楼主分享啊
9#
mw26973 发表于 2025-4-8 20:21
感谢大佬分享!
10#
wyk66d 发表于 2025-4-8 20:56
大佬真的太强了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-25 02:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表