发现比起混淆, emscripten 或 webassenbly 才是保护代码的好办法

2018-12-12 17:50:14 +08:00
 hakono
说到保护 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 来保护自己的代码。
虽说前端没有破不了的防护,但这两样东西真的是靠很简单的方法就能达到相当好的保护目的能。而且尤其是当你代码混淆+这些之后,对攻击者来说,那酸爽,简直了。
9728 次点击
所在节点    JavaScript
25 条回复
beordle
2018-12-12 19:14:34 +08:00
和 vmp 比较像,虚拟机加壳,应该是目前最强的了吧
Mohanson
2018-12-12 19:50:16 +08:00
然而你名字都没拼对。
hakono
2018-12-12 19:57:58 +08:00
@Mohanson ……………… n 和 m 太近,银轴稍微偏一下摸到了了就打歪了。后面直接复制粘贴就没注意到
hjc4869
2018-12-12 20:01:00 +08:00
只是目前相关工具还不成熟而已。
hakono
2018-12-12 20:04:46 +08:00
@hjc4869 是的,不过按照现在 WebAssembly 的普及速度来看,相关工具目测完善还要好几年。
一个前端 js 代码能在几年内达到一定的安全性能已经很好了
gam2046
2018-12-12 20:35:36 +08:00
其实现在浏览器正在慢慢充当一个操作系统的角色,浏览器本身复杂度越来越高,网页设计也越来越复杂。
heimeil
2018-12-12 20:43:36 +08:00
Rust 有个基于 WebAssembly 的项目,直接映射了所有 JS 对象,完全用 Rust 实现逻辑,JS 只是加载 wasm 的作用。
https://github.com/DenisKolodin/yew
Nasei
2018-12-12 21:11:38 +08:00
有可能他用 wasm 并不是为了加密, 像 u3d 做网页版就是把 c#编译成 wasm 吧?
hakono
2018-12-12 21:18:55 +08:00
@Nasei 是的,大部分用到 WebAssembly 的游戏都是 u3d 的。但从结果来看,编译成 wasm 后,想反向游戏代码难度的确比起 js 混淆是提升了一个量级的。
不过保护代码的确本来就是 WebAssembly 设计的目的之一。
zyEros
2018-12-12 21:21:27 +08:00
很成熟了...都用得腻了
mywaiting
2018-12-12 23:12:53 +08:00
我觉得如果浏览器所有的 Native API 提供一个类似 Proxy ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy ) 这样的实现,那么不用怎么逆向你的 WebAssembly 逻辑实现,分析出你的程序调用流也是分分中的事情。

有程序调用流,再来一个个逆向 WebAssembly 程序用到的数据结构

如果还能提供浏览器自身的内存映射结构出来让 IDA 搞,那目测也没有啥秘密可言~
realityone
2018-12-12 23:14:46 +08:00
为什么不尝试直接调用呢?
wdlth
2018-12-12 23:36:42 +08:00
因为是从 LLVM IR 来的,本身就不容易分析。
wwwe
2018-12-13 00:01:53 +08:00
然而 js 并不能转换为 asm.js 或者 wasm 啊
hakono
2018-12-13 00:18:55 +08:00
@mywaiting 是的,的确是个思路。
但问题还是回到了我 9 楼提到的等各种工具想法落实出来,也不知道要等几年。
一个前端 js 代码能在几年内提供一个比单纯混淆要高很多的反向难度的话已经够了。


@realityone 单纯直接调用有时不一定能解决所有问题啊。
secondwtq
2018-12-13 01:15:28 +08:00
看了前两段,这无非是顺便利用了“现在浏览器调试工具很不适合技术发展趋势”的缺陷而已

Google 和 Mozilla 等厂一方面鼓吹强行要在 Web 上做乱七八糟的应用,同时用 Web 技术做了自己的调试工具,结果拿来调试复杂应用的效果一塌糊涂,完美打了自己的脸

别说游戏,只要随便引几个稍微大点的 npm 包做个 bundle 就够卡死了

借地发点无关紧要的牢骚 ...
secondwtq
2018-12-13 01:18:00 +08:00
哪需要 41 MB,只要不到 10MB 就足够卡到需要载入时强行 kill 进程,调试到半路强行 kill 进程,跑着跑着两个进程都需要强行 kill ...
hakono
2018-12-13 01:26:20 +08:00
@secondwtq 哈哈,深有感触。js 调试比起其他语言真的是痛苦。 甚至连 js 都不用,在调试工具的 Network 里显示个很庞大的 json 就能直接让开发工具炸了。
murmur
2018-12-13 08:25:51 +08:00
@secondwtq chrome 好像稍微复杂一点的 js 格式化都没法用
flyzero
2018-12-13 08:39:32 +08:00
wasm 也需要比较新的游览器支持的,开发网站为了兼容,现在还是很少用 wasm 吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/516970

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX