目标是 sign 参数的生成,直接搜
进入sign函数内部查看
这里 _index_bg_wasm__WEBPACK_IMPORTED_MODULE_0__
名字很长,其实就是 wasm 模块的意思
前面已经写过文章介绍了三种方法,python如何调用wasm文件,直接上代码试试:
文件地址:https://match.yuanrenxue.com/api/match20/wasm
1 2 3
| In [1]: import pywasm
In [2]: runtime = pywasm.load('wasm.wasm')
|
报错:Exception: pywasm: missing import ./index_bg.js.__wbg_instanceof_Window_434ce1849eb4e0fc
果然没那么简单 😅 看一下源码,从外部js导入了其他函数
没办法,只能硬着头皮去肝wasm源码了,先上一段wasm 基础
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| | 代表导出函数 sign | 伪id 71 | export修饰 | $var0,$var1 参数名 i32代表类型 int32 (func $sign (;71;) (export "sign") (param $var0 i32) (param $var1 i32) (param $var2 i32) local 为当前函数内部用到的变量 (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32) (local $var11 i32) (local $var12 i32) (local $var13 i32) (local $var14 i32) (local $var15 i32) (local $var16 i32) (local $var17 i32) (local $var18 i32) (local $var19 i32) (local $var20 i32) (local $var21 i32) (local $var22 i32) (local $var23 i32) (local $var24 i32) (local $var25 i32) (local $var26 i32) (local $var27 i32) (local $var28 i32) (local $var29 i32) (local $var30 i32) (local $var31 i32) (local $var32 i32) (local $var33 i32) (local $var34 i32) (local $var35 i32) (local $var36 i64) global.get $global0 global.get 从全局变量中读东西 local.set $var3 local.set 写到局部变量中 读写一般都是成对出现的,一般为赋值操作 (约等于$var3 = $global0) i32.const 80 也是读操作,从类型定义了一个80的数 local.set $var4 写入到 $var4 (约等于:$var4 = 80) local.get $var3 读$var3 local.get $var4 读$var4 i32.sub 写操作,i32的减法操作 local.set $var5 写入到 $var5 (约等于:$var5 = $var3 - $var4)堆栈操作 先读的在前 local.get $var5 global.set $global0 local.get $var5 local.get $var1 i32.store offset=64 内存操作,store:缓存,load:读取,offset:偏移量 local.get $var5 local.get $var2 i32.store offset=68 i32.const 16 local.set $var6 local.get $var5 local.get $var6 i32.add 加操作,也属于写操作 local.set $var7 local.get $var7 local.get $var1 local.get $var2 call $func246 执行函数操作,可看之前的get操作一直到set停止,这里就相当于 将$var7,$var1,$var2,传入函数执行 local.get $var5 i32.load offset=16 local.set $var8
|
加密步骤其实只有这一步,len0 就是 content 的长度,下面几步是从内存中获取值,进入到 wasm 内部查看 sign函数
再次进入 sign 函数
一直往下滑,直到看到 md5 字样,然后再次进入函数内部
此时发现 content 长度发生变化,看一下长度,大概是经过了md5加密,那就先来看一下明文是啥?
这段代码的意思,大概相当于 md5($var56, $var55)
,利用 getStringFromWasm0 函数,我们可以查看传入的明文
1 2
| getStringFromWasm0(1114192, 31) >>> '1|1662882794000D#uqGdcw41pWeNXm'
|
就是在 content 加了一段盐值,经过多次调试发现,盐值不变
验证一下是否为标准的md5加密:
结果一直,至此逆向分析过程结束
python 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import requests import time import hashlib
yuanrenxue_headers = { "User-Agent": "yuanrenxue.project", "Cookie": "sessionid=o231j68mvw81ma7y5o199raleeqp9ft5" }
def get_sign(page, ts): data = f"{page}|{ts}D#uqGdcw41pWeNXm".encode() return hashlib.md5(data).hexdigest()
def main(): total = 0 for page in range(1, 6): api = "https://match.yuanrenxue.com/api/match/20" t1 = int(time.time() * 1000) sign = get_sign(page, t1) params = { "page": page, "sign": sign, "t": t1, } res = requests.get( api, params=params, headers=yuanrenxue_headers ) result = res.json()["data"] print(result) total += sum(d['value'] for d in result) print(total)
if __name__ == "__main__": main()
|
运行结果:
过关!
参考链接:
猿人学第20题(题目会不定时更新)_久见Bug了的博客-CSDN博客_猿人学
【JavaScript 逆向】猿人学 web 第二十题:新年挑战_Yy_Rose的博客-CSDN博客