| 導購 | 订阅 | 在线投稿
分享
 
 
 

Javascript代碼壓縮、加密算法的破解分析及工具實現

來源:互聯網  2008-10-21 08:21:12  評論

現在網上很多Javascript都進行了壓縮,同時代碼變得不可直接閱讀,也相當于一種簡單的加密了,本文對其中一種典型的算法進行分析,介紹如何解密代碼以及重新實現的壓縮工具算法。

典型代碼如下:

eval(function(E,I,A,D,J,K,L,H){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)K[C(D--)]=I[--A];function N(A){return K[A]==L[A]?A:K[A]}if(''.replace(/^/,String)){var M=E.match(J),B=M[0],F=E.split(J),G=0;if(E.indexOf(F[0]))F=[''].concat(F);do{H[A++]=F[G++];H[A++]=N(B)}while(B=M[G]);H[A++]=F[G]||'';return H.join('')}return E.replace(J,N)}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'),9,109,/[\w\$]+/g, {}, {}, []))

一、代碼解密

對于這類壓縮的代碼,無非是把js程序采用某種算法進行壓縮,然後自行用提供的函數還原,采用eval(SCRIPT)的方式執行來完成調用,那麽還原的方法就很簡單了,那前面的eval(和後面的)去掉,然後顯示出來就完成了,例如下面的頁面就可以實現代碼的還原:

1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

2<HTML>

3<HEAD>

4 <TITLE> 代碼還原 </TITLE>

5 <META NAME="Generator" CONTENT="EditPlus">

6 <META NAME="Author" CONTENT="">

7 <META NAME="Keywords" CONTENT="">

8 <META NAME="Description" CONTENT="">

9</HEAD>

10

11<BODY>

12<TEXTAREA NAME="tx1" ROWS="10" COLS="100"></TEXTAREA>

13<SCRIPT LANGUAGE="JavaScript">

14document.all.tx1.value =function(E,I,A,D,J,K,L,H){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)K[C(D--)]=I[--A];function N(A){return K[A]==L[A]?A:K[A]}if(''.replace(/^/,String)){var M=E.match(J),B=M[0],F=E.split(J),G=0;if(E.indexOf(F[0]))F=[''].concat(F);do{H[A++]=F[G++];H[A++]=N(B)}while(B=M[G]);H[A++]=F[G]||'';return H.join('')}return E.replace(J,N)}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'),9,109,/[\w\$]+/g, {}, {}, [])

15</SCRIPT>

16</BODY>

17</HTML>

通過上面方式運行,就可以在文本框中看到代碼了,實際的代碼是:

var index=100;for(var a=0;a<100;a++){ document.write(index+a+"<br>");}

很簡單,不是嗎

二、算法研究

由于代碼全部在一行中,不便于閱讀,可以通過格式化軟件格式化,本文這裏使用Intellij IDEA格式化,代碼如下

1eval(function(E, I, A, D, J, K, L, H) {

2 function C(A) {

3 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63)

4 }

5 while (A > 0)K[C(D--)] = I[--A];

6 function N(A) {

7 return K[A] == L[A] ? A : K[A]

8 }

9 if (''.replace(/^/, String)) {

10 var M = E.match(J),B = M[0],F = E.split(J),G = 0;

11 if (E.indexOf(F[0]))F = [''].concat(F);

12 do{

13 H[A++] = F[G++];

14 H[A++] = N(B)

15 } while (B = M[G]);

16 H[A++] = F[G] || '';

17 return H.join('')

18 }

19 return E.replace(J, N)

20}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'), 9, 109, /[\w\$]+/g, {}, {}, []))

Step 1:首先我們可以看出這是一個函數定義與調用合並在一起的,因此可以如下分解:(不再考慮eval)

1//E:加密壓縮後的script信息

2//I:字符串數組,可以理解爲解密需要字典

3//A:int 9

4//D:int 109

