操作符混淆工具

1 序

1.1 从一段神奇的JS代码说起

前段时间在公众号看到一段神奇的代码,它长这个样子:

(!(~+[])+{})[--[~[]][+[]]*[~+[]]+~~!+[]]+({}+[])[[~!+[]]*~+[]]

如果把这行代码扔到浏览器里面执行以下,就会输出sb字符串。

这是什么鬼,还有这种操作?

1.2 走进科学时间

上面的代码由!()*+-[]{}~这11种符号组成,其实这些符号都是JS的操作符,而上面的代码在执行后转换成字符串则是因为:

  • 当操作符作用的操作数类型不一致或者不是基本类型时,JS将自动完成类型转化;
  • 不同的操作符具有不同的优先级

将上面的代码按照 操作符优先级 进行区域划分,大致可以分为以下的几个部分。

可以看到实际上就是应用JS的类型隐式转换生成字符串,然后从字符串里提取想要的字符。 至于为什么上图的叶节点为什么是这样生成的值,请参照 es5.github.io/ 9 Type Conversion and Testing

2 操作符代码混淆器

收到前文的启发,本人萌发了一种“操作符代码混淆器”的想法。也就是利用上文提及的原理,将JS代码混淆成全部由操作符组成的“让人看着头疼的代码”。

这意味着一些简单的字符层面上的代码注入防范工作完全无法对我们的代码生效,因为我们的代码完全由“操作符”构成,根本就不包含敏感关键字。

"操作符代码混淆器"需要解决几个关键性的问题:

  • 操作符生成其他字符
  • 字符串组装成可执行代码

2.1 数字

生成数字实际上只要有一个数字0,我们完成可以通过自增操作符++生成数字1-9,所以我们只需要

// '数字集合'
$ = +[]; // 0
$ = {
    _: $++, // 0
    __: $++, // 1
    ___: $++, // 2
    ____: $++, // 3
    _____: $++, // 4
    $_: $++, // 5
    $__: $++, // 6
    $___: $++, // 7
    $____: $++, // 8
    $_____: $++, // 9
}

2.2 英文字符

从前文我们可以知道其逻辑是根据不同的类型转换成字符串时可以生成不同的描述性字符串

{} + [] // '[object Object]'
![] +[] // 'false'
!![] + [] // 'true'
[][$._] + [] //'undefined'

从上面我们可以得到 a b c d e f i j l n o r s t u这些字符。但是这很明显没办法包含所有英文字符,同时也没办法表示换行符等特殊字符。

2.3 通用字符

所以我们需要一个更加通用的方案来通过操作符生成其他字符。 基于我们现在已经得到的数字字符,我们可以使用八进制的表示方式来生成其他ASCII字符。

'\\' + $.__ + $._____ + $.$__ + '\\' // '\147' 即 g
'\\' + $.__ + $.$ + $._              // '\150' 即 h , 以此类推

但是这也随之带来一个问题,那就是我们为了使用八进制来表达ASCII字符,引入了'\\'这种常量字符串,这使得整个计划优点不完美,但是作者目前没有想到更好的实现方式。

// '字符集合'
$$ = '\\';

$$ = {
    _: $$ + $.__ + $._____ + $.__, // 141 a
    __: $$ + $.__ + $._____ + $.___, // 142 b
    ___: $$ + $.__ + $._____ + $.____, // 143 c
    ____: $$ + $.__ + $._____ + $._____, // 144 d
    _____: $$ + $.__ + $._____ + $.$_, // 145 e
    $_: $$ + $.__ + $._____ + $.$__, // 146 f
    $__: $$ + $.__ + $._____ + $.$___, // 147 g
    $___: $$ + $.__ + $.$_ + $._, // 150 h
    $____: $$ + $.__ + $.$_ + $.__, // 151 i
    $_____: $$ + $.__ + $.$_ + $.___, // 152 j
    $$_: $$ + $.__ + $.$_ + $.____, // 153 k
    $$__: $$ + $.__ + $.$_ + $._____, // 154 l
    $$___: $$ + $.__ + $.$_ + $.$_, // 155 m
    $$____: $$ + $.__ + $.$_ + $.$__, // 156 n
    $$_____: $$ + $.__ + $.$_ + $.$___, // 157 o
    $$$_: $$ + $.__ + $.$__ + $._, // 160 p
    $$$__: $$ + $.__ + $.$__ + $.__, // 161 q
    $$$___: $$ + $.__ + $.$__ + $.___, // 162 r
    $$$____: $$ + $.__ + $.$__ + $.____, // 163 s
    $$$_____: $$ + $.__ + $.$__ + $._____, // 164 t
    $$$$_: $$ + $.__ + $.$__ + $.$_, // 165 u
    $$$$__: $$ + $.__ + $.$__ + $.$__, // 166 v
    $$$$___: $$ + $.__ + $.$__ + $.$___, // 167 w
    $$$$____: $$ + $.__ + $.$___ + $._, // 170 x
    $$$$_____: $$ + $.__ + $.$___ + $.__, // 171 y
    $$$$$_: $$ + $.__ + $.$___ + $.___ // 172 z
}

2.4 执行容器

