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

前两天有 V 友问一个加密的 JS 怎么解密,于是今天脱壳?解密的脚本出来了。

  •  
  •   imdong ·
    imdong · 2019-08-31 18:52:01 +08:00 · 10127 次点击
    这是一个创建于 1671 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当时追了下代码挺感兴趣,正好还有时间,就开搞了。

    主要是看作者写的 “最牛加密” 挺不爽的...

    用了一下午的时间分析和写脚本,测试能解开普通默认的加密了

    没有去适配所谓的强加密什么的...

    当然,整体思路缕下来还是很简单的,

    就是先把一个数组(最开始的 base64)切开前后对换。

    然后代码部分可能用字符串处理的都用一个方法通过 rc4 解密返回调用。

    大致就是下面这样的了...

    // 此数组的值应该是 base64 为了方便看就明文了
    var arr = ['hello', 'alert', 'test', 'debug', 'world'];
    
    arr = [].concat(arr.splice(1, 3), arr);
    
    window[rc4(0, '密钥 1')](rc4(1, '密钥 2'));
    

    解密效果

    我认为互联网本应开源,而且前端没有真正意义的加密,能执行就一定能解密。

    当然,作者说 “绝对不可逆 / 耶稣也无法 100%还原” 是真的,

    因为 YUI compressor 压缩也是不可逆的...

    变量名都被改掉了,显然无可能还原了...

    解密代码:

    (function (js_body) {
        // 脱壳
        let js_arr = js_body.split("\n").pop().split(';'),
            fun_name = /var\s+(_0x[a-z0-9]+)=/.exec(js_arr[6])[1],
            reg_str = fun_name + '\\(' + "'([^']+)',\s*'([^']+)'" + '\\)',
            js_str = js_arr.slice(54, js_arr.length - 4).join(';'),
            code_shell = js_arr.slice(0, 54).join(';'),
            shell_obj = eval("(function(){" + code_shell + ";return " + fun_name + "})()");
        js_str = js_str.replace(new RegExp(reg_str, 'g'), function (str, id, key) {
            return '"' + shell_obj(id, key) + '"';
        }).replace(/([a-z0-9\-_A-Z)\]]+)\s?\[["']([^"']+)["']\]/g, '$1.$2').replace(/(?<!_)(0x[0-9a-f]+)/g, function (hex) {
            return parseInt(hex).toString();
        });
        // 还原混淆
        let obj = null, name = '';
        js_str = js_str.replace(/{(var\s+(_0x[0-9a-z]+)=(\{(.*)\}));/g, function (str, code_str, _name, obj_str) {
            obj = eval("(function () {return " + obj_str + "})()");
            name = _name;
            return '{';
        });
        if (obj) {
            let i = 5;
            while (js_str.indexOf(name) && --i > 0) {
                for (const key in obj) {
                    if (!obj.hasOwnProperty(key)) continue;
                    if (typeof obj[key] == 'function') {
                        let fun_info = /function\s*_0x[0-9a-z]+\(([^)]*)\){return\s*([^;]+);}/.exec(obj[key].toString());
                        js_str = js_str.replace(new RegExp(name + '\\.' + key + '\\(([^())]*)\\)', 'g'), function (string, args_str) {
                            let args = args_str.split(','),
                                fun_args = fun_info[1].split(','),
                                fun_body = fun_info[2];
                            fun_args.forEach(function (item, index) {
                                fun_body = fun_body.replace(item, args[index]);
                            });
                            return fun_body;
                        });
                    } else if (typeof obj[key] == 'string') {
                        js_str = js_str.replace(name + '.' + key, '"' + obj[key] + '"');
                    } else {
                        js_str = js_str.replace(name + '.' + key, obj[key].toString());
                    }
                }
            }
        }
        return js_str;
    })($('#resultSource').val() || $('#jsdata').val());
    
    

    我的小站:https://www.qs5.org/Post/673.html

    28 条回复    2019-09-02 09:31:26 +08:00
    shanlan
        1
    shanlan  
       2019-08-31 19:17:48 +08:00
    如果能讲讲解密思路就更好,这样直接上代码的话有点生硬。
    imdong
        2
    imdong  
    OP
       2019-08-31 19:43:29 +08:00   ❤️ 1
    @shanlan 嗯 我感觉可以,先去陪女朋友玩游戏,等下抽时间缕缕思路试下写写过程。
    cy97cool
        3
    cy97cool  
       2019-08-31 19:46:40 +08:00 via Android
    如果能针对这个 https://obfuscator.io 做个通用的反混淆就更好了
    lneoi
        4
    lneoi  
       2019-08-31 19:48:32 +08:00
    期待思路讲解
    imdong
        5
    imdong  
    OP
       2019-08-31 19:54:24 +08:00
    @cy97cool 卧槽,我怎么看着这俩的加密的核心思路是一毛一样的么?
    只是这个 sojson 自己又包了一点而已?
    unclemcz
        6
    unclemcz  
       2019-08-31 20:24:19 +08:00   ❤️ 4
    @imdong #2 关爱狗狗健康,请不要随意撒狗粮。
    xiangyuecn
        7
    xiangyuecn  
       2019-08-31 20:28:58 +08:00   ❤️ 3
    试了一下这个号称“最牛逼加密”,果然思路清奇

    首先把 eval 拦截一下看看,咦,没有?

    看一下加密后的代码,原来仅仅替换加密了一下变量名 y 和字符串而已。。。想看什么加密内容直接 console.log 就完事了。。。😂😂😂 前端真娱乐
    zsx
        8
    zsx  
       2019-08-31 21:16:04 +08:00
    简单看了一下,这个加密挺没意思的,就是普通的混淆
    目前碰到过的麻烦并且有点意思的 JS 混淆是这个: https://www.jshaman.com/

    至于 JS 加密,个人认为混淆不算加密,这个比较正经: https://www.v2ex.com/t/549319
    gunjianpan
        9
    gunjianpan  
       2019-08-31 21:33:29 +08:00
    @cy97cool ym cy dalao
    imdong
        10
    imdong  
    OP
       2019-09-01 00:05:42 +08:00
    @zsx 本帖说的 sojson.v5 和 jshaman、obfuscator 应该是 师出同门。

    因为加(hun)密(xiao)的原理都一模一样,几乎可以断定是同一套代码出来的。
    imdong
        11
    imdong  
    OP
       2019-09-01 00:06:50 +08:00
    至于 SecurityWorker 这个代码,那是真的大牛代码,惹不起...
    都上升到 VM 了,我等辣鸡瑟瑟发抖,不敢缩话。
    cydian
        12
    cydian  
       2019-09-01 00:27:05 +08:00 via Android
    也想看看分享的思路。
    gamexg
        13
    gamexg  
       2019-09-01 00:27:58 +08:00 via Android
    WebAssembly 现在是什么情况了?
    感觉这个难破解了。
    1981
        14
    1981  
       2019-09-01 04:12:48 +08:00 via Android   ❤️ 1
    https://github.com/insoxin/sojson.v5

    233,持续关注 sojson 很多年了,,,,
    jawnkuin
        15
    jawnkuin  
       2019-09-01 04:42:43 +08:00
    第一次听说前端可以加密…………
    几个月前有个公司要跟我们合作,最后方案有个数据要加密传输但是要在前端解密,让我无语了好久。

    最后发现他只是想 base64 转换一下而已,感觉前端很多不了解加签 /对称加密 /非对称加密这些概念……
    shew2356
        16
    shew2356  
       2019-09-01 09:00:24 +08:00 via iPhone
    @jawnkuin 没错,前端应该是各种编码,然后伪加密。
    herotiga
        17
    herotiga  
       2019-09-01 09:09:29 +08:00
    @jawnkuin 只能说好多是培训班出来的,计算机基础不牢
    jaskle
        18
    jaskle  
       2019-09-01 09:16:30 +08:00 via Android
    不涉及解析执行的话都很假,可以混淆一下,搞些 abcd 混淆
    watzds
        19
    watzds  
       2019-09-01 09:18:48 +08:00 via Android
    是不是每一行都加断点,找到入口就差不多了
    zsx
        20
    zsx  
       2019-09-01 10:09:06 +08:00
    @imdong #10 没注意才发现 obfuscator.io 里有别的配置项,那应该是一样的了
    fenghuang
        21
    fenghuang  
       2019-09-01 11:33:05 +08:00
    网站无法访问
    Nicoco
        22
    Nicoco  
       2019-09-01 12:19:09 +08:00
    @xiangyuecn 前端就是庙小妖风大,池浅王八多
    youwo
        23
    youwo  
       2019-09-01 13:28:33 +08:00 via iPhone
    坐等
    simonv3ex
        24
    simonv3ex  
       2019-09-01 13:35:25 +08:00
    @imdong #2 现在流行把狗骗进来杀?
    auchan
        25
    auchan  
       2019-09-01 15:49:06 +08:00
    不过一般的这种程度的混淆和加密够了
    KasuganoSoras
        26
    KasuganoSoras  
       2019-09-01 16:08:20 +08:00
    想起来以前听的 base64 加密的笑话
    imdong
        27
    imdong  
    OP
       2019-09-02 00:04:16 +08:00   ❤️ 1
    @watzds 额,道理是这样,可是这个没有入口,真实代码就在中间,掐头去尾就能用了...
    但是真实代码中间又混杂了一些花指令。

    @fenghuang 是我的博客不能访问么?能给下网络情况么?
    @auchan 讲道理,需要混淆的混淆也没用,没必要混淆的根本杞人忧天...
    hakono
        28
    hakono  
       2019-09-02 09:31:26 +08:00 via iPhone
    觉得前端没法加密其实也是井底之蛙了

    其实都不需要用上面大佬的 vm 虚拟机,把你的业务核心逻辑都用 WebAssembly 写了,基本上就能挡下一大部分想反向你代码的人了。
    因为反向 WebAssembly 类似于反向汇编,是需要有反向汇编等级的能力的人才能做好,基于 WebAssembly 你可以轻松把 pc 应用开发上的虚拟机 加壳那一套搬运到前端。啥 请个反向大佬就轻松破解? 太天真了,就算是大佬搞反汇编也是需要 OD 这类工具才能工作的,而就现在前端那狗屎一样调试工具,能保证加载个大点的 js 代码不崩都做不到,你还想有像 OD 种等级的强大反向工具,那是做梦了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5256 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 07:24 · PVG 15:24 · LAX 00:24 · JFK 03:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.