00438450 > 55 PUSH EBP
00438451 8BEC MOV EBP,ESP
00438453 83EC 0C SUB ESP,0xC
//第一个call观察发现没有参数,返回值eax也没被使用,可知这个call没有参数也没有返回值,
//即在C语言 == void fun(void),enter进去观察。(注释1-CALL 004383A0)
00438456 E8 45FFFFFF CALL 02.004383A0 ; 初始化函数地址
0043845B A1 40804300 MOV EAX,DWORD PTR DS:[0x438040] ; 获取映像基址
00438460 0305 44804300 ADD EAX,DWORD PTR DS:[0x438044] ; 获取代码RVA
//根据后面的函数猜测到这之前应该是初始化数据。
00438466 8945 F8 MOV DWORD PTR SS:[EBP-0x8],EAX
00438469 C745 FC 0000000>MOV DWORD PTR SS:[EBP-0x4],0x0
00438470 8D4D FC LEA ECX,DWORD PTR SS:[EBP-0x4]
00438473 51 PUSH ECX
00438474 6A 40 PUSH 0x40
00438476 8B15 4C804300 MOV EDX,DWORD PTR DS:[0x43804C]
//修改的地址是代码段基址
0043847C 52 PUSH EDX
0043847D 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00438480 50 PUSH EAX
//这里看到一个VirtualProtct函数,说明可能要修改页属性,推测这之上几行代码都是它的参数。
00438481 FF15 C0924300 CALL DWORD PTR DS:[0x4392C0] ; DS:[004392C0]=764750AB (kernel32.VirtualProtect)
00438487 E8 04FEFFFF CALL 02.00438290
0043848C 8D4D FC LEA ECX,DWORD PTR SS:[EBP-0x4]
0043848F 51 PUSH ECX
00438490 8B55 FC MOV EDX,DWORD PTR SS:[EBP-0x4]
00438493 52 PUSH EDX
00438494 A1 4C804300 MOV EAX,DWORD PTR DS:[0x43804C]
00438499 50 PUSH EAX
0043849A 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-0x8]
0043849D 51 PUSH ECX
//果不期然这里还有一个VirtualProtect,这个应该是恢复页属性。
//因为第一个VirtualProtect修改代码段基址,所以监视它,然后步过到这,发现代码被修改了。
//而这两个函数中间只有call 00438290可能修改,enter进去(注释2-call 00438290)
0043849E FF15 C0924300 CALL DWORD PTR DS:[0x4392C0] ; DS:[004392C0]=764750AB (kernel32.VirtualProtect)
//这里开始是messagebox
004384A4 6A 04 PUSH 0x4
004384A6 68 2C814300 PUSH 02.0043812C ; ASCII "Hello 15PB"
004384AB 68 38814300 PUSH 02.00438138 ; ASCII "欢迎使用免费加壳程序,是否运行主程序?"
004384B0 6A 00 PUSH 0x0
004384B2 FF15 BC924300 CALL DWORD PTR DS:[0x4392BC] ; user32.MessageBoxA
004384B8 8945 F4 MOV DWORD PTR SS:[EBP-0xC],EAX
004384BB 837D F4 06 CMP DWORD PTR SS:[EBP-0xC],0x6 ; 判断返回是否yes
004384BF 75 0B JNZ SHORT 02.004384CC
//这里是messagebox结束
004384C1 E8 1A000000 CALL 02.004384E0
//这里进入就是OEP(注释3-OEP图)了,然而在这里的时候发现IAT被加密了(注释4-IAT加密图)
//然后这中间只有前面这个call 004384E0可能加密。enter进入(注释5-CALL 004384E0)
004384C6 - FF25 3C804300 JMP DWORD PTR DS:[0x43803C] ; OEP入口
004384CC 6A 00 PUSH 0x0
004384CE FF15 B8924300 CALL DWORD PTR DS:[0x4392B8] ; kernel32.ExitProcess
004384D4 8BE5 MOV ESP,EBP
004384D6 5D POP EBP
004384D7 C3 RETN
注释1-CALL 004383A0
//发现函数中有操作fs寄存器的代码,访问Fs寄存器的一般是访问线程TEB以及PEB结构,再加上获取kernel32基址的话需要访问PEB结构中的模块链表。由以上对PEB和FS寄存器的了解,可知这段代码多半是kernel32基址。往下看会看到熟悉的函数。观察步过前跟步过后的参数推测这个是个初始化函数的地址。
004383A0 55 PUSH EBP
004383A1 8BEC MOV EBP,ESP
004383A3 51 PUSH ECX
004383A4 56 PUSH ESI
004383A5 C745 FC 0000000>MOV DWORD PTR SS:[EBP-0x4],0x0
004383AC 50 PUSH EAX
004383AD 64:A1 30000000 MOV EAX,DWORD PTR FS:[0x30] ; 获取PEB
004383B3 8B40 0C MOV EAX,DWORD PTR DS:[EAX+0xC]
004383B6 8B40 1C MOV EAX,DWORD PTR DS:[EAX+0x1C]
004383B9 8B00 MOV EAX,DWORD PTR DS:[EAX]
004383BB 8B00 MOV EAX,DWORD PTR DS:[EAX]
004383BD 8B40 08 MOV EAX,DWORD PTR DS:[EAX+0x8]
004383C0 8945 FC MOV DWORD PTR SS:[EBP-0x4],EAX
004383C3 58 POP EAX
004383C4 8B75 FC MOV ESI,DWORD PTR SS:[EBP-0x4]
004383C7 E8 F4FEFFFF CALL 02.004382C0
004383CC 68 C4804300 PUSH 02.004380C4 ; ASCII "LoadLibraryA"
004383D1 56 PUSH ESI
004383D2 A3 CC924300 MOV DWORD PTR DS:[0x4392CC],EAX
004383D7 FFD0 CALL EAX
004383D9 68 D4804300 PUSH 02.004380D4 ; ASCII "GetModuleHandleA"
004383DE 56 PUSH ESI
004383DF A3 C8924300 MOV DWORD PTR DS:[0x4392C8],EAX
004383E4 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC]
004383EA 68 E8804300 PUSH 02.004380E8 ; ASCII "VirtualProtect"
004383EF 56 PUSH ESI
004383F0 A3 C4924300 MOV DWORD PTR DS:[0x4392C4],EAX
004383F5 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC]
004383FB 68 F8804300 PUSH 02.004380F8 ; ASCII "user32.dll"
00438400 A3 C0924300 MOV DWORD PTR DS:[0x4392C0],EAX
00438405 FF15 C8924300 CALL DWORD PTR DS:[0x4392C8]
0043840B 68 04814300 PUSH 02.00438104 ; ASCII "MessageBoxA"
00438410 50 PUSH EAX
00438411 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC]
00438417 68 10814300 PUSH 02.00438110 ; ASCII "ExitProcess"
0043841C 56 PUSH ESI
0043841D A3 BC924300 MOV DWORD PTR DS:[0x4392BC],EAX
00438422 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC]
00438428 68 1C814300 PUSH 02.0043811C ; ASCII "VirtualAlloc"
0043842D 56 PUSH ESI
0043842E A3 B8924300 MOV DWORD PTR DS:[0x4392B8],EAX
00438433 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC]
00438439 A3 B4924300 MOV DWORD PTR DS:[0x4392B4],EAX
0043843E 5E POP ESI
0043843F 8BE5 MOV ESP,EBP
00438441 5D POP EBP
00438442 C3 RETN
最后
00438439 A3 B4924300 MOV DWORD PTR DS:[0x4392B4],EAX
数据窗口跟随,发现初始化了一些函数
注释2-call 00438290
//明显有一行代码是异或,显而易见这个call的功能就是解密代码段
00438290 8B0D 44804300 MOV ECX,DWORD PTR DS:[0x438044] ; 获取代码段RVA
00438296 33C0 XOR EAX,EAX
00438298 030D 40804300 ADD ECX,DWORD PTR DS:[0x438040] ; 代码段基址=代码段RVA+映像基址
0043829E 3905 4C804300 CMP DWORD PTR DS:[0x43804C],EAX ; 代码段长度
004382A4 76 17 JBE SHORT 02.004382BD
004382A6 EB 08 JMP SHORT 02.004382B0
004382A8 8DA424 00000000 LEA ESP,DWORD PTR SS:[ESP]
004382AF 90 NOP
004382B0 803408 15 XOR BYTE PTR DS:[EAX+ECX],0x15 ; 代码段基址+偏移异或代码
004382B4 40 INC EAX
004382B5 3B05 4C804300 CMP EAX,DWORD PTR DS:[0x43804C]
004382BB ^ 72 F3 JB SHORT 02.004382B0
004382BD C3 RETN
注释3-OEP图
注释4-IAT加密图
注释5-CALL 004384E0
//IAT填充,需要先获取函数地址,于是在GetProcAddress下断,找到它,然后跟踪它分析,发现,有一行代码对它的返回值异或,之后将这个值保存在局部变量,紧接申请一个内存,将局部缓冲区的一块原本准备好的内容+刚刚加密的值宝贝走,然后填充到IAT地址。
004385B9 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC] ; kernel32.GetProcAddress
004385BF 6A 40 PUSH 0x40
004385C1 68 00300000 PUSH 0x3000
004385C6 6A 20 PUSH 0x20
004385C8 35 15151515 XOR EAX,0x15151515 ; 修改IAT函数
004385CD 6A 00 PUSH 0x0
004385CF 8945 DB MOV DWORD PTR SS:[EBP-0x25],EAX ; 保存加密之后的iat函数
004385D2 FF15 B4924300 CALL DWORD PTR DS:[0x4392B4] ; kernel32.VirtualAlloc
004385D8 F30F6F45 D0 MOVDQU XMM0,DQWORD PTR SS:[EBP-0x30] ; 移位64位到数据到mm0
004385DD 8B55 CC MOV EDX,DWORD PTR SS:[EBP-0x34]
004385E0 F30F7F00 MOVDQU DQWORD PTR DS:[EAX],XMM0 ; 赋值给申请的空间
004385E4 F30F6F45 E0 MOVDQU XMM0,DQWORD PTR SS:[EBP-0x20]
004385E9 F30F7F40 10 MOVDQU DQWORD PTR DS:[EAX+0x10],XMM0
004385EE 8907 MOV DWORD PTR DS:[EDI],EAX ; 将函数压入堆栈
004385F0 8B4E 04 MOV ECX,DWORD PTR DS:[ESI+0x4]
004385F3 83C6 04 ADD ESI,0x4
004385F6 8BFE MOV EDI,ESI
004385F8 85C9 TEST ECX,ECX