Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)

早些年,Microsoft公司针对脚本保护方面,在推出Microsoft Internet Explorer的同时在其Scripting虚拟机中引入了一种新的技术:Script Encoding。但在其文档中又特别提到了这样一点:

  注意,这种编码只能防止别人在无意中查看到您的代码,并不能防止蓄意黑客查看您的编码内容及其方法。

所以很快网上就已经出现了解密的方法。直到前几天,我在需要解密一个webshell时也需要用到了VBScript.encode解密,于是到网上到处找解密程序,最多的就是html源码版的,而且都是一模一样,汗…。于是复制->保存decoder.Html->运行->解密;代码解了一截就停住了,一时半刻不知是什么原因,于是baidu了好一会儿,得知两点:

  • encode加密对中文字是不处理的;
  • 网上这个HTML代码的解密不处理特殊字符。后来在一边文章中得知其中一个特殊符号是’ ×’(叉)

于是凭这两点,我们可以把密文中的特殊字符先全部替换为中文字,例如 ’破军’ ,再进行解码,待解密完后再把’破军’换回’×’。但这时新的问题又出现了,见下图;

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》

图1

由于密文过长导致的,如果是不是太长的解密,这方法是没问题的。在这里即使我点’否’,它还是解不出来,这不知是归咎于脚本引擎的运行效率还是这个解密算法的效率了。

于是我又找到一个用程序写的解密工具,见下图:

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》

图2

这工具找来的时候还绑有马儿,真不爽。把替换好的密文放进去解密,从图中看到它的提示,相信它也是用到webbrower之类的控件,来运行html代码的吧!翻译过来跟前面截图的提示是一个意思。

于是我很不情愿的翻查凌乱的硬盘,找到两个很旧的工具一个是‘ASP工具’:测试一下,有点慢,而且最后还是解密不全告终。

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》

图 3

另一个是‘asp编码/反编码工具’又测试一下:

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》

    图4

    速度还可以,而且能跑出明文,但试过几次后发现它只能保存.sf后缀(作者指定的),而且解密很长的密文时有一点点卡,虽然这不是致命的问题,但是我们要秉承毛主席的话:’自己动手,丰衣足食。’下面开始我们代码的编写过程:

    实际上刚开始我也是像’Asp网站助手加解密工具’的思路写的第一个程序,发现不行,于是又把html里的JavaScript脚本翻译成Delphi语言继续尝试(这时我还不是很了解Scripting Encoder解密算法,就直接翻译),通过跟踪发现能解密成原文,但真正运行起来就是得不到结果,程序卡住了。

    《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》

   图5
  最后又去baidu了找资料,找到一篇文章《Microsoft Windows Scripting Encoder加密算法的研究》,作者不详。从中又了解到两点:

  • Script Encoder编码处理的脚本中,只有ASCII 32~ASCII 126,以及ASCII 9(TAB符)被编码,这编码与一个长度为64的线性表有关。而且对于所有的字符,编码表是完全相同的。表如下:
const itab : array[0..63] of byte = ( {table order}
$00,$02,$01,$00,$02,$01,$02,$01,$01,$02,$01,$02,$00,$01,$02,$01,
$00,$01,$02,$01,$00,$00,$02,$01,$01,$02,$00,$01,$02,$01,$01,$02,
$00,$00,$01,$02,$01,$02,$01,$00,$01,$00,$00,$02,$01,$00,$01,$02,
$00,$01,$02,$01,$00,$00,$02,$01,$01,$00,$00,$02,$01,$00,$01,$02);
  • 每个字符对应有3种形式,例如:’a’被编码后可能为‘C‘(大写);m(小写);l(小写),而到底是哪个就根据哪个64位的线性表了。

Script Encoder的编码集:(ASCII 9,32-126):

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》
图6(每3个对应1个ASCII字符)

