JS混淆编码从原理到实现

2019/08/14

写在前面

当年刚上大一的时候,我在某微信公众号上读过一篇标题为《史上最奇葩的十大编程语言》的文章,对其中介绍的BrainfuckOok!印象尤其深刻。后来接触到JSFuckJJEncodeAAEncode,更是大感奇妙。这几种编码既可以用于前端代码混淆,也可以用于 XSS 攻击,最重要的是它们很好玩

昨天下午,我正坐在工位上美滋滋地吃着公司的下午茶,突然看到了一篇解析JSFuck原理的文章 (博主说要写一个系列的文章结果太监了),顿时来了兴趣,产生了自己搞一种混淆编码的冲动。下班之后,我蹭着公司的网又查了一些资料,总算搞懂了这些有趣的混淆编码的原理,然后实现了自己的WHUTOSA_Encode

AAEncode示例

如果你对这类混淆编码不了解,当你第一次见到下面这段“代码”,估计会有点懵:

゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(o)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [o] [o];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [o]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[o]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Θ゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((゚ー゚) + (o^_^o))+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((゚ー゚) + (゚Θ゚))+ (o^_^o)+ (゚Θ゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ (゚ー゚)+ (゚Д゚) .゚Д゚ノ+ (゚Д゚) .゚ω゚ノ+ (゚Д゚) ['c']+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (゚ー゚) + (゚Θ゚))+ ((o^_^o) - (゚Θ゚))+ ((゚ー゚) + (゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚) .゚Θ゚ノ+ ((゚ー゚) + (゚ー゚))+ ((゚ー゚) + (゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(o゚ー゚o)+ ((゚ー゚) + (゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚) .゚Д゚ノ+ ((゚ー゚) + (゚ー゚))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[o]) (゚Θ゚)) ('_');

如果你把这串颜文字拿到浏览器控制台去跑,会在控制台打印“我爱北京天安门”。

原理解析

前置知识-使用Function的构造函数进行函数定义

借助new Function()或者Function.constructor,我们可以创建新的函数。

比如:

a = Function.constructor('i', 'console.log(i+1)');
a(5);
new Function('console.log("java是最好的语言");')();

运行上面的代码,可以在控制台输出6java是最好的语言

更具体的解析可以看这篇文章

前置知识-JS类型转换

JavaScript 是一门非常恶心神奇的编程语言,不同类型的值还可以相互转换,用==进行比较还有可能返回true

比如1+2+'3'可以得到'33'1=='1'的结果是true['a','b']+2的结果是'a,b2'……

更详细说明可以看这里

fuckingJS

混淆编码原理解析

JSFuckjjencode这样的混淆编码,其根本原理就是使用奇奇怪怪的变量名来表示数字和字母,然后用这些变量拼接出正常的 JS 语句,最后通过eval()或者new Function()之类的方式执行代码和定义函数。

比如jjencode开始的这一段:

$ = ~[];
$ = {
    ___: ++$,
    $$$$: (![] + "")[$],
    __$: ++$,
    $_$_: (![] + "")[$],
    _$_: ++$,
    $_$$: ({} + "")[$],
    $$_$: ($[$] + "")[$],
    _$$: ++$,
    $$$_: (!"" + "")[$],
    $__: ++$,
    $_$: ++$,
    $$__: ({} + "")[$],
    $$_: ++$,
    $$$: ++$,
    $___: ++$,
    $__$: ++$
};

第一句是把变量$赋值为-1,这里利用了JS的自动类型转换,实际上也可以换成$ = ~''之类的写法。

第二句则是把变量$赋值为一个对象,对象的这些属性实际上是十六进制数字。比如___: ++$会让最终的$.___0

而如果要实现通过Function.constructor来定义函数,还需要有{'n','s','t','r','u','o'}这几个字母,可以在{'true','false','undefine','object'}中获取到,而后面这四个字符串全部都可以通过 JS 的类型转换来取得。

更详细的解释可以看扩展阅读中的文章。生成各种 ASCII 字符的更多方法可以参考JSFuck的方式

实现自己的混淆编码

生成WHUTOSA_Encode的代码

// 设计字符映射关系
map = {
    "0": "",
    "1": "",
    "2": "",
    "3": "",
    "4": "",
    "5": "",
    "6": "",
    "7": "",
    "8": "",
    "9": "",
    "a": "大学",
    "b": "开学",
    "c": "武汉",
    "d": "开大",
    "e": "理工",
    "f": "武大"
};

function encode(text) {
    let result = "";
    for (let i = 0; i < text.length; i++) {
        n = text.charCodeAt(i);
        if (n < 128) {
            result += '+\"\\\\\"' + numToString(n.toString(8));
        } else {
            result += '+\"\\\\\"+理工大' + numToString(n.toString(16));
        }
    }
    return result;
}

function numToString(num) {
    let result = "";
    for (let i = 0; i < num.length; i++) {
        n = num.charAt(i);
        result += "+" + map[n];
    }
    return result;
}

// 拼接出结果
function printEncrypt(text) {
    console.log(
    	// 这里实际上就是生成各种字符串变量
        "学=~[],武=++学,汉=++学,理=++学,工=++学,开=++学,源=++学,技=++学,术=++学,协=++学,会=++学,大会=![]+\"\",开会=!![]+\"\",大汉={}+\"\",理会=[][学]+\"\",大学=大会[汉],开学=大汉[理],武汉=大汉[源],开大=理会[理],理工=开会[工],武大=大会[武],开源=理会[汉],技术=大汉[汉],协会=开会[汉],武理=大会[工],武理工=开会[武],理工大=理会[武],开源技术=武汉+技术+开源+武理+武理工+协会+理工大+武汉+武理工+技术+协会,开源协会=协会+理工+武理工+理工大+协会+开源+\" \","
        // 这里是使用Function.constructor()()执行代码
        + "[][开源技术][开源技术]([][开源技术][开源技术](开源协会"
        + "+\"\\\"\""
        + encode(text)
        + "+\"\\\"\""
        + ")())()"
    );
}

yourJavaScriptCode = "console.log('武汉理工大学开源技术协会')";
printEncrypt(yourJavaScriptCode);

运行WHUTOSA_Encode的结果

运行生成的代码:

=~[],=++,=++,=++,=++,=++,=++,=++,=++,=++,=++,大会=![]+"",开会=!![]+"",大汉={}+"",理会=[][]+"",大学=大会[],开学=大汉[],武汉=大汉[],开大=理会[],理工=开会[],武大=大会[],开源=理会[],技术=大汉[],协会=开会[],武理=大会[],武理工=开会[],理工大=理会[],开源技术=武汉+技术+开源+武理+武理工+协会+理工大+武汉+武理工+技术+协会,开源协会=协会+理工+武理工+理工大+协会+开源+" ",[][开源技术][开源技术]([][开源技术][开源技术](开源协会+"\""+"\\"++++"\\"++++"\\"++++"\\"++++"\\"++++"\\"++++"\\"++++"\\"+++"\\"++++"\\"++++"\\"++++"\\"+++"\\"+++"\\"+理工大++开学+++"\\"+理工大++武汉+++"\\"+理工大+++++"\\"+理工大++开大+理工++"\\"+理工大+++++"\\"+理工大++开学+++"\\"+理工大++武大+++"\\"+理工大++理工+++"\\"+理工大+++++"\\"+理工大++++武大+"\\"+理工大++++武大+"\\"+理工大++武大++大学+"\\"+++"\\"+++"\"")())()

将在控制台输出“武汉理工大学开源技术协会”:

运行结果

运行结果

破解方式

只要截获Function.constructor,就可以看到混淆编码前的原文。

先重定向Function.constructor

Function.prototype.__defineGetter__('constructor', function () {
    return function () {
        console.log('constructor', JSON.stringify(arguments));
    };
});

然后运行混淆编码后的代码,就可以在控制台中看到原文。

破解

WHUTOSA_Encode破解

扩展阅读


(转载本站文章请注明作者和出处)

Show Disqus Comments

Post Directory