V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hsuehly
V2EX  ›  程序员

各位彭于晏们,最牛逼的纯前端加密,欢迎挑战。

  •  
  •   hsuehly · 2023-08-25 11:02:39 +08:00 · 6740 次点击
    这是一个创建于 448 天前的主题,其中的信息可能已经有所发展或是发生改变。

    闲来没事,简简单单写了一个 demo ,欢迎各位大佬前来挑战,地址: https://hsuehly.github.io/wasm_test/ 期待宴晏们各显神通。

    44 条回复    2023-08-26 10:20:49 +08:00
    maybedk
        1
    maybedk  
       2023-08-25 11:41:49 +08:00
    不就是多对多加密么,研究过一点
    hsuehly
        2
    hsuehly  
    OP
       2023-08-25 11:56:28 +08:00
    @maybedk 嗯,不错,可以尝试破解一下
    tool2d
        3
    tool2d  
       2023-08-25 12:01:26 +08:00
    1. 查看在 wasm 代码,有一个 syscall/js.stringVal 入口,下断点。断在了'syscall/js.stringVal': (_0x2bfa63,_0x135c65,_0x549bc9)=>{

    2. 往下找,附近有一个 const _0x5d948b = _0x17e230[_0x3631d8..的语句。把这个_0x5d948b 变量传到外面,就是加密后的文字了。

    大部分时候,把 wasm 当成黑盒 RPC API 调用就可以了。没必要白盒破解算法的。
    tool2d
        4
    tool2d  
       2023-08-25 12:11:37 +08:00
    wasm 加密有个很严重的问题,就是他最后一定会和 JS 进行交互,想办法把计算后的数据给传出去。

    这步不可能省略,一般都是 stringVal/setStringVal 之类的,很容易出问题。

    还不如 JS 里套一层 JS 虚拟机进行算法加密,至少可以模糊掉 JS 交互部分。
    DreamNya
        5
    DreamNya  
       2023-08-25 12:37:22 +08:00   ❤️ 1
    a='test'
    b=window.encrypt(a)
    c=window.decrypt(b)
    a==c

    前端破解加密方式和 key 其实没啥用,我直接调用你的接口达成目的就行了,不需要知道你具体是怎么保证正常运行的。
    可能一些后端程序缺少环境才需要破你的加密方式(比如自动签到、自动爬虫)。
    shui14
        6
    shui14  
       2023-08-25 13:02:17 +08:00
    wasm 只是增加成本而已,它不是破不了,最起码的,node py 都有现成工具先转 c 再分析,或者直接调用它
    这些都是防君子防不了小人,前端加密,法务兜底

    wasm 最大的意义在于抹平差异,比如 webgpu 当前变动大,还有一些传统软件成为部分可能,ffmpeg ,opencv ,tensorflow 等等,再一个它或许可以像 docker 一样,成为边缘计算的容器,比 serverless function 更近一步,加密混淆纯属路走歪了,绝对的安全在后端(边缘节点),当前这些叫混淆“加盐”
    hsuehly
        7
    hsuehly  
    OP
       2023-08-25 13:14:28 +08:00 via iPhone
    @DreamNya 不错不错,那如果我整个页面的生命周期只调用一次加密函数,和解密函数,然后我在 wasm 中判断第二次调用,给你返回错误的密文该怎么破
    hsuehly
        8
    hsuehly  
    OP
       2023-08-25 13:15:09 +08:00 via iPhone
    @shui14 你可以尝试在后端程序直接调用一下我写的 wasm
    DreamNya
        9
    DreamNya  
       2023-08-25 13:18:32 +08:00
    @hsuehliuyang 把你调用加密函数的函数 hook 掉置空,然后等我来调用,伪装成网页正常的调用…… 类似于破解禁止重放攻击
    hsuehly
        10
    hsuehly  
    OP
       2023-08-25 13:22:53 +08:00 via iPhone
    @DreamNya 但是你只能调一次啊
    gps949
        11
    gps949  
       2023-08-25 13:37:43 +08:00
    AES-CBC?
    bigha
        12
    bigha  
       2023-08-25 13:54:30 +08:00
    @hsuehliuyang

    这不是随便调嘛

    ```
    import requests

    r=requests.Session()

    pdata={
    'group':'ceshi',
    'action':'decrypt',
    'para':'NB_00edbf52008972d16934ab5a45d68a21d7aa6f3ba0d6b3a8d5e61cafd2c0c4777ced03'
    }

    response=requests.get("https://rpc.ping8.top/business/invoke",params=pdata)
    print(response.text)
    ```

    ![7afbd1b6257c4f6078ed8.png]( https://tu.ping8.top/file/7afbd1b6257c4f6078ed8.png)
    santom
        13
    santom  
       2023-08-25 14:18:22 +08:00
    你这个长度无限的吗?
    hsuehly
        14
    hsuehly  
    OP
       2023-08-25 14:20:21 +08:00 via iPhone
    @bigha wasm 限制我去了,你之前逆的那个写了
    hsuehly
        15
    hsuehly  
    OP
       2023-08-25 14:27:45 +08:00 via iPhone
    @gps949 不错,可以找一下 key 藏在哪个地方
    tmtstudio
        16
    tmtstudio  
       2023-08-25 15:19:03 +08:00
    @tool2d #4 大佬试过套虚拟机的方案吗,对性能影响大吗
    lisxour
        17
    lisxour  
       2023-08-25 15:22:01 +08:00
    @tool2d #4 一般都用 wasm 做 hash 之类的计算,你就算在 js 层拿到结果没啥用,你不破解算法,你也模拟不了请求
    lisxour
        18
    lisxour  
       2023-08-25 15:26:10 +08:00
    @tmtstudio 只要网站不需要非常繁重的 js 运算,对于使用者来说,不会有感官上的慢,但在代码层面可能会慢几倍,甚至十几倍都有可能。
    tool2d
        19
    tool2d  
       2023-08-25 16:24:41 +08:00
    @lisxour "你不破解算法,你也模拟不了请求"

    以前一直研究游戏的通讯协议,后端有无数种方法可以限制非法调用。总觉得前端这种明文调用,又想分享,又想加密,出发点就挺矛盾的。

    我游戏客户端的话,把加密和陷阱做的很复杂,全部走自定义二进制协议,基本上想脱离客户端,后端去模拟请求,是不太可能的事情。
    hsuehly
        20
    hsuehly  
    OP
       2023-08-25 16:30:44 +08:00
    @tool2d wasm 也算虚拟机,逆向加密肯定是先解算法找到 key 优先,这样效率是最高的,最后不行了才会上自动化,现在看来在 wasm 里写加密逻辑还是比较安全的,当然你可以把 wasm 当作库直接调用,但是我可以在 wasm 里直接判断环境,不是我的环境直接终止运行
    bigha
        21
    bigha  
       2023-08-25 16:32:12 +08:00
    @lisxour 你看我也没破解楼主的算法,也可以模拟请求,你不信,你试试

    https://code.ping8.top/dKdNj-o4mUd/raw

    所以前端加密就是个伪命题,不管伪装的有多厉害,总能被破解,

    当然作为防守的一方,针对 ip 整一些限流之类的手段也很常见
    tool2d
        22
    tool2d  
       2023-08-25 16:38:47 +08:00
    @hsuehliuyang 真想限制第三方的非法请求,在后端写 3 句加密代码,能顶上前端写 10 句。

    你在 wasm 里判断环境,难度挺大的,就是一个全封闭的环境,连调用最基础的时间和随机数,都需要 JS 去供给。
    hsuehly
        23
    hsuehly  
    OP
       2023-08-25 16:41:01 +08:00
    @tool2d 你可以试一下在 python 或者 nodejs 或者其他有 wasmruntime 的语言运行一下,你看可以运行成功不
    hsuehly
        24
    hsuehly  
    OP
       2023-08-25 16:42:06 +08:00
    @hsuehliuyang 更简单的,把我的 wasm 文件放在你的网页上试一下
    tool2d
        25
    tool2d  
       2023-08-25 16:48:30 +08:00
    @hsuehliuyang wasm 本来就是跨平台的啊,绑定输入输出 API 就可以了。

    如果非要说不能移植,那你可能 wasm 调用的 js ,强依赖于某个浏览器 API 。

    重赏之下,必有勇夫。你 V2 发一个 10 万悬赏帖,肯定有人能把你 key 给破出来。
    lisxour
        26
    lisxour  
       2023-08-25 17:15:00 +08:00
    @bigha #21 那是楼主写的后端就有问题,假设我一个接口有一个 time 、sign 参数,其余参数加不加密并不是重点

    1. time 参数和服务器不能差太多(甚至可以和服务器对时,以便转换成服务器时间)
    2. time 参数不能隔太久(以防重放,当然也有 csrftoken 方案,但是这里 time 也是能达到这种效果的)
    3. sign 参数是用其他参数计算出来的

    这种情况下,你写死了 para 提交,服务器就能判断出来,必须得破解 sign 算法,才能模拟提交

    加密这种东西得和后端相辅相成,只在 js 端做没啥意义
    MaydayV
        27
    MaydayV  
       2023-08-25 17:21:14 +08:00
    这个长度真的,太牛了哈哈哈哈


    NB_d532d5371e2df4b7378f236b33ee12705ee21b8fb5e88426f7a35c28e83d3d9d663fa32cf379542fe4c855ce9e925af984f609a497e6ebe922b3991de17efabd4e954f40be6aecf8c8e890bcf4d39d2809452b14e510b38f7b1c3fc3bb7a5323f9d7526fa0c628528b25d1fe88f64b8a0e398cc6508cc6f5381cce2a444fd1d5dd6ba348a8ecc5c7d1769a823b4aaef722a72be93ba55071d42301cd6fec1585ad9c11c5b0c16dd1ee5da3f5daad6d614eb1d23d6442101417d46cb99e25166a908950f524a4291dae198ff50a79907dfb981eaf43a7a957430e89bc5a71778ec679f2d3a51d94d6e80dad0c2f83cbbca552b0d3635316b93e82b1b930d077cbbc9769287bf4df339009c798545c9defab8c5f4be041fb53613869447b1e06d0b1349749921ebf89d2883d8d19033b3adee5d51e1acbd9b9bc3762c75c2f86de5ffc9ef91381bb08d354dcb97c9ceb4267afe64e928e02b68b16d880a92afef80708ab0fd37045cdd28ec1dbbb406911a9782a1c11c8ca1a2de4fccfd89f11008c48440a1c9bb5cbcd25e07cdb7db20f390511aeb6d0acf4e688df6aad08ec8b17fb4c85cec5f13d8e076177965be2cefa29de25c970cfc4c6f36910f96dde0a48c69dbc2ea1c2e125ec99ec94855dc6b60a6a60c14c900d7d20f650780fa45f16e442c2812bdaf65e87cfa5ebd690dcec9586f83b2a1600b06c9f14f2ced779f3c891a0fda0302264cd9e3351c187cc5e869981763e5cb8995a208f3325350f1f783b38a07bdea3727e162956df55eeb1641f05d209c6490cd3c10276c3c8b789731c4aa487ddc41e22d9cd2b6ce50053cd0c82e406bd0a8c8fc7d60518dfd819b2b3177f4d9e57f397979caa39bbb910c50b313f6b5ceafa1b271c34e561ccfe376f4f25cbf9e94e73a1ee9d3de0b50261ed2d1adbb121f8ee0e24315f313fdf3a355022c2be48e3ea17a265e2a868d83366ed19e866b574f5345f08c1f5f1c342167d15c288ce7e8efce6bc1b85140eb9b5b53b1fc112ae8877642f79d75f3ffce380dc5f30c2aab8696649bfdd193b34a0894a46ecb5dfb6745974fa5d8c5e117e842bf6f513f59da500df35598d8f590ad40b81f56564b6493637b0ea18ce3f8bc9f2d038c26b38d9ea2959d885227e3f33aee7f616b2237b7f2eda8e82434502f3c306453d65fd90005caa61dc4352a609bce773be45af1340b78c5827cde744cfd1d049af135f0efb17c21b9d49d29e7018a28a04acac556c519e6b7d2a344e25087c394518f959d63bbf58b00ac11be6805e494125f013772278ef0dad43e8606224a386e25a7587d31302132cb090fde4c9ed53a5487717fb5313f2747f5428e3157ca53437489d2e39221879271efadc5e65a4fa20450c8312dbaa03494a1f857d35e6e381cc36eea7faac99f6974b2a48f3cea2efcc1a364a006f5a7346cd494f0dd4f1241d80322a287238208eab51af9abb34b3cc5e84c85b06e0660c0f03dfa3e653b0f2b3bbadd0920c80656313facdfcf6fdfe155e8dc91907f136b31922184e09d6624c4074dee7585fe79d810f7fcfe0a426ac873734a8c9e198bb4e6cc25a045b1455298e3e8aa19a66d959f397f3f04d505f218b3e5e92303dd7671ff2b9aa9e0578fdfaad31745f876839409c03587158c5513bedc45559f51c16ebd0c4b58a03d44246369705e91fc75d8055b550b2709cfbb53c79ff9f5871d5c30e6c35d0dce8ca432c83a6c23bdb373913558219e526778105893c20655eb86bedaa2a2596f7577522e2febec4084916156fe9d4f141007d5d01c67749aeec96e6c8c09c5df4e36ae31b12df02d5639be558f6140f7c3b690af837d3d5a1803d637a10b75dd3fb5af6edd99b3a5e07f0d9adfa90ebbd3f593a68717f6c13ba14454bcd628c2c803e6e3def82c702162466366d528f96e0cc0fdaab6eb24e0d9b019bb029f6ae8e5f077b2241b2af03b4566357aac11715dd3771c6c682a51c168d833e6be7a3c2872dce940ba307c06421fabae5b697ea32f5bf83e00669004dcb56c23e09011253f94f7a25db9b07dfd1ed4047782db3c080ce4f1c800c08dc4e149e533c96ce72fd83a842886ad50a36e58c8c8e1faccaa049ff426c8477f77ce989780fdeb74b38baf82bc2e3e2630c248a68d5c82cbdbbbfef22d32679ba1f9be18ffc162badf990127f1daf5ca31364c2492e4c30d33bbb576187842bed658df2c190676ecf949dff1ef75e445c52d5e1e3cae703a7883a3f35b184b334bc72908960b7ec819ed575eebb4897aa02330c6d10ff5df9fe6e0502067476f5b789840919cac5afc7f0150af69a93eff8757e634200661f054b4d593546cd7d6ccdaa595962302fbcfc71d843125891b26d0f9d857ec39dfda671af1d716474090acaaaaa81dd449f05dcf8b89d9ffe319270de17864c283b73f29e91a40f8d6d7666c9daf3e775e52a9beb67013eb132b60447646cd68273f25a8f6ec5457ecf7140a71b3ca59cf6a0fa4182a83cf38245c6d4a198db59232bce3e92e39aaa5169e15dd5240f65cca9754d71a2841ba88e33b2f5908359ae23e1560320f098d9a7b33e27a675f7d09d50896d6ffa075aad41611f7092869e768bfcbe330901711b8e901b58daede4bc64fb9dd897b371a2a2fc0da35c6e3bd26dbbc8bc14e073287389b732c4cfce75918d79b9f9fb9fb5ea90ad136b65f14f32a6a92335e9e171afcd86a5b6de93764e23b77a9c96ed4921b47992c40174722550bc3d83a6b344fc99e486754f04c9302f1595683687fd09703a1f5500ab421eb8398f36d3cbb491ba79120e70c6a585eadb38f9861e39dbd982382610c32162da0e
    bigha
        28
    bigha  
       2023-08-25 17:28:41 +08:00
    @lisxour 那必须的 如果和后端联动起来 那才是彻底把路子堵死了
    hsuehly
        29
    hsuehly  
    OP
       2023-08-25 17:30:52 +08:00
    @MaydayV 秀儿
    kuanat
        30
    kuanat  
       2023-08-25 17:32:21 +08:00 via Android   ❤️ 5
    OP 发了不少帖子了,一直想证明前端利用 wasm 做混淆很难破解。这个结论本身没问题,你要逆向 wasm 的内部逻辑就要走汇编调试那一套。只靠单纯的前端技术应付不了,但是在做逆向的人眼里,没什么区别。

    这里大部分回复的都是在说,wasm/js 的交互机制决定了,多数时间把 wasm 当黑盒,用 RPC 方式调用就好了。没有必要去理会内部实现。

    这里讨论的隐藏前提是用混淆手段防机器人的,基于加密参数限制非 web 客户端对于后端 api 的调用。

    然后 OP 提出,这个加密逻辑全生命流程只能执行一次。说实话我想象不到这样的代码的应用场景,特别是防机器人的方面。(比较接近的是类似微信读书,原始 html 用 canvas 重渲染然后删掉原始数据)

    对于 RPC 调用的应对,OP 认为可以在 wasm 内部做针对外部环境的检测。这一点我从根本上就不认同。

    因为从根本上,客户端就不是可信的运行环境。别说浏览器了,手机 app 为什么都要做 root 越狱检测,都是一样的道理。这是个技术之外的哲学问题,你能判断自己是不是生活在虚拟世界里吗?

    至于实践方面,我是比较赞同 @tool2d 的,基于虚拟机的混淆,模糊掉控制流和调用逻辑,给逆向的人造成的烦躁感远比 wasm 大多了。

    而且虚拟机类型的混淆是可以高度自动化的,你可以每天都变换生成参数和算法。然而逆向虚拟机类混淆是没有什么自动化手段的。
    hsuehly
        31
    hsuehly  
    OP
       2023-08-25 17:42:25 +08:00
    @kuanat 更正一下
    对于 RPC 调用的应对,我认为可以在 wasm 内部限制解密的次数
    对于直接把 wasm 当库调用,我可以在里面判断环境
    你们把 wasm 当黑盒,那你们肯定不清楚里面做了什么,所以上面两项破解条件,就是理解 wasm 里做了什么
    hsuehly
        32
    hsuehly  
    OP
       2023-08-25 17:43:35 +08:00
    @hsuehliuyang 要破解上面两项,就要知道 wasm 里面做了什么
    LifStge
        33
    LifStge  
       2023-08-25 17:50:49 +08:00
    wasm 还是比较好分析的 主要还是看代码量了 导入导出 太规范了 反倒容易分析 确实就楼上说的 没必要分析逻辑的 只需要找指定的接口
    自动化调用强依赖 js 的话 直接内置个浏览器就行了啊
    wasm 的处理流程 直接就是用 ghidra 啥的 二进制分析工具 分析流程就是了 比纯看 wasm 汇编方便不少
    找到关键接口 直接整个模块转 c 代码 修改或添加代码 再编译回去 然后拦截替换就行了 js 端就不用说了吧 混淆也就是分析费力 但是一般也不需要分析那么多 直接改代码 拦截替换就行了.
    felixlong
        34
    felixlong  
       2023-08-25 17:55:48 +08:00
    @hsuehliuyang 你这套方案还不如直接用 Flutter 写你的整个 Web 呢。那样比你这个安全多了。
    cherryas
        35
    cherryas  
       2023-08-25 18:01:54 +08:00
    从干活的角度不如昨天的强制关闭调试窗口
    Sh4ww
        36
    Sh4ww  
       2023-08-25 18:04:05 +08:00   ❤️ 1
    现实是,主流的平台或者厂商没几个用 wasm 的
    LifStge
        37
    LifStge  
       2023-08-25 18:15:47 +08:00
    wasm 二进制内容 修改逻辑不多的话 直接 用 wasm-dis 转文本格式 然后修改添加逻辑后 再用 wasm-as 转回二进制就行 也不需要反编译到 c 改完再编译回去(这样麻烦点吧了).
    hsuehly
        38
    hsuehly  
    OP
       2023-08-25 18:34:22 +08:00
    如果大家仔细看 wasm 里的内容的话,会发现里面的函数也进行了混淆,但是好像没有人提这一点
    linuxsogood
        39
    linuxsogood  
       2023-08-25 18:34:23 +08:00
    @hsuehliuyang #7 跟游戏外挂一下,直接修改内存不就好了,光凭前端你还能阻挡住不能改内存吗?
    AEP203
        40
    AEP203  
       2023-08-26 00:00:32 +08:00
    不知道啥玩意 JS 混淆器,前端代码除了一堆花指令没啥特别的,有空再还原下 wasm ,前端代码: https://codefile.io/f/bKSY6N3nSW
    yuezk
        41
    yuezk  
       2023-08-26 08:39:22 +08:00
    hsuehly
        42
    hsuehly  
    OP
       2023-08-26 09:12:52 +08:00 via iPhone
    @yuezk 对 ob 的
    hsuehly
        43
    hsuehly  
    OP
       2023-08-26 09:14:19 +08:00 via iPhone
    @yuezk 期待大佬更新关于 wasm 的
    yuezk
        44
    yuezk  
       2023-08-26 10:20:49 +08:00
    @hsuehliuyang #43 对 wasm 不熟,在 MDN 上查了一下,但那些指令理解起来还是很费劲。单从内容看,wasm 是用 Go 编译的,用了 crypto/aes 和 crypt/cipher 模块,算法应该是 AES-CBC 。但是我对 Go 和 wasm 的指令都不熟悉,对 AES-CBC 了解过一些,核心算法是对加密内容分成每 16byte 一块,然后和 key 进行 XOR 操作。查找了一下 wasm 中的 xor 操作,整个文件的 xor 操作一共也就是 93 处。对于那些熟悉算法的和 wasm 指令的人来说破解应该不难。

    另外,即便不理解算法,也有可能从内存中的 dump 中读取,看到过类似 aes-finder 的工具,不过没有实操过。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2664 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:29 · PVG 23:29 · LAX 07:29 · JFK 10:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.