5//J:regexpr 正則表達式

6//K:object

7//L:object

8//H:array

9function decode(E, I, A, D, J, K, L, H) {

10 function C(A) {

11 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63)

12 }

13 while (A > 0)K[C(D--)] = I[--A];

14 function N(A) {

15 return K[A] == L[A] ? A : K[A]

16 }

17 if (''.replace(/^/, String)) {

18 var M = E.match(J),B = M[0],F = E.split(J),G = 0;

19 if (E.indexOf(F[0]))F = [''].concat(F);

20 do{

21 H[A++] = F[G++];

22 H[A++] = N(B)

23 } while (B = M[G]);

24 H[A++] = F[G] || '';

25 return H.join('')

26 }

27 return E.replace(J, N)

28}

29var decode_str=decode('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'), 9, 109, /[\w\$]+/g, {}, {}, []));

Step 2:其中對于函數function C(A)采用多重3元表達式處理的方式,可以用if/else如下分解

1function C(A){

2 var res;

3 if (A < 62) {

4 var r = null;

5 if (A < 26) r = 65; //'A'-'Z'

6 else {

7 if (A < 52) r = 71; //'z'=122 控制以下

8 else r = -4;

9 }

10 res = String.fromCharCode(A + r);

11 }

12 else {

13 if (A < 63) res = '_'; //即A=62

14 else {

15 if (A < 64) res = '$';//即A=63

16 else res = C(A >> 6) + C(A & 63); //如果A>63,進行64進制的高低位分解爲2部分

17 }

18 }

19 return res;

20}

更加深刻的理解上面算法,就是一個仿base64編碼變換的算法,可以參見文章:Base64相關

變換的碼表是將0-63的數字變換爲

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$

對應序列位置的字母。

Step 3:代碼while (A > 0)K[C(D--)] = I[--A];的分析

實際上這裏就是將字典內容與序號值進行對照,記錄到Object對象中,運算順序如下表:

D=109,A=9,K["Bt"]=br

D=108,A=8,K["Bs"]=write

D=107,A=7,K["Br"]=document

D=106,A=6,K["Bq"]=0

D=105,A=5,K["Bp"]=a

D=104,A=4,K["Bo"]=for

D=103,A=3,K["Bn"]=100

D=102,A=2,K["Bm"]=index

D=101,A=1,K["Bl"]=var

Step 4:代碼if (''.replace(/^/, String)) 分析

看起來很高深的一個代碼,你想空字符串無論怎麽替換,還是空字符串,在javascript中,空字符串=false,非空字符串=true

所以這個if語句怎麽都不會執行,這裏是一個混淆視聽的代碼,呵呵,你如果想,也可以寫上更多亂七八糟的代碼來達到同樣效果。

Step5:關鍵代碼return E.replace(J, N),這裏用到了函數N:

function N(A) {

return K[A] == L[A] ? A : K[A]

}

注意L對象從來沒有賦值,所以L[A]返回的應該是undefined,所以可以翻譯爲

function N(A) {

return K[A] == undefined ? A : K[A]

}

這下看起來就很好理解,關鍵代碼就下面這些

1function decode(E, I, A, D, J, K, L, H) {

2 function C(A) {

3 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63)

4 }

5 while (A > 0)K[C(D--)] = I[--A];

6 function N(A) {

7 return K[A] == undefined ? A : K[A]

8 }

9 return E.replace(J, N)

10}

綜上分析,該算法的原理就是從腳本文件中提取單詞,存入字典表中,這裏使用|分割的字符串,然後將單詞對應的序號(仿base64編碼值)寫入原來代碼的地方,

就構成了該算法的核心了,所以實現該壓縮算法的代碼也不難了

