文件运行后自动升级了。汗。
升级完成后再看壳。外壳还是ASPACK的,不过内壳变了,成了EncryptPE了,我对yoda's Protector没什么研究,不知道是不是这种壳。粗略分析了一下,有IAT替换操作,看来脱内壳要修复IAT了。如下是分析代码的粗略过程。
载入后,F7一直跟下去,很快就有发现了
0066E205 FF55 04 call dword ptr ss:[ebp+4] ; KERNEL32.GetTempPathA
这里开始取系统的TEMP目录了
0066E208 83F8 04 cmp eax,4
0066E20B 0F8C 07010000 jl unpacked.0066E318
0066E211 01E8 add eax,ebp
0066E213 83C0 23 add eax,23
0066E216 8A10 mov dl,byte ptr ds:[eax]
0066E218 80FA 5C cmp dl,5C
0066E21B 74 04 je short unpacked.0066E221
0066E21D 40 inc eax
0066E21E C600 5C mov byte ptr ds:[eax],5C
0066E221 31C9 xor ecx,ecx
0066E223 8A9429 29010000 mov dl,byte ptr ds:[ecx+ebp+129]
0066E22A 885401 01 mov byte ptr ds:[ecx+eax+1],dl
0066E22E 80FA 00 cmp dl,0
0066E236 8B85 49010000 mov eax,dword ptr ss:[ebp+149]
这里开始计算定位数据了,取文件名。
ss:[0066E153]=0007A200
eax=0066E03D (unpacked.0066E03D), ASCII "\V220080618.EPE"
0066E25C 50 push eax ; unpacked.0066E02E
overlay部分生成的文件的绝对路径拿到了
eax=0066E02E (unpacked.0066E02E), ASCII "C:\WINDOWS\TEMP\V220080618.EPE"
0066E25D FF55 08 call dword ptr ss:[ebp+8]
开始从文件中读取数据,调用CreateFileA函数
ss:[0066E012]=7C801A24 (KERNEL32.CreateFileA)
0066E260 83F8 FF cmp eax,-1
0066E263 74 67 je short unpacked.0066E2CC
0066E265 50 push eax
0066E266 6A 00 push 0
0066E268 8B8D 49010000 mov ecx,dword ptr ss:[ebp+149]
0066E26E 51 push ecx
0066E26F 6A 00 push 0
0066E271 6A 04 push 4
0066E273 6A 00 push 0
0066E275 50 push eax
0066E276 FF55 0C call dword ptr ss:[ebp+C] ; KERNEL32.CreateFileMappingA
堆栈操作,保存现场,执行文件映射地址的准备CreateFileMappingA
0066E279 83F8 00 cmp eax,0
0066E27C 74 4B je short unpacked.0066E2C9
0066E27E 50 push eax
0066E27F 8B8D 49010000 mov ecx,dword ptr ss:[ebp+149]
0066E285 51 push ecx
0066E286 6A 00 push 0
0066E288 6A 00 push 0
0066E28A 68 1F000F00 push 0F001F
0066E28F 50 push eax
0066E290 FF55 10 call dword ptr ss:[ebp+10]
文件映射完成,映射的文件头地址已经得出
eax=00830000, (ASCII "MZP")
0066E293 83F8 00 cmp eax,0
0066E296 74 2E je short unpacked.0066E2C6
0066E2B5 8A16 mov dl,byte ptr ds:[esi]
0066E2B7 32D6 xor dl,dh
0066E2B9 8810 mov byte ptr ds:[eax],dl
0066E2BB 46 inc esi
0066E2BC 40 inc eax
0066E2BD 49 dec ecx
0066E2BE 83F9 00 cmp ecx,0
0066E2C1 ^ 75 F2 jnz short unpacked.0066E2B5
这个循环是检验映射地址内的PE文件头标志“MZP”
0066E2CC 89E8 mov eax,ebp
0066E2CE 83C0 24 add eax,24
0066E2D1 50 push eax
0066E2D2 FF55 1C call dword ptr ss:[ebp+1C] ; KERNEL32.LoadLibraryA
0066E2D5 83F8 00 cmp eax,0
开始装配PE文件头和映射代码了这里看EAX
eax=71120000 (V2200806.71120000), ASCII "MZP"
0066E2D8 74 3E je short unpacked.0066E318
0066E2DA 89C3 mov ebx,eax
0066E2DC 89E8 mov eax,ebp
0066E2DE 05 3A010000 add eax,13A
0066E2E3 50 push eax ; unpacked.0066E144
eax=0066E144 (unpacked.0066E144), ASCII "EncryptPE_Init"
0066E2E4 53 push ebx
EBX 71120000 ASCII "MZP"
0066E2E5 FF542F 04 call dword ptr ds:[edi+ebp+4]
0066E2E9 83F8 00 cmp eax,0
0066E2EC 74 2A je short unpacked.0066E318
这里就是送参数入栈,准备替换API地址了。注意EAX是准备替换的虚拟函数名,EBX是文件头基址
整理一下:
0066E2CC 89E8 mov eax,ebp
0066E2CE 83C0 24 add eax,24
0066E2D1 50 push eax
0066E2D2 FF55 1C call dword ptr ss:[ebp+1C]
0066E2D5 83F8 00 cmp eax,0
0066E2D8 74 3E je short unpacked.0066E318
0066E2DA 89C3 mov ebx,eax
0066E2DC 89E8 mov eax,ebp
0066E2DE 05 3A010000 add eax,13A
0066E2E3 50 push eax
0066E2E4 53 push ebx
0066E2E5 FF542F 04 call dword ptr ds:[edi+ebp+4]
0066E2E9 83F8 00 cmp eax,0
0066E2EC 74 2A je short unpacked.0066E318
0066E2EE 8945 00 mov dword ptr ss:[ebp],eax
0066E2F1 89EB mov ebx,ebp
0066E2F3 81C3 52010000 add ebx,152
0066E2F9 8B8D 4D010000 mov ecx,dword ptr ss:[ebp+14D]
0066E2FF 01CB add ebx,ecx
0066E301 8B8D 49010000 mov ecx,dword ptr ss:[ebp+149]
0066E307 01CB add ebx,ecx
0066E309 53 push ebx
0066E30A EB 0A jmp short unpacked.0066E316
0066E30C B3 FF mov bl,0FF
0066E30E DAAE A0FCFA0E fisubr dword ptr ds:[esi+EFAFCA0>
0066E314 6207 bound eax,qword ptr ds:[edi]
0066E316 FFD0 call eax ; V2200806.EncryptPE_Init
0066E318 6A 00 push 0
0066E31A FF55 20 call dword ptr ss:[ebp+20]
0066E2EE 8945 00 mov dword ptr ss:[ebp],eax
eax=7120A1CC (V2200806.EncryptPE_Init)
ss:[0066E00A]=7C800000 (KERNEL32.7C800000)
这里开始替换函数了。原理是在系统的TEMP目录中生成一个V220080618.EPE文件,也就是程序中overlay的内容,以其内容作为虚拟文件头,通过内存映射的方法连接到代码的顶端,用这段代码中的函数地址替换系统的API函数地址。所以
0066E2D8 74 3E je short unpacked.0066E318
可能就是MAGIC JMP了,想要拿到能修复的IAT数据必须JMP跳过去
0066E2EC 74 2A je short unpacked.0066E318
这里一样也不能忽视
0066E2F1 89EB mov ebx,ebp
0066E2F3 81C3 52010000 add ebx,152
0066E2F9 8B8D 4D010000 mov ecx,dword ptr ss:[ebp+14D]
0066E2FF 01CB add ebx,ecx
0066E301 8B8D 49010000 mov ecx,dword ptr ss:[ebp+149]
0066E307 01CB add ebx,ecx
0066E309 53 push ebx
0066E30A EB 0A jmp short unpacked.0066E316
0066E30C B3 FF mov bl,0FF
0066E30E DAAE A0FCFA0E fisubr dword ptr ds:[esi+EFAFCA0>
0066E314 6207 bound eax,qword ptr ds:[edi]
0066E316 FFD0 call eax
0066E318 6A 00 push 0
0066E31A FF55 20 call dword ptr ss:[ebp+20]
0066E31D CC int3
思路是阻止壳替换API函数地址,拿到修复的IAT数据。
根据ESP定律,断在了
006E86F3 - E9 A7B1D1FF jmp unpacked.0040389F
这里就是跳转到OEP入口了,所以OEP是40389F。原来程序是VC++的,还真幸运,OEP没有被偷代码。
0040389F 55 push ebp
004038A0 8BEC mov ebp,esp
004038A2 6A FF push -1
004038A4 68 F8724000 push unpacked.004072F8
004038A9 68 04554000 push unpacked.00405504
004038AE 64:A1 00000000 mov eax,dword ptr fs:[0]
004038B4 50 push eax
004038B5 64:8925 00000000 mov dword ptr fs:[0],esp
004038BC 83EC 58 sub esp,58
004038BF 53 push ebx
004038C0 56 push esi
004038C1 57 push edi
004038C2 8965 E8 mov dword ptr ss:[ebp-18],esp
004038C5 90 nop
004038C6 E8 3B522E00 call unpacked.006E8B06