Const dectab : array[0..2,0..$7f] of byte = ( {table to decrypt}
  ($00,$01,$02,$03,$04,$05,$06,$07,$08,$57,$0A,$0B,$0C,$0D,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $2E,$47,$7A,$56,$42,$6A,$2F,$26,$49,$41,$34,$32,$5B,$76,$72,$43,
    $38,$39,$70,$45,$68,$71,$4F,$09,$62,$44,$23,$75,$3C,$7E,$3E,$5E,
    $FF,$77,$4A,$61,$5D,$22,$4B,$6F,$4E,$3B,$4C,$50,$67,$2A,$7D,$74,
    $54,$2B,$2D,$2C,$30,$6E,$6B,$66,$35,$25,$21,$64,$4D,$52,$63,$3F,
    $7B,$78,$29,$28,$73,$59,$33,$7F,$6D,$55,$53,$7C,$3A,$5F,$65,$46,
    $58,$31,$69,$6C,$5A,$48,$27,$5C,$3D,$24,$79,$37,$60,$51,$20,$36),
  ($00,$01,$02,$03,$04,$05,$06,$07,$08,$7B,$0A,$0B,$0C,$0D,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $32,$30,$21,$29,$5B,$38,$33,$3D,$58,$3A,$35,$65,$39,$5C,$56,$73,
    $66,$4E,$45,$6B,$62,$59,$78,$5E,$7D,$4A,$6D,$71,$3C,$60,$3E,$53,
    $FF,$42,$27,$48,$72,$75,$31,$37,$4D,$52,$22,$54,$6A,$47,$64,$2D,
    $20,$7F,$2E,$4C,$5D,$7E,$6C,$6F,$79,$74,$43,$26,$76,$25,$24,$2B,
    $28,$23,$41,$34,$09,$2A,$44,$3F,$77,$3B,$55,$69,$61,$63,$50,$67,
    $51,$49,$4F,$46,$68,$7C,$36,$70,$6E,$7A,$2F,$5F,$4B,$5A,$2C,$57),
  ($00,$01,$02,$03,$04,$05,$06,$07,$08,$6E,$0A,$0B,$0C,$06,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $2D,$75,$52,$60,$71,$5E,$49,$5C,$62,$7D,$29,$36,$20,$7C,$7A,$7F,
    $6B,$63,$33,$2B,$68,$51,$66,$76,$31,$64,$54,$43,$3C,$3A,$3E,$7E,
    $FF,$45,$2C,$2A,$74,$27,$37,$44,$79,$59,$2F,$6F,$26,$72,$6A,$39,
    $7B,$3F,$38,$77,$67,$53,$47,$34,$78,$5D,$30,$23,$5A,$5B,$6C,$48,
    $55,$70,$69,$2E,$4C,$21,$24,$4E,$50,$09,$56,$73,$35,$61,$4B,$58,
    $3B,$57,$22,$6D,$4D,$25,$28,$46,$4A,$32,$41,$3D,$5F,$4F,$42,$65));

都是前辈整理的,直接拿来用咯!下面我们来实现程序的关键函数:

function strdencode(const encodestring:widestring):widestring;
var
pos0:byte;                      //线性表位置
res:word;                       //一个密文
uncodestring:ansistring;        //明文
encrypted_pos:longword;         //待处理密文位置
code_end:longword;              //密文结束位置
h_str:string;                   //原文头尾处理
tem:integer;                    //临时
 
begin
encrypted_pos := pos('#@~^',encodestring);
code_end := pos('^#~@',encodestring);
 
if encrypted_pos=0 then begin
messagebox(form1.Handle,'找不到开始标志,请确保脚本完整。','提示:',mb_ok);
exit;
end else encrypted_pos:=encrypted_pos+4+8;
if code_end=0 then begin
messagebox(form1.Handle,'脚本末尾不完整,若要继续解密,结果将会是不完整的或有差错的!','提示:',mb_ok);
code_end:=length(encodestring);
end else code_end:=code_end-8;
 
pos0:=0;
res:=0;
 
while encrypted_pos<code_end do begin
//开始的判断能处理所有特殊字符,包括中文字
if ord(encodestring[encrypted_pos])>$80 then begin
uncodestring:=uncodestring+encodestring[encrypted_pos];
inc(encrypted_pos);
continue;
end;
 
res:=ord(encodestring[encrypted_pos]);
 
if res<$80 then begin {encrypted?}
res:=dectab[itab[pos0],res];
 
if res=$ff then begin {special char}
inc(encrypted_pos);
res:=ord(encodestring[encrypted_pos]);
case res of
$26 : res:=$0a;
$23 : res:=$0d;
$2a : res:=$3e;
$21 : res:=$3c;
$24 : res:=$40;
end;
end;
uncodestring:=uncodestring+chr(res);
end;
 
inc(encrypted_pos);
pos0:=(pos0+1) mod 64;
end;
//处理头部
tem:=pos('#@~^',encodestring);
h_str:=midstr(encodestring,1,tem-1);
tem:= pos('.encode',lowerCase(h_str));
if tem<>0 then begin
delete(h_str,tem,7);
result:=h_str+uncodestring
end else result:=h_str+uncodestring;
 
//处理尾部
tem:=pos('^#~@',encodestring);
if tem<>0 then
begin
h_str:=midstr(encodestring,tem+4,length(encodestring)-tem-3);
result:=result+h_str;
end;
end;

这就是程序最终实现图:(关键就是用到两个表:itab[],dectab[];一个函数strdencode();这样你就可以实现不同语言写的程序了!)

《Microsoft Windows Scripting Encoder解密算法浅析(Delphi实现程序)》
图7

文章就到此为止了,有不对的地方请见谅并指出。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注