首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
宝塔
V2EX  ›  JavaScript

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

  •  4
     
  •   hakono · 340 天前 · 4365 次点击
    这是一个创建于 340 天前的主题,其中的信息可能已经有所发展或是发生改变。
    说到保护 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 来保护自己的代码。
    虽说前端没有破不了的防护,但这两样东西真的是靠很简单的方法就能达到相当好的保护目的能。而且尤其是当你代码混淆+这些之后,对攻击者来说,那酸爽,简直了。
    第 1 条附言  ·  340 天前
    WebAssembly 打错成了 webassenbly,大家见谅
    第 2 条附言  ·  340 天前
    似乎大家都把目标集中到了 webassembly 上啊,但是实际上我感觉正文里提到的 emscripten 代码体积过大导致调试工具崩溃根本无法启动才是更加现实的防调试的方法。

    就比如我最近尝试反向的一个页游为例,整个游戏的主体 js 代码体积 41MB。
    看到这个体积估计大家就想到会发生什么了。
    下好断点一进入 js 代码内部,开发工具当场卡死然后崩溃。无论 chrome 还是 firefox 都是如此。一年前如此,一年后新版 chrome,firefox 依旧无法处理如此巨大的 js。


    对于这种代码反向个毛啊,连最基本的调试工具都启动不了。直接没调试工具硬读代码?那真的可以放弃反向这代码了

    所以大家如果追求代码安全性的话,可以尝试用这个思路,用 emscripten 或者 WebAssembly,然后塞入极其大量的无用代码(不去调用)只是放那占体积。当 js 代码体积变得极其庞大,那么这个代码就无法被目前所有的浏览器开发工具调试。就如我上面说的那个体积 41MB 的 js 主体文件。
    第 3 条附言  ·  339 天前
    根据 10 楼的经验,只需要不到 10M 体积的 js 代码就能让开发工具崩溃。大家可以尝试用这种比较邪门的方法保护自己的代码。
    但是考虑到今后开发工具优化的可能性(虽然看各大厂商这几年搞的这调试工具,开个大一点的 json 都能卡死,优化性能的可能性估计不太大),可以将 js 代码提升到 20M 左右确保接下来一两年没有任何调试工具可以来破解你的前端 js 代码。嘻嘻。
    至于性能问题,用的既然是 emscripten,或者 webassenbly,再庞大的代码都不用担心性能问题
    25 回复  |  直到 2019-03-06 14:11:20 +08:00
        1
    beordle   340 天前
    和 vmp 比较像,虚拟机加壳,应该是目前最强的了吧
        2
    Mohanson   340 天前 via Android
    然而你名字都没拼对。
        3
    hakono   340 天前
    @Mohanson ……………… n 和 m 太近,银轴稍微偏一下摸到了了就打歪了。后面直接复制粘贴就没注意到
        4
    hjc4869   340 天前
    只是目前相关工具还不成熟而已。
        5
    hakono   340 天前
    @hjc4869 是的,不过按照现在 WebAssembly 的普及速度来看,相关工具目测完善还要好几年。
    一个前端 js 代码能在几年内达到一定的安全性能已经很好了
        6
    gam2046   340 天前
    其实现在浏览器正在慢慢充当一个操作系统的角色,浏览器本身复杂度越来越高,网页设计也越来越复杂。
        7
    heimeil   340 天前
    Rust 有个基于 WebAssembly 的项目,直接映射了所有 JS 对象,完全用 Rust 实现逻辑,JS 只是加载 wasm 的作用。
    https://github.com/DenisKolodin/yew
        8
    Nasei   340 天前
    有可能他用 wasm 并不是为了加密, 像 u3d 做网页版就是把 c#编译成 wasm 吧?
        9
    hakono   340 天前
    @Nasei 是的,大部分用到 WebAssembly 的游戏都是 u3d 的。但从结果来看,编译成 wasm 后,想反向游戏代码难度的确比起 js 混淆是提升了一个量级的。
    不过保护代码的确本来就是 WebAssembly 设计的目的之一。
        10
    zyEros   340 天前
    很成熟了...都用得腻了
        11
    mywaiting   340 天前
    我觉得如果浏览器所有的 Native API 提供一个类似 Proxy ( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy ) 这样的实现,那么不用怎么逆向你的 WebAssembly 逻辑实现,分析出你的程序调用流也是分分中的事情。

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

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


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

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

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

    借地发点无关紧要的牢骚 ...
        17
    secondwtq   340 天前
    哪需要 41 MB,只要不到 10MB 就足够卡到需要载入时强行 kill 进程,调试到半路强行 kill 进程,跑着跑着两个进程都需要强行 kill ...
        18
    hakono   340 天前
    @secondwtq 哈哈,深有感触。js 调试比起其他语言真的是痛苦。 甚至连 js 都不用,在调试工具的 Network 里显示个很庞大的 json 就能直接让开发工具炸了。
        19
    murmur   340 天前
    @secondwtq chrome 好像稍微复杂一点的 js 格式化都没法用
        20
    flyzero   340 天前 via Android
    wasm 也需要比较新的游览器支持的,开发网站为了兼容,现在还是很少用 wasm 吧
        21
    reus   340 天前
    这就是做传统逆向和协议分析的人擅长的了
    所以说 wasm 必然会让一部分只懂 js 的程序员失业,别以为前端就只能用 js
        22
    no1xsyzy   339 天前
    没用过 WebAssembly。难道还可以加壳,加花指令吗?
    说真的,能加花吗?
        23
    zyEros   339 天前
    唉...你们没想过用 vscode 等工具来调试大的 js bundle 么....谁说 debug 一定要在 devtool 里面了
        24
    zyEros   275 天前
    我们研发了最新的 JS 保护代码方案,https://github.com/qiaozi-tech/SecurityWorker,敬请期待
        25
    glass99   256 天前
    @zyEros Nice! 能给个 QQ 或者微信认识一下不
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4200 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 27ms · UTC 03:10 · PVG 11:10 · LAX 19:10 · JFK 22:10
    ♥ Do have faith in what you're doing.