能力值:
(RANK:570 )
2 楼
这东西比较适合练耐性还有就是复习一下各种ANTI DEBUG,还有就是测试一下你OD的抗ANTI能力,假如过不了某写ANTI,就得去找插件或者自己动手了。这里涉及的ANTI有时间校验、ISDEBUG标记、检测Drx、检测INT3、ZwQueryInformationProcess、OUTPUTDEBUGSTRING文件自校验和通过CREATEFILE ANTI DUMP,最后是一个压缩壳。
原程序可在下面连接下载:
http://www.pediy.com/tools/PACK/Protectors/MSLRH/MSLRHv0.31a.rar
这里是已脱壳的程序
http://www.nxer.cn/709394/attachment/1163338396_0.rar
由于有大量时间检查,于是便找来ULTRAEDIT把RDTSC直接替换成XOR EAX,EAX了。运行程序发现出错,有自校验,只好细心跟了,跟了大半天,终于到了自校验的位置,由于不是简单的对比加跳转,必须还原改动过的值。只好去论坛找文章看看有没有更好的方法对付RDTSC。查到前辈写的脱这个的文章,知道了DEJUNK插件,学习了一下,写了下面脚本:
ActivePatList1 = _mslrh01
[CODE_mslrh01]
S = 0f31
R = 33c0
后面有2种解码,分别是XOR 11和XOR 15,所以对应3种情况,替换了825处。
看了前辈的文章之后,对一些之前不明白的ANTI也较为清楚了,下面按流程一步一步列出来。
00456AA0 810424 6F130000 add dword ptr ss:[esp],136F
00456AA7 64:FF35 0000000>push dword ptr fs:[0]
00456AAE 64:8925 0000000>mov dword ptr fs:[0],esp
00456AB5 EB 05 jmp short [MSLRH].00456ABC
装了SEH之后便是
0045745C 33C0 xor eax,eax
0045745E 0FB600 movzx eax,byte ptr ds:[eax]
内存访问错误,进入SEH后继续。大量相同规律的花指令,程序没有乱序,方向总是向下,有意义的代码没怎么花,时间校验的cmp eax,0fff也没花。这是第一次跟这个壳的时候总结的经验,所以可以向下寻找没有花的地方,然后在最接近的cmp eax,0fff直接跳过去,这是第一次跟这个程序时总结出来的经验。
004587B6 8B4424 0C mov eax,dword ptr ss:[esp+C]
004587BA 33C9 xor ecx,ecx
004587BC 3348 04 xor ecx,dword ptr ds:[eax+4]
004587BF 3348 08 xor ecx,dword ptr ds:[eax+8]
004587C2 3348 0C xor ecx,dword ptr ds:[eax+C]
004587C5 3348 10 xor ecx,dword ptr ds:[eax+10]
004587C8 8B6424 08 mov esp,dword ptr ss:[esp+8]
004587CC 64:8F05 0000000>pop dword ptr fs:[0]
这里检查dr0到dr3是否为0,没有下硬断,则ecx为0
00459191 51 push ecx
00459192 33C9 xor ecx,ecx
00459194 E8 00000000 call [MSLRH].00459199
00459199 5F pop edi
0045919A 81C7 C4090000 add edi,9C4
004591A0 5A pop edx
004591A1 83C2 15 add edx,15
004591A4 0FB60439 movzx eax,byte ptr ds:[ecx+edi]
004591A8 33C2 xor eax,edx
004591AA 880439 mov byte ptr ds:[ecx+edi],al
004591AD 41 inc ecx
004591AE 81F9 93000000 cmp ecx,93
004591B4 ^ 72 EE jb short [MSLRH].004591A4
004591B6 EB 05 jmp short [MSLRH].004591BD
这段是对00459b5d-00459bf0进行解码(简单的XOR)。假如曾经下过硬断,那么这里的KEY就不对了。正确的是15。解码前要恢复为清除时间校验而覆盖的数据,解码之后再此清除时间校验,后同。
00459B5D 8B5C24 20 mov ebx,dword ptr ss:[esp+20]
00459B61 66:BB 0000 mov bx,0
00459B65 0FB703 movzx eax,word ptr ds:[ebx]
00459B68 2D 4D5A0000 sub eax,5A4D
00459B6D 74 08 je short 复件_[MS.00459B77
00459B6F 81EB 00000100 sub ebx,10000
00459B75 ^ EB EE jmp short 复件_[MS.00459B65
通过在堆栈中返回系统的地址找KERNEL32的基址。Billy Belceb病毒编写教程里有提到过这种方法。现在EBX是KERNEL32的基址
00459B77 8BFB mov edi,ebx
00459B79 037B 3C add edi,dword ptr ds:[ebx+3C]
00459B7C 83C7 78 add edi,78
00459B7F 8B3F mov edi,dword ptr ds:[edi]
00459B81 03FB add edi,ebx
00459B83 57 push edi
EDI输出表地址
00459B84 83C7 20 add edi,20
00459B87 8B3F mov edi,dword ptr ds:[edi]
00459B89 03FB add edi,ebx
00459B8B 33C0 xor eax,eax
00459B8B 33C0 xor eax,eax
00459B8D 40 inc eax
00459B8E 8B0F mov ecx,dword ptr ds:[edi]
00459B90 03CB add ecx,ebx
00459B92 83C7 04 add edi,4
00459B95 8139 47657450 cmp dword ptr ds:[ecx],50746547
00459B9B ^ 75 F0 jnz short 复件_[MS.00459B8D
00459B9D 8179 04 726F634>cmp dword ptr ds:[ecx+4],41636F72
00459BA4 ^ 75 E7 jnz short 复件_[MS.00459B8D
历遍输出表的AddressOfNames,对比头8个字符识别出GetProcAddress
00459BA6 6BC0 02 imul eax,eax,2
00459BA9 5F pop edi
00459BAA 57 push edi
00459BAB 83C7 24 add edi,24
00459BAE 8B3F mov edi,dword ptr ds:[edi]
00459BB0 03FB add edi,ebx
00459BB2 03F8 add edi,eax
00459BB4 66:8B07 mov ax,word ptr ds:[edi]
00459BB7 6BC0 04 imul eax,eax,4
00459BBA 5F pop edi
00459BBB 83C7 1C add edi,1C
00459BBE 8B3F mov edi,dword ptr ds:[edi]
00459BC0 03FB add edi,ebx
00459BC2 03F8 add edi,eax
00459BC4 8B7F FC mov edi,dword ptr ds:[edi-4]
00459BC7 03FB add edi,ebx
00459BC9 803F CC cmp byte ptr ds:[edi],0CC
00459BCC /75 09 jnz short 复件_[MS.00459BD7
取得GetProcAddress在内存中的位置还不忘检查其入口有没有断点。。。
00459BD7 E8 00000000 call 复件_[MS.00459BDC
00459BDC 58 pop eax
00459BDD 2D EC3A0000 sub eax,3AEC
00459BE2 B0 00 mov al,0
00459BE4 05 00200100 add eax,12000
00459BE9 8BF0 mov esi,eax
00459BEB 891E mov dword ptr ds:[esi],ebx
00459BED 897E 10 mov dword ptr ds:[esi+10],edi
将KERNEL32的基址存入EP,GetProcAddress则放在EP+10
00459BF7 5F pop edi
00459BF8 81C7 C4090000 add edi,9C4
00459BFE 0FB60439 movzx eax,byte ptr ds:[ecx+edi]
00459C02 83F0 15 xor eax,15
00459C05 880439 mov byte ptr ds:[ecx+edi],al
00459C08 41 inc ecx
00459C09 81F9 3F0C0000 cmp ecx,0C3F
00459C0F ^ 72 ED jb short [MSLRH].00459BFE
00459C11 EB 05 jmp short [MSLRH].00459C18
对0045a5bb-0045b1fa解码,同样是XOR 15。
0045A5D0 E8 00000000 call 复件_[MS.0045A5D5
0045A5D5 832C24 18 sub dword ptr ss:[esp],18
0045A5D9 FF36 push dword ptr ds:[esi]
0045A5DB FF56 10 call dword ptr ds:[esi+10] ; KERNEL32.GetProcAddress
0012FF98 77E60000 KERNEL32.77E60000
0012FF9C 0045A5BD ASCII "OutputDebugStringA"
指令间穿插字符。。
0045A5DE 8946 14 mov dword ptr ds:[esi+14],eax ; KERNEL32.OutputDebugStringA
存进EP+14的位置。似乎EP要被重写为输入表了
下一个API地址的载入方法对于我来说比较新鲜。
0045A5EB E8 10000000 call 复件_[MS.0045A600
0045A600 FF36 push dword ptr ds:[esi]
0045A602 FF56 10 call dword ptr ds:[esi+10]
0045A605 8946 18 mov dword ptr ds:[esi+18],eax ; KERNEL32.GetCommandLineA
0045A5EB处CALL的返回地址竟然是
0045A5F0 47 65 74 43 6F 6D 6D 61 6E 64 4C 69 6E 65 41 00 GetCommandLineA.
把OD的堆栈参考骗过去了,只提示是返回地址,没有字符参考。不过跟进KERNEL32的领域就能显示字符参考了。而且后面将地址保存的时候也有注释,这个技巧意义不大。后面全是类似的技巧和函数的载入,就忽略了。
0045B1C9 8CC9 mov cx,cs
0045B1CB 32C9 xor cl,cl
0045B1CD 83F9 00 cmp ecx,0
0045B1D0 75 28 jnz short 复件_[MS.0045B1FA
上面的代码似乎是检查操作系统的,就不会有后面PEB的检查了。据说如果是WIN9X就会跳走
0045B1D2 64:FF35 3000000>push dword ptr fs:[30]
0045B1D9 58 pop eax
0045B1DA 0FB648 02 movzx ecx,byte ptr ds:[eax+2]
0045B1DE 884E 0C mov byte ptr ds:[esi+C],cl
将ISDEBUG标记写入0046800C。当然我有插件。
0045B1E1 8B40 0C mov eax,dword ptr ds:[eax+C]
0045B1E4 8B40 0C mov eax,dword ptr ds:[eax+C]
0045B1E7 8D58 20 lea ebx,dword ptr ds:[eax+20]
0045B1EA 8D48 18 lea ecx,dword ptr ds:[eax+18]
0045B1ED 8103 C8000000 add dword ptr ds:[ebx],0C8
0045B1F3 B8 00000000 mov eax,0
0045B1F8 0101 add dword ptr ds:[ecx],eax
0045B1FA 33C9 xor ecx,ecx
0045B1FC E8 00000000 call 复件_[MS.0045B201
改写PEB中程序在内存中的基址和大小信息,大小+0c8,基址+0。有意义?
0045B1FC E8 00000000 call 复件_[MS.0045B201
0045B201 5F pop edi ; 复件_[MS.0045B201
0045B202 81C7 C1090000 add edi,9C1
0045B208 0FB60439 movzx eax,byte ptr ds:[ecx+edi]
0045B20C 83F0 11 xor eax,11
0045B20F 880439 mov byte ptr ds:[ecx+edi],al
0045B212 41 inc ecx
0045B213 81F9 521D0000 cmp ecx,1D52
0045B219 ^ 72 ED jb short 复件_[MS.0045B208
0045B21B EB 05 jmp short 复件_[MS.0045B222
0045bbc2-0045d914解码,这次是XOR 11
0045C56C E8 00000000 call [MSLRH].0045C571
0045C571 810424 CA090000 add dword ptr ss:[esp],9CA
0045C578 64:FF35 0000000>push dword ptr fs:[0]
0045C57F 64:8925 0000000>mov dword ptr fs:[0],esp
0045C586 33DB xor ebx,ebx
0045C588 8B1B mov ebx,dword ptr ds:[ebx]
安装完SEH就立刻产生内存访问错误进入了。
0045D8DF 8B4424 0C mov eax,dword ptr ss:[esp+C]
0045D8E3 33C9 xor ecx,ecx
0045D8E5 3348 04 xor ecx,dword ptr ds:[eax+4]
0045D8E8 3348 08 xor ecx,dword ptr ds:[eax+8]
0045D8EB 3348 0C xor ecx,dword ptr ds:[eax+C]
0045D8EE 3348 10 xor ecx,dword ptr ds:[eax+10]
继续检查DRX
0045DA76 884E 0D mov byte ptr ds:[esi+D],cl
这里将检查结果存在0046800D了。
0045E42A FF56 14 call dword ptr ds:[esi+14] ; KERNEL32.OutputDebugStringA
0045EDD4 FF56 18 call dword ptr ds:[esi+18] ; KERNEL32.GetCommandLineA
0045EDD7 40 inc eax
0045EDD8 33C9 xor ecx,ecx
0045EDDA 41 inc ecx
0045EDDB 803C01 00 cmp byte ptr ds:[ecx+eax],0
0045EDDF 74 0C je short 复件_[MS.0045EDED
0045EDE1 803C01 22 cmp byte ptr ds:[ecx+eax],22
0045EDE5 ^ 75 F3 jnz short 复件_[MS.0045EDDA
0045EDE7 C60401 00 mov byte ptr ds:[ecx+eax],0
0045EDEB ^ EB ED jmp short 复件_[MS.0045EDDA
0045EDED 6A 00 push 0
0045EDEF 6A 00 push 0
0045EDF1 6A 03 push 3
0045EDF3 6A 00 push 0
0045EDF5 6A 00 push 0
0045EDF7 68 00000080 push 80000000
0045EDFC 50 push eax
0045EDFD FF56 1C call dword ptr ds:[esi+1C]
一段计算字符长度未经优化的代码。然后是CREATEFILE打开自己,这样就DUMP不了了。修改EIP直接跳过
0045F7A7 837E 40 00 cmp dword ptr ds:[esi+40],0
0045F7AB 74 24 je short [MSLRH].0045F7D1
0045F7AD FF56 24 call dword ptr ds:[esi+24]
0045F7B0 50 push eax
0045F7B1 6A 00 push 0
0045F7B3 68 00040000 push 400
0045F7B8 FF56 28 call dword ptr ds:[esi+28]
0045F7BB 8BDC mov ebx,esp
0045F7BD 83EB 04 sub ebx,4
0045F7C0 6A 00 push 0
0045F7C2 6A 00 push 0
0045F7C4 6A 04 push 4
0045F7C6 53 push ebx
0045F7C7 6A 07 push 7
0045F7C9 50 push eax
0045F7CA FF56 40 call dword ptr ds:[esi+40]
0045F7CD 58 pop eax
0045F7CE 8846 0E mov byte ptr ds:[esi+E],al
比较ntdll.是ZwQueryInformationProcess否获取成功,获取成功就用该API检查是否被DEBUG,将结果写入0046800E
00460178 8CC9 mov cx,cs
0046017A 32C9 xor cl,cl
0046017C 83F9 00 cmp ecx,0
0046017F 0F84 A1130000 je [MSLRH].00461526
00460185 8B46 38 mov eax,dword ptr ds:[esi+38]
00460188 8078 01 4C cmp byte ptr ds:[eax+1],4C
0046018C 0F85 94130000 jnz [MSLRH].00461526
检查系统,前半部分检查是不是WIN9X,如果是则通过
SetUnhandledExceptionFilter
在KERNEL32中的偏移来确定具体是哪一个系统?我这里是2K,跳走了
00461ED2 58 pop eax ; [MSLRH].00461ED2
00461ED3 2D E2BD0000 sub eax,0BDE2
00461ED8 B0 00 mov al,0
00461EDA 05 00200100 add eax,12000
00461EDF 8BF0 mov esi,eax
00461EE1 807E 0C 00 cmp byte ptr ds:[esi+C],0
00461EE5 74 51 je short [MSLRH].00461F38
00461F38 807E 0D 00 cmp byte ptr ds:[esi+D],0
00461F3C ^ 0F85 AF41FFFF jnz [MSLRH].004560F1
00461F42 74 04 je short [MSLRH].00461F48
00461F44 75 02 jnz short [MSLRH].00461F48
00461F4B 807E 0E 00 cmp byte ptr ds:[esi+E],0
00461F4F ^ 0F85 9C41FFFF jnz [MSLRH].004560F1
00461F55 E8 0A000000 call [MSLRH].00461F64
00461F6C 807E 0F 00 cmp byte ptr ds:[esi+F],0
00461F70 ^ 0F85 7B41FFFF jnz [MSLRH].004560F1
00461F76 50 push eax
00461F77 E8 02000000 call [MSLRH].00461F7E
0046800F不知道是什么的校验值,估计是针对某操作系统的。后面开始自校验了,清除所有断点,还原花指令。
00461F92 59 pop ecx
00461F9D 83E9 05 sub ecx,5
00461FAA 33DB xor ebx,ebx
00461FB6 B8 9CBE0000 mov eax,0BE9C
00461FC5 8BF9 mov edi,ecx ; [MSLRH].00461F8D
00461FD1 2BF8 sub edi,eax
00461FDD 0FB607 movzx eax,byte ptr ds:[edi]
00461FEA 03D8 add ebx,eax
00461FF6 47 inc edi ; [MSLRH].004560F1
00462001 3BF9 cmp edi,ecx ; [MSLRH].00461F8D
0046200D ^\72 CE jb short [MSLRH].00461FDD
计算004560f1到00461f8d的校验和(从花指令入口处到进入自校验之前的代码)
0046200F BF 00704400 mov edi,[MSLRH].00447000
00462014 B9 00BC0000 mov ecx,0BC00
00462023 0FB607 movzx eax,byte ptr ds:[edi]
00462030 02DF add bl,bh
00462032 32DF xor bl,bh
00462034 32C3 xor al,bl
00462040 8807 mov byte ptr ds:[edi],al
0046204C 47 inc edi
00462057 49 dec ecx
00462062 ^\75 B5 jnz short [MSLRH].00462019
对00447000开始大小为BC00的区域解码,KEY就是刚才的校验和。
00462064 E8 00000000 call [MSLRH].00462069
00462069 59 pop ecx
0046206A 2959 16 sub dword ptr ds:[ecx+16],ebx
0046206D 61 popad
0046206E 60 pushad
0046206F BE 00704400 mov esi,[MSLRH].00447000
00462074 8DBE 00A0FBFF lea edi,dword ptr ds:[esi+FFFBA000]
0046207A 57 push edi
0046207B 83CD FF or ebp,FFFFFFFF
0046207E 68 0FDE9F00 push 9FDE0F
00462083 C3 retn
这里的结果仍然跟校验和关联
0046206A 2959 16 sub dword ptr ds:[ecx+16],ebx
之后,最后两条指令便变成
0046207E 68 D0284500 push [MSLRH].004528D0
00462083 C3 retn
跳到下一部分,据前辈的文章说,就是UPX核心了。
004528d8-004529a1是将00447000解压到00401000。
004529e0-00452a1a是填写IAT(在00450fe7获得API名字,将地址填进00415028,就是说没加密)。
用OLLYDUMP下来就完成脱壳了
能力值:
(RANK:570 )
3 楼
同一个壳的不同版本,由于有了前一个版本的经验,这次跟起来很轻松,显然经验是大多数新人所欠缺的,只能将勤补拙了。另外一个问题就是,当你遇到你所不知道的ANTI时,你会怎么办?到论坛请教高手?还是尝试自己弄清楚?我只想说,探索精神很重要。有的时候,象这里的例子,其实完全可以自己解决的。此外通过脱这个壳,有的API的运用,其实可以很巧妙,例如本例子中的SetUnhandledExceptionFilter,无论你怎么BP,都是断不下来的。
源程序下载http://emadicius.rvlcnsecurity.com/programas/MSLRHv0.32a.zip
已脱壳的程序
http://www.nxer.cn/709394/attachment/1163728509_0.rar
用OD加载程序时报错。现在用WINDBG载入OD,bp messageboxa。用OD载入MSLRHv0.32a。断下。
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012c5c8 00454059 00120106 0012c5e0 004bb410 USER32!MessageBoxA
0012cbe4 0045dce7 004bc1ea 063f0050 005bd670 image00400000!Error+0x3d
0012d2d0 0045f7eb 063f0000 76bc1f1c 76bc2075 image00400000!Createlistwindow+0x2af7
00000000 00000000 00000000 00000000 00000000 image00400000!Decoderange+0x180b
在反汇编窗口输入00454059
0045401c 55 push ebp
0045401d 8bec mov ebp,esp
0045401f 81c4fcf9ffff add esp,0FFFFF9FCh
00454025 8d450c lea eax,[ebp+0Ch]
00454028 50 push eax
00454029 8b5508 mov edx,dword ptr [ebp+8]
0045402c 52 push edx
0045402d 8d8dfcf9ffff lea ecx,[ebp-604h]
00454033 51 push ecx
00454034 e81b2c0500 call image00400000!Createpatchwindow+0x79f4 (004a6c54)
00454039 83c40c add esp,0Ch
0045403c 8d85fcf9ffff lea eax,[ebp-604h]
00454042 8b157c3b4d00 mov edx,dword ptr [image00400000!__CPPdebugHook+0x23a54 (004d3b7c)]
00454048 6810200000 push 2010h
0045404d 6810b44b00 push offset image00400000!__CPPdebugHook+0xb2e8 (004bb410)
00454052 50 push eax
00454053 52 push edx
00454054 e8bdb40500 call image00400000!Createpatchwindow+0x102b6 (004af516)
00454059 6a00 push 0 ;MESSAGEBOX的返回地址
0045405b e878dafdff call image00400000!Animate (00431ad8)
00454060 59 pop ecx
00454061 8be5 mov esp,ebp
00454063 5d pop ebp
00454064 c3 ret
在00454064下断,返回OD按确定。
0045dcd1 eb30 jmp image00400000!Createlistwindow+0x2b13 (0045dd03)
0045dcd3 837df402 cmp dword ptr [ebp-0Ch],2
0045dcd7 7513 jne image00400000!Createlistwindow+0x2afc (0045dcec)
0045dcd9 8d4e50 lea ecx,[esi+50h]
0045dcdc 51 push ecx
0045dcdd 68eac14b00 push offset image00400000!__CPPdebugHook+0xc0c2 (004bc1ea)
0045dce2 e83563ffff call image00400000!Error (0045401c)
0045dce7 83c408 add esp,8 ;返回到这里
0045dcea eb17 jmp image00400000!Createlistwindow+0x2b13 (0045dd03)
这里比较EBP-C是否为2,是则弹出错误窗口。
0:000> ? ebp-0c
Evaluate expression: 1233604 = 0012d2c4
重新载入OD,下条件断点
0:000> ba w4 0012d2c4 "r @$t0=poi(0012d2c4);j(@$t0!=2)'g'"
OD载入MSLRHv0.32a。
0045c651 7527 jne image00400000!Createlistwindow+0x148a (0045c67a)
0045c653 0fb79534faffff movzx edx,word ptr [ebp-5CCh]
0045c65a 81c280000000 add edx,80h
0045c660 8b8da0f9ffff mov ecx,dword ptr [ebp-660h]
0045c666 c1e103 shl ecx,3
0045c669 81c1e0000000 add ecx,0E0h
0045c66f 3bd1 cmp edx,ecx
0045c671 7407 je image00400000!Createlistwindow+0x148a (0045c67a)
0045c673 c745f402000000 mov dword ptr [ebp-0Ch],2
0045c67a 837df400 cmp dword ptr [ebp-0Ch],0 ss:0023:0012d2c4=00000002 ;断在这里
0045c67e 7524 jne image00400000!Createlistwindow+0x14b4 (0045c6a4)
这里对比ebp-5CC和ebp-660。一定条件ebp-0Ch=2。
0:000> db ebp-660
0012cc70 ff 00 00 00 00 00 00 00-00 00 00 00 f8 19 05 00 ................
重新载入OD,下条件断点
0:000> ba w4 0012cc70 "r @$t0=poi(0012cc70);j(@$t0!=ff)'g'"
OD载入MSLRHv0.32a。
eax=0012cc14 ebx=004caf4c ecx=00000020 edx=000000e0 esi=01b028a8 edi=0012cc74
eip=004a3547 esp=0012cb90 ebp=0012cb98 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00200212
image00400000!Createpatchwindow+0x42e7:
004a3547 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:0023:0012cc74=00160106 ds:0023:01b028a8=00000000
在内存窗口中输入ESI
01b02908 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........................
01b02920 00 00 00 00 00 00 00 00 2e 65 64 61 74 61 00 00 00 10 04 00 00 10 00 00 .........edata..........
01b02938 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 e0 ........................
01b02950 2e 65 64 61 74 61 00 00 00 d0 00 00 00 20 04 00 00 c8 00 00 00 04 00 00 .edata....... ..........
01b02968 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 c0 00 00 00 00 03 00 00 00 ............@...........
01b02980 00 30 00 00 00 f0 04 00 00 2c 00 00 00 cc 00 00 00 00 00 00 00 00 00 00 .0.......,..............
01b02998 00 00 00 00 40 00 00 c0 00 00 00 00 00 00 00 00 00 50 00 00 00 20 05 00 ....@............P... ..
01b029b0 00 50 00 00 00 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 e0 .P.................. ...
01b029c8 2e 74 65 78 74 00 00 00 00 10 00 00 00 70 05 00 00 00 00 00 00 48 01 00 .text........p.......H..
象PE头。向上移看看,果然
01b02830 50 45 00 00 4c 01 05 00 fe df 9c 42 00 00 00 00 00 00 00 00 e0 00 0f 01 PE..L......B............
01b02848 0b 01 05 0c 00 30 01 00 00 90 00 00 00 10 04 00 00 20 05 00 00 20 05 00 .....0........... ... ..
01b02860 00 f0 04 00 00 00 40 00 00 10 00 00 00 02 00 00 04 00 00 00 04 00 00 00 ......@.................
01b02878 04 00 00 00 00 00 00 00 00 80 05 00 00 10 00 00 00 00 00 00 02 00 00 00 ........................
01b02890 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 00 00 00 00 ff 00 00 00 ........................
01b028a8 00 00 00 00 00 00 00 00 f8 19 05 00 88 01 00 00 00 f0 04 00 f8 29 00 00 .....................)..
既然是PE,用LORDPE打开MSLRHv0.32a。
可选头部大小 00e0
RVA数及大小 FF
点RVA数及大小旁边的减号
可选头部大小 0850
RVA数及大小 FE
再点加
可选头部大小 0858
RVA数及大小 FF
这两项是相关联的,可见OD中EBP-660和EBP-5CC就是这两项了,校验不正确就报错。程序在系统中能正确运行。RVA数及大小错,只影响OD加载。
0045c671 7407 je image00400000!Createlistwindow+0x148a (0045c67a)
为了以后对该ANTI 免疫,将上面的JE改成JMP。
现在可以用OD分析了。该壳跟上一版差不多,又是RDTSC海,不过限制宽了,从FF变成FFFF,最多只能防单步,有等于没有。同样是插入宏的方式加花,方向向下,看到有意义的地方直接下断F9过去就好了。相同的地方就不说了,说说不同的地方,不过不代表不需要处理CreateFile。
00453118 64:FF35 0000000>push dword ptr fs:[0]
0045311F 64:8925 0000000>mov dword ptr fs:[0],esp
00453126 33C0 xor eax,eax
00453128 CD 01 int 1
0045312A 40 inc eax
0045312B 40 inc eax
此处在INT 1后下断就可以了。然后是用CREATEMUTEX建立互斥对象,存在则继续,不存在则新建一个进程,自己退出。修改EIP直接跳到后面就可以了。再来是FindWindow,也查IMPORTRECT窗口,最好也自己动手把窗口标题改了。
SetUnhandledExceptionFilter用得有点诡异。
00455216 8B46 38 mov eax,dword ptr ds:[esi+38] ;[esi+38]=SetUnhandledExceptionFilter
00455219 8B40 0B mov eax,dword ptr ds:[eax+B]
0045521C 8908 mov dword ptr ds:[eax],ecx ;ECX是程序自定义的SEH
我们来看看为什么可以这么用
77E678A7 >/$ 8B4C24 04 mov ecx,dword ptr ss:[esp+4]
77E678AB |. A1 4C04EC77 mov eax,dword ptr ds:[77EC044C]
77E678B0 |. 890D 4C04EC77 mov dword ptr ds:[77EC044C],ecx
77E678B6 \. C2 0400 retn 4
SetUnhandledExceptionFilter入口点+B的地方刚好是4C04EC77。当然也可以+5。
0045549A 33DB xor ebx,ebx
0045549C F7F3 div ebx
除0错误,进入SEH例程,之后便来到最后的自校验了。
该版本跟前一个版本一样,将一些DEBUG的校验放到最后,校验值的存放位置45700c到45700F,处理CREATEMUTEX和CreateFile后,直接在该处下内存断点就能到最后的自校验了,仍然是UPX内核。
能力值:
(RANK:570 )
6 楼
从对记事本加壳到最后把壳脱掉,大概用了一星期,但是实际上在分析代码的时间也就几小时。其他时间都在看相关分析文章,或者对着一大堆代码,就是不想分析。
对于这个经典的壳,我想再也没有象我这么简单的分析了。用ATTACH法找到OEP,然后定位加密的数据表,找出数据结构和解密算法,直接用程序自身的解密算法将数据解密,覆盖被加密的部分。ATTACH法是从看雪的精华集看到的,似乎因为局限性,近年好象没怎么看到文章提到,或者你可以通过这篇文章对其了解一下,假如壳只是简单的解密或者解压程序,例如前两篇脱文那种。这个方法可以秒杀那种壳,当然假如目标程序会隐藏进程或者不会进入消息循环,那么这个方法是无能为力的。
加壳的程序
http://www.pediy.com/tools/PACK/Protectors/PE-Armor/PE-Armor0.74.rar
脱掉的记事本
http://www.nxer.cn/709394/attachment/1163996037_0.rar
在主页下了pe-armor0.74,对记事本加壳。运行一下,等了超过1分钟,记事本的窗口才出来,CPU运行都这么久,绝对适合锻炼耐性的壳。佩服那些跟完整个壳的人。看堆栈中的返回地址,一层一层向上,找到伪OEP(真正的被偷掉了)。
重新加载程序,在伪OEP处下内存写入断点,在程序解码完伪OEP之后,在该位置下断。SHIFT+F9来到这个位置。看堆栈看寄存器
EAX 0006FFE0
ECX 00000101
EDX FFFFFFFF
EBX 7FFDF000
ESP 0006FFB0
EBP 0006FFC0
0006FFB0 0006FFE0 指针到下一个 SEH 记录
0006FFB4 010065D0 SE 句柄
0006FFB8 01001888 notepad.01001888
0006FFBC FFFFFFFF
0006FFC0 0006FFF0
0006FFC4 77E67903 返回到 KERNEL32.77E67903
程序入口点堆栈结尾一般都是C4,储存的是返回系统的地址。一般入口EAX为0,EBP则是XXXXFFF0。现在的堆栈入口是一个SEH,可见包含SEH的装入语句,即
PUSH FS:[0]
mov fs:[0],esp
我们看到EAX=入口堆栈的数据,可知程序是先将FS[0]移入EAX再PUSH的。因此入口点可以修复如下
PUSH EBP
MOV EBP,ESP ;这两句不需要解释了,几乎都有的
PUSH -1 ;-1=FFFFFFFF
PUSH 01001888
PUSH 010065D0
MOV eax,fs:[0]
push eax
mov fs:[0],esp
然后DUMP下来就好了。运行DUMP,发现出错了,看到错误窗口之后点取消就可以调试了。看堆栈的返回地址,找到出问题的地方,输入表被加密了。现在必须跟踪壳处理输入表的过程。重新载入未脱壳的程序,刚才找到输入表的首址为01001000,在该处下内存写入断点。
002B7E98 8907 mov dword ptr ds:[edi],eax ;写入输入表
002B7E9A 5A pop edx ;当前数据位置
002B7E9B 0FB642 FF movzx eax,byte ptr ds:[edx-1]
002B7E9F 03D0 add edx,eax
002B7EA1 42 inc edx ;下一个数据的位置
002B7EA2 83C7 04 add edi,4 ;下一个API
002B7EA5 59 pop ecx ;未处理API数
002B7EA6 49 dec ecx
002B7EA7 ^ 0F85 F7F9FFFF jnz 002B78A4 ;未完就下一个
002B7EAD E9 F4280000 jmp 002BA7A6 ;另外的处理流程
--------这里EDX指向一张表
DWORD RVA,在输入表范围内
BYTE DLL NAME的长度
STRING ASCII字符,DLL NAME
DWORD 需要处理的API数
接下来是一个结构
BYTE 长度,数据指针-1取得其长度,指针+长度+1获得下一数据的指针
DATA 加密了的API NAME
跟踪的过程中注意看其指向的内存位置和读取数据的方法,很容易就知道各常量的长度和用途了。
--------回到正题
002B71E5 8B3A mov edi,dword ptr ds:[edx] ;输入表中该DLL的起始位置
002B71E7 68 00FE98B7 push B798FE00
002B71EC 50 push eax
002B71ED E8 5D000000 call 002B724F ;将代码写到堆栈中并运行
--------堆栈中的代码
0006FF4C 873424 xchg dword ptr ss:[esp],esi
0006FF4F 8B36 mov esi,dword ptr ds:[esi]
0006FF51 81F6 EBFF7108 xor esi,871FFEB
0006FF57 75 19 jnz short 0006FF72
进入堆栈前用的是CALL,如果返回处有INT3,XOR的结果就不为0。
0006FF59 8B7424 50 mov esi,dword ptr ss:[esp+50]
0006FF5D 56 push esi
0006FF5E 8B36 mov esi,dword ptr ds:[esi]
0006FF60 81F6 EBFF7178 xor esi,7871FFEB
0006FF66 75 09 jnz short 0006FF71
这里也是一样ESP+50处是call 002B724F的返回地址,巧妙的ANTI DEBUG。
0006FF68 5E pop esi
0006FF69 83C6 4C add esi,4C ;将刚才对比的地址+4C
0006FF6C 897424 48 mov dword ptr ss:[esp+48],esi
0006FF70 8D7424 58 lea esi,dword ptr ss:[esp+58]
0006FF74 51 push ecx ;垃圾代码
0006FF75 B9 01000000 mov ecx,1 ;垃圾代码
0006FF7A 8136 EBFF7074 xor dword ptr ds:[esi],7470FFEB
0006FF80 83EE FC sub esi,-4 ;垃圾代码
0006FF83 49 dec ecx ;垃圾代码
0006FF84 ^ 75 F4 jnz short 0006FF7A ;垃圾代码
0006FF86 59 pop ecx ;垃圾代码
0006FF87 8D7424 58 lea esi,dword ptr ss:[esp+58] ;垃圾代码
0006FF8B FFD6 call esi
0006FF8D 5E pop esi
0006FF8E F3: prefix rep:
0006FF8F 68 61722B00 push 2B7261 ;被0006FF6C处指令改写
0006FF94 C2 5000 retn 50
进入CALL之后发现还是垃圾。call 002B724F其实就相当于一个短跳转,转向当前位置+4C+5。看来看后面,居然是将EAX还原和释放堆栈。晕!将002B71E7处的代码直接修改为JMP 002B7336,后面就不说类似的代码修复过程了, 直接给出有意义的代码。
---------代码总结如下:
002B71E5 8B3A mov edi,dword ptr ds:[edx] ;输入表中该DLL的起始位置
002B7336 0BFF or edi,edi
002B7338 75 05 jnz short 002B733F
002B733A E9 6C340000 jmp 002BA7AB
似乎EDI=0即为IAT处理完毕。
002B733F 03BD 36F44000 add edi,dword ptr ss:[ebp+40F436]
RVA+IMG BASE,写入输入表的位置。
002B7494 83C2 05 add edx,5
002B74C4 8BF2 mov esi,edx
002B74C6 56 push esi ;API的第一个参数(这里是DLLNAME)
002B74C7 8D85 0A624000 lea eax,dword ptr ss:[ebp+40620A]
002B74FA 50 push eax ;返回地址
002B74FB 8B85 2AF44000 mov eax,dword ptr ss:[ebp+40F42A]
002C0072 6A 00 push 0 ;没搞懂
002C0074 50 push eax ;调用API的地址(GETMODULEHANDLEA)
002C0075 8B85 1AFD4000 mov eax,dword ptr ss:[ebp+40FD1A]
002C007B 68 00FE2FC7 push C72FFE00
002C0080 50 push eax ; 缓冲区域
002C0081 E8 5D000000 call 002C00E3
该处实际就是使用GETMODULEHANDLEA取得KERNEL32的基址
---------说明
此后程序将会把API入口点的代码移到缓冲区域,先在缓冲区域运行API入口点的代码,然后再直接跳进API的区域。所以在API入口下断是不行的。此后直接在返回地址下断就可以了。
---------继续分析~~
002B7508 0BC0 or eax,eax ;判断是否获取成功
002B750A 75 1E jnz short 002B752A
0006FF90 0FB64E FF movzx ecx,byte ptr ds:[esi-1]
0006FF94 01CE add esi,ecx
0006FF96 89F2 mov edx,esi
0006FF99 FFC2 inc edx
0006FF9B 8B0A mov ecx,dword ptr ds:[edx]
0006FF9D 81E1 00000080 and ecx,80000000
堆栈运行中有这样一段代码,取DLLNAME前面的一个BYTE并与DLLNAME的地址相加后再加1,得到下一个数据的首址。
002B7746 8BF0 mov esi,eax
002B7748 0BC9 or ecx,ecx
002B774A 0F85 62070000 jnz 002B7EB2
此处校验ECX高位是否为80。API数怎么可能占DWORD这么大空间呢。对比EDX指向的表(注意给出的每个DLL数据段的最后4个字节,该处就是ECX读取的地方)。
002C137F D4 12
002C138F 00 00 0C 43 4F 4D 44 4C 47 33 32 2E 44 4C 4C 00 ...COMDLG32.DLL.
002C139F 09 00 00 00 ....
002C141F 94
002C142F 11 00 00 0B 53 48 45 4C 4C 33 32 2E 44 4C 4C 00 ..SHELL32.DLL.
002C143F 04 00 00 00 ...
002C146F 44 11
002C147F 00 00 0A 4D 53 56 43 52 54 2E 44 4C 4C 00 13 00 ...MSVCRT.DLL..
002C148F 00 00 ..
002C155F 00 10 00 00 0C ...
002C156F 41 44 56 41 50 49 33 32 2E 44 4C 4C 00 07 00 00 ADVAPI32.DLL...
002C157F 00 .
002C15DF 80
002C15EF 10 00 00 0C 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C ...KERNEL32.DLL
002C15FF 00 30 00 00 80 .0..?
002C18AF 20 10 00 00 09 47 44 49 33 32 2E 44 ...GDI32.D
002C18BF 4C 4C 00 17 00 00 00 LL....
002C19EF A8 11 00 00 0A 55 ..U
002C19FF 53 45 52 33 32 2E 44 4C 4C 00 46 00 00 80 SER32.DLL.F..?
002C1E2F C4 12 00 00 0C 57 49 4E 53 50 ...WINSP
002C1E3F 4F 4F 4C 2E 44 52 56 00 03 00 00 00 OOL.DRV....
只有KERNEL32.DLL和USER32.DLL所在的表有80,在输入表中的RVA分别为1080和11A8,对比之前DUMP出的程序的IAT。
01001070 <>10 17 F4 77 F7 29 F6 77 02 59 F4 77 00 00 00 00 赭?鲼Y赭....
01001080 00 10 02 01 20 10 02 01 40 10 02 01 60 10 02 01 . @`
010011A0 <>4E 7E 56 77 00 00 00 00 00 20 02 01 20 20 02 01 N~Vw.....
010011B0 40 20 02 01 60 20 02 01 80 20 02 01 A0 20 02 01 @ ` ??
刚好是那些位置被加密了。看来80是API是否被加密的标记,继续跟下去看看它是如何解密的。
002B7EB2 8B0A mov ecx,dword ptr ds:[edx]
002B7EB4 81E1 FFFFFF7F and ecx,7FFFFFFF ;获取需要解密的API数
002B7EBA 51 push ecx
002B7EBB 52 push edx
002B800B C1E1 05 shl ecx,5
002B800E 6A 04 push 4
002B8010 68 00100000 push 1000
002B8015 51 push ecx
002B8016 6A 00 push 0
002B8018 8D85 2D6D4000 lea eax,dword ptr ss:[ebp+406D2D]
002B801E 50 push eax ;此为返回地址
002B801F 8B85 32F44000 mov eax,dword ptr ss:[ebp+40F432]
002C0072 6A 00 push 0
002C0074 50 push eax
002C0075 8B85 1AFD4000 mov eax,dword ptr ss:[ebp+40FD1A]
002C007B 68 00FE2FC7 push C72FFE00
002C0080 50 push eax
002C0081 E8 5D000000 call 002C00E3
此处准备调用VirtualAlloc申请空间了。关于call 002C00E3,前面已经解释过了,在返回地址处下断就可以了。
002B802B 8985 82F44000 mov dword ptr ss:[ebp+40F482],eax
保存申请到的空间地址。
002B8197 8907 mov dword ptr ds:[edi],eax
002B8199 83C0 20 add eax,20
002B819C 83C7 04 add edi,4
002B819F 49 dec ecx
002B81A0 0BC9 or ecx,ecx
002B81A2 ^ 75 F3 jnz short 002B8197
002B81A4 59 pop ecx
这里直接从输入表填入加密后的地址,看来输入表解密在后面
002B81D2 58 pop eax
002B81D3 8BF8 mov edi,eax
002B81D5 57 push edi
002B81D6 51 push ecx
002B81D7 E9 8B040000 jmp 002B8667
将加密后的地址传入EDI,准备解密了。
002B81DC 8D47 1C lea eax,dword ptr ds:[edi+1C]
002B820C 66:C707 FF35 mov word ptr ds:[edi],35FF
写入PUSH DWORD PTR DS:[0]指令。
002B8360 C747 06 8134240>mov dword ptr ds:[edi+6],243481
XOR DWORD PTR SS:[ESP],0的形式。
002B84B6 8947 02 mov dword ptr ds:[edi+2],eax
把前面的指令改写为PUSH DWORD PTR DS:[75001c]。
002B84E6 C647 0D C3 mov byte ptr ds:[edi+D],0C3
写入RETN
002B865F 8947 09 mov dword ptr ds:[edi+9],eax
该处经过一些复杂的运算,用RDTSC随机生成一个密钥。
--------总结
输入表中加密的地址为20H对齐,750000处的代码为
00750000 FF35 1C007500 push dword ptr ds:[75001C]
00750006 813424 5BDE27CD xor dword ptr ss:[esp],CD27DE5B
0075000D C3 retn
75001C处保存加密过的数据。
--------回到正题
002B8662 5A pop edx
002B8663 83C7 20 add edi,20
002B8666 49 dec ecx
002B8667 0BC9 or ecx,ecx
002B8669 ^ 0F85 6DFBFFFF jnz 002B81DC
这里判断是否需要处理下一个加密数据地址,直接在后面下断跳出循环
002B866F 59 pop ecx
002B8670 5F pop edi
002B8671 83C2 04 add edx,4
002B8674 51 push ecx
002B8675 0FB602 movzx eax,byte ptr ds:[edx]
002B8678 0BC0 or eax,eax
002B867A 0F85 B4090000 jnz 002B9034
进入下一个循环,先跟一次看看是干什么的
002B9034 42 inc edx
002B9035 52 push edx
002B9036 60 pushad
002B9037 68 FF559EB6 push B69E55FF
002B903C 8BF2 mov esi,edx
002B903E 68 3E3F8F00 push 8F3F3E
002B9043 8DBD FCF94000 lea edi,dword ptr ss:[ebp+40F9FC]
002B9049 68 00FE98C7 push C798FE00
002B904E 50 push eax
002B904F E8 5D000000 call 002B90B1
002B9043处取解密API的缓存区
002B91A4 0FB64E FF movzx ecx,byte ptr ds:[esi-1] ;取字符长度
0006FF68 50 push eax
0006FF69 AC lods byte ptr ds:[esi]
0006FF6A 34 79 xor al,79
0006FF6C 2C 55 sub al,55
0006FF6E C0C0 03 rol al,3
0006FF71 F6D0 not al
0006FF73 AA stos byte ptr es:[edi]
0006FF74 31C0 xor eax,eax
0006FF76 49 dec ecx
0006FF77 ^ 75 F0 jnz short 0006FF69
0006FF79 AA stos byte ptr es:[edi]
0006FF7A 58 pop eax
在堆栈中解密数据,得到的是一个API NAME。到这里,EBX指向的那个表所有常量的结构和用法都很清楚了。我直接写了代码还原表中的加密的API NAME,然后用直接用GetProcAddress取地址,按顺序排成一张表,再手动覆盖原来被加密的IAT,最后用IMPORTRECT修复就OK了。
002B7E97 60 pushad
002B7E98 8BEC mov ebp,esp
002B7E9A BE EE152C00 mov esi,2C15EE
此处把表的入口传给ESI,手动修改。反正只有两个表被加密。
002B7E9F 8B3E mov edi,dword ptr ds:[esi]
002B7EA1 83C6 05 add esi,5
002B7EA4 56 push esi
002B7EA5 B8 DB56E777 mov eax,KERNEL32.GetModuleHandleA
002B7EAA FFD0 call eax
002B7EAC 50 push eax
002B7EAD 0FB646 FF movzx eax,byte ptr ds:[esi-1]
002B7EB1 03F0 add esi,eax
002B7EB3 46 inc esi
002B7EB4 0FB60E movzx ecx,byte ptr ds:[esi]
002B7EB7 83C6 04 add esi,4
002B7EBA 51 push ecx
002B7EBB 0FB60E movzx ecx,byte ptr ds:[esi]
002B7EBE 46 inc esi
002B7EBF 57 push edi
002B7EC0 AC lods byte ptr ds:[esi]
002B7EC1 34 79 xor al,79
002B7EC3 2C 55 sub al,55
002B7EC5 C0C0 03 rol al,3
002B7EC8 F6D0 not al
002B7ECA AA stos byte ptr es:[edi]
002B7ECB 33C0 xor eax,eax
002B7ECD 49 dec ecx
002B7ECE ^ 75 F0 jnz short 002B7EC0
002B7ED0 AA stos byte ptr es:[edi]
002B7ED7 8B0C24 mov ecx,dword ptr ss:[esp]
002B7EDA 51 push ecx
002B7EDB 8B45 FC mov eax,dword ptr ss:[ebp-4]
002B7EDE 50 push eax
002B7EDF B8 4B56E777 mov eax,KERNEL32.GetProcAddress
002B7EE4 FFD0 call eax
002B7EE6 85C0 test eax,eax
002B7EE8 74 10 je short 002B7EFA
此处跳转需要说明一下,有时解密后的API NAME的后面会包含多余字符,所以当获取API地址失败时便把最后一个字节填00
002B7EEA 5F pop edi
002B7EEB 8907 mov dword ptr ds:[edi],eax
002B7EED 83C7 04 add edi,4
002B7EF0 46 inc esi
002B7EF1 59 pop ecx
002B7EF2 49 dec ecx
002B7EF3 ^ 75 C5 jnz short 002B7EBA
002B7EF5 61 popad
002B7EF6 CC int3
002B7EFA 4F dec edi
002B7EFB 4F dec edi
002B7EFC AA stos byte ptr es:[edi]
002B7EFD ^ EB D8 jmp short 002B7ED7
看关于这个壳的分析文章时,有提及关于特殊代码加密的问题。虽然我没有使用这个功能加壳,还在学习中,不想搞得太复杂,不过在上述的表中的末尾,有这样一个表
002C0AFD 00 58 44 4C 4C 2E 44 4C 4C 00 46 75 DLL.DLL.Fu
002C0B0D 6E 63 32 46 75 6E 63 00 54 65 73 74 44 65 62 75 nc2Func.TestDebu
002C0B1D 67 00 45 6E 43 72 79 70 74 00 44 65 43 72 79 70 g.EnCrypt.DeCryp
002C0B2D 74 00 43 52 43 00 54 65 73 74 42 6D 70 00 43 72 t.CRC.TestBmp.Cr
002C0B3D 65 61 74 65 44 69 61 6C 6F 67 50 61 72 61 6D 41 eateDialogParamA
002C0B4D 00 44 69 61 6C 6F 67 42 6F 78 50 61 72 61 6D 41 .DialogBoxParamA
002C0B5D 00 45 78 69 74 50 72 6F 63 65 73 73 00 46 72 65 .ExitProcess.Fre
002C0B6D 65 52 65 73 6F 75 72 63 65 00 47 65 74 50 72 6F eResource.GetProcAddress
002C0B7D 63 41 64 64 72 65 73 73 00 47 65 74 56 65 72 73 cAddress.GetVers
002C0B8D 69 6F 6E 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E ion.GetModuleHan
002C0B9D 64 6C 65 41 00 47 65 74 43 75 72 72 65 6E 74 50 dleA.GetCurrentP
002C0BAD 72 6F 63 65 73 73 00 47 65 74 43 75 72 72 65 6E rocess.GetCurren
002C0BBD 74 50 72 6F 63 65 73 73 49 64 00 47 65 74 43 6F tProcessId.GetCo
002C0BCD 6D 6D 61 6E 64 4C 69 6E 65 41 00 4C 6F 61 64 4C mmandLineA.LoadL
002C0BDD 69 62 72 61 72 79 41 00 4C 6F 63 6B 52 65 73 6F ibraryA.LockReso
002C0BED 75 72 63 65 00 53 65 6E 64 4D 65 73 73 61 67 65 urce.SendMessage
002C0BFD 41 00 73 65 6E 64 00 72 65 63 76 00 00 A.send.recv..
程序在解密API NAME之后再对比是否上述表中的API,似乎对比成功之后就特别照顾。我这么修复IAT,似乎也能解决特定API加密。