技术解析

发现比起混淆, emscripten 或 webassenbly 才是保护代码的好办法
0
2021-09-02 04:01:40
idczone
说到保护 js 代码,一般都是做混淆
但是最近尝试反向一些网页游戏的代码,然后发现现在越来越多的游戏都是直接上的 emscripten 或者 webassenbly。
和反向混淆比起来,那真的是痛苦到无以复加


首先说 emscripten 吧,用了 emscripten 的游戏很多都会选择把最终游戏代码塞到一个 js 文件里,一个 js 文件 5MB 打底,稍微大一点的 10MB 打底的单个 js 代码文件。
这么做最大的好处就是:F12 开启工具启动调试,下个 xhr 断点,然后能做的就是等待开发工具卡死,然后几分钟后提示无响应。见过各种网站那么多防止开启调试工具的手段,这才是最有效的方法,让调试工具直接崩溃。
鉴于有人可能会反驳电脑性能不行,E5-2620 V3 + 64G 内存的机子依旧无法调试。


然后启动调试工具才只是过了第一道关卡,第二道代码部分就更难受了。满眼都是靠着定义的内存块来储存除了数据,比如下面这种画风。相当于模拟了一块相当大的内存,所有数据都是在内存块里进行操作,传递数据都是用指针。
```javascript
Module.HEAP = z;
Module.HEAP8 = p;
Module.HEAP16 = r;
Module.HEAP32 = n;
Module.HEAPU8 = co;
Module.HEAPU16 = OXb;
Module.HEAPU32 = PXb;
Module.HEAPF32 = I;
Module.HEAPF64 = rg;
```
遇到这些代码能做的只有最原始的记录下内存地址来分析,然后还要经受 js 代码里的各种层层嵌套的混淆的折磨。想看看 api 的 post 数据是怎么加密的,上了瀑布图,才发现这加密代码部分被几十个混淆过的函数翻来覆去搞来搞去,几十几百个指针被倒腾来倒腾去,光是这点反向难度就已经远超混淆了
也许你会说,不就是分析内存和指针吗,但问题是浏览器的开发工具可没有方便的辅助内存分析和指针的工具。



最后说说 webassenbly,这个更加不用提了。
编译成 wasm,一个 wasm 解压出 20M,30M 的字节码。嗯……看的太痛苦了,尝试还原为 c 代码,花了十几分钟反编译,反编译出 200M 的 c 代码,emmmmmmm …………
问题是可阅读性依旧没任何变化
而且体积倒也不重要,但问题是怎么去调试这编译好的 wasm 文件。开发工具可没有针对 wasm 做优化,进了 wasm 代码块就全都是满眼的字节码,和看汇编没区别
但问题是汇编我好歹还有 OD 这方便的工具来调试,但这 webassenbly 我拿什么来调试。而且编译出这个 wasm 的 c 之类的源代码很可能也是经过混淆的。可以说 webassenbly 将反向 js 难度提更高了。


所以,从我这几条经验来看,真的建议开发者在遇到较大代码量时,可以考虑上 emscripten 或者 webassenbly 来保护自己的代码。
虽说前端没有破不了的防护,但这两样东西真的是靠很简单的方法就能达到相当好的保护目的能。而且尤其是当你代码混淆+这些之后,对攻击者来说,那酸爽,简直了。
和 vmp 比较像,虚拟机加壳,应该是目前最强的了吧

然而你名字都没拼对。

……………… n 和 m 太近,银轴稍微偏一下摸到了了就打歪了。后面直接复制粘贴就没注意到

只是目前相关工具还不成熟而已。

是的,不过按照现在 WebAssembly 的普及速度来看,相关工具目测完善还要好几年。
一个前端 js 代码能在几年内达到一定的安全性能已经很好了

其实现在浏览器正在慢慢充当一个操作系统的角色,浏览器本身复杂度越来越高,网页设计也越来越复杂。

Rust 有个基于 WebAssembly 的项目,直接映射了所有 JS 对象,完全用 Rust 实现逻辑,JS 只是加载 wasm 的作用。
https://github.com/DenisKolodin/yew

有可能他用 wasm 并不是为了加密, 像 u3d 做网页版就是把 cwasm 吧?

是的,大部分用到 WebAssembly 的游戏都是 u3d 的。但从结果来看,编译成 wasm 后,想反向游戏代码难度的确比起 js 混淆是提升了一个量级的。
不过保护代码的确本来就是 WebAssembly 设计的目的之一。

很成熟了...都用得腻了

我觉得如果浏览器所有的 Native API 提供一个类似 Proxy ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy ) 这样的实现,那么不用怎么逆向你的 WebAssembly 逻辑实现,分析出你的程序调用流也是分分中的事情。
有程序调用流,再来一个个逆向 WebAssembly 程序用到的数据结构
如果还能提供浏览器自身的内存映射结构出来让 IDA 搞,那目测也没有啥秘密可言~

为什么不尝试直接调用呢?

因为是从 LLVM IR 来的,本身就不容易分析。

然而 js 并不能转换为 asm.js 或者 wasm 啊

是的,的确是个思路。
但问题还是回到了我 9 楼提到的等各种工具想法落实出来,也不知道要等几年。
一个前端 js 代码能在几年内提供一个比单纯混淆要高很多的反向难度的话已经够了。

单纯直接调用有时不一定能解决所有问题啊。

看了前两段,这无非是顺便利用了“现在浏览器调试工具很不适合技术发展趋势”的缺陷而已
Google 和 Mozilla 等厂一方面鼓吹强行要在 Web 上做乱七八糟的应用,同时用 Web 技术做了自己的调试工具,结果拿来调试复杂应用的效果一塌糊涂,完美打了自己的脸
别说游戏,只要随便引几个稍微大点的 npm 包做个 bundle 就够卡死了
借地发点无关紧要的牢骚 ...

哪需要 41 MB,只要不到 10MB 就足够卡到需要载入时强行 kill 进程,调试到半路强行 kill 进程,跑着跑着两个进程都需要强行 kill ...

哈哈,深有感触。js 调试比起其他语言真的是痛苦。 甚至连 js 都不用,在调试工具的 Network 里显示个很庞大的 json 就能直接让开发工具炸了。

chrome 好像稍微复杂一点的 js 格式化都没法用

wasm 也需要比较新的游览器支持的,开发网站为了兼容,现在还是很少用 wasm 吧

这就是做传统逆向和协议分析的人擅长的了
所以说 wasm 必然会让一部分只懂 js 的程序员失业,别以为前端就只能用 js

没用过 WebAssembly。难道还可以加壳,加花指令吗?
说真的,能加花吗?

唉...你们没想过用 vscode 等工具来调试大的 js bundle 么....谁说 debug 一定要在 devtool 里面了

我们研发了最新的 JS 保护代码方案,https://github.com/qiaozi-tech/SecurityWorker,敬请期待

Nice! 能给个 QQ 或者微信认识一下不

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服