Windows脚本编码器算法分析与破译 by lake2(http://mrhupo.126.com)
大家对脚本一定很熟悉吧,呵呵,脚本编写简单无需编译所以非常方便。不过,脚本的一个缺点是它不能保护脚本的内容,因为随便谁拿到一个脚本程序都可以用记事本打开来看内容。这样就不安全了嘛,比如你的知识产权可能不保;web服务器上连接数据库的asp文件会泄露sql的用户名密码;分析源代码找到设计漏洞……
呵呵,不过微软开发了一个脚本编码器(Script encoder)来弥补脚本的不足。脚本编码器对文件中的脚本代码进行编码,其他内容不动且以普通文本形式显示,而经过编码后的程序可以直接由相应的程序执行,执行结果与未编码的程序相同。这个不是本文的讨论范围,感兴趣就去下载吧,微软还附赠了中文使用说明的哦。下载地址:http://www.microsoft.com/downloads/details.aspx?FamilyID=6a326d9c-f47e-4c92-b42a-b3d43029e96f&displaylang=zh-cn
本文的目的就是对脚本编码器的加密算法进行分析并找出破译方法,内容可能枯燥无味,若你有兴趣就继续看吧。先说一下,脚本编码器的解密软件早已经有了(你可以see http://www.csdn.net/cnshare/soft/13/13303.shtm),这里是分析——“授人以鱼,不如授人以渔”。
你还有兴趣啊?呵呵,那好,待我准备好工具就开始。东西也不多,记事本程序、Script encoder程序、ascii码表、一张草稿纸足矣。呵呵,我是用纯密码学去分析破译,所以用不着对程序进行反汇编(再说我还不会汇编):P
这里先给出个密码学术语——选择明文攻击:攻击者能够得到任意明文所对应的密文。现在我们手上有加密程序,就可以构造任意明文来加密得到密文,符合选择明文攻击的条件。
脚本编码器能够处理asp、htm、vbs、js等类型的文件,都是将文件中的脚本加密。比如asp、htm,就加密“<%”“%>"和“<SCRIPT>”“</SCRIPT>”之间的内容;vbs、js则加密整个文件。程序会自动改掉原来的语言标识。比如我的asp文件原来是“LANGUAGE="VBScript"”,现在成了“LANGUAGE="VBScript.Encode"”。
现在我的内容是“2004年12月16日”,加密之后就成了“#@~^CwAAAA==+Z!*年8 月8v日kAEAAA==^#~@”,注意这里仅仅是为了分析算法,所以并不去管程序的语法。
多分析几个密文就可以发现规律:密文以“#@~^******==”(*代表任意字母)开始(方便叙述以后就叫前缀,后面类同);中间是与明文等长度的字符(中间密文);又以“******==^#~@”(*代表任意字母)结束(后缀)。
下面就分别来分析。
先来说说中间密文,这个最复杂也最重要,因为它是由明文加密而得,只与明文和算法有关,如果要想知道代码内容的话只需要能破译中间密文就行了。
中间密文长度与明文相同,但是明文中的英文字母、数字和英文符号(也就是ascii码9和32~127)是经过加密了的,而其他字符不变。中间密文不是对明文的简单替换,也就是说“a”加密之后不会是同一个字符,但是也是有规律可循。以下是对10个“a”加密后的结果:#@~^CgAAAA==CmlCmlmllmygMAAA==^#~@
去掉前缀后缀看看有什么规律,呵呵,对,中间密文里始终只出现“C”、“m”、“l”三个字符,也就是说每个字符只由三个字符来替换(注意有四个例外:回车始终用“@#@&”、“<”用“@!”,“>”用“@*”、“@”用“@$”)。你还将发现不同明文的密文出现的位置始终一样。比如若干个a的密文,第1、4、13、17、21、……位是C;若干个b的密文也只有第1、4、13、17、21、……位是8。也就是说密文中的三个字符出现的位置是固定的。不知道你理解没有,看例子:
10个a的密文:CmlCmlmllm 10个b的密文:8(48(4(44(
不过即使这样我怎么知道密文哪一位出现哪个字符呢?呵呵,那就把长度加到150来看看。呵呵,发现规律了:密文中三个字符出现的位置是以64为周期的序列。现在我们只需知道前面64位的排列序列就行了。
这里我把序列提取出来了,这里用“1”、“2”、“3”来代替字符,序列是:1231232332321323132311233213233211323231311231321323112331123132
举个例子,a的密文第一个是C,查找上面的序列,1就代表C了,所以凡是出现1的位置都会出现C(如果在那个位置明文是a的话),超过了又从头开始查找。
序列搞定了,不过字符替换规则的公式一直找不到(或许没有^_^),没办法,只好用穷举法了。下表列出了所有字符的替换规则:
_____________________________________ ASCII | Char | 1 | 2 | 3 | ------------------------------------- 9 (Tab) 7 i d 13 (CR) @#@& @#@& @#@& 32 (Space) ~ , P 33 ! Z e " 34 " E r J 35 # : [ a 36 $ y f ^ 37 % Y u ] 38 & ' L [ 39 ' v E B 40 ( c v ` 41 ) b * # 42 * M C e 43 + Q 3 _ 44 , S B ~ 45 - R (Space) O 46 . (Space) c R 47 / & J z 48 0 T Z ! 49 1 q 8 F 50 2 + y (Space) 51 3 f 2 & 52 4 * W c 53 5 X l * 54 6 + v 55 7 { F G 56 8 0 R % 57 9 1 0 , 58 : l = ) 59 ; I p i 60 < @! @! @! 61 = x { ' 62 > @* @* @* 63 ? _ Q g 64 @ @$ @$ @$ 65 A ) z b 66 B $ ~ A 67 C / ; Z 68 D 9 G f 69 E 3 A 2 70 F o w s 71 G ! V M 72 H u _ C 73 I ( & q 74 J B x 9 75 K F n | 76 L J d S 77 M \ t H 78 N H g 1 79 O 6 } r 80 P K h n 81 Q } 5 p 82 R ] " I 83 S j U ? 84 T P : ? 85 U i ` j 86 V # j . 87 W (Tab) q 88 X p o ( 89 Y e I 5 90 Z t \ } 91 [ , ] $ 92 \ w ' - 93 ] D Y T 94 ^ ? % 7 95 _ m | { 96 ' | # = 97 a C m l 98 b 8 ( 4 99 c ^ 1 m 100 d [ 9 N 101 e n + 102 f W 6 0 103 g L T o 104 h 4 4 t 105 i r b k 106 j % N L 107 k V 0 3 108 l s ^ V 109 m h s : 110 n U (Tab) x 111 o G K W 112 p 2 a w 113 q 5 $ ; 114 r . M D 115 s d k / 116 t O D Y 117 u ; ! E 118 v - 7 \ 119 w A S h 120 x a X 6 121 y z H X 122 z " . y 123 { ` P (Tab) 124 | k - u 125 } N ) 8 126 ~ = ? U 127 g / Q ------------------------------------- (Tab)——Tab键 (CR)——回车 (Space)——空格 ——ascii码为127的字符,似乎显不出来 _____________________________________
呵呵,很多是吧,我是写了个asp文件来输出字符,脚本的便利性又一次体现出来了。
这里要说一下,前面不是列出了四个特例么,它们都是以@开始的字符,虽然占了两个位置,但是只算作一位(“@#@&”算两位),所以注意中间密文中的“@”不记入长度计算中哦。
现在知道怎么解密了吧:先获得密文位置,匹配字符序列,得到一个数字,然后查替换表找到数字对应的密文字符,密文字符所对应的就是明文。
比如这里有个中间密文:“@#@&kW”,@#@&是回车占两位,所以k在第三位,查序列,得到3,再查替换表3的纵行,就找到了k对应的明文i;同理,W对应明文f。呵呵,怎么样,你译对了吗?
到了这里你就可以自己破译密文了。要是有兴趣可以自己写个程序,不过既然已经有人写了那就实行“拿来主义”吧。这里我不介意罗嗦两句吧。这个算法虽然属于替换密码,不过密文与位置还有关,所以密文隐藏了明文的统计特征,要是没有选择明文攻击的话还是很难破的。呵呵,举个例子来看看这算法的好处。“红粉佳人”这个asp木马你该知道吧,可杀毒软件会将它列为病毒,嗯,为了躲避追杀我们可以用脚本编码器对“红粉佳人”加密,虽然实际上加密之后杀毒软件查不到了,不过我们可以假设杀毒软件公司又从加密代码里提出了特征码,现在又可以查杀了。呵呵,由于这个算法的性质,其实我们在加密时可以在源代码里多添几个回车、空格,那么密文就完全变了,嘿嘿,看它怎么杀。
中间密文分析完了,现在来看看前缀后缀吧。
前缀的中的“#@~^”和“==”是不变的,而接下来的六个字母与明文的长度有关系。注意一个汉字长度为1,回车长度为2。通过分析发现六字母的第二位只能是A、Q、g、w,且是循环的。每循环一次第一位改变一次。第一位以A开头依次按大写字母顺序、小写字母、数字、符号变换。下面是明文长度从1至10的六字母:
AQAAAA AgAAAA AwAAAA BAAAAA BQAAAA BgAAAA BwAAAA CAAAAA CQAAAA CgAAAA
很容易我们可以推出当明文长度为100时的六个字母:ZAAAAA
这里有个特殊情况要注意:在asp文件中类似“<%response.write("lake2")%>”的格式可以简写为“<%="lake2"%>”,脚本编码器在加密“<%="lake2"%>”时会保留“<%=”,所以明文长度不能算上“=”。
这个,前缀的六个字母如果只用前两位来表示长度的话可能会碰到不够的情况,这时候就会向第三位变动,第三位变动规则与第一位一样;当然可能第三位也会不够,不过在实际中几乎是不可能的,除非你蓄意制造如此长的明文。
同前缀类似,后缀也是六个字母在变动。这六个字母与明文的ascii码有关。你会发现“ac”与“bd”的后缀相同,因为“ac”与“bd”ascii码和相同。这里计算ascii时只计算替换规则表里的字符,汉字不算。它的变动规则同前缀的六字母,这里就不讨论了。
呵呵,到这里分析差不多完了,不知道你头晕了没有,反正我是分不清东西南北了:)
感谢你看完我的文章,呵呵,不知你看懂了没有,下面有个去掉了前后缀的密文,试试解密啊^_^
“uVsK~sXP6Dbnx9”(注意第二个是ascii码为127的字符,而不是空格哟)
2004-12-18 
|