背景
某站点响应被加密, 需要对数据进行解密.
过反调试
进入到详情页面,发现F12 无效, 无法调试. 右键也无法进入开发者调试界面
鼠标移动到 url 栏, 按 F12 即可过掉这个反调试.
现在很顺利的打开了调试界面, 但我并没有下断点, 竟然自己断在了这里.

很明显,这也是反调试, 当上一行代码与下一行代码间隔时间大于 500ms,就重定向到主页。
总结: 此处也可以将这片代码 交给 AI, AI 基本也能分析个八九不离十
ok 我们直接 patch js. 我习惯使用 charles.
用 charles 的 map local 功能

然后 将 js 替换为本地的 min_book.txt
min_book.txt 的内容也很简单, 把这两行注释掉就可以了,不过最好还是直接删掉. 避免出麻烦.

然后 将 js 替换为本地的 min_book.txt

然后F5刷新, 发现没有反调试了.
后面我试了另一种方式. 也是可行的。 那就是禁用断点, 一律不在此处暂停.

关键函数定位
ok 反调试过了, 直接搜索关键字 html5_pages
搜索结果有几十处,其中有一处
这里比较可疑, 是将数据转为 json 的地方, 我们打上断点.
刷新后发现在此处断下. 然后一路调试到了这里

这里 b 的值就是加密的内容.
继续单步走.
发现 z 就是 解密后的内容, 那看来解密函数就是 Module._DeString(p)

我们进入 _DeString 函数看看.

根据上下文猜测是 wasm 代码保护.
断点打在 asm[name].apply(null, arguments), 发现成功断下,F11 直接步进,进入函数内部, 发现跳转到 wat代码 (wasm 文本可读格式).

补 WebAssembly 环境
试试用 node 补环境.
问问 gpt

补环境,以下代码来自 chatgpt
1 | WebAssembly.instantiate(wasmBytes, {}) |
运行后报错
1 | node:internal/process/promises:288 |
大概是env 的问题, 谷歌搜索了一下,回答是 wasm 还依赖env 下的一些函数. 缺少 imports. 我们在 DeString.js 里面搜索一些 env.


补上 wasmImports 后的代码如下
1 | const fs = require("fs") |
注意. _emscripten_run_script, _emscripten_resize_heap, _emscripten_memcpy_big 这些函数都是从 DeString.js 抠出来的.
继续运行。 报错如下
1 | HEAPU8.set(bytes, ptr) |
交给 gpt 帮忙修复. 修复后的代码如下
1 | const fs = require("fs") |
继续运行, 报错如下

继续补 printChar. 把DeString.js 中的函数抠出来
1 | function printChar(stream, curr) { |
补上还报错, 如下

运行后, 发现解密成功.
下面给出完整 node 补 wasm 运行环境代码.
以下代码在 Node v18.20.8 下运行通过
1 | const fs = require("fs") |
zip 解密分析
发现解密后的响应中的 zip 文件无法解压.
解密后的 json 数据中有图片缩略图地址 和 *.zip。 这个 *.zip 是无法解压的. 猜测这个 zip 做了手脚.
抓包发现 有 很多这种 blob 请求

全局搜索 blob. 都打上断点, 发现在此处断下.

然后将这个函数贴给 AI

然后让 AI python 还原, 代码如下
1 | def decrypt_pdf_with_password(input_path, output_path): |
运行后, zip 转为 restored_document.pdf. 用浏览器打开, 输入密码, 即可看到高清大图.