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

2019-08-31 18:52:01 +08:00
 imdong

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

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

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

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

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

就是先把一个数组(最开始的 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

10210 次点击
所在节点    程序员
28 条回复
fenghuang
2019-09-01 11:33:05 +08:00
网站无法访问
Nicoco
2019-09-01 12:19:09 +08:00
@xiangyuecn 前端就是庙小妖风大,池浅王八多
youwo
2019-09-01 13:28:33 +08:00
坐等
simonv3ex
2019-09-01 13:35:25 +08:00
@imdong #2 现在流行把狗骗进来杀?
auchan
2019-09-01 15:49:06 +08:00
不过一般的这种程度的混淆和加密够了
KasuganoSoras
2019-09-01 16:08:20 +08:00
想起来以前听的 base64 加密的笑话
imdong
2019-09-02 00:04:16 +08:00
@watzds 额,道理是这样,可是这个没有入口,真实代码就在中间,掐头去尾就能用了...
但是真实代码中间又混杂了一些花指令。

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

其实都不需要用上面大佬的 vm 虚拟机,把你的业务核心逻辑都用 WebAssembly 写了,基本上就能挡下一大部分想反向你代码的人了。
因为反向 WebAssembly 类似于反向汇编,是需要有反向汇编等级的能力的人才能做好,基于 WebAssembly 你可以轻松把 pc 应用开发上的虚拟机 加壳那一套搬运到前端。啥 请个反向大佬就轻松破解? 太天真了,就算是大佬搞反汇编也是需要 OD 这类工具才能工作的,而就现在前端那狗屎一样调试工具,能保证加载个大点的 js 代码不崩都做不到,你还想有像 OD 种等级的强大反向工具,那是做梦了

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

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

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

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

© 2021 V2EX