# 免责声明:本案例仅供学习和参考,禁止商用
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代码也是成功了

1489

被折叠的 条评论
为什么被折叠?



