zoukankan      html  css  js  c++  java
  • Javascript代码压缩、加密算法的破解分析及工具实现

    现在网上很多Javascript都进行了压缩,同时代码变得不可直接阅读,也相当于一种简单的加密了,本文对其中一种典型的算法进行分析,介绍如何解密代码以及重新实现的压缩工具算法。
    典型代码如下:

    JavaScript代码
    1. 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(和后面的)去掉,然后显示出来就完成了,例如下面的页面就可以实现代码的还原:

    JavaScript代码
    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. <BODY>  
    11. <TEXTAREA NAME="tx1" ROWS="10" COLS="100"></TEXTAREA>  
    12. <SCRIPT LANGUAGE="JavaScript">  
    13. document.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, {}, {}, [])  
    14. </SCRIPT>  
    15. </BODY>  
    16. </HTML>  


    通过上面方式运行,就可以在文本框中看到代码了,实际的代码是:
    var index=100;for(var a=0;a<100;a++){ document.write(index+a+"<br>");}
    很简单,不是吗

    二、算法研究
    由于代码全部在一行中,不便于阅读,可以通过格式化软件格式化,本文这里使用Intellij IDEA格式化,代码如下

    JavaScript代码
    1. eval(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)

    JavaScript代码
    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  
    9. function 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. }  
    29. var 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如下分解

    JavaScript代码
    1. function 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对象中,运算顺序如下表:

    JavaScript代码
    1. D=109,A=9,K["Bt"]=br  
    2. D=108,A=8,K["Bs"]=write  
    3. D=107,A=7,K["Br"]=document  
    4. D=106,A=6,K["Bq"]=0  
    5. D=105,A=5,K["Bp"]=a  
    6. D=104,A=4,K["Bo"]=for  
    7. D=103,A=3,K["Bn"]=100  
    8. D=102,A=2,K["Bm"]=index  
    9. D=101,A=1,K["Bl"]=var  


    Step 4:代码if (''.replace(/^/, String)) 分析
    看起来很高深的一个代码,你想空字符串无论怎么替换,还是空字符串,在javascript中,空字符串=false,非空字符串=true
    所以这个if语句怎么都不会执行,这里是一个混淆视听的代码,呵呵,你如果想,也可以写上更多乱七八糟的代码来达到同样效果。

    Step5:关键代码return E.replace(J, N),这里用到了函数N:

    JavaScript代码
    1. function N(A) {  
    2. return K[A] == L[A] ? A : K[A]  
    3. }  


    注意L对象从来没有赋值,所以L[A]返回的应该是undefined,所以可以翻译为

    JavaScript代码
    1. function N(A) {  
    2. return K[A] == undefined ? A : K[A]  
    3. }  

    这下看起来就很好理解,关键代码就下面这些

    JavaScript代码
    1. function 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编码值)写入原来代码的地方,
    就构成了该算法的核心了,所以实现该压缩算法的代码也不难了

    三、工具实现
    具体实现采用java,代码就不介绍,写完代码之后才发现这是JSA(http://sourceforge.net/project/showfiles.php?group_id=175776)的压缩算法的再实现,该工具对jquery-1.2.3.min.js压缩测试调用运行成功,压缩率为40%。

    【运行方法】
    ====================================
    命令提示符下面运行,要求JRE 1.5+

    Usage:java JSEncoder.jar jsfile outputfile [offset].
    jsfile:待压缩的文件
    outputfile:输入的文件
    offset:可选整数值,>=

  • 相关阅读:
    SqlServer Alwayson 搭建排错记录(一)
    SqlServer图形数据库初体验
    SqlServer报错:主体“dbo”不存在
    IIS重叠回收
    No module named 'revoscalepy'问题解决
    SqlServer查询文件组被占用情况
    SqlServer作业指定目标服务器
    [持续更新]UnsatisfiedLinkError常见问题及解决方案
    Android加载SO库UnsatisfiedLinkError错误的原因及解决方案
    _set_invalid_parameter_handler异常处理函数
  • 原文地址:https://www.cnblogs.com/MaxIE/p/1245570.html
Copyright © 2011-2022 走看看