js逆向之wasm专题--荔枝网

# 免责声明:本案例仅供学习和参考,禁止商用

1,确定要逆向的目标

2,xhr断点

3,这个入参已经有值了 ,所以我需要进到异步里面去

4,在这里打上断点

5,这里注意了,因为入参已经存在了,所以加密值不是这里生成的

6,所以需要往上点一个栈

7,进到后,鼠标悬浮n发现这个headers值还是有,所以还得往前跟

8,要推到下一个promise.then的后一个栈

9,看到这个代码后,先复习一下异步任务

10,通过fetch来复习

11,通过上面的fetch结构,来分析网页的结构

12,从这个c.default里面进去,

这里有一个坑,就是S进去后可能会因为url地址的不同也就是传参的不同会进到不同的函数里面,

所以如果进入后发现返回的参数不一致就跳回来,不过现在这个是对的

13,从这个m这里进去

14,在这个i这里打上断点

15,从e函数进来后,在这个return语句上打上断点就可以看到这个数据

16,从a.apply进来,这里就是核心函数

17,这个参数值是一个一个对应的

18,将核心代码扣下来

19,根据报错信息,慢慢补全

20,这个w是核心,是wasm的首字母

这个w没有function,location,说明是赋值过来的

搜w = ,然后在每一个位置打上断点

21,经过测试,在这个位置

22.接下来,就有点难度了

看堆栈

23,进到栈后

24,这里逻辑需要理清楚,我用箭头标清楚了,这个赋值是一步传一步的,很有意思

25,这个逻辑在这,从上面的图梳理出来了

I = fetch(I),这个fetch就是对里面的I也就是一个wasm的url发请求

A.sent = I

A.t1 = A.sent

A.t2 = B

A.sent = A.t0(A.t1, A.t2)

Q = A.sent

C = Q.instance

O(C, E)

26,这个I对应的请求网址

就是这个wasm文件

27,这里看一下A.t0是怎么生成的

从A.t0里面进去

打上断点,从q里面进去

往下滑可以看到

在instantiate打上断点, 记住我们的目的不是要把这个instantiate扣下来,我们是为了看这个A.t0是怎么生成的,因为我刷新页面将这个wasm文件下载下来,然后调用里面的instantiate方法

28,接下来继续补代码

先将这个wasm文件下载下来

移动到pycharm里面去

将这个encrypt_data函数收起来,然后再创建一个函数

29,运行代码看结果

30,找k的位置

31,G不存在,找G

这个G和i一并拿

找U

找s

找Y

找R

找S

找K

找N

补完N后报错信息就变了

在每一个catch后面打印异常捕获的信息

运行代码后结果

self和window先不管,先补E

然后补P

补完P和x后就只剩补环境了,和变量依赖和函数依赖

这个window和self是指向同一个空间的 ,这个小window是在Window里面的

以后遇到环境检测上来就把global给删了

删了以后又报这个错了,我原本就已经补完了,所以是因为wasm的问题,这时候就需要用代理监控来补环境

代理监控

function watch(obj, name) {
    return new Proxy(obj, {
        get: function (target, property, receiver) {
            try {
                if (typeof target[property] === 'function') {
                    console.log(
                        "对象 =>" +
                        name +
                        ",读取属性:" +
                        property +
                        ",值为:" +
                        "function" +
                        ",类型为:" +
                        typeof target[property]
                    );
                } else {
                    console.log(
                        "对象 =>" +
                        name +
                        ",读取属性:" +
                        property +
                        ",值为:" +
                        target[property] +
                        ",类型为:" +
                        typeof target[property]
                    );
                }
            } catch (e) {
            }
            return target[property]; // 需要返回属性值
        },
        set: (target, property, newValue, receiver) => {
            try {
                console.log(
                    "对象 =>" +
                    name +
                    ",设置属性:" +
                    property +
                    ",值为:" +
                    newValue +
                    ",类型为:" +
                    typeof newValue
                );
                target[property] = newValue; // 实际设置属性值
                return true; // 表示设置成功
            } catch (e) {
            }
            return Reflect.set(target, property, newValue, receiver)
        }
    });
}
window = watch(window, "window");
self = watch(self, "self")

补完后运行代码

32,接下来document也要补

32,补环境补了这些代码

delete global;
function Window() {

}
window = new Window();
self = window;
self.self = window;
Location = function Location(){}
Location.prototype = {
    "ancestorOrigins": {},
    "href": "https://www.gdtv.cn/channels/4#205",
    "origin": "https://www.gdtv.cn",
    "protocol": "https:",
    "host": "www.gdtv.cn",
    "hostname": "www.gdtv.cn",
    "port": "",
    "pathname": "/channels/4",
    "search": "",
    "hash": "#205"
}
location = new Location();
window.location = location;

document = {
    location:window.location
}
window.document = document;

最终的结果也是成功了