前文我们只是将代码内容转换成了字符串的形式,这么一个字符串还需要能够跑起来。 好,我们的第一想法可能是eval方法

eval() 函数可计算某个字符串,并执行其中的的 JavaScript代码。

假设我们已经将代码转换成了字符串,但是下面的用户调用方式未免显得太过没有逼格。

var codeStr = '混淆过的代码';
// 用户调用
eval(codeStr)

所以我们的目标是生成的代码用户可以直接扔到浏览器里面开始执行,即我们需要一个可以执行的函数容器:

// 字符串集合
$$$ = {
    _: {} + [], // '[object Object]'
    __: ![] + [], // 'false'
    ___: !![] + [], // 'true'
    ____: [][$._] + [] //'undefined'
}

// 替换字符集, 这里不替换的话无法根据constructor找到Function
$$.___ = $$$._[$.$_]; // c
$$._____ = $$$.___[$.____] // e
$$.$$____ = $$$.____[$.__]; //n 
$$.$$_____ = $$$._[$.__]; // o
$$.$$$___ = $$$.___[$.__]; // r
$$.$$$____ = $$$.__[$.____]; // s
$$.$$$_____ = $$$.___[$._]; // t
$$.$$$$_ = $$$.____[$._]; // u


$$$._____ = $$.___ + $$.$$_____ + $$.$$____ + $$.$$$____ + $$.$$$_____ + $$.$$$___ + $$.$$$$_ + $$.___ + $$.$$$_____ + $$.$$_____ + $$.$$$___; // 'constructor'
$$$.$_ = $$.$$$___ + $$._____ + $$.$$$_____ + $$.$$$$_ + $$.$$$___ + $$.$$____; // 'return'

$$$.$__ = ($._)[$$$$._][$$$$._] // Function

// 执行容器调用方式
$$$.$__($$$.$__($$$.$_ + '\"' + '这里是经过混淆后的代码' + '\"'())();
// 实际上就是
// Function(Function()('return \"' + '这里是经过混淆后的代码' + '\"')())()

3 结论

通过以上实现,基本实现了一个简单代码混淆工具的逻辑,可以只使用操作符对代码进行混淆,但依旧遗留了一些问题

  • 代码依赖字符串,生成的代码也会包含字符串常量,并不是完全的“操作符化”;
  • 工具的代码本身很难阅读,使得维护和开发非常困难,这个工作可以依赖构建工具进行优化;
  • 目前只包含了对ASCII字符的处理,对字符集以外字符的处理是有问题的;
  • 本工具的应用场景具有局限性

4 相关资料

一段神奇的javascript代码 运算符优先级 Annotated ECMAScript 5.1 - 9 Type Conversion and Testing jjencode JS代码加密混淆工具 jjencode

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏鸿的学习笔记

实现一个简单数据库

数据系统,简单来说就是一个提供数据存储和搜索的软件。当你传入数据给数据系统时,它会把数据存储起来;当你需要你存入的数据时,数据系统会返回给你。现...

773
来自专栏地方网络工作室的专栏

Shell 从日志文件中选择时间段内的日志输出到另一个文件

Shell 从日志文件中选择时间段内的日志输出到另一个文件 情况是这样的,某系统的日志全部写在一个日志文件内,所以这个文件非常大,非常长,每次查阅的时候非常的不...

1628
来自专栏子勰随笔

我理解的高可用

1867
来自专栏Python小屋

Python把列表中的数字尽量等分成n份

问题描述:假设一个列表中含有若干整数,现在要求将其分成n个子列表,并使得各个子列表中的整数之和尽可能接近。 下面的代码并没有使用算法,而是直接将原始列表分成n...

4088
来自专栏Golang语言社区

社区leaf学习笔记|01. leaf开源游戏服务器搭建

Leaf 是一个由 Go 语言(golang)编写的开发效率和执行效率并重的开源游戏服务器框架。Leaf 适用于各类游戏服务器的开发,包括 H5(HTML5)游...

1166
来自专栏企鹅号快讯

AJAX 简介

AJAX简介 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。 什么是 AJAX ? AJAX = 异步 JavaScript 和 XM...

1808
来自专栏深度学习思考者

C++学习(一)——标准库类型之string全解析

0. 标准库类型之string类   用户程序要使用 string 类型对象,必须包含相关头文件。如果提供了合适的 using 声明,那么编写出来的程序将会...

1907
来自专栏CSDN技术头条

开源搜索和分析引擎Elasticsearche在Bay的性能优化实践,单集群日搜索请求超4亿

摘要:Elasticsearch是基于Apache Lucene的开源搜索和分析引擎,允许用户以近乎实时的方式存储,搜索和分析数据。虽然Elasticsearc...

2138
来自专栏达摩兵的技术空间

异步IO(一)

在web2.0的时候,其实前端就很熟悉异步编程了,只不过那时大家使用的是ajax(典型的网络请求)实现的,还有一些前端的事件机制(针对事件定义回调事件)。

984
来自专栏GreenLeaves

Oracle PL/SQL编程之过程

1、简介 过程用于执行特定的操作,当建立过程时,既可以指定输入参数(in),也可以指定输出参数(out),通过在过程中使用输入参数,可以将数据传递到执行部分,通...

1856

扫码关注云+社区