-
-
[原创]对PeCompact 2.x--IAT加密壳详解
-
发表于: 2009-7-13 01:31 6891
-
最近学习脱壳,看了那个对一个IAT加密壳的分析,发现有很多东西看的莫名其妙,,说实话水平不行的原因,所以写这个帮助跟我一样的初学者
附件去这个求助贴里下吧:http://bbs.pediy.com/showthread.php?t=92330
1.首先设置调试器,异常,取消内存访问异常的对勾,方便在那个向0地址写入的时候停下,F9。
看堆栈窗口:
00720F8C:异常处理回调函数地址,记下,先Ctrl+G,跳转到该地址,F2下断,防止跑飞。
2.shift+F7进入异常发生时的系统代码处
这时堆栈窗口:
3.F9,断在刚才的00720F8C异常处理回调函数
00720F8C B8 11FD71F0 MOV EAX,F071FD11
00720F91 8D88 9E120010 LEA ECX,DWORD PTR DS:[EAX+1000129E]
00720F97 8941 01 MOV DWORD PTR DS:[ECX+1],EAX
00720F9A 8B5424 04 MOV EDX,DWORD PTR SS:[ESP+4] ; 最后一个参数,EXCEPTION_RECORD结构
00720F9E 8B52 0C MOV EDX,DWORD PTR DS:[EDX+C] ; 取异常发生地址
00720FA1 C602 E9 MOV BYTE PTR DS:[EDX],0E9 ; 放入指令JMP
00720FA4 83C2 05 ADD EDX,5
00720FA7 2BCA SUB ECX,EDX ; 跳转到00720FAF处,改变程序流程
00720FA9 894A FC MOV DWORD PTR DS:[EDX-4],ECX ; 写入jmp地址
00720FAC 33C0 XOR EAX,EAX
00720FAE C3 RETN ; 异常返回,跳转到新EIP处
00720FAF B8 78563412 MOV EAX,12345678
00720FB4 64:8F05 0000000>POP DWORD PTR FS:[0] ; 恢复原来的SEH链
00720FBB 83C4 04 ADD ESP,4 ; 平衡堆栈
反复看了好多次,终于知道为什么要在00720FAF处下断点了,高手写的文章,总是把我们菜菜弄的晕头转向
4.在00720FAF处F2下断,F9,向下拉:
里面有调用VirtualAlloc分配临时空间,有call edi,这就是有些脱壳教程中选择在VirtualAlloc处下断点,然后再搜索代码 call edi的原因了。
直接拉到最后的jmp eax处下断,F9,F8就到入口点了,这时候dump,IAT的kernel32.dll的部分是加密的,需要修复一下。
5.重新运行程序,在命令行处键入D 5d4090, 在此处下硬件写入断点,调试器设置那,把忽略“内存访问异常”对勾选上,F9,F9,F9.......最后跑飞的那个
6.在那个003D14A7处下硬件执行断点,重新运行后断在这里
003D14A7 C783 CC1A0010 0>MOV DWORD PTR DS:[EBX+10001ACC],0
003D14B1 8B02 MOV EAX,DWORD PTR DS:[EDX] ;edx就是那个OriginalFirstThunk指向的数组
003D14B3 85C0 TEST EAX,EAX
003D14B5 74 67 JE SHORT 003D151E
003D14B7 52 PUSH EDX
003D14B8 8983 CC1A0010 MOV DWORD PTR DS:[EBX+10001ACC],EAX
003D14BE A9 00000080 TEST EAX,80000000 ;函数导入方式
003D14C3 74 09 JE SHORT 003D14CE
003D14C5 25 FFFFFF7F AND EAX,7FFFFFFF
003D14CA 6A 00 PUSH 0
003D14CC EB 0E JMP SHORT 003D14DC
003D14CE 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
003D14D1 0341 08 ADD EAX,DWORD PTR DS:[ECX+8] ;eax是个rva+00400000=IMAGE_IMPORT_BY_NAME结构
003D14D4 33C9 XOR ECX,ECX
003D14D6 66:8B08 MOV CX,WORD PTR DS:[EAX] ;取函数序号
003D14D9 51 PUSH ECX
003D14DA 40 INC EAX
003D14DB 40 INC EAX
003D14DC 50 PUSH EAX ;取函数名字符串
003D14DD FF75 FC PUSH DWORD PTR SS:[EBP-4]
003D14E0 FF93 0A210010 CALL DWORD PTR DS:[EBX+1000210A] 加密函数
003D14E6 5A POP EDX
003D14E7 50 PUSH EAX ;eax就是返回的要放入IAT的新地址
003D14E8 8B02 MOV EAX,DWORD PTR DS:[EDX]
003D14EA A9 00000080 TEST EAX,80000000
003D14EF 75 18 JNZ SHORT 003D1509
;下面是一堆清零操作,把函数序号和函数名字符串都清零了,
003D14F1 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
003D14F4 0341 08 ADD EAX,DWORD PTR DS:[ECX+8]
003D14F7 C600 00 MOV BYTE PTR DS:[EAX],0
003D14FA 40 INC EAX
003D14FB C600 00 MOV BYTE PTR DS:[EAX],0
003D14FE 40 INC EAX
003D14FF 8A08 MOV CL,BYTE PTR DS:[EAX]
003D1501 C600 00 MOV BYTE PTR DS:[EAX],0
003D1504 40 INC EAX
003D1505 84C9 TEST CL,CL
003D1507 ^ 75 F6 JNZ SHORT 003D14FF
003D1509 58 POP EAX
003D150A 85C0 TEST EAX,EAX
003D150C ^ 0F84 3FFFFFFF JE 003D1451
;在IAT处写入新地址
003D1512 8906 MOV DWORD PTR DS:[ESI],EAX
;把OringinalFirstThunk也改了
003D1514 8902 MOV DWORD PTR DS:[EDX],EAX
003D1516 83C2 04 ADD EDX,4
003D1519 83C6 04 ADD ESI,4
;循环
003D151C ^ EB 89 JMP SHORT 003D14A7
003D151E 33C0 XOR EAX,EAX
注意:
下面是OriginalFirstThunk指向数组的内容:
加上00400000后指向下面的数组:
6.要修复IAT就要让加密函数返回正确的函数地址,所以在加密函数处跟进
003D00DD 55 PUSH EBP
003D00DE 8BEC MOV EBP,ESP
003D00E0 83C4 FC ADD ESP,-4
003D00E3 53 PUSH EBX
003D00E4 57 PUSH EDI
003D00E5 56 PUSH ESI
003D00E6 E8 00000000 CALL 003D00EB ; 返回函数字符串
003D00EB 5B POP EBX
003D00EC 81EB FE103E00 SUB EBX,3E10FE
003D00F2 FF75 10 PUSH DWORD PTR SS:[EBP+10] ; 函数序号
003D00F5 FF75 0C PUSH DWORD PTR SS:[EBP+C] ; 函数名
003D00F8 FF75 08 PUSH DWORD PTR SS:[EBP+8] ; 7C800000
003D00FB FF93 2F103E00 CALL DWORD PTR DS:[EBX+3E102F]
003D0101 8945 FC MOV DWORD PTR SS:[EBP-4],EAX ; 保存返回的函数真实地址
003D0104 8B8B 61103E00 MOV ECX,DWORD PTR DS:[EBX+3E1061]
003D010A 3B4D 08 CMP ECX,DWORD PTR SS:[EBP+8]
003D010D 75 63 JNZ SHORT 003D0172
003D010F 33C0 XOR EAX,EAX
003D0111 0383 43103E00 ADD EAX,DWORD PTR DS:[EBX+3E1043] ; 注意
003D0117 74 0D JE SHORT 003D0126
003D0119 05 07000000 ADD EAX,7
003D011E 3B83 47103E00 CMP EAX,DWORD PTR DS:[EBX+3E1047]
003D0124 72 25 JB SHORT 003D014B
003D0126 6A 40 PUSH 40
003D0128 68 00100000 PUSH 1000
003D012D 68 00100000 PUSH 1000
003D0132 6A 00 PUSH 0
003D0134 FF93 3F103E00 CALL DWORD PTR DS:[EBX+3E103F] ; 分配缓冲区
003D013A 8983 43103E00 MOV DWORD PTR DS:[EBX+3E1043],EAX ; 保存返回地址=加密的IAT地址
003D0140 05 00100000 ADD EAX,1000
003D0145 8983 47103E00 MOV DWORD PTR DS:[EBX+3E1047],EAX
003D014B 8DBB E9103E00 LEA EDI,DWORD PTR DS:[EBX+3E10E9]
003D0151 8BF7 MOV ESI,EDI
003D0153 81C7 01000000 ADD EDI,1
003D0159 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 取真实函数地址
003D015C AB STOS DWORD PTR ES:[EDI]
003D015D 8BBB 43103E00 MOV EDI,DWORD PTR DS:[EBX+3E1043] ; 取加密值
003D0163 8BC7 MOV EAX,EDI
003D0165 B9 07000000 MOV ECX,7 ; 循环次数
003D016A 018B 43103E00 ADD DWORD PTR DS:[EBX+3E1043],ECX ; 下一个双字
003D0170 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>; 加密地址里内容就是简单跳转到真实地址
003D0172 5E POP ESI
003D0173 5F POP EDI
003D0174 5B POP EBX
003D0175 C9 LEAVE
003D0176 C2 0C00 RETN 0C
要绕过加密处理,我的方法是在003D015C处修改成jmp 003D0172,这样返回的EAX就是正确的函数地址了,不知道为什么前面的帖把绕过解密的步骤一笔带过,根本看不出所以然来,难道是考验新人。
步骤:
重新运行,还使用刚才的那个003D14A7硬件执行断点,同时在达到OEP之前的那个jmp eax处下断,
F9运行,到达硬件断点后,ctrl+G 003D015C到修改处修改代码,删除硬件断点,F9.单步到OEP处,dump,fix即可。
写的比较乱,参照上个IAT加密帖看吧,高手飘过
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- 出售二手驱动、内核、漏洞、加密解密等编程书籍 4364
- [原创]python获取QQ空间前100篇blog的地址和标题的方法 8212
- [求助]翻译求助 4896
- [原创]对PeCompact 2.x--IAT加密壳详解 6892
- [原创]简单的堆栈平衡原理脚本 5152