FlexHex_212
PEID0.94:ASProtect 2.1x SKE -> Alexey Solodovnikov
Version 0.13: ASProtect 2.11 SKE build 03.13 Release [1]
VC6.0
加壳选项:
stolen code
CRC
SDK函数
Stolen code用补区段方法解决
CRC的解决:2个脚本对照跑
SDK函数:写code及修改字符串搞定
入口点:
00401000 Fl> 68 01D09B00 push FlexHEX.009BD001
00401005 E8 01000000 call FlexHEX.0040100B
0040100A C3
retn
0040100B C3
retn
DUMP+REFIX:
Volx脚本:Aspr2.XX_IATfixer_v1.02.osc
运行完毕,Resume两次来到OEP,提示无stolen
oep。
004A0B14 55
push ebp
004A0B15 8BEC
mov ebp,esp
004A0B17 6A FF
push -1
004A0B19 68 08FD5A00 push FlexHEX.005AFD08
004A0B1E 68 E05F4A00 push FlexHEX.004A5FE0
004A0B23 64:A1 00000000
mov eax,dword ptr fs:[0]
LordPE选择进程dump,ImportREC选择进程,填入OEP,自动获取,最后一个Thunk明显不是函数,删除,Level1+Asprotect插件,还有7个无效。先修复dump,存为dumped_.exe。
Microsoft Visual C++ 6.0
Stolen code 1:
OD载入,第一处错误,堆栈:
0012F77C 004AD9B9 返回到 dumped_.004AD9B9 来自 dumped_.004A3EC0
来到:
004A3EC0 - E9 3BC15A01 jmp 01A50000
// 到壳里
载入原程序:
01A50000 8B5424 0C mov
edx,dword ptr ss:[esp+C]
// stolen
01A50004 8B4C24 04 mov
ecx,dword ptr ss:[esp+4]
// stolen
01A50008 85D2
test edx,edx
// stolen
01A5000A E8 F1FF0B00 call 01B10000
// 变形跳转
参考VC6.0程序:Linehy 表达式计算器 1.0.5:
Ctrl+S搜索:
mov edx,dword ptr ss:[esp+C]
mov ecx,dword ptr ss:[esp+4]
test edx,edx
对照参考程序,继续跟踪原程序,从变形跳转进入,来到:
01B200A5 - FF6424 FC jmp
dword ptr ss:[esp-4]
; 01A500FA
跟随:
01A500FA 33C0
xor eax,eax
; stolen
01A500FC 8A4424 08 mov
al,byte ptr ss:[esp+8] ;
stolen
01A50100 57
push edi
; stolen
01A50101 C1CF 99
ror edi,99
01A50104 83CF 95
or edi,FFFFFF95
01A50107 337C24 28 xor
edi,dword ptr ss:[esp+28]
01A5010B F2:
prefix repne:
一模一样,不用再继续跟了,直接拷贝二进制代码:
8B 54 24 0C 8B 4C 24 04 85 D2
74 47 33 C0 8A 44 24 08 57 8B F9 83 FA 04 72 2D F7 D9 83 E1 03 74
08 2B D1 88 07 47 49 75 FA 8B
C8 C1 E0 08 03 C1 8B C8 C1 E0 10 03 C1 8B CA 83 E2 03 C1 E9 02 74
06 F3 AB 85 D2 74 06 88 07 47
4A 75 FA 8B 44 24 08 5F C3
恢复后汇编代码如下:
004A3EC0 8B5424 0C mov
edx,dword ptr ss:[esp+C]
004A3EC4 8B4C24 04 mov
ecx,dword ptr ss:[esp+4]
004A3EC8 85D2
test edx,edx
004A3ECA 74 47
je short dumped_.004A3F13
004A3ECC 33C0
xor eax,eax
004A3ECE 8A4424 08 mov
al,byte ptr ss:[esp+8]
004A3ED2 57
push edi
004A3ED3 8BF9
mov edi,ecx
004A3ED5 83FA 04
cmp edx,4
004A3ED8 72 2D
jb short dumped_.004A3F07
004A3EDA F7D9
neg ecx
004A3EDC 83E1 03
and ecx,3
004A3EDF 74 08
je short dumped_.004A3EE9
004A3EE1 2BD1
sub edx,ecx
004A3EE3 8807
mov byte ptr ds:[edi],al
004A3EE5 47
inc edi
004A3EE6 49
dec ecx
004A3EE7 ^ 75 FA
jnz short dumped_.004A3EE3
004A3EE9 8BC8
mov ecx,eax
004A3EEB C1E0 08
shl eax,8
004A3EEE 03C1
add eax,ecx
004A3EF0 8BC8 mov
ecx,eax
004A3EF2 C1E0 10
shl eax,10
004A3EF5 03C1
add eax,ecx
004A3EF7 8BCA
mov ecx,edx
004A3EF9 83E2 03
and edx,3
004A3EFC C1E9 02
shr ecx,2
004A3EFF 74 06
je short dumped_.004A3F07
004A3F01 F3:AB
rep stos dword ptr es:[edi]
004A3F03 85D2
test edx,edx
004A3F05 74 06
je short dumped_.004A3F0D
004A3F07 8807
mov byte ptr ds:[edi],al
004A3F09 47
inc edi
004A3F0A 4A
dec edx
004A3F0B ^ 75 FA
jnz short dumped_.004A3F07
004A3F0D 8B4424 08 mov
eax,dword ptr ss:[esp+8]
004A3F11 5F
pop edi
004A3F12 C3
retn
004A3F13 8B4424 04 mov
eax,dword ptr ss:[esp+4]
004A3F17 C3
retn
保存为dumped_1.exe。
暗桩-CRC验证?:
载入dumped_1.exe,F9就退出,载入原程序,修复IAT脚本运行后F9也一样退出,但是寻找OEP的脚本不会退出。
好,2个脚本比较跟踪:
Aspr2.XX_IATfixer_v1.02.osc
Asprotect 2.xx SKE OEP finder.txt
层层进入:
004A0BEE E8 F4210A00 call FlexHEX.00542DE7
00542DF7 E8 2ECD0000 call FlexHEX.0054FB2A
0054FB6E FF50 50 call
dword ptr ds:[eax+50]
; FlexHEX.00408D80
再进入后发现在下面的call后跳转不一样:
00408DA9 8BF1
mov esi,ecx
00408DAB E8 10C80400 call dumped_1.004555C0
00408DB0 85C0
test eax,eax
00408DB2 0F84 BA0C0000 je dumped_1.00409A72
; 这里不一样的跳转
呵呵,这里很熟,CRC验证,参考:Web Log Explorer
3.1 Standard Edition
进入00408DAB的call来到不同的地方:
0045562A /0F85 2B000000 jnz FlexHEX.0045565B ;
nop
nop掉就ok了,其实就是得到eax的值=1。
Stolen code 2:
继续往下,又一个不可读的地址,堆栈:
0012DB9C 004AE6B7 返回到 dumped_1.004AE6B7 来自 dumped_1.004AA5D0
跟随到:
004AE6B2 E8 19BFFFFF call dumped_1.004AA5D0
004AA5D0 - E9 2B5A5B01 jmp 01A60000 ; stolen
code
004AE6B7 59
pop ecx
同样参考程序,拷贝二进制:
8B 4C 24 04 F7 C1 03 00 00 00
74 14 8A 01 41 84 C0 74 40 F7 C1 03 00 00 00 75 F1 05 00 00 00 00 8B 01 BA
FF FE FE 7E 03 D0 83 F0 FF 33 C2 83 C1 04 A9 00 01 01 81 74 E8 8B 41 FC 84
C0 74 32 84 E4 74 24 A9 00 00 FF 00 74 13 A9 00 00 00 FF 74 02 EB CD 8D 41
FF 8B 4C 24 04 2B C1 C3 8D 41 FE 8B 4C 24 04 2B C1 C3 8D 41 FD 8B 4C 24 04
2B C1 C3 8D 41 FC 8B 4C 24 04 2B C1 C3
恢复后的代码:
004AA5D0 8B4C24 04 mov ecx,dword
ptr ss:[esp+4]
004AA5D4 F7C1 03000000 test ecx,3
004AA5DA 74 14
je short dumped_1.004AA5F0
004AA5DC 8A01
mov al,byte ptr ds:[ecx]
004AA5DE 41
inc ecx
004AA5DF 84C0
test al,al
004AA5E1 74 40
je short dumped_1.004AA623
004AA5E3 F7C1 03000000 test ecx,3
004AA5E9 ^ 75 F1
jnz short dumped_1.004AA5DC
004AA5EB 05 00000000 add eax,0
004AA5F0 8B01
mov eax,dword ptr ds:[ecx]
004AA5F2 BA FFFEFE7E mov edx,7EFEFEFF
004AA5F7 03D0
add edx,eax
004AA5F9 83F0 FF xor
eax,FFFFFFFF
004AA5FC 33C2
xor eax,edx
004AA5FE 83C1 04 add
ecx,4
004AA601 A9 00010181 test eax,81010100
004AA606 ^ 74 E8
je short dumped_1.004AA5F0
004AA608 8B41 FC mov
eax,dword ptr ds:[ecx-4]
004AA60B 84C0
test al,al
004AA60D 74 32
je short dumped_1.004AA641
004AA60F 84E4
test ah,ah
004AA611 74 24
je short dumped_1.004AA637
004AA613 A9 0000FF00 test eax,0FF0000
004AA618 74 13
je short dumped_1.004AA62D
004AA61A A9 000000FF test eax,FF000000
004AA61F 74 02
je short dumped_1.004AA623
004AA621 ^ EB CD
jmp short dumped_1.004AA5F0
004AA623 8D41 FF lea
eax,dword ptr ds:[ecx-1]
004AA626 8B4C24 04 mov ecx,dword
ptr ss:[esp+4]
004AA62A 2BC1
sub eax,ecx
004AA62C C3
retn
004AA62D 8D41 FE lea
eax,dword ptr ds:[ecx-2]
004AA630 8B4C24 04 mov ecx,dword
ptr ss:[esp+4]
004AA634 2BC1
sub eax,ecx
004AA636 C3
retn
004AA637 8D41 FD lea
eax,dword ptr ds:[ecx-3]
004AA63A 8B4C24 04 mov ecx,dword
ptr ss:[esp+4]
004AA63E 2BC1
sub eax,ecx
004AA640 C3
retn
004AA641 8D41 FC lea
eax,dword ptr ds:[ecx-4]
004AA644 8B4C24 04 mov ecx,dword
ptr ss:[esp+4]
004AA648 2BC1
sub eax,ecx
004AA64A C3
retn
SDK函数:
又异常了,终于到了这7个未修复的函数出场了,堆栈:
0012E558 0040C035 返回到 dumped_1.0040C035 来自 dumped_1.00539C64
跟随到:
0040C02F 51
push
ecx
0040C030 E8 2FDC1200 call dumped_1.00539C64
00539C64 - FF25 88705900 jmp dword ptr ds:[597088]
0040C035 85C0
test eax,eax
0040C037 75 04
jnz short dumped_1.0040C03D
总共7个:
00539C64 - FF25 88705900 jmp dword ptr ds:[597088]
// 第1个
00539C6A - FF25 84705900 jmp dword ptr ds:[597084]
// 第2个
00539C70 - FF25 80705900 jmp dword ptr ds:[597080]
// 第3个
00539C76 - FF25 70705900 jmp dword ptr ds:[597070]
// 第4个
00539C7C - FF25 7C705900 jmp dword ptr ds:[59707C]
// 第5个
00539C82 - FF25 78705900 jmp dword ptr ds:[597078]
// 第6个
00539C88 - FF25 74705900 jmp dword ptr ds:[597074]
// 第7个
估计就是注册标志等函数。
OEP FIND脚本运行到OEP,然后7个函数下断,F9运行观察断点位置,发现只有前面3个函数断下,剩下的估计是About的内容。先解决程序启动用到的3个函数:
00539C64 - FF25 88705900 jmp dword ptr ds:[597088]
// 第1个
00539C6A - FF25 84705900 jmp dword ptr ds:[597084]
// 第2个
00539C70 - FF25 80705900 jmp dword ptr ds:[597080]
// 第3个
先从第1个函数入手:
0040C02F 51
push ecx
0040C030 E8 2FDC1200 call dumped_2.00539C64
00539C64 - FF25 88705900 jmp dword ptr ds:[597088]
堆栈:
0012E54C 0040C035 返回到 FlexHEX.0040C035 来自 FlexHEX.00539C64
0012E550 0012E57C // [esp+4]
0012E554 0012E55C // [esp+8]
0012E558 00000001
0040C035 85C0
test eax,eax
0040C037 75 04
jnz short dumped_2.0040C03D
跟踪发现前3个堆栈结构类似,老办法搞定注册标志。
空地写上注册标志:
00596E80 63 79 74 6F
cyto
空地写上code:
00596D00 8B4424 04 mov
eax,dword ptr ss:[esp+4]
00596D04 C700 806E5900 mov dword ptr ds:[eax],dumped_1.00596E80
; ASCII "cyto"
00596D0A 8B4424 08 mov
eax,dword ptr ss:[esp+8]
00596D0E C700 806E5900 mov dword ptr ds:[eax],dumped_1.00596E80
; ASCII "cyto"
00596D14 B8 01000000 mov eax,1
00596D19 C2 0C00
retn 0C
修改前3个函数的地址:
0059706C 00000000
00597070 01775EF0
// 第4个
00597074 017763CC
// 第7个
00597078 01776068
// 第6个
0059707C 01776208
// 第5个
00597080 00596D00 dumped_1.00596D00 // 第3个
00597084 00596D00 dumped_1.00596D00 // 第2个
00597088 00596D00 dumped_1.00596D00 // 第1个
0059708C 00000000
另存为dumped_2.exe,可以运行了,但是点击About就异常退出。
Activate,用到第6个函数:
还是加载原程序,Find OEP脚本运行,然后下断剩下的jmp函数,点击About,竟然没反应,看来这几个jmp函数应该是注册过后才会断下的。
点击Activate,断在第6个函数:
0040C2CA 51
push ecx
0040C2CB E8 B2D91200 call FlexHEX.00539C82
00539C82 - FF25 78705900 jmp dword ptr ds:[597078]
堆栈:
0012F168 0040C2D0 返回到 FlexHEX.0040C2D0 来自 FlexHEX.00539C82
0012F16C 0012F968 ASCII "87654321"
// 练码
0012F170 0012F864 ASCII "ExtTrial"
0012F174 00000001
0040C2D0 85C0
test eax,eax
; 未注册返回0
0040C2D2 74 0B
je short FlexHEX.0040C2DF
0040C2D4 6A 00
push 0
0040C2D6 6A 40
push 40
0040C2D8 68 F82A5E00 push dumped_2.005E2AF8
; UNICODE "Software has been successfully activated."
写上code:
mov veax,1
retn 0C
这个可以利用上面写的code:
00596D14 B8 01000000 mov eax,1
00596D19 C2 0C00
retn 0C
修改jmp函数地址为:
00597078 00596D14 dumped_2.00596D14 // 第6个
呵呵,又搞定一个函数。
About:
点击About异常,提示01A20000不易读取,估计是stolen
code,堆栈看不出消息来源,只好搜索jmp 01A20000,只有一处:
0040A00C - E9 EF5F6101 jmp 01A20000
试了下,的确点击About在这里断下。
往下还看到几个:
0040A071 - E9 FD5F6101 jmp 01A20073
0040A0A9 - E9 D65F6101 jmp 01A20084
...
看来挺多的,而且乱码一大段,stolen挺多,还是补区段搞定吧。
补区段:
载入原程序,这次用IAT修复的脚本走,修改CRC验证跳转,并写上已经搞定的jmp函数的code,这下就可以启动程序了,而且状态与脱壳后的程序一样。
Alt+M,对可疑区段各个下断,用到的区段如下:
解码:
未知:Route Check?
Stolen code:
删除脱壳修改过代码的dumped_2.exe的IAT区段,然后把这些区段添进去,Rebuild
PE后修复IAT,再解决Route Check:
01778A66 8B40 34 mov
eax,dword ptr ds:[eax+34]
01778A69 FFD0
call eax
01778A6B 2945 0C sub
dword ptr ss:[ebp+C],eax
保存为cyto.exe,可以运行了,About也没问题,发现01B00000的3个区段没用到,可能是上面分析修复的stolen
code 1与stolen code 2(好像不是stolen code,而是Emulate Standard system Functions?),可以删除这些区段,只是还要修复IAT。01A20000的几个区段才是Stolen
code。
解决About的注册标志:
恢复Stolen code是个体力活,为了得到跳转实现与否的所有代码,只好不停的点击About(还好不用重新加载),然后修改跳转获得。
试了下,非常多的代码,而且用到其中的SDK函数:第1个,第4个。
其中第1个函数取出注册信息cyto与内置的字符串比较:
005E2914 4C 69 63 65 6E 73 65 64 Licensed
005E2908 4D 75 6C 74 69 55 73 65 72 MultiUser
如果不一样的话提示Invalid:
第4个函数也取出注册信息与字符串:“100-”比较,如果相等的话就继续与1,3...等几个数值比较
01A20336 3C 31
cmp al,31
01A202DE 3C 33
cmp al,33
不同的数值表示不同的版本。
其实这些已经无关紧要了,只是注册显示问题而已,直接修改Invalid来的更快。
搜索:Invalid
005E281C 49 00 6E 00 76 00 61 00 6C 00 69 00 64
00 00 00 I.n.v.a.l.i.d...
修改为:
005E281C 4C 00 69 00 63 00 65 00 6E 00 73 00 65
00 64 00 L.i.c.e.n.s.e.d.
005E282C 20 00 74 00 6F 00 20 00 63 00 79 00 74
00 6F 00 .t.o. .c.y.t.o.
005E283C 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 ................