1, 首先把od调试异常都钩掉,Od 载入 断在:
006530D4 > /EB 01 jmp 006530D7h
两次F7 到:
006530D8 E8 00000000 call 006530DDh
记住Esp=0012FFA4, 把这个值纪录下来,为了以后对esp下DWORD硬件访问断点到达oep。
由于是双进程壳,就有两种执行流程,父进程执行流程和子进程执行流程,父进程创建并调试子进程,接受子进程调试事件,控制子进程的运行,两种执行流程,必然有个分界点,这里是CreateMutexA,壳对CreateMutexA入口有断点检测,所以在CreateMutexA+0x51下断,这里下硬件断:
7C80EA2D C2 0C00 retn 000Ch //下硬件断点
返回到达:
00656DD6 8985 C66C4000 mov dword ptr [ebp+00406CC6h] , eax
00656DDC 8D85 3A271F03 lea eax , dword ptr [ebp+031F273Ah]
00656DE2 2D FCCEDE02 sub eax , 02DECEFCh
00656DE7 FF10 call dword ptr [eax]
00656DE9 BB CA7DB9FE mov ebx , FEB97DCAh //这里改eax=B7,
使程序按照子进程的流程运行
继续单步到:
00656E3D F1 int1 //产生异常,正常运行的话父进程接受这个异常,并通过GetContextThread 和SetContextThread 改变eip,进而改变子进程的流程,这里改eip= 0x00656E5C
然后运行断在:
0065364A F3:AE scasb //异常,这里不处理
8次Shift+F9忽略8个异常,运行到:
00657766 87DF xchg edi , ebx //这里处理异常,和int1 异常一样,改eip,这里 eip= 00657791
00657791 C3 ret
2,下面开始看他怎么处理IAT 表
00653F44 8B3B mov edi , dword ptr [ebx] 开始
00653F46 03BD 1E424000 add edi , dword ptr [ebp+0040421Eh]
00653F4C 803F 44 cmp byte ptr [edi] , 44h
。。。
。。。
。。。
00653F7A 3D 88BF46CF cmp eax , CF46BF88h //比较hash值
00653F7F 75 20 jne 00653FA1h
00653F81 8B85 1A424000 mov eax , dword ptr [ebp+0040421Ah] //等于处理
00653F87 D1E1 shl ecx , 1
00653F89 03C1 add eax , ecx
00653F8B 0FB700 movzx eax , word ptr [eax]
00653F8E C1E0 02 shl eax , 02h
00653F91 0385 26424000 add eax , dword ptr [ebp+00404226h]
00653F97 8B00 mov eax , dword ptr [eax]
00653F99 0385 1E424000 add eax , dword ptr [ebp+0040421Eh] //得到API地址,EAX 7C831EDD kernel32.DeleteFileA
00653F4到00653F7A是取出API 字符串名字,并运算得到一个函数值,然后比较是不是IAT表里的API,是的话到:
00653D67 8B18 mov ebx , dword ptr [eax]
这里可以看到开始取DeleteFileA 入口内容,并开始做变形处理存放到
00DF0000 /EB 01 jmp 00DF0003h
00653E23 F3:A4 movsb
这里下断,断几次,会看到00DF0000 里发生变化:
00DF0000 /EB 01 jmp 00DF0003h
00DF0003 8BFF mov edi , edi
00DF0005 55 push ebp
00DF0006 8BEC mov ebp , esp
00DF0008 FF75 08 push dword ptr [ebp+08h]
00DF000B EB 07 jmp 00DF0014h
00DF0014 ^\EB F8 jmp 00DF000Eh
00DF000E - E9 D21EA47B jmp 7C831EE5h //跳到DeleteFileA+8
在来到这里:
0065418A 8907 mov dword ptr [edi] , eax 写壳的IAT
0065418C EB 02 jmp 00654190h
这里edi=00657E1F,eax=DF00000
[esp-3C]-[esp-38]= DeleteFileA
这里可以打补丁修复IAT,我申请的内存地址:E20000
二进制代码:
8B 44 24 C4 2B 44 24 C8 89 07 E9 81 41 83 FF
00E20000 8B4424 C4 mov eax , dword ptr [esp-3Ch]
00E20004 2B4424 C8 sub eax , dword ptr [esp-38h]
00E20008 8907 mov dword ptr [edi] , eax
00E2000A - E9 814183FF jmp 00654190h
00E2000F 90 nop
0065418A修改为:
0065418A - E9 71BE7C00 jmp 00E20000h
0065418F 90 nop
这时把开始记录的 esp=0012FFA4,对0012FFA4下DWORD硬件访问断点,然后运行,直奔stolen OEP:
00654CB5 F7D2 not edx ; ntdll.KiFastSystemCallRet
00654CB7 39C2 cmp edx , eax
00654CB9 F7C0 74E7F921 test eax , 21F9E774h
00654CBF 0FACC2 48 shrd edx , eax , 00000048h
00654CC3 0FBDC8 bsr ecx , eax
00654CC6 C7C2 2431C7CD mov edx , CDC73124h
00654CCC 85C0 test eax , eax
00654CCE 0FBAEA 31 bts edx , 31h
00654CD2 F7D2 not edx
00654CD4 F7C1 25C4A65C test ecx , 5CA6C425h
00654CDA 3BD0 cmp edx , eax
3,修复Stolen Code:
首先修复Stolen OEP,观察栈
00654CDF 55 push ebp //1
00654CE0 EB 01 jmp 00654CE3h
。。。
00654CE3 8BEC mov ebp , esp //2
00654CE5 EB 01 jmp 00654CE8h
。。。
00654CE8 6A FF push FFh //3
。。。
00654CED 68 683FA8D9 push D9A83F68h
00654CF2 810424 009CB326 add dword ptr [esp] , 26B39C00h //4 push 005BDB68
00654CF9 68 97AB43E7 push E743AB97h
00654CFE 810424 8181FE18 add dword ptr [esp] , 18FE8181h //5 push 00422D18
00654D05 64:A1 00000000 mov eax , dword ptr fs:[00000000h] //6
00654D0E 50 push eax //7
00654D12 64:8925 0000000>mov dword ptr fs:[00000000h] , esp //8
00654D19 EB 01 jmp 00654D1Ch
。。。
00654D1C 83C4 A4 add esp , A4h //9
。。。
00654D22 53 push ebx //10
00654D23 EB 01 jmp 00654D26h
。。。
00654D26 56 push esi
00654D27 EB 01 jmp 00654D2Ah //11
。。。
00654D2A 57 push edi //12
00654D2B EB 01 jmp 00654D2Eh
。。。
00654D2E 8965 E8 mov dword ptr [ebp-18h] , esp //13
00654D31 EB 01 jmp 00654D34h
。。。
00654D34 FF15 21816500 call dword ptr [00658121h] ;kernel32.GetVersion //14
。。。
00654D3D A3 A4A75E00 mov dword ptr [005EA7A4h] , eax //15
00654D42 EB 01 jmp 00654D45h
。。。
00654D45 A1 A4A75E00 mov eax , dword ptr [005EA7A4h] //16
00654D4A EB 01 jmp 00654D4Dh
。。。
00654D4D C1E8 08 shr eax , 08h //17
00654D50 EB 01 jmp 00654D53h
。。。
00654D53 25 FF000000 and eax , 000000FFh //18
00654D58 EB 01 jmp 00654D5Bh
。。。
00654D5B A3 B0A75E00 mov dword ptr [005EA7B0h] , eax //18
00654D60 EB 01 jmp 00654D63h
。。。
00654D63 8B0D A4A75E00 mov ecx , dword ptr [005EA7A4h] //19
00654D69 EB 01 jmp 00654D6Ch
。。。
00654D6C 81E1 FF000000 and ecx , 000000FFh //20
00654D72 EB 01 jmp 00654D75h
00654D75 - E9 D58FDCFF jmp 0041DD4Fh //跳到程序代码段
在0041DD00到0041DD4F 不上上面代码:
二进制代码:
55 8B EC 6A FF 68 68 DB 5B 00 68 18 2D 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 C4 A4
53 56 57 89 65 E8 FF 15 21 81 65 00 A3 A4 A7 5E 00 A1 A4 A7 5E 00 C1 E8 08 25 FF 00 00 00 A3 B0
A7 5E 00 8B 0D A4 A7 5E 00 81 E1 FF 00 00 00
修复后的oep:
0041DD00 55 push ebp
0041DD01 8BEC mov ebp , esp
0041DD03 6A FF push FFh
0041DD05 68 68DB5B00 push 005BDB68h
0041DD0A 68 182D4200 push 00422D18h
0041DD0F 64:A1 00000000 mov eax , dword ptr fs:[00000000h]
0041DD15 50 push eax
0041DD16 64:8925 0000000>mov dword ptr fs:[00000000h] , esp
0041DD1D 83C4 A4 add esp , A4h
0041DD20 53 push ebx
0041DD21 56 push esi
0041DD22 57 push edi
0041DD23 8965 E8 mov dword ptr [ebp-18h] , esp
0041DD26 FF15 21816500 call dword ptr [00658121h] ; kernel32.GetVersion
0041DD2C A3 A4A75E00 mov dword ptr [005EA7A4h] , eax
0041DD31 A1 A4A75E00 mov eax , dword ptr [005EA7A4h]
0041DD36 C1E8 08 shr eax , 08h
0041DD39 25 FF000000 and eax , 000000FFh
0041DD3E A3 B0A75E00 mov dword ptr [005EA7B0h] , eax
0041DD43 8B0D A4A75E00 mov ecx , dword ptr [005EA7A4h]
0041DD49 81E1 FF000000 and ecx , 000000FFh
0041DD4F 890D ACA75E00 mov dword ptr [005EA7ACh] , ecx
4,修复IAT,这里我用Universal Import Fixer (UIF) v1.2
New IAT VA:5EE0000
5,修复代码重定向
肉眼观察有3种:
1种
0041DD7C 6A 01 push 01h
0041DD7E E8 5D24FEFF call 004001E0h
004001E0 - E9 CB8A0200 jmp 00428CB0h
把call 004001E0h 改成call 00428CB0h
2种
0041DE73 - E9 BC23FEFF jmp 00400234h
0041DE78 90 nop
0041DE79 90 nop
00400234 833D 9CA75E00 0>cmp dword ptr [005EA79Ch] , 01h
0040023B - E9 3ADC0100 jmp 0041DE7Ah
把call 0041DE73 改成cmp dword ptr [005EA79Ch] , 01h
3种
00401B89 FF15 558C6500 call dword ptr [00658C55h]
//这里是对00401B93 后面的代码 解码
00401B8F DF67 D8 fbld [edi-28h]
00401B92 46 inc esi
00401B93 B7 1E mov bh , 1Eh
00401B95 4C dec esp
00401B96 56 push esi
00401B97 0102 add dword ptr [edx] , eax
。。。。。
00401BF8 FF15 798C6500 call dword ptr [00658C79h]
//这里运行后在对00401B93后面的代码 加密
00401BFE 3F aas
00401BFF 25 2C218D85 and eax , 858D212Ch
00401C04 FC cld
00401C05 FEFF ??? ; Unknown command
00401C06 FFFF5F ??? ; Unknown command
00401C07 FF5F 5E call far fword ptr [edi+5Eh]
00401C0A 5B pop ebx
00401C0B 81C4 58030000 add esp , 00000358h
00401C11 3BEC cmp ebp , esp
00401C13 E8 B8B90100 call 0041D5D0h
00401C18 8BE5 mov esp , ebp
00401C1A 5D pop ebp
00401C1B C3 ret
前面 1,2种有规律可循,可以直接脚本修复,这里用PeSpin_Code_Redirection_Fix.txt 就可以修复,不过脚本不完善,还得手工修复几处
第3种,手动,运行解密代码后,nop 掉解密代码,和 加密代码,还有之间的 没用的垃圾,
这里我添上我修复的二进制代码,有三处:
00401B83:
89 85 EC FC FF FF 90 90 90 90 90 90 90 90 90 90 C7 85 E8 FC FF FF 00 00 00 00 8B 8D E8 FC FF FF
3B 8D EC FC FF FF 7D 4D 8B 95 E8 FC FF FF 0F BE 84 15 FC FE FF FF 83 E0 06 8B 8D E8 FC FF FF 88
84 0D FC FE FF FF 8B 95 E8 FC FF FF 0F BE 84 15 FC FE FF FF 83 F0 1E 8B 8D E8 FC FF FF 88 84 0D
FC FE FF FF 8B 95 E8 FC FF FF 83 C2 01 89 95 E8 FC FF FF EB A5 90 90 90 90 90 90 90 90 90 90 8D
85 FC FE FF FF 5F 5E 5B 81 C4 58 03 00 00 3B EC E8 B8 B9 01 00 8B E5 5D C3
00401CA6:
90 90 90 90 90 90 90 90 90 90 C7 45 FC 00 00 00 00 EB 09 8B 45 FC 83 C0 01 89 45 FC 8B 4D 08 03
4D FC 0F BE 11 85 D2 74 20 8B 45 08 03 45 FC 0F BE 08 89 4D F8 8B 55 F8 83 C2 36 89 55 F8 8B 45
F8 03 45 F4 89 45 F4 EB CA 90 90 90 90 90 90 90 90 90 90 8B 45 F4 5F 5E 5B 83 C4 4C 3B EC E8 C7
B8 01 00 8B E5 5D C3
401973:
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 8B 85 D8 FE FF FF 3B 85 DC FE FF FF 75 16 6A 00 68 E8 42 5B 00 68 B0 42 5B 00
8B 4D F0 E8 97 F6 07 00 EB 14 6A 00 68 E8 42 5B 00 68 8C 42 5B 00 8B 4D F0 E8 81 F6 07 00
6,Dump文件,并修复IAT
工具LordPE + ImportREC
7,手动修复壳的双进程保护
正常载入od,在WaitForDebugEvent下硬件执行断点,返回到:
00657043 0BC0 or eax , eax
00657045 0F84 1D060000 je 00657668h
0065704B 8B85 346D4000 mov eax , dword ptr [ebp+00406D34h]
00657051 35 C19B54D3 xor eax , D3549BC1h
00657056 3D C29B54D3 cmp eax , D3549BC2h
0065705B 0F84 DB050000 je 0065763Ch
00657061 3D C09B54D3 cmp eax , D3549BC0h
00657066 74 50 je 006570B8h
00657068 3D C49B54D3 cmp eax , D3549BC4h
0065706D 0F84 F5050000 je 00657668h
00657073 3D C39B54D3 cmp eax , D3549BC3h
00657078 0F84 3A050000 je 006575B8h
0065707E 3D C59B54D3 cmp eax , D3549BC5h
00657083 0F84 70050000 je 006575F9h
观察ebx= 006569E2 的值:
006569E2 03 00 00 00 C0 09 00 00 10 0F 00 00 58 00 00 00 ...?.. ..X...
006569F2 3C 00 00 00 40 00 00 00 00 00 40 00 00 00 00 00 <...@.....@.....
00656A02 00 00 00 00 00 F0 FD 7F D4 30 65 00 00 00 00 00 .....瘕?e.....
00656A12 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............
[Ebx+C] ExceptionCode 异常代码 这里我们要看ExceptionCode = 0xC000001D
[Ebx+28] ExceptionAddress就是子进程异常发生的地址
一路跟过来到:
00657B8A 68 486A6500 push 00656A48h
00657B8F FFB5 9A6C4000 push dword ptr [ebp+00406C9Ah]
00657B95 8D85 34480E39 lea eax , dword ptr [ebp+390E4834h]
00657B9B 2D F1EFCD38 sub eax , 38CDEFF1h
00657BA0 FF10 call dword ptr [eax] //GetThreadContext
得到调试线程上下环境
。。。
在来到这里
0065735C C647 08 00 mov byte ptr [edi+08h] , 00h ; //edi=ExceptionAddress的数字字符串
00657360 8D85 5E241F13 lea eax , dword ptr [ebp+131F245Eh]
00657366 2D 0ECADE12 sub eax , 12DECA0Eh
0065736B FFD0 call eax
接着对edi=ExceptionAddress的数字字符串进行hash运算,来到这里:
00655746 33FF xor edi , edi
00655748 EB 07 jmp 00655751h
edx = hash 值
然后查表:
006573EA BF 898C6500 mov edi , 00658C89h //表的首地址
006573EF B9 B48A0000 mov ecx , 00008AB4h
006573F4 E8 03000000 call 006573FCh
。。。。。
00657405 3B07 cmp eax , dword ptr [edi]
00657407 74 26 je 0065742Fh //循环比较hash值,等于就跳
00657409 83C7 0B add edi , 0Bh //这里得到结构大小是B
0065740C EB 07 jmp 00657415h
0065740E FA cli
0065740F EB 01 jmp 00657412h
00657411 FFEB jmp far ebx ; Illegal use of register
00657413 04 E3 add al , E3h
00657415 ^ EB F8 jmp 0065740Fh
00657417 6983 E90B0BC9 7>imul eax , dword ptr [ebx-36F4F417h] , 858DD577h
00657421 4B dec ebx
00657422 D01E rcr byte ptr [esi] , 1
00657424 132D 705CDE12 adc ebp , dword ptr [12DE5C70h]
0065742A FFE0 jmp eax
0065742C 0FFFDE ??? ; Unknown command
0065742D FFDE call far esi ; Illegal use of register
0065742F BE 5BE71EFF mov esi , FF1EE75Bh
00657434 81EE 137DB9FE sub esi , FEB97D13h
0065743A 8D85 221380E1 lea eax , dword ptr [ebp-1E7FECDEh]
00657440 2D 1B983FE1 sub eax , E13F981Bh
00657445 FFD0 call eax //edi=查找到的地址,开始解释执行
。。。。。
006577C7 0FB647 08 movzx eax , byte ptr [edi+08h] //操作码1,转到相应的函数
006577CB 8D9D D5CA1F02 lea ebx , dword ptr [ebp+021FCAD5h]
006577D1 81EB EE4FDF01 sub ebx , 01DF4FEEh
006577D7 8B0483 mov eax , dword ptr [ebx+eax*4]
006577DA 2D 6FD45CE3 sub eax , E35CD46Fh
006577DF 03C5 add eax , ebp
006577E1 E8 03000000 call 006577E9h
。。。
006577F2 /FFE0 jmp eax //跳到相应的函数
006577F4 |8B4424 26 mov eax , dword ptr [esp+26h]
006577F8 |85C0 test eax , eax
006577FA |5B pop ebx
006577FB |5A pop edx
006577FC |C9 leave
。。。。
006579A9 BB 819C54D3 mov ebx , D3549C81h
006579AE 81EB C19B54D3 sub ebx , D3549BC1h
006579B4 8B1433 mov edx , dword ptr [ebx+esi] //得到子进程的efl
006579B7 8B47 04 mov eax , dword ptr [edi+04h] //操作数
006579BA 0FB65F 09 movzx ebx , byte ptr [edi+09h] //操作码2
006579BE 83FB 05 cmp ebx , 05h
006579C1 74 02 je 006579C5h
006579C3 F7D2 not edx
006579C5 83E2 01 and edx , 01h
006579C8 4A dec edx
006579C9 0F85 4E010000 jne 00657B1Dh
006579CF 807F 0A 02 cmp byte ptr [edi+0Ah] , 02h //指令长度
006579D3 74 0A je 006579DFh
006579D5 0FBAE0 1F bt eax , 1Fh
006579D9 73 2A jnc 00657A05h
006579DB F7D8 neg eax
006579DD EB 0D jmp 006579ECh
006579DF 0FBAE0 07 bt eax , 07h
006579E3 73 20 jnc 00657A05h
006579E5 F7D8 neg eax
006579E7 25 FF000000 and eax , 000000FFh
006579EC BB F79E0000 mov ebx , 00009EF7h
006579F1 81EB 3F9E0000 sub ebx , 00009E3Fh
006579F7 0FB657 0A movzx edx , byte ptr [edi+0Ah] //计算跳转的地址
006579FB 2BC2 sub eax , edx
006579FD 290433 sub dword ptr [ebx+esi] , eax //修改子进程eip
00657A00 E9 2E010000 jmp 00657B33h
00657A05 BB B6D30000 mov ebx , 0000D3B6h
00657A0A 81EB FED20000 sub ebx , 0000D2FEh
00657A10 0FB657 0A movzx edx , byte ptr [edi+0Ah] //计算跳转的地址
00657A14 03C2 add eax , edx
00657A16 010433 add dword ptr [ebx+esi] , eax //修改子进程eip
00657A19 E9 15010000 jmp 00657B33h
。。。
最后通过SetContextThread 改变子进程线程上下环境,来运行子进程
以上分析,可以得到表的结构:
struct Pepsin
{
异常发生地址的hash值 // 4个字节
操作数 //4个字节
操作码1 //1个字节
操作码2 //1个字节
指令长度 //1个字节
};
只要知道操作码1、操作码2和操作数,所代表汇编代码,遍历表00658C89,就能修复 8dc0 异常了!
8,最后运行程序,看看是否还有需要修复的代码,对照着修改!
Ok,总算搞捏!
附上两个脚本:
一个双进程处理脚本.txt脚本 直接跑到:
0065418A 8907 mov dword ptr [edi] , eax
一个PeSpin_Code_Redirection_Fix.txt 脚本,修复代码重定向
- 标 题:菜鸟 [第一阶段 第四题] 分析
- 作 者:EricAzhe
- 时 间:2010-10-26 17:00:43
- 链 接:http://bbs.pediy.com/showthread.php?t=123550