目标是 sign 参数的生成,直接搜
进入sign函数内部查看
这里 _index_bg_wasm__WEBPACK_IMPORTED_MODULE_0__
名字很长,其实就是 wasm 模块的意思
前面已经写过文章介绍了三种方法,python如何调用wasm文件,直接上代码试试:
文件地址:https://match.yuanrenxue.com/api/match20/wasm
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 基础
| 代表导出函数 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 函数,我们可以查看传入的明文
getStringFromWasm0(1114192, 31)
>>> '1|1662882794000D#uqGdcw41pWeNXm'
就是在 content 加了一段盐值,经过多次调试发现,盐值不变
验证一下是否为标准的md5加密:
结果一直,至此逆向分析过程结束
python 代码
import requests
import time
import hashlib
yuanrenxue_headers = {
"User-Agent": "yuanrenxue.project",
"Cookie": "sessionid=替换成你自己的cookie"
}
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()
运行结果:
过关!