function get_encrypt_headers() {
    // 1,自行创建wasm对象  A.t0就是这个WebAssembly.instantiate
    WebAssembly.instantiate(wasm_code, B123).then(ret => {
        // C与w不能加var,让这两个变量作为全局变量
        C = ret.instance;
        w = C.exports;

        function encrypt_data(A, g, I, B, Q, C) {
            try {
                var E = L(A, w.__wbindgen_export_0, w.__wbindgen_export_1)
                    , D = h
                    , i = L(g, w.__wbindgen_export_0, w.__wbindgen_export_1)
                    , o = h
                    , Y = L(I, w.__wbindgen_export_0, w.__wbindgen_export_1)
                    , N = h
                    , J = L(B, w.__wbindgen_export_0, w.__wbindgen_export_1)
                    , k = h
                    , K = L(Q, w.__wbindgen_export_0, w.__wbindgen_export_1)
                    , y = h;
                return G(w.a(E, D, i, o, Y, N, J, k, K, y, function (A) {
                    if (1 == H)
                        throw new Error("out of js stack");
                    return M[--H] = A,
                        H
                }(C)))
            } finally {
                M[H++] = void 0
            }
        }

        var result = encrypt_data(
            "GET",
            "https://gdtv-api.gdtv.cn/api/channel/v1/news?beginScore=0&channelId=205&pageSize=11",
            "WEB_252daa40-bafc-11f0-95af-cb0adf5a6594",
            "WEB_PC",
            "",
            undefined
        );
        // 将map对象转为普通对象
        var headers_obj = Object.fromEntries(result)
        // 将obj对象转为字符串
        var headers_str = JSON.stringify(headers_obj);
        console.log(headers_str);
    })
}

打印的结果

import requests
import json,subprocess

headers_info_str = subprocess.run(['node','荔枝网.js'],capture_output=True,text=True,encoding='utf-8')
headers_info = json.loads(headers_info_str.stdout)

headers = {
    "accept": "application/json, text/plain, */*",
    "accept-language": "zh-CN,zh;q=0.9",
    "content-type": "application/json",
    "origin": "https://www.gdtv.cn",
    "priority": "u=1, i",
    "referer": "https://www.gdtv.cn/",
    "sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
    "x-itouchtv-ca-key": headers_info["X-ITOUCHTV-Ca-Key"],
    "x-itouchtv-ca-signature": headers_info["X-ITOUCHTV-Ca-Signature"],
    "x-itouchtv-ca-timestamp": str(headers_info["X-ITOUCHTV-Ca-Timestamp"]),
    "x-itouchtv-client": "WEB_PC",
    "x-itouchtv-device-id": headers_info["X-ITOUCHTV-DEVICE-ID"]
}
url = "https://gdtv-api.gdtv.cn/api/channel/v1/news"
params = {
    "beginScore": "0",
    "channelId": "205",
    "pageSize": "11"
}
response = requests.get(url, headers=headers, params=params)

print(response.text)
print(response)

运行Python代码也是成功了

03-26
### 逆向工程与反编译概述 逆向工程是一种通过对软件的目标代码进行分析,将其转化为更高级别的表示形式的过程。这一过程通常用于研究现有系统的内部结构、功能以及实现细节。在Java和Android领域,反编译工具被广泛应用于逆向工程中。 #### Java逆向工程中的Jad反编译工具 Jad是一款经典的Java反编译工具,能够将`.class`字节码文件转换为可读的`.java`源代码[^1]。虽然它可能无法完全恢复原始源代码,但它提供了足够的信息来帮助开发者理解已编译的Java程序逻辑。Jad支持多种反编译模式,并允许用户自定义规则以适应不同的需求。此外,其命令行接口和图形界面使得复杂代码的分析变得更加便捷。 #### Android逆向工程中的JEB反编译工具 针对Android应用的逆向工程,JEB是由PNF Software开发的一款专业级工具[^2]。相较于其他同类产品,JEB不仅具备强大的APK文件反编译能力,还能对Dalvik字节码执行高效而精准的操作。它的核心优势在于以下几个方面: - **广泛的平台兼容性**:除Android外,还支持ARM、MIPS等多种架构的二进制文件反汇编。 - **混淆代码解析**:内置模块能有效应对高度混淆的代码,提供分层重构机制以便于深入分析。 - **API集成支持**:允许通过编写Python或Java脚本来扩展功能并完成特定任务。 #### APK反编译流程及其意义 当涉及到具体的APK包时,可以通过一系列步骤提取其中的信息来进行全面的安全评估或者学习目的的研究工作[^3]。这些步骤一般包括但不限于获取资产目录(`assets`)内的资源数据;解密XML配置文档如`AndroidManifest.xml`定位应用程序启动点;最后利用上述提到的各种专用软件重现整个项目框架供进一步探讨。 ```bash # 使用apktool反编译APK示例 apktool d your_app.apk -o output_directory/ ``` 以上命令展示了如何借助开源工具ApkTool轻松拆卸目标安卓档案至易于探索的状态下。 ### 结论 无论是传统的桌面端还是现代移动端环境里头,恰当运用合适的反编译解决方案都是达成逆向工程项目成功不可或缺的一环。每种工具有各自专精之处,在实际应用场景当中应当依据具体需求做出明智的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值