python实现sojson V5反混淆

加密方式

sojson V5方式的加密分为了3部分

  • 密文array
  • 解密函数
  • 混淆后的原代码

在经过一些试验后,发现sojson几乎所有版本的混淆都包含这三部分,不同的只是无用代码和变量/函数名的混淆


sojson的核心加密方式总结为如下:

  • 将所有函数调用,对象属性访问改为数组+字符串索引的方式,如:a.b() ===> a['b']()
  • 在处理完所有函数调用,对象属性后,将源码中所有的字符串进行加密操作
  • 将剩余的变量名,函数名,对象名进行随机化操作 如__0x123456
  • 将if语句改为逻辑与运算 如if(a==1){b=2} ===> __0xAAA==1 && b=2
    • 逻辑与,即当前面判断为false时不进行后面的判断,和if很像
  • 将数字拆分运算,比如把1变为3-5-6+9
  • fuckjs操作:将false改为![] 将true改为!![] 将NaN改为+[![]] 将undefined改为[][[]]等

在知道加密方式后,我们可以知道 变量名 函数名 对象名无法进行还原, 但字符串在运行时必然要进行还原,因此我们只需要找到解密函数,然后进行手动调用就可以还原字符串。


混淆分析

js原文:

(function(w, d) { 
 w.update = "2019年09月12日15:24:29更新"; 
 d.info = "这个是一个本站对JavaScript 脚本的一个最牛加密,兼容性适中,解密难度极大"; 
})(window, document);

普通混淆之后的js:

//密文array
/*1.基本数据开始*/
var a = ['jsjiami.com.v6', 'ZjsgjilBUDamOPlriw.EVcomBp.lv6==', '5p+76Zev6aOL6K2W6ICh57Czw59KXsO7woIUw6fCgMKLw5TCqg==', 'KFXCvcKCJFM=', 'IWQXKgw=', 'Gks8Kg==', 'w4h1w7oOag=='];
//有的版本中, 这里会有一段是为了重新排序array的匿名自执行函数, 此时只要将整个基本数据直接执行可以得到最终的密文array
/*1.基本数据结束*/

//解密函数
/*2.解密基本数据的函数*/
(function (c, d, e) {
    var f = function (g, h, i, j) {
        h = h >> 0x8;
        if (h < g) {
            while (--g) {
                j = c['shift']();
                if (h === g) {
                    h = j;
                    i = c['shift']();
                } else if (i['replace'](/[ZglBUDOPlrwEVBpl=]/g, '') === h) {
                    c['push'](j);
                }
            }
            c['push'](c['shift']());
        }
        return 0x242ed;
    };
    return f(++d, e) >> d ^ e;
}(a, 0x1eb, 0x1eb00));
var b = function (c, d) {
    c = ~~'0x' ['concat'](c);
    var e = a[c];
    if (b['gPvZlv'] === undefined) {
        (function () {
            var f = typeof window !== 'undefined' ? window : typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global : this;
            var g = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            f['atob'] || (f['atob'] = function (h) {
                var i = String(h)['replace'](/=+$/, '');
                for (var j = 0x0, k, l, m = 0x0, n = ''; l = i['charAt'](m++); ~l && (k = j % 0x4 ? k * 0x40 + l : l, j++ % 0x4) ? n += String['fromCharCode'](0xff & k >> (-0x2 * j & 0x6)) : 0x0) {
                    l = g['indexOf'](l);
                }
                return n;
            });
        }());
        var o = function (p, d) {
            var r = [],
                s = 0x0,
                t, u = '',
                v = '';
            p = atob(p);
            for (var w = 0x0, x = p['length']; w < x; w++) {
                v += '%' + ('00' + p['charCodeAt'](w)['toString'](0x10))['slice'](-0x2);
            }
            p = decodeURIComponent(v);
            for (var y = 0x0; y < 0x100; y++) {
                r[y] = y;
            }
            for (y = 0x0; y < 0x100; y++) {
                s = (s + r[y] + d['charCodeAt'](y % d['length'])) % 0x100;
                t = r[y];
                r[y] = r[s];
                r[s] = t;
            }
            y = 0x0;
            s = 0x0;
            for (var z = 0x0; z < p['length']; z++) {
                y = (y + 0x1) % 0x100;
                s = (s + r[y]) % 0x100;
                t = r[y];
                r[y] = r[s];
                r[s] = t;
                u += String['fromCharCode'](p['charCodeAt'](z) ^ r[(r[y] + r[s]) % 0x100]);
            }
            return u;
        };
        b['fuFDUP'] = o;
        b['uzmgkx'] = {};
        b['gPvZlv'] = !![];
    }
    var A = b['uzmgkx'][c];
    if (A === undefined) {
        if (b['GkZZBA'] === undefined) {
            b['GkZZBA'] = !![];
        }
        e = b['fuFDUP'](e, d);
        b['uzmgkx'][c] = e;
    } else {
        e = A;
    }
    return e;
};
/*2.解密基本数据的函数结束*/

// -------------------(以上作为decode.js文件)-------------------

//混淆后的原代码(作为en.js文件)
/*3.加密的数据主体*/
(function (c, d) {
    var e = {
        'RAMoq': '2019年09月12日15:24:29更新',
        'EaZaN': '这个是一个本站对JavaScript 脚本的一个最牛加密,兼容性适中,解密难度极大'
    };
    c[b('0', 'ZdTU')] = e[b('1', 'FnxY')];
    d[b('2', 'FnxY')] = e[b('3', 'jPNw')];
}(window, document));
/*3.加密的数据主体结束*/

// -------------------(以上作为en.js文件)-------------------

python实现

前提是js代码能在脱离浏览器环境下运行,可以先在fiddler中试运行一下。

思路:调用函数b完成解密以上数据,还原过程是将b函数返回的数据替换还原即可

import execjs
import re


def js_from_file(file_name):
    with open(file_name, 'r', encoding='UTF-8') as file:
        result = file.read()
    return result


# 解密函数
decode_func = "b"
# 解密前的js
origin_js = js_from_file('./en.js')
# 解码函数
context1 = execjs.compile(js_from_file('./decode.js'))

# 使用正则将所有函数解密, 并替换
s = re.compile(r'b\("(.*?)", "(.*?)"\)', re.S)
any_decode_func = s.finditer(origin_js)
for i in any_decode_func:
    x1 = i.group(1)
    x2 = i.group(2)
    # print(f"--{x1}--, --{x2}--")
    result1 = context1.call(decode_func, x1, x2)
    # print(result1)
    origin_js = origin_js.replace(i.group(), f"\"{result1}\"")

print(origin_js)

最终结果:

(function (c, d) {
  var e = {
    RAMoq:
      "2019年09月12日15:24:29更新",
    EaZaN:
      "这个是一个本站对JavaScript 脚本的一个最牛加密,兼容性适中,解密难度极大"
  };
  c["update"] = e["RAMoq"];
  d["info"] = e["EaZaN"];
})(window, document);
//这是破解混淆后的(依然像js原文那样调用即可)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值