这里先说两个,一个是JSA另一个是JSO*。

JSA是个Java写的东西,在sourceforge上可以下载,特别推荐一下。JSA的分析功能对我不是很有用,不过格式化的本领不错,而且还可以直接解出类似Parcker的Eval(……)的压缩代码。混淆虽然只是变量名混淆,不过可以设置每个变量的混淆后的名称,挺人性化的。压缩采用的也是Packer2的方法,不过修改了一点。细节上JSA似乎内置了一个Parser,格式化时会自动行的结尾补上空格。

JSO*是dotNet 1.1写的东西,要钱,同样也有格式化、变量混淆,但是没有分析功能。和JSA相比多了一个批量处理的功能,混淆的选项也更多些,不过基本上都是变量混淆。特色的地方是把字符串常量都放到了一个数组里,引用的地方都变成了数组的元素,并且把整数都转为16进制。在一个就是把所有函数调用都由window.alert变成了window["alert"]形式。所谓的加密就没有什么特色了,完全Packer2照搬。

JSA的主要目的是格式化和分析,因此重点放在JSO*上。因为JSO*估计使用正则表达式之类的方法来实现了一个简单的Parser,必须由用户自己注意,代码里一定不能缺少“;”,否则混淆、加密后就可能无法使用。混淆并加密后的代码咋看之下却是难以看清,但是复制到JSA中进行格式化后倒也清晰了不少。除了字符串变成了数组的引用,函数调用成[]之外,基本可以原封不动还原代码。如果JSA再完善些,估计直接还原回原代码是不成问题了。

其他国产的Javascript保护工具基本用的用的都是网络上常用的方法,最多就是重复嵌套几次(最多的我看到用escape进行了4次,选项我选择了最高强度);再或者就是用之前说的压缩方法。

由上面的分析,可以得出一个结论,暂时国内软件似乎还不能做到很好保护JavaScript的代码。毕竟就算去掉了空格和换行,可以用其他工具来格式化;将10进制数转为16进制,也可以直接转换回来;把字符串常量放到数组里,同样还是可以用正则表达式替换的方法直接还原;而将函数调用的写法换一下,只能安慰一下自己。毕竟源代码的布局,流程还是没有改变的。

posted @ 2008-04-07 22:13 陈鹏(偶是坏人) 阅读(130) | 评论 (0)编辑

由于最近做的东西都是纯Javascript脚本的到网上下一些现成产品的代码,发现都有加密或混淆,因为很多加密其实是用Packer2的压缩实现的,就先讨论一下压缩吧,毕竟压缩后的代码至少可以让下载的速度快些吧。

目前JavaScript压缩的基本方法如下:
1、最常用的方法,将所有的注释去掉,然后将所有的回车去掉,最后把多余的空格也去掉。
2、高级点的方法,除了方法1的几个去除步骤外,加上了一个重命名变量的功能,把所有的变量名和方法名都变成由两三个字符组合的,达到进一步减肥的目的。
3、最后,用一些简单的压缩算法。

这里就不讨论方法1和方法2了。方法1过于简单;至于方法2,现在不少JavaScript代码保护软件的混淆就是这么做的,所以下次再探讨。

用与JavaScript的压缩算法和普通的压缩不同,不能使用太复杂的方法,毕竟解压的代码也是明码写在文件里的嘛。目前比较流行的是Packer2还有一个压缩效果很好的MemTronic's HTML JavaScript Cruncher-Compressor。个人认为Packer2的实现更好些,因为MemTronic's HTML JavaScript Cruncher-Compressor使用了ASCII码127之后的不可见字符,保存文件时弄错了编码,就前功尽弃。所以我们重点来讨论Packer2。

MemTronic's HTML JavaScript Cruncher-Compressor的实现我没有认真分析(代码好长,不是很想看),不过效果确实挺好的(不过你要是叫作者换成可见的字符,他就不一定有这个效果了),可惜保存到文件时比较麻烦,我复制到Microsoft Script Editor 7保存,有些字符就丢失了。用Unicode或者UTF8之类的编码保存,文件又会增大不少。

看到用不可见字符做分隔的方法,我之前也考虑用127之后的不可见字符来做个**进制,当初设想是当字典的索引成百上千后能省那么一点点,最后也是因为不可见字符的原因,放弃之。

Paker2的方法是首先用正则表达式将所有字符串取出,作为一个字典。然后将源代码中的字符串用字典中的索引来替换。最后在替换好的代码外加入一个Eval(……)的外壳,web页面在客户端运行时就能动态解压了。下面拿个具体的代码来看一下:

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('0(\'1\');',2,2,'alert|xxx'.split('|'),0,{}));
function(p,a,c,k,e,d)就是Packer2的标志。然后加入了一大堆的花指令,搞不懂作者想什么,压缩的东西还要弄得这么复杂。想看原来的代码也不需要什么特殊的工具,只要把最后的return p改为,document.getElementById(你的输出的目标).value = p就可以了。

我自己简化后的解压部分代码如下:
eval((function (e, d)
{
    e 
= e.replace(new RegExp('\\b\\w+\\b''g'), function ($0)
    {
        
return d[$0];
    });
    
return e;
}(
'0(\'1\');''alert|xxx'.split('|'))));
简化一下实际就成了上面这个样子。可以很明了地看到,传入两个参数。参数e是经过替换后的代码,里面的数字对应字典里的位置。参数d对应的就是字典,为了节约,用“|”作分隔符和并成字符串。解压的原理也是一样,一个正则表达式的替换。

晕倒,居然忘了说压缩,还是如同上面的那个方法,在正则表达式替换的时候来个回调,先判断取得的字符串是否存在字典表里,如果不存在就增加,否则就取已存在的字符串的位置索引,然后把位置索引return回去让正则表达式自己做替换,重复n次,再然后,就OK啦。

放眼望去,现在不少东西是用Packer2的方法来做“加密”,连MapBar的最新版本的核心代码都是用Parcker2来压缩的,不过MapBar比较狠,还用JSOB之类的东西混淆了一回。挺流行的JQuery也是使用这种方法来做压缩的。

最后,鄙视以下,居然发现一个号称综合了到部分产品优点的Javascript混淆加密工具(300¥)加密后也可以清楚地看到function(p,a,c,k,e,d),而且连花指令都一模一样。这年头,难道没人知道碰到这种东西拿JSA出来格式化一下,什么都搞定了吗?
posted @ 2008-04-07 17:09 陈鹏(偶是坏人) 阅读(327) | 评论 (2)编辑