升级!Safengine Licensor 1.85DEMO 默认加壳IAT修复
本帖最后由 wuqing1501 于 2010-12-4 23:21 编辑【文章标题】: Safengine Licensor 1.85DEMO 默认加壳IAT修复
【文章作者】: wuqing1501(笨笨鼠)
【作者邮箱】: 自己搜吧
【作者主页】: 自己搜吧
【作者QQ号】: 自己搜吧
【软件名称】: 么有啊
【软件大小】: 不详
【下载地址】: 自己搜索下载
【加壳方式】: 不详
【保护方式】: iat加密
【编写语言】: 不详
【使用工具】: 老三样
【操作平台】: 不详
【软件介绍】: 怎么一个WS了得!
【作者声明】: 只是感兴趣,没有其他目的。没有技术含量,大牛们飘过吧!
--------------------------------------------------------------------------------
【详细过程】
说明一下由于自己的粗心使得原来对脚本少了几个校验,导致有部分的一字节没有修复,现在脚本已经增加校验,这样脱壳后修复的IAT中那一个字节已经修复了所以重新上传脚本,在这里补充一下原来文章中缺少的部分内容。
操作步骤:
1、先到达OEP然后跑脚本,
2、等脚本跑完后,运行UIF修复然后 ,LP dump,IRC修复,
3、最后用LP把UIF最后修复IAT申请的区段DUMP下来补区段,记得把CODE段修改为可写,然后重建PE,
4、最后用区段修正脚本修正一下,在DUMP一次就可以了。
附件没有更新,附件中的脚本还是有问题的脚本,可以直接复制贴子中的脚本。新脚本采用最新版1.86DEMO加壳测试通过,NN放水没有修改代码,大家可以自己拿附件中的样品自己加壳测试!
首先声明:
菜鸟学习之用,欢迎大牛们拍砖。
脚本的产生是偶然事件;
脚本不具有通用性;原因在于生成代码在服务端!就算不在我也搞不定!
样品采用SL1.85DEMO默认加壳,只有IAT的加密,甚至没有DLL模拟,貌似也只加密IAT!如果有DLL模拟的话还是参看CEKTOP大牛的文章吧,论坛就有的。
整个过程其实就是写一下我写脚本的过程。
其实,就是想看看SL的DEMO版加壳后的程序,我能否修复IAT,也没有什么内容大家就飘过吧,其实对于IAT加密解密,我是个菜鸟,不折不扣的菜鸟,看着高手们的文章都分析的那么透彻,只有看的福分,因为俺技术太菜了分析不了那么清楚,更不敢瞎说误人子弟, 所以我在这里不贴那么多的代码,不做详细的分析,因为没有那个能力,人又笨还不会做视频,只好写个文章纪念一下吧!
为什么说是不完全修复呢,因为我也感觉到很奇怪,因为大多数的API已经修复了,但是SL对于FF25 FF15。。。之类的IAT调用都给抽了 换成了CALL的类型 那样 就比原来的调用多了一个字节,而修复好的API中这个字节必须要NOP掉软件才能正常运行的,而我没有完全修复的就是因为有太多的字节需要NOP而我写的脚本没有能够完全修复!
在说一下我写好的脚本如果从出问题的API地方开始修复的话 那些个字节是可以NOP掉的,但是如果使用脚本自动修复的话修复后的有很多的字节本应该NOP掉的但是却没有执行,所以软件就出错了!不过脚本已经可以修复大多数的字节了!
嗯,还是贴点代码吧,对于强大SL,具体怎么到EOP那就看各位的本事,俺比较菜至今不能到达那个神圣的光明之巅,所以自己用DEMO加壳自己脱那样的话OEP就不用找了 哈哈哈!
开始吧,OD载入程序:
00601F5A >E8 21000000 CALL 00601F80 ; 入口
00601F5F 53 PUSH EBX
00601F60 61 POPAD
00601F61 66:65:6E OUTS DX,BYTE PTR ES:
00601F64 67:696E 65 204C>IMUL EBP,DWORD PTR SS:,63694C20
00601F6C 65:6E OUTS DX,BYTE PTR ES:直接在OEP附近下硬件断点吧,不能再OEP头字节哦,因为SL会偷代码的哦!记得使用一下带有DRX protcet 的插件哦还有强大的SOD,再使用个牛X的OD,F9运行,停在OEP附近处:0040532D 8BEC MOV EBP,ESP ; oep附近就是OEP的第二条代码
0040532F 6A FF PUSH -1 ; 第一条被偷了代码为push ebp
00405331 68 A0614000 PUSH 004061A0
00405336 68 C0544000 PUSH 004054C0
0040533B 64:A1 00000000MOV EAX,DWORD PTR FS:
00405341 50 PUSH EAX
00405342 64:8925 0000000>MOV DWORD PTR FS:,ESP
00405349 83EC 68 SUB ESP,68
0040534C 53 PUSH EBX
0040534D 56 PUSH ESI
0040534E 57 PUSH EDI看下IAT是被怎么处理的:
FF15类型的:加密后多一个字节
原程序:00405357|.6A 02 PUSH 2
00405359|.FF15 98604000 CALL DWORD PTR DS:[<&MSVCRT.__set_app_ty>;msvcrt.__set_app_type
0040535F|.59 POP ECX加密后:00405357 6A 02 PUSH 2
00405359 E8 D6521F00 CALL 005FA634//IAT被抽走了
0040535E 58 POP EAX //多出了一个字节,修复需要NOP的地方
0040535F 59 POP ECXFF25类型的://加密后字节一样
原型:004053B9|.68 10704000 PUSH 00407010
004053BE|.E8 D3000000 CALL <JMP.&MSVCRT._initterm>
004053C3|.A1 74714000 MOV EAX,DWORD PTR DS:加密后004053B9 68 10704000 PUSH 00407010
004053BE E8 3E591F00 CALL 005FAD01 //
004053C3 A1 74714000 MOV EAX,DWORD PTR DS:JMP类型的://加密后多一个字节
原程序:004054C0 $- FF25 94604000 JMP DWORD PTR DS:[<&MSVCRT._except_handl>;msvcrt._except_handler3; 结构化的异常处理程序
004054C6 $- FF25 90604000 JMP DWORD PTR DS:[<&MSVCRT._controlfp>];msvcrt._controlfp加密后:004054C0 E8 66661F00 CALL 005FBB2B//IAT被抽走了
004054C5 4D DEC EBP //多出了一个字节,修复需要NOP的地方
004054C6 E8 2E681F00 CALL 005FBCF9//IAT被抽走了
004054CB A7 CMPS DWORD PTR DS:,DWORD PTR ES:MOV reg,api类型:
mov eax,api ://加密后字节一样
原型:0040538A|.A1 A4604000 MOV EAX,DWORD PTR DS:[<&MSVCRT._adjust_f>加密后: 0040538A E8 C2561F00 CALL 005FAA51mov exx,api ://加密后多一个字节
原型:0040129D .8B3D 18604000 MOV EDI,DWORD PTR DS:[<&KERNEL32.CloseHa>;kernel32.CloseHandle
004012A3 .74 0A JE SHORT 004012AF
004012A5 .50 PUSH EAX ; /hObject
004012A6 .FFD7 CALL EDI ; \CloseHandle加密后:0040129D E8 04341F00 CALL 005F46A6
004012A2 3A740A 50 CMP DH,BYTE PTR DS:
004012A6 FFD7 CALL EDI查看一下加密后的API调用的开始代码:005FA634 68 567D5E5A PUSH 5A5E7D56
005FA639 9C PUSHFD
005FA63A 814424 04 39018>ADD DWORD PTR SS:,40860139
005FA642 60 PUSHAD
005FA643^ E9 55FFFFFF JMP 005FA59D所有类型的API加密后调用的代码都是这个,所以我们搜索加密后的API的时候这个就是判断是否是加密过的API的依据。
分析了加密后的代码,我们要想修复IAT的话我的想法是:我们可以通过跨区段调用CALL 来搜寻整个程序中的所有的CALL 然后判断出是加密api的CALL进行处理!不管程序怎么加密API最终调用的时候都要返回到真实的API上面的,那我们就找他是怎么解密API的以及解密过程中用到了那些代码,并且判断哪些代码可以作为我们写脚本的特征码,那就开始吧。
具体的加密解密过程,我没有能力分析清楚,大牛们都已经分析过了,很WS,而且调用API的过程不是计算的,而是根据API的名字一个一个的自己找的!另外kernel32.GetModuleHandleA这个函数都是自己写的,所有的API都经过这个调用。
根据上面代码我们可以得到判断是否是加密的API的特征码为:68????????9C81442404????????60
具体说下针对上面不同的加密类型所用到的代码吧
对于FF 和JMP类型的,解密过程中最后解密API是这样的005FA780 894424 24 MOV DWORD PTR SS:,EAX ; msvcrt.__set_app_type//这里还有可能是ESP+xx
005FA784 61 POPAD
005FAA8B FF4424 08 INC DWORD PTR SS: ; SE1_85de.0040535F
005FAA8F 9D POPFD
005FAA90 C3 RETN还有这样的;005FA780 894424 24 MOV DWORD PTR SS:,EAX ; msvcrt.__set_app_type//这里还有可能是ESP+xx
005FA784 61 POPAD
005FAA8F 9D POPFD
005FAA90 C3 RETN总之,运行过程中都用到了 MOV DWORD PTR SS:,EAX
POPAD
POPFD
RETN这个就是我们寻找解密API过程中的特征码,经过测试,只有这个代码 MOV DWORD PTR SS:,EAX下断的话脚本效率较高。所以我们就以这个作为特征码即:8944242?
对于MOV reg,API类型的
最好找到API的最后代码都是类似这样的;005F6521 8B1D 1D655F00 MOV EBX,DWORD PTR DS:
005F6527 8D6424 FC LEA ESP,DWORD PTR SS:
005F652B C3 RETN只是针对不同的寄存器数值稍微有些变化,由此我们得到的特征码为:8B??????????8D6424FCC3
对于寄存器为EAX时比较特殊所以单独列出来:0040538A|.A1 A4604000 MOV EAX,DWORD PTR DS:[<&MSVCRT._adjust_f>
005F6527 8D6424 FC LEA ESP,DWORD PTR SS:
005F652B C3 RETN所以针对EAX的特征码为:A1????????8D6424FCC3
有了以上的分析我们就可以写脚本了,其他的就是增加一些判断而已。
有了上面这些还是不能修复IAT的原因就是我一开始就说的那个API被加密后有些多了一个字节,我们需要把那些字节NOP掉,说下我的方法吧:
当API解密过程到达最终找到API的时候我们可以看到 ESP+4 中的值就是我们CALL调用地址的下一行代码,如果有多余的那个字节的话,它会返回到下面一行,我们就可以根据这个来判断CALL下面的是否有字节需要NOP!
而对于FF25类型的加密,最后ESP+4中的值并不是我们CALL调用的地址附近,但是所有的FF25的都需要NOP掉一个字节,这样也有利于我们的判断了。
基本上对于API的加密我就只懂这些了。
有了上面这些我们就可以写脚本修复了。
当我们跑完脚本后 用UIF修复一下,然后DUMP 然后IRC修复IAT,修复好后发现不能跨平台,原因就是修复后的IAT和程序中的IAT需要修正一下区段,原理和NN修复VP1.82脚本中的修复时一样的。这样我们修复好后就可以跨平台运行了!
下面我贴出写好的脚本,水平很菜脚本写的很烂,见笑了!
IAT修复脚本: var codebase
var codebase
var oep
var codeend
var apiaddr
var calladdr
var fixaddr
var retaddr
var fffixtype
var temaddr
var temeax
var temebx
var temecx
var temedx
var temebp
var temesp
var temesi
var temedi
var logfile
mov codebase,00401000
mov secode1,00412000
mov secode2,00607000
mov oep,eip
mov temeax,eax
mov temebx,ebx
mov temecx,ecx
mov temedx,edx
mov temebp,ebp
mov temesp,esp
mov temesi,esi
mov temedi,edi
mov eip,secode1
findsec1call:
find eip,#8944242?#
cmp $RESULT,0
je findsec1bp
mov addr,$RESULT
bp addr
add addr,1
mov eip,addr
jmp findsec1call
findsec1bp:
mov eip,secode1
findsec1movexx:
find eip,#8B??????????8D6424FCC3#
cmp $RESULT,0
je findsec1bp1
mov addr,$RESULT
bp addr
add addr,a
mov eip,addr
jmp findsec1movexx
findsec1bp1:
mov eip,secode1
findsec1moveax:
find eip,#A1????????8D6424FCC3#
cmp $RESULT,0
je findsec2bp
mov addr,$RESULT
bp addr
add addr,a
mov eip,addr
jmp findsec1moveax
findsec2bp:
mov eip,secode2
findsec2call:
find eip,#8944242?#
cmp $RESULT,0
je findsec2bp1
mov addr,$RESULT
bp addr
add addr,1
mov eip,addr
jmp findsec2call
findsec2bp1:
mov eip,secode2
findsec2movexx:
find eip,#8B??????????8D6424FCC3#
cmp $RESULT,0
je findsec2bp2
mov addr,$RESULT
bp addr
add addr,a
mov eip,addr
jmp findsec2movexx
findsec2bp2:
mov eip,secode2
findsec2moveax:
find eip,#A1????????8D6424FCC3#
cmp $RESULT,0
je start
mov addr,$RESULT
bp addr
add addr,a
mov eip,addr
jmp findsec2moveax
start:
mov eip,codebase
findcall:
find eip,#E8???????0#
cmp $RESULT,0
je exit
mov calladdr,$RESULT
GCI calladdr,DESTINATION
mov fixaddr,$RESULT
find fixaddr,#68????????9C81442404????????60#,0f
cmp $RESULT,0
jne startrfix
find fixaddr,#e9????????90c39090#,9
cmp $RESULT,0
jne clearnop
find fixaddr,#c7c?????????c39090#,9
cmp $RESULT,0
je next
find fixaddr,#c7c0#,2
cmp $RESULT,0
je clearnop
add calladdr,1
mov eip,calladdr
jmp findcall
startrfix:
mov eip,fixaddr
find eip,#68????????9CFF442408#,0a
cmp $RESULT,0
je startiatfix
mov iataddr,
eval "jmp {apiaddr}"
asm fixaddr,$RESULT
add fixaddr,6
eval "{retn}"
asm fixaddr,$RESULT
jmp findff
startiatfix:
mov esp,temesp
mov eip,calladdr
findgo:
esto
mov temaddr,eip
find temaddr,#8B??????????8D6424FCC3#,0b
cmp $RESULT,0
mov retaddr,$RESULT
jnz findexx
find temaddr,#A1????????8D6424FCC3#,0a
cmp $RESULT,0
mov retaddr,$RESULT
jnz fixeax
find temaddr,#8944242?#,4
cmp $RESULT,0
mov retaddr,$RESULT
je findgo
gn eax
cmp $RESULT,0
je findgo
findret:
sti
find eip,#C3#,1
cmp $RESULT,0
mov retaddr,$RESULT
je findret
gn
cmp $RESULT,0
je findret
fixret:
mov apiaddr,
eval "jmp {apiaddr}"
asm fixaddr,$RESULT
add fixaddr,5
mov ,#00909090#
add fixaddr,1
eval "{retn}"
asm fixaddr,$RESULT
jmp findff
findff:
mov fffixtype,
sub fffixtype,calladdr
cmp fffixtype,5
je next
clear:
add calladdr,5
mov ,#90#
sub fixaddr,1
mov ,#90#
jmp next
clearnop:
add calladdr,5
mov ,#90#
jmp next
findexx:
find retaddr,#8B1D#,2
cmp $RESULT,0
jnz fixebx
find retaddr,#8B0D#,2
cmp $RESULT,0
jnz fixecx
find retaddr,#8B15#,2
cmp $RESULT,0
jnz fixedx
find retaddr,#8B25#,2
cmp $RESULT,0
jnz fixesp
find retaddr,#8B2D#,2
cmp $RESULT,0
jnz fixebp
find retaddr,#8B3D#,2
cmp $RESULT,0
jnz fixedi
find retaddr,#8B35#,2
cmp $RESULT,0
jnz fixesi
jmp next
fixeax:
add retaddr,9
bp retaddr
esto
gn eax
cmp $RESULT,0
mov iataddr,eax
je next
eval "mov eax,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp next
fixebx:
add retaddr,a
bp retaddr
esto
gn ebx
cmp $RESULT,0
mov iataddr,ebx
je next
eval "mov ebx,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixecx:
add retaddr,a
bp retaddr
esto
gn ecx
cmp $RESULT,0
mov iataddr,ecx
je next
eval "mov ecx,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixedx:
add retaddr,a
bp retaddr
esto
gn edx
cmp $RESULT,0
mov iataddr,edx
je next
eval "mov edx,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixesp:
add retaddr,a
bp retaddr
esto
gn esp
cmp $RESULT,0
mov iataddr,esp
je next
eval "mov esp,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixebp:
add retaddr,a
bp retaddr
esto
gn ebp
cmp $RESULT,0
mov iataddr,ebp
je next
eval "mov ebp,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixesi:
add retaddr,a
bp retaddr
esto
gn esi
cmp $RESULT,0
mov iataddr,esi
je next
eval "mov esi,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
fixedi:
add retaddr,a
bp retaddr
esto
gn edi
cmp $RESULT,0
mov iataddr,edi
je next
eval "mov edi,{iataddr}"
asm fixaddr,$RESULT
add fixaddr,6
mov ,#009090#
eval "{retn}"
asm fixaddr,$RESULT
jmp clearnop
next:
add calladdr,1
mov eip,calladdr
mov esp,temesp
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
mov esi, 0
mov edi, 0
mov ebp, 0
mov fffixtype,0
mov calladdr,0
jmp findcall
exit:
mov eip,oep
mov esp,temesp
mov edi,temedi
mov esi,temesi
mov ebp,temebp
mov eax,temeax
mov ebx,temebx
mov ecx,temecx
mov edx,temedx
bc
ret
区段修正脚本:var iatbase
var iatend
var ptr
var tmp
var oldaddr
var newaddr
mov iatbase, 00412000
mov oldaddr, 00e30000 //uif修复后的iat rva
mov newaddr, 00608000
mov ptr, iatbase
jmp startfix
next:
add ptr, a
startfix:
find ptr,#ff25??????00c3#
cmp $RESULT,0
je fixmovreg
mov ptr,$RESULT
mov tmp, ptr
add tmp,2
sub , oldaddr
add , newaddr
jmp next
fixmovreg:
mov ptr, iatbase
nextfind:
add ptr, a
fix:
find ptr,#8b????????00c3#
cmp $RESULT,0
je done
mov ptr,$RESULT
mov tmp, ptr
add tmp,2
sub , oldaddr
add , newaddr
jmp nextfind
done:
ret上面的脚本是通过NN的脚本修改的,有的是自己写的,在这里向他们表示感谢!有了他们的牛X的脚本,我们菜鸟们才能学习写出一些简单的脚本!
最后的说明:上面的脚本我测试了可以修复IAT,并且正常情况下是可以修复那一个字节的,但是,运行脚本过程中我却发现最后修复的代码中有很多的字节没有NOP掉,然后我测试了一下,如果从那个CALL调用开始运行脚本直接修复的话是可以修复那个字节的 但是如果直接从OEP开始跑脚本的话,就会有很多的字节没有NOP掉!这个目前没有研究清楚原因,在此不在多说,也希望大牛们能指点一二,能给出更好的处理一个字节问题的解决方法,因为目前的强壳包括NP 包括vmp 还有VP之类的都有这个情况,想处理那个字节 还是有点麻烦,我自己测试的样品最后没有完全修复就是因为有好多个字节没有NOP掉,最后不得已人肉之,但是太费劲了,自己太菜了,没有那么打的精力搞这个了,所以写这篇文章希望我这个小菜抛砖,能引来大牛们的玉!也希望大家能共享你们更好的修复方法。
在此先谢过!
http://u.115.com/file/f5f2239e9e#脚本及样品.rar
http://dl.dbank.com/c0cma9vo49
完全修复后的样品没有测试是否可以跨平台哦
电脑速度慢打开WIN7虚拟机需要太多时间了大家测试一下吧
--------------------------------------------------------------------------------
【经验总结】
1、NP之WS大家都懂得,太费劲了!人肉不值钱,但是太费精力!
2、通过写脚本,自己也学到了一些东西,前前后后修复这个DEMO的加壳样品用了整整一天的时间!汗颜自己的水平太菜啊!
3、自己多动手调试的话,比看什么文章都起作用。
4、感谢那些一直帮助过我的人,我藏在心里,在这里就不再一一点名感谢那些个TV了!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于笨笨鼠, 没啥版权随便转随便看吧,又没技术含量的东西!
2010年12月03日 18:52:26 顶礼膜拜! 晕啊 好东西得好好研究下~~~顶大牛 我看到官网上把授权系统搞下来会奖励100,000:funk:eweqw 感谢分享
支持了 好文彩,学习下楼主大作 精力真旺盛啊。。。 不错的文章 safengine 哈 哎哟不错哦 很久没看到这样的长篇大论了