rainforwind

背景

很多年前了解到有一个将js代码转换为颜文字的混淆工具,混淆也就意味着输出的一段颜文字可以直接执行并且得到与原js相同的结果。今天想分析一下他的执行原理,记录如下。

混淆工具地址:https://utf-8.jp/public/aaencode.html

示例:

输入:

console.log("rock")

输出:

゚ω゚ノ= /`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゚]) (゚Θ゚)) (\'_\');

解析过程很简单:

1. 把奇怪的变量名替换成正常的字母便于识别;

2. 把确定的常量带入,常量表达式直接求值(基本上就是几种:算数计算,字符串拼接(非string类型变量可以拼出一些\'undefined\',\'true\',\'false\',\'object\'之类的值用来提供字符,下文中的constructor就是从这些字符里拼出来的),从字符串取字符(用[]操作))。

很快就可以化简到如下形式:

X=3[\'constructor\'][\'constructor\'];
X ( X (\'return\"\\143\\157\\156\\163\\157\\154\\145\\56\\154\\157\\147\\50\\42\\162\\157\\143\\153\\42\\51\"\') (1)) (\'_\');

里面的8进制作为ascii转出来看一下:

> "\143\157\156\163\157\154\145\56\154\157\147\50\42\162\157\143\153\42\51"
输出:\'console.log("rock")\'

原理就很明白了:

通过一个数值对象,取其构造方法,得到一个函数。再取该函数的构造方法,得到一个可以构造函数实例的方法X。

X的参数是函数代码的字符串标识,返回一个函数实例。

于是乎我们就可以将任意一个输入的字符串当做代码执行了。

 

所以上面的例子中第一行的3不重要,换成其他对象也可以;第二行最后的两个参数1和\'_\'也不中要,因为两层X实例化出来的函数都不消费参数。

另外上面的例子中套了一层 \'return <转义后的代码>\' 的结构,所以用了两层X来执行最终的结果。这个例子中不添加这一层嵌套也能达到效果,可能是为了增加混淆度。

所以我再简化一下来示例代码原理,如下:

> \'\'[\'constructor\'][\'constructor\']("\143\157\156\163\157\154\145\56\154\157\147\50\42\162\157\143\153\42\51")()
输出:rock

 

PS:

其他小技巧:将每一个小表情解释成变量或简短的算数表达式,来表示一个数字,然后通过加减法来凑八进制标识的每一位数字,只有0-7,比较好凑,也保证了表情密度,让人不容易注意到表情之外的冗余加减号和括号。

分类:

技术点:

相关文章:

  • 2021-10-07
  • 2022-01-05
  • 2021-11-29
  • 2021-12-02
  • 2021-12-02
  • 2021-06-16
  • 2022-01-14
  • 2022-01-02
猜你喜欢
  • 2021-12-02
  • 2022-12-23
  • 2021-12-02
  • 2022-12-23
  • 2021-12-02
  • 2021-12-02
相关资源
相似解决方案