DotFix NiceProtect 2.x-3.x (Max Protection) 脱壳分析
标 题: 【原创】DotFix NiceProtect 2.x-3.x (Max Protection) 脱壳分析作 者: KuNgBiM
时 间: 2008-01-03,10:13
链 接: http://bbs.pediy.com/showthread.php?t=57604
【文章标题】DotFix NiceProtect 2.x-3.x (Max Protection) 脱壳分析
【文章作者】KuNgBiM/
【作者邮箱】kungbim@163.com
【脱壳目标】MetaTrader 4 Client Terminal 主程序
【下载地址】http://www.metaquotes.net/files/mt4setup.exe
【程序简介】国外的一款外汇交易软件
【加壳方式】DotFix NiceProtect 2.x - 3.x
【保护选项】Max Protection
【使用工具】OllyICE,LordPE,ImportREC
【脱壳平台】三元钱一张的非正版WinXPsp2
【作者声明】只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【脱壳内容】
OllyICE载入目标程序,忽略所有异常。
00BD20CC > /E9 FF000000jmp terminal.00BD21D0; EP
00BD20D1 |60 pushad
00BD20D2 |8B7424 24mov esi,dword ptr ss:
00BD20D6 |8B7C24 28mov edi,dword ptr ss:
00BD20DA |FC cld
00BD20DB |B2 80mov dl,80
00BD20DD |33DB xor ebx,ebx
00BD20DF |A4 movsb
00BD20E0 |B3 02mov bl,2
00BD20E2 |E8 6D000000call terminal.00BD2154
00BD20E7^|73 F6jnb short terminal.00BD20DF
00BD20E9 |33C9 xor ecx,ecx
00BD20EB |E8 64000000call terminal.00BD2154
00BD20F0 |73 1Cjnb short terminal.00BD210E
00BD20F2 |33C0 xor eax,eax
00BD20F4 |E8 5B000000call terminal.00BD2154
00BD20F9 |73 23jnb short terminal.00BD211E
00BD20FB |B3 02mov bl,2
00BD20FD |41 inc ecx
00BD20FE |B0 10mov al,10
【避开调试器检测及代码解压缩】(虽然现在很多修改版的OD都能跑,不过既然是脱壳,那么就一定要避开它检测!)
命令窗:bp FindWindowA
Shift+F9 运行:
——————————— 过时的调试器检测办法 ——————————————
0012FBB8 00BACA18 /CALL 到 FindWindowA 来自 terminal.00BACA16
0012FBBC 00BAC9CA |Class = "OLLYDBG"
0012FBC0 00BAC986 指向下一个 SEH 记录的指针
0012FBC4 00BAC02E SE处理程序
0012FBC8 00BAB317 返回到 terminal.00BAB317 来自 terminal.00BABCDC
0012FBCC 00BAAC9B 返回到 terminal.00BAAC9B 来自 terminal.00BAB30B
0012FBD0 00BAA2FF 返回到 terminal.00BAA2FF 来自 terminal.00BAA96F
0012FBD4 7C9237BF 返回到 ntdll.7C9237BF
————————————————————————————————————
77D2E591 >8BFF mov edi,edi; 中断后取消函数断点
77D2E59355 push ebp
77D2E5948BEC mov ebp,esp
77D2E59633C0 xor eax,eax
77D2E59850 push eax
77D2E599FF75 0Cpush dword ptr ss:
77D2E59CFF75 08push dword ptr ss:
77D2E59F50 push eax
77D2E5A050 push eax
77D2E5A1E8 4CFFFFFFcall USER32.77D2E4F2
77D2E5A65D pop ebp
77D2E5A7C2 0800retn 8 ; 在此F2下断
命令窗:bc FindWindowA
Shift+F9 继续运行,中断后取消断点:
00BACA1885C0 test eax,eax ; 返回到这里,继续F7
00BACA1A75 05jnz short terminal.00BACA21
00BACA1CE8 70060000call terminal.00BAD091
00BACA21E8 0B000000call terminal.00BACA31
00BACA263036 xor byte ptr ds:,dh
00BACA282037 and byte ptr ds:,dh
00BACA2A76 77jbe short terminal.00BACAA3
00BACA2C6B21 29imul esp,dword ptr ds:,29
00BACA2F2900 sub dword ptr ds:,eax
00BACA31EB 01jmp short terminal.00BACA34
00BACA33- E9 5AEB01EAjmp EABCB592
00BACA3852 push edx
00BACA394A dec edx
00BACA3AEB 01jmp short terminal.00BACA3D
5次F7:
00BAD0A1 /EB 01jmp short terminal.00BAD0A4; 注意观察ESP变化,使用ESP定律中断2次即可
00BAD0A3 |EB 5Ajmp short terminal.00BAD0FF
00BAD0A5EB 01jmp short terminal.00BAD0A8
00BAD0A7EA 524AEB06 72DD jmp far DD72:06EB4A52
00BAD0AE^ 73 E5jnb short terminal.00BAD095
00BAD0B01F pop ds
00BAD0B1A8 EBtest al,0EB
00BAD0B301EA add edx,ebp
00BAD0B5B9 0A000000mov ecx,0A
00BAD0BAEB 03jmp short terminal.00BAD0BF
00BAD0BC1838 sbb byte ptr ds:,bh
00BAD0BEDEEB fsubp st(3),st
00BAD0C001EA add edx,ebp
命令窗:hr esp
Shift+F9中断后:
00BAD0A5 /EB 01jmp short terminal.00BAD0A8; 第1次中断,继续
00BAD0A7 |EA 524AEB06 72DD jmp far DD72:06EB4A52
00BAD0AE^ 73 E5jnb short terminal.00BAD095
00BAD0B01F pop ds
00BAD0B1A8 EBtest al,0EB
00BAD0B301EA add edx,ebp
00BAD0B5B9 0A000000mov ecx,0A
00BAD0BAEB 03jmp short terminal.00BAD0BF
00BAD0A94A dec edx; 第2次中断后来到这里
00BAD0AAEB 06jmp short terminal.00BAD0B2
00BAD0AC^ 72 DDjb short terminal.00BAD08B
00BAD0AE^ 73 E5jnb short terminal.00BAD095
00BAD0B01F pop ds
00BAD0B1A8 EBtest al,0EB
00BAD0B301EA add edx,ebp
00BAD0B5B9 0A000000mov ecx,0A
00BAD0BAEB 03jmp short terminal.00BAD0BF
00BAD0BC1838 sbb byte ptr ds:,bh
00BAD0BEDEEB fsubp st(3),st
00BAD0C001EA add edx,ebp
取消所有断点,Alt+M打开内存镜像,在PE header段设置访问断点,Shift+F9运行中断后,再次在CODE区段设置访问断点,Shift+F9运行后即可到达程序内部,当然这时的IAT也是没加密的了。
00541DBF33DB xor ebx,ebx; 程序内部
00541DC13BC3 cmp eax,ebx
00541DC38906 mov dword ptr ds:,eax
00541DC574 62je short terminal.00541E29
00541DC757 push edi
00541DC88B3D 08C25500mov edi,dword ptr ds:; kernel32.GetProcAddress
00541DCE68 88985800push terminal.00589888 ; ASCII "OpenThemeData"
00541DD350 push eax
00541DD4FFD7 call edi
00541DD68946 04mov dword ptr ds:,eax
00541DD98B06 mov eax,dword ptr ds:
00541DDB68 78985800push terminal.00589878 ; ASCII "CloseThemeData"
00541DE050 push eax
00541DE1FFD7 call edi
00541DE38B0E mov ecx,dword ptr ds:
00541DE568 64985800push terminal.00589864 ; ASCII "DrawThemeBackground"
00541DEA51 push ecx
00541DEB8946 08mov dword ptr ds:,eax
00541DEEFFD7 call edi
00541DF08B16 mov edx,dword ptr ds:
00541DF268 48985800push terminal.00589848 ; ASCII "DrawThemeParentBackground"
00541DF752 push edx
【以上步骤我们完全可以用脚本来完成】
代码:
/*
Script written by KuNgBiM
Script: DotFix NiceProtect 辅助脚本
Debugging options: Tick all items in OllyDbg's Debugging Options-Exceptions
Test Environment : OllyDbg 1.10, ODBGScript 1.65, WinXP
*/
#log
var tmp
// 相当于“bp FindWindowA”不过插件不能直接支持这样的下断命令
gpa "FindWindowA","user32.dll"
cmp $RESULT,0
je error
// 寻找“retn 8”特征准备返回
find $RESULT,#C20800#
cmp $RESULT,0
je error
bp $RESULT
esto
bc eip
// 按5次F7
sti
sti
sti
sti
sti
// ESP定律(两次)
mov tmp,esp
bphws tmp,"r"
esto
esto
bphwc tmp
msg "请用Alt+M打开内存镜像,在PE header段设置访问断点,Shift+F9运行中断后,再次在CODE区段设置访问断点,Shift+F9运行后即可到达程序内部,当然这时的IAT也是没加密的了。"
msg "提示: 修补StolenCode及VM code由你自己去完成! ^_^"
ret
error:
msg "脚本错误!"
ret
【修补StolenCode】
查看程序函数可知程序是Visual C++ 6.0(MFC)编译,所以我们可以搜索特征代码来完成OEP查找:
Ctrl+S:
A1 ?? ?? ?? 00 89 45 94 8D 45 94 50 FF 35 ?? ?? ?? 00 8D 45 9C 50 8D 45 90 50 8D 45 A0 50
找到:
0055B6D2DE16 ficom word ptr ds:; 这里开始StolenCode(OEP)
0055B6D42E:59pop ecx
0055B6D6^ 70 91jo short terminal.0055B669
0055B6D869DB 89A25FC4imul ebx,ebx,C45FA289
0055B6DEB1 C4mov cl,0C4
0055B6E068 9AA3D7BApush BAD7A39A
0055B6E546 inc esi
0055B6E6F3:prefix rep:
0055B6E72B33 sub esi,dword ptr ds:
0055B6E9C6 ???; 未知命令
0055B6EAF4 hlt
0055B6EBD952 27fst dword ptr ds:
0055B6EED959 85fstp dword ptr ds:
0055B6F1AE scasb
0055B6F21B51 ABsbb edx,dword ptr ds:
0055B6F557 push edi
0055B6F61AACD1 8007EB40sbb ch,byte ptr ds:
0055B6FDE5 01in eax,1
0055B6FFC0BA CF7DD900 89 sar byte ptr ds:,89
0055B706^ EB FAjmp short terminal.0055B702
0055B70897 xchg eax,edi
0055B70914 98adc al,98
0055B70B50 push eax
0055B70CCC int3
0055B70D1C CFsbb al,0CF
0055B70F01F5 add ebp,esi
0055B7112A4406 FBsub al,byte ptr ds:
0055B7151AB2 3D16CFC2sbb dh,byte ptr ds:
0055B71BB9 D6272F5Emov ecx,5E2F27D6
0055B7206B2A 28imul ebp,dword ptr ds:,28
0055B723AA stosb
0055B7241D 86F5D51Dsbb eax,1DD5F586
0055B72940 inc eax
0055B72ADE1E ficomp word ptr ds:
0055B72C80A3 495D897D 22 and byte ptr ds:,22
0055B733DC27 fsub qword ptr ds:
0055B7358B80 6CBE3285mov eax,dword ptr ds:
0055B73BB2 2Bmov dl,2B
0055B73D^ 70 85jo short terminal.0055B6C4
0055B73FC2 0212retn 1202
0055B7426BF0 1Aimul esi,eax,1A
0055B74526:61popad
0055B74775 0Cjnz short terminal.0055B755; 这里以上的代码都被StolenCode了
0055B74968 54B85500push terminal.0055B854
0055B74EFF15 B4CC5500call dword ptr ds: ; msvcrt.__setusermatherr
0055B75459 pop ecx
0055B755E8 E8000000call terminal.0055B842
0055B75A68 94905700push terminal.00579094
0055B75F68 90905700push terminal.00579090
0055B764E8 D3000000call terminal.0055B83C ; jmp 到 msvcrt._initterm
0055B769A1 7C975900mov eax,dword ptr ds:; 找到这里,然后向上看
0055B76E8945 94mov dword ptr ss:,eax
0055B7718D45 94lea eax,dword ptr ss:
0055B77450 push eax
0055B775FF35 78975900push dword ptr ds:
0055B77B8D45 9Clea eax,dword ptr ss:
0055B77E50 push eax
0055B77F8D45 90lea eax,dword ptr ss:
0055B78250 push eax
0055B7838D45 A0lea eax,dword ptr ss:
0055B78650 push eax
0055B787FF15 C0CC5500call dword ptr ds: ; msvcrt.__getmainargs
现在我们必须修复StolenCode,程序才能正常运行。
随便找一个由Visual C++ 6.0(MFC)编译的程序作为补代码对照程序,我这里所使用的是程序目录内自带的另一个程序MetaEditor.exe。
从0055B732开始,到0055B7B3填充以下的对照代码:
55 8B EC 6A FF 68 80 73 45 00 68 AC BF 44 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 68 53 56 57 89 65 E8 33 DB 89 5D FC 6A 02 FF 15 D4 DB 44 00 59 83 0D 30 27 46 00 FF 83 0D 34 27 46 00 FF FF 15 D8 DB 44 00 8B 0D 14 27 46 00 89 08 FF 15 DC DB 44 00 8B 0D 10 27 46 00 89 08 A1 E0 DB 44 00 8B 00 A3 2C 27 46 00 E8 16 01 00 00 39 1D 60 17 46 00
填充完毕后,建立新EIP:
0055B6D255 push ebp ; 在此处建立新EIP
0055B6D38BEC mov ebp,esp
0055B6D56A FFpush -1
0055B6D768 80734500push terminal.00457380 ; ① push 00575F40
0055B6DC68 ACBF4400push terminal.0044BFAC ; ② push 0055B858
0055B6E164:A1 00000000 mov eax,dword ptr fs:
0055B6E750 push eax
0055B6E864:8925 00000000 mov dword ptr fs:,esp
0055B6EF83EC 68sub esp,68
0055B6F253 push ebx
0055B6F356 push esi
0055B6F457 push edi
0055B6F58965 E8mov dword ptr ss:,esp
0055B6F833DB xor ebx,ebx
0055B6FA895D FCmov dword ptr ss:,ebx
0055B6FD6A 02push 2
0055B6FFFF15 D4DB4400call dword ptr ds: ; ③call dword ptr ds:
0055B70559 pop ecx
0055B706830D 30274600 FF or dword ptr ds:,FFFFFFFF; ④or dword ptr ds:,FFFFFFFF
0055B70D830D 34274600 FF or dword ptr ds:,FFFFFFFF; ⑤or dword ptr ds:,FFFFFFFF
0055B714FF15 D8DB4400call dword ptr ds: ; ⑥call dword ptr ds:
0055B71A8B0D 14274600mov ecx,dword ptr ds:; ⑦mov ecx,dword ptr ds:
0055B7208908 mov dword ptr ds:,ecx
0055B722FF15 DCDB4400call dword ptr ds: ; ⑧call dword ptr ds:
0055B7288B0D 10274600mov ecx,dword ptr ds:; ⑨mov ecx,dword ptr ds:
0055B72E8908 mov dword ptr ds:,ecx
0055B730A1 E0DB4400mov eax,dword ptr ds:; ⑩mov eax,dword ptr ds:
0055B7358B00 mov eax,dword ptr ds:
0055B737A3 2C274600mov dword ptr ds:,eax; ⑾mov dword ptr ds:,eax
0055B73CE8 16010000call terminal.0055B857 ; ⑿call 0055B857
0055B741391D 60174600cmp dword ptr ds:,ebx; ⒀cmp dword ptr ds:,ebx
0055B74775 0Cjnz short terminal.0055B755
0055B74968 54B85500push terminal.0055B854
0055B74EFF15 B4CC5500call dword ptr ds: ; msvcrt.__setusermatherr
0055B75459 pop ecx
0055B755E8 E8000000call terminal.0055B842
0055B75A68 94905700push terminal.00579094 ; 【⑤】暴露
0055B75F68 90905700push terminal.00579090 ; 【④】暴露
0055B764E8 D3000000call terminal.0055B83C ; jmp 到 msvcrt._initterm
0055B769A1 7C975900mov eax,dword ptr ds:
0055B76E8945 94mov dword ptr ss:,eax
0055B7718D45 94lea eax,dword ptr ss:
0055B77450 push eax
0055B775FF35 78975900push dword ptr ds:
0055B77B8D45 9Clea eax,dword ptr ss:
0055B77E50 push eax
0055B77F8D45 90lea eax,dword ptr ss:
0055B78250 push eax
0055B7838D45 A0lea eax,dword ptr ss:
0055B78650 push eax
0055B787FF15 C0CC5500call dword ptr ds: ; msvcrt.__getmainargs
0055B78D68 8C905700push terminal.0057908C
0055B79268 00905700push terminal.00579000
0055B797E8 A0000000call terminal.0055B83C ; jmp 到 msvcrt._initterm
0055B79C83C4 24add esp,24
0055B79FA1 C4CC5500mov eax,dword ptr ds:
0055B7A48B30 mov esi,dword ptr ds:
0055B7A68975 8Cmov dword ptr ss:,esi
0055B7A9803E 22cmp byte ptr ds:,22
0055B7AC75 3Ajnz short terminal.0055B7E8
0055B7AE46 inc esi
0055B7AF8975 8Cmov dword ptr ss:,esi
0055B7B28A06 mov al,byte ptr ds:
0055B7B43AC3 cmp al,bl
0055B7B674 04je short terminal.0055B7BC
0055B7B83C 22cmp al,22
0055B7BA^ 75 F2jnz short terminal.0055B7AE
0055B7BC803E 22cmp byte ptr ds:,22
0055B7BF75 04jnz short terminal.0055B7C5
0055B7C146 inc esi
0055B7C28975 8Cmov dword ptr ss:,esi
0055B7C58A06 mov al,byte ptr ds:
0055B7C73AC3 cmp al,bl
0055B7C974 04je short terminal.0055B7CF
0055B7CB3C 20cmp al,20
0055B7CD^ 76 F2jbe short terminal.0055B7C1
0055B7CF895D D0mov dword ptr ss:,ebx
0055B7D28D45 A4lea eax,dword ptr ss:
0055B7D550 push eax
0055B7D6FF15 70C25500call dword ptr ds: ; kernel32.GetStartupInfoA
0055B7DCF645 D0 01 test byte ptr ss:,1
0055B7E074 11je short terminal.0055B7F3
0055B7E20FB745 D4movzx eax,word ptr ss:
0055B7E6EB 0Ejmp short terminal.0055B7F6
0055B7E8803E 20cmp byte ptr ds:,20
0055B7EB^ 76 D8jbe short terminal.0055B7C5
0055B7ED46 inc esi
0055B7EE8975 8Cmov dword ptr ss:,esi
0055B7F1^ EB F5jmp short terminal.0055B7E8
0055B7F36A 0Apush 0A
0055B7F558 pop eax
0055B7F650 push eax
0055B7F756 push esi
0055B7F853 push ebx
0055B7F953 push ebx
0055B7FAFF15 BCC15500call dword ptr ds: ; kernel32.GetModuleHandleA
0055B80050 push eax
0055B801E8 6D010000call terminal.0055B973
0055B8068945 98mov dword ptr ss:,eax
0055B80950 push eax
0055B80AFF15 C8CC5500call dword ptr ds: ; msvcrt.exit
0055B8108B45 ECmov eax,dword ptr ss:; 【①】暴露
0055B8138B08 mov ecx,dword ptr ds:
0055B8158B09 mov ecx,dword ptr ds:
0055B817894D 88mov dword ptr ss:,ecx
0055B81A50 push eax
0055B81B51 push ecx
0055B81CE8 15000000call terminal.0055B836 ; jmp 到 msvcrt._XcptFilter
0055B82159 pop ecx
0055B82259 pop ecx
0055B823C3 retn
下面修复说明请见上面的程序标注。
①
在对照程序 MetaEditor.exe 中所调用的地址为:
00457380FFFFFFFF
004573840044BF64MetaEdit.0044BF64
004573880044BF78MetaEdit.0044BF78
FF FF FF FF 64 BF 44 00
那么我们这个程序所调用的地址应该为:0055B810
数据窗口中搜索Ctrl+S:
FF FF FF FF 10 B8 55 00
找到:
00575F40FFFFFFFF
00575F440055B810terminal.0055B810
00575F480055B824terminal.0055B824
①为:push 00575F40
②③⑥⑧⑩
没什么难度,直接找到该函数即可:
MSVCRT._except_handler3 ;②
msvcrt.__set_app_type);③
msvcrt.__p__fmode ;⑥
msvcrt.__p__commode ;⑧
msvcrt._adjust_fdiv ;⑩
②为:push 0055B858
③为:call dword ptr ds:
⑥为:call dword ptr ds:
⑧为:call dword ptr ds:
⑩为:mov eax,dword ptr ds:
分析对照程序 MetaEditor.exe 中发现④⑤的内存地址与【④】【⑤】的内存地址对应:
④为:or dword ptr ds:,FFFFFFFF
⑤为:or dword ptr ds:,FFFFFFFF
⑦=⑤-0x20=00599774
⑦为:mov ecx,dword ptr ds:
⑨=④-0x20=00599770
⑨为:mov ecx,dword ptr ds:
⑾=④-0x4=0059978C
⑾为:mov dword ptr ds:,eax
⑿:
分析对照程序 MetaEditor.exe 中发现:
0044BFA833C0 xor eax,eax
0044BFAAC3 retn
0044BFABC3 retn ; 调用此处
0044BFAC- FF25 D0DB4400jmp dword ptr ds:[<&MSVCRT._except_handler3>]; msvcrt._except_handler3
0044BFB2- FF25 ECDC4400jmp dword ptr ds:[<&MSVCRT._controlfp>]; msvcrt._controlfp
那么该程序就应该调用:
0055B85433C0 xor eax,eax
0055B856C3 retn
0055B857C3 retn ; 调用此处
0055B858- FF25 DCCC5500jmp dword ptr ds:[<&msvcrt._except_handler3>]; msvcrt._except_handler3
0055B85E- FF25 68CD5500jmp dword ptr ds:[<&msvcrt._controlfp>]; msvcrt._controlfp
⑿为:call 0055B857
⒀:
数据窗口中搜索Ctrl+S:(找到最后一组)
00 00 00 00 01 00 00 00 00 00 00 00
⒀为:
cmp dword ptr ds:,ebx
【修补代码汇总(二进制)】
55 8B EC 6A FF 68 40 5F 57 00 68 58 B8 55 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 68 53 56 57 89 65 E8 33 DB 89 5D FC 6A 02 FF 15 B8 CC 55 00 59 83 0D 90 97 59 00 FF 83 0D 94 97 59 00 FF FF 15 A8 CC 55 00 8B 0D 74 97 59 00 89 08 FF 15 AC CC 55 00 8B 0D 70 97 59 00 89 08 A1 B0 CC 55 00 8B 00 A3 8C 97 59 00 E8 16 01 00 00 39 1D 88 97 59 00
【抓取及修复】
以上的StolenCode已经全部修补完毕,所以这时我们可以直接用LordPE抓取,ImportREC修复即可。
OEP=0015B6D2
RVA=0015C000
SIZE=000010B4
脱壳后的程序运行正常!脱壳完毕!
【VM code 处理】
此部分还未弄懂,暂时略过。o(∩_∩)o
【加密选项总结】
代码:
该程序所使用到的保护选项有:
Rename sections to: .data
Compress resources
Optimize an rebuild exe file
Use scrambling
Protect original entry point
Encrypt code section
Convert stolen byte to VM
Use anti-tracing protection
Use anti-debug protection
Stolen Bytes Protection
--------------------------------------------------------------------------------
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
页:
[1]