H

JavaScript 反混淆

HackApt-37 Team已验证会员

黑客倉庫站長

贡献: 83%

JavaScript 反混淆​

1 常量的混淆原理​

1.1 对象属性的两种访问方式​

在JavaScript中,有两种访问对象的方法。
与点访问
带括号的访问
1
2
3
4
5
6
7
8
9
10
11
12
13
功能人(名称){
this.name=name;
}
People.Prototype.SayHello=function(){
console.log('Hello');
}
var p=新人('pname');
console.log(p.name); //pname
P.Sayhello(); //你好
console.log(p ['name']); //pname
p ['sayhello'](); //你好
访问括号可用于混淆其中的字符串。

1.2 常见的混淆方式​

1.2.1 十六进制字符串​

以下代码是一个示例:
1
2
3
4
5
6
7
8
9
date.prototype.format=function(formatstr){
var str=formatstr;
var Week=['day','一个','两个','三','四','五','six'];
str=str.replace(/yyyy | yyyy/,this.getluceear());
str=str.replace(/mm/,(this.getMonth() + 1)9?(this.getMonth() + 1).toString():'0'' +(this.getMonth() + 1));
str=str.replace(/dd | dd/,this.getDate()9?
返回str;
}
console.log(new Date()。格式('yyyy-mm-dd'));
对于代码中出现的字符串,它们可以转换为十六进制。
1
2
3
4
5
6
7
8
9
10
date.prototype.format=function(formatstr){
var str=formatstr;
var Week=['day','一个','两个','三','四','五','six'];
str=str.replace(/yyyy | yyyy/,this.getluceear());
str=str.replace(/mm/,(this.getMonth() + 1)9?(this.getMonth() + 1).toString():'0'' +(this.getMonth() + 1));
str=str.replace(/dd | dd/,this.getDate()9?
返回str;
}
console.log(new Date()。格式('\ x79 \ x79 \ x79 \ x79 \ x79 \ x2d \ x4d \ x4d \ x4d \ x4d \ x2d \ x2d \ x64 \ x64');

1.2.2 unicode 字符串​

在JS中,除了以十六进制形式表示外,字符串还支持Unicode编码。
花一个周=['day','一个','二','三','四','五','six'];例如,它可以转换为:
1
var Week=['\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u516d'];
此外,JS Parser还支持Unicode编码以显示在标识符中:
1
2
3
4
5
6
7
8
9
date.protype。\ u0066 \ u006f \ u0072 \ u006d \ u0061 \ u0061 \ u0074=function(formatstr){
var \ u0073 \ u0074 \ u0072=\ u0066 \ u006f \ u0072 \ u006d \ u006d \ u0061 \ u0074 \ u0074 \ u0053 \ u0074 \ u0074 \ u0072;
var Week=['\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u516d'];
str=str ['replact'](/yyyy | yyyy/,this ['getlyal']());
str=str ['替换'](/mm/,(this ['getMonth']() + 1)9?(this ['getMonth']() + 1)['toString']():'0' +(this ['getMonth']('getMonth']()()()()()() + 1));
str=str ['替换'](/dd | dd/,this ['getDate']()9?this ['getDate']()['toString']():'0'0' + this ['getDate']());
返回str;
}
console.log(新\ u0077 \ u0069 \ u006e \ u0064 \ u006f \ u0077 ['\ u0044 \ u0061 \ u0061 \ u0074 \ u 0065']()['格式']('\ x79 \ x79 \ x79 \ x2d \ x4d \ x4d \ x4d \ x4d \ x2d \ x2d \ x64 \ x64') );

1.2.3 字符串的 ASCII 码​

为了完成字符串的ASCII代码混淆,需要在此处使用两个函数,一个是字符串对象下的charcodeat方法,另一个是字符串类中的FronCharCode方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
console.log('g'.CharCodeat(0)); //71
console.log('e'.CharCodeat(0)); //101
console.log(string.fromcharcode(71,101));
功能字符串tobyte(str){
var bytearr=[];
for(var i=0; i str.length; i ++){
bytearr.push(str.CharCodeat(i));
}
返回bytearr;
}
console.log(StringTobyte('Geekby'));
将代码转换为字符串后,请使用eval函数执行:
1
2
3
4
5
6
7
8
9
10
date.protype。\ u0066 \ u006f \ u0072 \ u006d \ u0061 \ u0061 \ u0074=function(formatstr){
var \ u0073 \ u0074 \ u0072=\ u0066 \ u006f \ u0072 \ u006d \ u006d \ u0061 \ u0074 \ u0074 \ u0053 \ u0074 \ u0074 \ u0072;
var Week=['\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u516d'];
eval(string。 104、105、115、91、39、103、101、116、70、117、108、108、89、101、97、114、39、93、93、40、41、41、59));
str=str ['替换'](/mm/,(this ['getMonth']() + 1)9?(this ['getMonth']() + 1)['toString']():'0' +(this ['getMonth']('getMonth']()()()()()() + 1));
str=str ['替换'](/dd | dd/,this ['getDate']()9?this ['getDate']()['toString']():'0'0' + this ['getDate']());
返回str;
}
Console.Log(新\ U0077 \ U0069 \ U006E \ U0064 \ U0064 \ U006F \ U0077 ['\ U0044 \ U0061 \ U0061 \ U0074 \ U0065 \ U0065']() 116)]('\ x79 \ x79 \ x79 \ x2d \ x4d \ x4d \ x4d \ x2d \ x2d \ x64 \ x64'));
//输出结果2020-07-04
202111181532498.png-water_print

1.2.4 字符串常量编码或加密​

字符串常数编码或加密的核心思想是首先编码或加密字符串以获得Ciphertext,然后在使用它之前,调用相应的解码或解密函数以解密其以获取明文。
base64编码和解码在JS中随附的函数用于编码,并且ATOB用于解码。
但是,在实际的混淆应用程序中,最好使用自定义功能然后混淆它们。在这里,我们使用ATOB代替BASE64解码,处理的代码为:
1
2
3
4
5
6
7
8
9
date.protype。\ u0066 \ u006f \ u0072 \ u006d \ u0061 \ u0061 \ u0074=function(formatstr){
var \ u0073 \ u0074 \ u0072=\ u0066 \ u006f \ u0072 \ u006d \ u006d \ u0061 \ u0074 \ u0074 \ u0053 \ u0074 \ u0074 \ u0072;
var Week=['\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u516d'];
eval(string。 104、105、115、91、39、103、101、116、70、117、108、108、89、101、97、114、39、93、93、40、41、41、59));
str=str [atob('cmvwbgfjzq==')](/mm/,(this atob('z2v0tw9udgg=')]() + 1)() + 1)9? (this [atob('z2v0tw9udgg=')]() + 1);
str=str [atob('cmvwbgfjzq==')](/dd | dd/,this [atob('z2v0rgf0zq==')]()9?此[atob('z2v0rgf0zq==')]();
返回str;
}
Console.Log(新\ U0077 \ U0069 \ U006E \ U0064 \ U0064 \ U006F \ U0077 ['\ U0044 \ U0061 \ U0061 \ U0074 \ U0065 \ U0065']() 116)]('\ x79 \ x79 \ x79 \ x2d \ x4d \ x4d \ x4d \ x2d \ x2d \ x64 \ x64'));

1.2.5 数值常量转换​

在算法加密过程中,将使用一些固定的数值常数。例如,MD5中的常数为0x67452301,0xefcdab89,0x98badcfe,0x10325476。
SHA1中的常数0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0。
因此,在标准算法的相反方向上,通常会搜索这些数值常数以找到代码的关键位置,或确定使用了哪种算法。当然,十六进制形式不一定用代码编写。例如,0x67452301,代码可以写为十进制1732584193。出于安全原因,可以简单地加密这些数值常数。
可以使用独家或功能使用加密。例如,a^b=c,然后c^b=a。
以SHA1算法中的0xC3D2E1F0为例,以0xc3d2e1f0 ^0x12345678=0xD1E6B788,然后在代码中,然后在0xD1E6B788 ^0x12345678 ^0x12345678可以使用0x12345678可以理解0xc3dd2d2d2d2d2d2e1f0,一个键,可以随机生成。
简而言之,混淆溶液不一定单独使用,也可以将它们用于各种溶液之间的结合。

2 增加逆向工作量​

2.1 数组混淆​

将代码中的所有字符串提取到数组中,然后以数组订阅的形式访问所有需要引用的字符串。
1
2
3
4
var bigarr=['date','gettime','log'];
console [bigarr [2]](新窗口[bigarr [0]]()[bigarr [1]]());
console ['log'](new Window.date()。getTime())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var bigarr=[
'\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u4e94',
'\ u516d','cmvwbgfjzq==','z2v0tw9udgg=','dg9tdhjpbmc=',
'z2v0rgf0zq==','ma==',''['构建器'] [''fromCharCode']
];
date.protype。\ u0066 \ u006f \ u0072 \ u006d \ u0061 \ u0061 \ u0074=function(formatstr){
var \ u0073 \ u0074 \ u0072=\ u0066 \ u006f \ u0072 \ u006d \ u006d \ u0061 \ u0074 \ u0074 \ u0053 \ u0074 \ u0074 \ u0072;
var Week=[Bigarr [0],Bigarr [1],Bigarr [2],Bigarr [3],Bigarr [4],Bigarr [5],Bigarr [6]];
eval(string。 104、105、115、91、39、103、101、116、70、117、108、108、89、101、97、114、39、93、93、40、41、41、59));
str=str [atob(bigarr [7])](/mm/,(此[atob(bigarr [8])]() + 1)9?
str=str [atob(bigarr [7])](/dd | dd/,this [atob(bigarr [10])]()9?this [atob(bigarr [10])]()[atob(bigarr [9])](bigarr [9]): Atob(Bigarr [bigarr [11])
返回str;
}
console.log(新\ u0077 \ u0069 \ u006e \ u0064 \ u0064 \ u006f \ u0077 ['\ u0044 \ u0061 \ u0061 \ u0074 \ u0065'']() 116)]('\ x79 \ x79 \ x79 \ x2d \ x4d \ x4d \ x4d \ x2d \ x2d \ x64 \ x64'));

2.2 数组乱序​

上面提取的阵列顺序被破坏,在采用元素时,请恢复它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var bigarr=[
'\ u65e5','\ u4e00','\ u4e8c','\ u4e09','\ u56db','\ u4e94','\ u4e94',
'\ u516d','cmvwbgfjzq==','z2v0tw9udgg=','dg9tdhjpbmc=',
'z2v0rgf0zq==','ma==',''['构建器'] [''fromCharCode']
];
(函数(arr,num){
var shuffer=function(nums){
while( - nums){
arr.unshift(arr.pop());
}
};
Shuffer(++ num);
}(Bigarr,0x20));
console.log(bigarr);

2.3 花指令​

在代码中添加一些毫无意义的代码是花朵说明的核心。例如:稍微更改二项式this.getMonth() + 1:
1
2
3
4
5
函数_0x20ab1fxe1(a,b){
返回A + B;
}
//_0x20ab1fxe1(this.getMonth(),1);
_0x20ab1fxe1(new Date()。getMonth(),1); //输出11
它也可以进一步嵌套:
1
2
3
4
5
6
7
函数_0x20ab1fxe2(a,b){
返回A + B;
}
函数_0x20ab1fxe1(a,b){
返回_0x20ab1fxe2(a,b);
}
_0x20ab1fxe1(new Date()。getMonth(),1); //输出11
此外,为了进一步提高代码复杂性,具有相同功能的代码可以放置在不同的功能中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
函数_0x20ab1fxe2(a,b){
返回A + B;
}
函数_0x20ab1fxe1(a,b){
返回_0x20ab1fxe2(a,b);
}
函数_0x20ab1fxe3(a,b){
返回A + B;
}
函数_0x20ab1fxe4(a,b){
返回_0x20ab1fxe3(a,b);
}
_0x20ab1fxe4('0',_0x20ab1fxe1(new Date()。getMonth(),1));
//输出'11'

2.4 jsfuck​

JSFUCK可以被视为一种编码。它可以将JS代码转换为只能由6个字符表示的代码,并且可以正常执行。
这6个字符是[](]()!+。转换后的JS代码很难读取,并且可以用作一些简单的混淆措施。
在线编码网站:http://www.jsfuck.com

3 代码执行流程的防护原理​

3.1 流程平坦化​

该代码最初是按逻辑顺序执行的,控制流平面是将原始代码的基本块拆分。
使用开关案例分发按顺序执行的代码块,并使用分配器和变量连接原始代码的逻辑。
如以下代码:
1
2
3
4
5
6
7
8
9
10
功能test1(){
var a=1000;
var b=a + 2000;
var c=b + 3000;
var d=c + 4000;
var e=d + 5000;
var f=e + 6000;
返回f;
}
console.log(test1());
该过程扁平化后,它变为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
函数test2(){
var arrstr='7 | 5 | 1 | 3 | 2 | 4 | 6'.split('|'),i=0;
尽管(![]) {
switch(arrstr [i ++]){
案例'1':
var c=b + 3000;
继续;
案例“ 2':
var e=d + 5000;
继续;
案例“ 3':
var d=c + 4000;
继续;
案例“ 4':
var f=e + 6000;
继续;
案例“ 5':
var b=a + 2000;
继续;
案例'6':
返回f;
继续;
案例'7':
var a=1000;
继续;
}
休息;
}
}
console.log(test2());
//输出21000
 
后退
顶部