現在網上很多Javascript都進行了壓縮,同時代碼變得不可直接閱讀,也相當于一種簡單的加密了,本文對其中一種典型的算法進行分析,介紹如何解密代碼以及重新實現的壓縮工具算法。 典型代碼如下: eval(function(E,I,A,D,J,K,L,H){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)K[C(D--)]=I[--A];function N(A){return K[A]==L[A]?A:K[A]}if(''.replace(/^/,String)){var M=E.match(J),B=M[0],F=E.split(J),G=0;if(E.indexOf(F[0]))F=[''].concat(F);do{H[A++]=F[G++];H[A++]=N(B)}while(B=M[G]);H[A++]=F[G]||'';return H.join('')}return E.replace(J,N)}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'),9,109,/[\w\$]+/g, {}, {}, [])) 一、代碼解密 對于這類壓縮的代碼,無非是把js程序采用某種算法進行壓縮,然後自行用提供的函數還原,采用eval(SCRIPT)的方式執行來完成調用,那麽還原的方法就很簡單了,那前面的eval(和後面的)去掉,然後顯示出來就完成了,例如下面的頁面就可以實現代碼的還原: 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 2<HTML> 3<HEAD> 4 <TITLE> 代碼還原 </TITLE> 5 <META NAME="Generator" CONTENT="EditPlus"> 6 <META NAME="Author" CONTENT=""> 7 <META NAME="Keywords" CONTENT=""> 8 <META NAME="Description" CONTENT=""> 9</HEAD> 10 11<BODY> 12<TEXTAREA NAME="tx1" ROWS="10" COLS="100"></TEXTAREA> 13<SCRIPT LANGUAGE="JavaScript"> 14document.all.tx1.value =function(E,I,A,D,J,K,L,H){function C(A){return A<62?String.fromCharCode(A+=A<26?65:A<52?71:-4):A<63?'_':A<64?'$':C(A>>6)+C(A&63)}while(A>0)K[C(D--)]=I[--A];function N(A){return K[A]==L[A]?A:K[A]}if(''.replace(/^/,String)){var M=E.match(J),B=M[0],F=E.split(J),G=0;if(E.indexOf(F[0]))F=[''].concat(F);do{H[A++]=F[G++];H[A++]=N(B)}while(B=M[G]);H[A++]=F[G]||'';return H.join('')}return E.replace(J,N)}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'),9,109,/[\w\$]+/g, {}, {}, []) 15</SCRIPT> 16</BODY> 17</HTML> 通過上面方式運行,就可以在文本框中看到代碼了,實際的代碼是: var index=100;for(var a=0;a<100;a++){ document.write(index+a+"<br>");} 很簡單,不是嗎 二、算法研究 由于代碼全部在一行中,不便于閱讀,可以通過格式化軟件格式化,本文這裏使用Intellij IDEA格式化,代碼如下 1eval(function(E, I, A, D, J, K, L, H) { 2 function C(A) { 3 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63) 4 } 5 while (A > 0)K[C(D--)] = I[--A]; 6 function N(A) { 7 return K[A] == L[A] ? A : K[A] 8 } 9 if (''.replace(/^/, String)) { 10 var M = E.match(J),B = M[0],F = E.split(J),G = 0; 11 if (E.indexOf(F[0]))F = [''].concat(F); 12 do{ 13 H[A++] = F[G++]; 14 H[A++] = N(B) 15 } while (B = M[G]); 16 H[A++] = F[G] || ''; 17 return H.join('') 18 } 19 return E.replace(J, N) 20}('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'), 9, 109, /[\w\$]+/g, {}, {}, [])) Step 1:首先我們可以看出這是一個函數定義與調用合並在一起的,因此可以如下分解:(不再考慮eval) 1//E:加密壓縮後的script信息 2//I:字符串數組,可以理解爲解密需要字典 3//A:int 9 4//D:int 109 5//J:regexpr 正則表達式 6//K:object 7//L:object 8//H:array 9function decode(E, I, A, D, J, K, L, H) { 10 function C(A) { 11 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63) 12 } 13 while (A > 0)K[C(D--)] = I[--A]; 14 function N(A) { 15 return K[A] == L[A] ? A : K[A] 16 } 17 if (''.replace(/^/, String)) { 18 var M = E.match(J),B = M[0],F = E.split(J),G = 0; 19 if (E.indexOf(F[0]))F = [''].concat(F); 20 do{ 21 H[A++] = F[G++]; 22 H[A++] = N(B) 23 } while (B = M[G]); 24 H[A++] = F[G] || ''; 25 return H.join('') 26 } 27 return E.replace(J, N) 28} 29var decode_str=decode('Bl Bm=Bn;Bo(Bl Bp=Bq;Bp<Bn;Bp++){ Br.Bs(Bm+Bp+"<Bt>");}','var|index|100|for|a|0|document|write|br'.split('|'), 9, 109, /[\w\$]+/g, {}, {}, [])); Step 2:其中對于函數function C(A)采用多重3元表達式處理的方式,可以用if/else如下分解 1function C(A){ 2 var res; 3 if (A < 62) { 4 var r = null; 5 if (A < 26) r = 65; //'A'-'Z' 6 else { 7 if (A < 52) r = 71; //'z'=122 控制以下 8 else r = -4; 9 } 10 res = String.fromCharCode(A + r); 11 } 12 else { 13 if (A < 63) res = '_'; //即A=62 14 else { 15 if (A < 64) res = '$';//即A=63 16 else res = C(A >> 6) + C(A & 63); //如果A>63,進行64進制的高低位分解爲2部分 17 } 18 } 19 return res; 20} 更加深刻的理解上面算法,就是一個仿base64編碼變換的算法,可以參見文章:Base64相關 變換的碼表是將0-63的數字變換爲 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$ 對應序列位置的字母。 Step 3:代碼while (A > 0)K[C(D--)] = I[--A];的分析 實際上這裏就是將字典內容與序號值進行對照,記錄到Object對象中,運算順序如下表: D=109,A=9,K["Bt"]=br D=108,A=8,K["Bs"]=write D=107,A=7,K["Br"]=document D=106,A=6,K["Bq"]=0 D=105,A=5,K["Bp"]=a D=104,A=4,K["Bo"]=for D=103,A=3,K["Bn"]=100 D=102,A=2,K["Bm"]=index D=101,A=1,K["Bl"]=var Step 4:代碼if (''.replace(/^/, String)) 分析 看起來很高深的一個代碼,你想空字符串無論怎麽替換,還是空字符串,在javascript中,空字符串=false,非空字符串=true 所以這個if語句怎麽都不會執行,這裏是一個混淆視聽的代碼,呵呵,你如果想,也可以寫上更多亂七八糟的代碼來達到同樣效果。 Step5:關鍵代碼return E.replace(J, N),這裏用到了函數N: function N(A) { return K[A] == L[A] ? A : K[A] } 注意L對象從來沒有賦值,所以L[A]返回的應該是undefined,所以可以翻譯爲 function N(A) { return K[A] == undefined ? A : K[A] } 這下看起來就很好理解,關鍵代碼就下面這些 1function decode(E, I, A, D, J, K, L, H) { 2 function C(A) { 3 return A < 62 ? String.fromCharCode(A += A < 26 ? 65 : A < 52 ? 71 : -4) : A < 63 ? '_' : A < 64 ? '$' : C(A >> 6) + C(A & 63) 4 } 5 while (A > 0)K[C(D--)] = I[--A]; 6 function N(A) { 7 return K[A] == undefined ? A : K[A] 8 } 9 return E.replace(J, N) 10} 綜上分析,該算法的原理就是從腳本文件中提取單詞,存入字典表中,這裏使用|分割的字符串,然後將單詞對應的序號(仿base64編碼值)寫入原來代碼的地方, 就構成了該算法的核心了,所以實現該壓縮算法的代碼也不難了
󰈣󰈤
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有