1.准备
简介:
PEiD(PE Identifier)是一款著名的查壳工具,其功能强大,几乎可以侦测出所有的壳,其数量已超过470 种PE 文档 的加壳类型和签名。
整个过程需要测试文件成品:https://www.lanzous.com/b07r7qu0d
首先使用PEiD检测之前做的一个异常捕捉测试程序。源码在下面,编译器为VC++ 6.0,编译方法为 Win32 Release
#include <stdio.h> class CExcepctionBase { public: virtual const char* GetExcepctionInfo() = 0; }; class CDiv0Excepction :public CExcepctionBase { public: CDiv0Excepction() { printf("CExcepctionDiv0()\r\n"); } virtual ~CDiv0Excepction() { printf("~CDiv0Excepction()\r\n"); } virtual const char* GetExcepctionInfo() { return "div zero excepction"; } }; class CAccessExcepction :public CExcepctionBase { public: CAccessExcepction() { printf("CAccessExcepction()\r\n"); } virtual ~CAccessExcepction() { printf("~CAccessExcepction()\r\n"); } virtual const char* GetExcepctionInfo() { return "access excepction"; } }; void TestExcepction(int n) { try { if (1 == n) { throw 3; } if (2 == n) { throw 3.0f; } if (3 == n) { throw ‘3‘; } if (4 == n) { throw 3.0; } if (5 == n) { throw CDiv0Excepction(); } if (6 == n) { throw CAccessExcepction(); } if (7 == n) { CAccessExcepction excAccess; throw& excAccess; } } catch (int n) { printf("catch int %d\r\n", n); } catch (float f) { printf("catch float %f\r\n", f); } catch (char c) { printf("catch char %c\r\n", c); } catch (double d) { printf("catch double %f\r\n", d); } catch (CExcepctionBase &exc) { printf("catch error %s\r\n", exc.GetExcepctionInfo()); } catch (CAccessExcepction *pExc) { printf("catch error %s\r\n", pExc->GetExcepctionInfo()); } catch (...) { printf("catch ... ..."); } printf("Test End!\r\n"); } int main() { for (int i = 1; i <= 8; ++i) { TestExcepction(i); } return 0; }
使用PEiD检测情况
2.文件判定分析
2.1 函数定位
从PEiD的分析情况,可以看到“Microsoft Visual C++ 6.0”的字符串,使用OD打开PEiD,找到字符串位置后下断点
00438FF6 |> \8BAC24 9C0400>mov ebp,dword ptr ss:[esp+0x49C] 00438FFD |> 6A 18 push 0x18 00438FFF |. 68 285A4000 push upPEiD.00405A28 ; ASCII "Microsoft Visual C++ 6.0" 00439004 |> 8D4D 04 lea ecx,dword ptr ss:[ebp+0x4] 00439007 |. E8 04D4FFFF call upPEiD.00436410
实际上,运行到此处时,已经结束了文件判断分析阶段,得到了结果,在上一条指令(红线指引),我们可以返回到跳转之前的函数,即是文件判定函数。
2.2 文件判定函数分析
接着向上查找,找到函数的入口处,设置断点,开始文件判定函数的分析
00438C20 /$ 81EC 88040000 sub esp,0x488 00438C26 |. 53 push ebx 00438C27 |. 55 push ebp 00438C28 |. 56 push esi 00438C29 |. 57 push edi 00438C2A |. B0 72 mov al,0x72 ; 定义特征码 00438C2C |. 884424 2F mov byte ptr ss:[esp+0x2F],al 00438C30 |. 884424 31 mov byte ptr ss:[esp+0x31],al 00438C34 |. 884424 34 mov byte ptr ss:[esp+0x34],al 00438C38 |. 884424 39 mov byte ptr ss:[esp+0x39],al 00438C3C |. 884424 3D mov byte ptr ss:[esp+0x3D],al 00438C40 |. B0 63 mov al,0x63 ; 定义特征码 00438C42 |. 884424 40 mov byte ptr ss:[esp+0x40],al 00438C46 |. 884424 41 mov byte ptr ss:[esp+0x41],al 00438C4A |. B0 73 mov al,0x73 ; 定义特征码 00438C4C |. 884424 43 mov byte ptr ss:[esp+0x43],al 00438C50 |. 884424 44 mov byte ptr ss:[esp+0x44],al 00438C54 |. B0 6C mov al,0x6C ; 定义特征码 00438C56 |. 884424 47 mov byte ptr ss:[esp+0x47],al 00438C5A |. 884424 48 mov byte ptr ss:[esp+0x48],al 00438C5E |. 8BB424 A00400>mov esi,dword ptr ss:[esp+0x4A0] 00438C65 |. 8B46 0C mov eax,dword ptr ds:[esi+0xC] ; PE首地址,即IMAGE_NT_HEADERS 00438C68 |. 8B56 18 mov edx,dword ptr ds:[esi+0x18] ; ".text"节首地址 00438C6B |. B1 6D mov cl,0x6D ; 定义特征码 00438C6D |. 884C24 36 mov byte ptr ss:[esp+0x36],cl 00438C71 |. 884C24 3E mov byte ptr ss:[esp+0x3E],cl 00438C75 |. B3 41 mov bl,0x41 ; 定义特征码 00438C77 |. C64424 2C 7B mov byte ptr ss:[esp+0x2C],0x7B 00438C7C |. C64424 2D 4F mov byte ptr ss:[esp+0x2D],0x4F 00438C81 |. C64424 2E 75 mov byte ptr ss:[esp+0x2E],0x75 00438C86 |. C64424 30 50 mov byte ptr ss:[esp+0x30],0x50 00438C8B |. C64424 32 6F mov byte ptr ss:[esp+0x32],0x6F 00438C90 |. C64424 33 67 mov byte ptr ss:[esp+0x33],0x67 00438C95 |. C64424 35 61 mov byte ptr ss:[esp+0x35],0x61 00438C9A |. C64424 37 44 mov byte ptr ss:[esp+0x37],0x44 00438C9F |. C64424 38 69 mov byte ptr ss:[esp+0x38],0x69 00438CA4 |. C64424 3A 7D mov byte ptr ss:[esp+0x3A],0x7D 00438CA9 |. C64424 3B 5C mov byte ptr ss:[esp+0x3B],0x5C 00438CAE |. 885C24 3C mov byte ptr ss:[esp+0x3C],bl 00438CB2 |. 885C24 3F mov byte ptr ss:[esp+0x3F],bl 00438CB6 |. C64424 42 65 mov byte ptr ss:[esp+0x42],0x65 00438CBB |. C64424 45 2E mov byte ptr ss:[esp+0x45],0x2E 00438CC0 |. C64424 46 64 mov byte ptr ss:[esp+0x46],0x64 00438CC5 |. C64424 18 4D mov byte ptr ss:[esp+0x18],0x4D 00438CCA |. C64424 19 53 mov byte ptr ss:[esp+0x19],0x53 00438CCF |. C64424 1A 43 mov byte ptr ss:[esp+0x1A],0x43 00438CD4 |. C64424 1B 46 mov byte ptr ss:[esp+0x1B],0x46 00438CD9 |. 0FB740 06 movzx eax,word ptr ds:[eax+0x6] ; eax中为IMAGE_NT_HEADERS首地址,[eax+0x6]为Section Number(节数目) = 3 00438CDD |. 8D0C80 lea ecx,dword ptr ds:[eax+eax*4] ; 节数目乘5 00438CE0 |. 8B6CCA E8 mov ebp,dword ptr ds:[edx+ecx*8-0x18] ; 得到".data"所占大小 00438CE4 |. 8D44CA D8 lea eax,dword ptr ds:[edx+ecx*8-0x28] ; 保存".data"节的首地址 00438CE8 |. 8B78 14 mov edi,dword ptr ds:[eax+0x14] ; ".data"在磁盘中的偏移 00438CEB |. 8B46 04 mov eax,dword ptr ds:[esi+0x4] ; 第二个参数指向结构中的第二项数据 00438CEE |. 03FD add edi,ebp ; ".data"偏移地址+".data"节所占大小=".data"节末尾 00438CF0 |. 8BAC24 9C0400>mov ebp,dword ptr ss:[esp+0x49C] ; 获取第一个参数 00438CF7 |. 8D8F 00390000 lea ecx,dword ptr ds:[edi+0x3900] ; .data节在内存中的位置 00438CFD |. 3BC1 cmp eax,ecx ; 判断第二个参数是否不小于.data节(.data之后就是OEP),如果成功,跳过OEP检查 00438CFF |. 73 1A jnb XupPEiD.00438D1B ; 跳过OEP检查 00438D01 |. 8B55 20 mov edx,dword ptr ss:[ebp+0x20] ; 获取到程序入口地址 00438D04 |. 85D2 test edx,edx ; 检查OEP 00438D06 |. 74 13 je XupPEiD.00438D1B 00438D08 |. 8B4E 18 mov ecx,dword ptr ds:[esi+0x18] ; .text节首地址 00438D0B |. 8B79 14 mov edi,dword ptr ds:[ecx+0x14] ; .text节文件偏移 00438D0E |. 0379 10 add edi,dword ptr ds:[ecx+0x10] ; .text节文件偏移+.text节大小=.text节末尾 00438D11 |. 3BD7 cmp edx,edi ; 判断OEP是否在.text节中 00438D13 |. 0F82 E4020000 jb upPEiD.00438FFD ; 如果在,跳转,检查结束
通过,分析实际上这个函数就做了两件事,一是判定第二个参数是否在.data节中,二是判断OEP是否在.text节中。对于节区以及对应位置功能的判断,可以使用PEView,010 Editor以及结合OD寄存器区判断,这里不给出判定过程了。但是,在这里却没有用到特征码,我们将最后一步的跳转命令nop。分析OEP检查错误情况的代码。
2.3 OEP检查错误和编译器判断
00438D13 90 nop ; 如果在,跳转,检查结束 00438D14 90 nop 00438D15 90 nop 00438D16 90 nop 00438D17 90 nop 00438D18 90 nop ; ************下面的代码是OEP检查失败的情况************ 00438D19 |. 8BFA mov edi,edx ; OEP偏移地址存入EDI,0x1634 00438D1B |> 2BC7 sub eax,edi ; 保存.data节的末尾地址 00438D1D |. 83F8 09 cmp eax,0x9 ; 判断OEP是否在.data节中 00438D20 |. 0F82 D7020000 jb upPEiD.00438FFD ; 不在就跳转 00438D26 |. 8B16 mov edx,dword ptr ds:[esi] ; edx保存IMAGE_DOS_HEADER首地址 00438D28 |. 8D0C3A lea ecx,dword ptr ds:[edx+edi] ; 得到OEP的地址 00438D2B |. 8B11 mov edx,dword ptr ds:[ecx] ; 将OEP前四个直接存入edx中,edx=0x6AEC8B55 00438D2D |. 81FA 496E7374 cmp edx,0x74736E49 ; OEP与特征码比较 00438D33 |. 75 15 jnz XupPEiD.00438D4A ; 条件成立,跳转,不成立则继续比较OEP后双字的数据 00438D35 |. 8179 04 616C6C5>cmp dword ptr ds:[ecx+0x4],0x536C6C61 ; OEP与特征码比较 00438D3C |. 75 0C jnz XupPEiD.00438D4A ; 成立则跳转 00438D3E |. 6A 17 push 0x17 ; 压入字符串长度 00438D40 |. 68 B45A4000 push upPEiD.00405AB4 ; ASCII "InstallShield 2003 Stub" 00438D45 |. E9 BA020000 jmp upPEiD.00439004 ; 跳转到显示字符串函数处 00438D4A |> 81FA 64617461 cmp edx,0x61746164 ; OEP与特征码比较 00438D50 |. 75 27 jnz XupPEiD.00438D79 00438D52 |. 8179 04 312E636>cmp dword ptr ds:[ecx+0x4],0x61632E31 ; 下面实际上就是一些其他版本的特征码比较了 00438D59 |. 75 1E jnz XupPEiD.00438D79 00438D5B |. 68 B45A4000 push upPEiD.00405AB4 ; ASCII "InstallShield 2003 Stub" 00438D60 |. 8D4D 04 lea ecx,dword ptr ss:[ebp+0x4] 00438D63 |. E8 38E9FFFF call upPEiD.004376A0 00438D68 |. 5F pop edi 00438D69 |. 5E pop esi 00438D6A |. C645 00 01 mov byte ptr ss:[ebp],0x1 00438D6E |. 5D pop ebp 00438D6F |. B0 01 mov al,0x1 00438D71 |. 5B pop ebx 00438D72 |. 81C4 88040000 add esp,0x488 00438D78 |. C3 retn 00438D79 |> 3D 00020000 cmp eax,0x200 00438D7E |. BD 00020000 mov ebp,0x200 00438D83 |. 77 02 ja XupPEiD.00438D87 00438D85 |. 8BE8 mov ebp,eax 00438D87 |> 6A 1D push 0x1D 00438D89 |. 8D4424 30 lea eax,dword ptr ss:[esp+0x30] 00438D8D |. 50 push eax 00438D8E |. 8D8C24 98000000 lea ecx,dword ptr ss:[esp+0x98] 00438D95 |. E8 26E5FFFF call upPEiD.004372C0 00438D9A |. 8B16 mov edx,dword ptr ds:[esi] 00438D9C |. 8D4C24 10 lea ecx,dword ptr ss:[esp+0x10] 00438DA0 |. 51 push ecx 00438DA1 |. 55 push ebp 00438DA2 |. 03D7 add edx,edi 00438DA4 |. 52 push edx 00438DA5 |. 8D8C24 9C000000 lea ecx,dword ptr ss:[esp+0x9C] 00438DAC |. E8 4FE6FFFF call upPEiD.00437400 00438DB1 |. 84C0 test al,al 00438DB3 |. 74 26 je XupPEiD.00438DDB 00438DB5 |. 8BB424 9C040000 mov esi,dword ptr ss:[esp+0x49C] 00438DBC |. 6A 1B push 0x1B 00438DBE |. 68 985A4000 push upPEiD.00405A98 ; ASCII "Silicon Realms Install Stub" 00438DC3 |. 8D4E 04 lea ecx,dword ptr ds:[esi+0x4] 00438DC6 |. E8 45D6FFFF call upPEiD.00436410 00438DCB |. 5F pop edi 00438DCC |. C606 01 mov byte ptr ds:[esi],0x1 00438DCF |. 5E pop esi 00438DD0 |. 5D pop ebp 00438DD1 |. B0 01 mov al,0x1 00438DD3 |. 5B pop ebx 00438DD4 |. 81C4 88040000 add esp,0x488 00438DDA |. C3 retn 00438DDB |> 8B46 04 mov eax,dword ptr ds:[esi+0x4] 00438DDE |. 2BC7 sub eax,edi 00438DE0 |. 3D 00400000 cmp eax,0x4000 00438DE5 |. BD 00400000 mov ebp,0x4000 00438DEA |. 77 02 ja XupPEiD.00438DEE 00438DEC |. 8BE8 mov ebp,eax 00438DEE |> 6A 04 push 0x4 00438DF0 |. 8D4424 1C lea eax,dword ptr ss:[esp+0x1C] 00438DF4 |. 50 push eax 00438DF5 |. 8D8C24 98000000 lea ecx,dword ptr ss:[esp+0x98] 00438DFC |. E8 BFE4FFFF call upPEiD.004372C0 00438E01 |. 8B16 mov edx,dword ptr ds:[esi] 00438E03 |. 8D4C24 10 lea ecx,dword ptr ss:[esp+0x10] 00438E07 |. 51 push ecx 00438E08 |. 55 push ebp 00438E09 |. 03D7 add edx,edi 00438E0B |. 52 push edx 00438E0C |. 8D8C24 9C000000 lea ecx,dword ptr ss:[esp+0x9C] 00438E13 |. E8 E8E5FFFF call upPEiD.00437400 00438E18 |. 84C0 test al,al 00438E1A |. 74 24 je XupPEiD.00438E40 00438E1C |. 8BB424 9C040000 mov esi,dword ptr ss:[esp+0x49C] 00438E23 |. 68 845A4000 push upPEiD.00405A84 ; ASCII "InstallShield AFW" 00438E28 |. 8D4E 04 lea ecx,dword ptr ds:[esi+0x4] 00438E2B |. E8 70E8FFFF call upPEiD.004376A0 00438E30 |. 5F pop edi 00438E31 |. C606 01 mov byte ptr ds:[esi],0x1 00438E34 |. 5E pop esi 00438E35 |. 5D pop ebp 00438E36 |. B0 01 mov al,0x1 00438E38 |. 5B pop ebx 00438E39 |. 81C4 88040000 add esp,0x488 00438E3F |. C3 retn 00438E40 |> 8B46 0C mov eax,dword ptr ds:[esi+0xC] ; eax为IMAGE_NT_HEADERS地址=0x64800D8 00438E43 |. 8B40 28 mov eax,dword ptr ds:[eax+0x28] ; eax为代码段的地址 00438E46 |. 50 push eax 00438E47 |. 8BCE mov ecx,esi 00438E49 |. E8 32A40100 call upPEiD.00453280 ; 计算偏移位置,得到正确的OEP 00438E4E |. 8BF8 mov edi,eax 00438E50 |. 8B46 18 mov eax,dword ptr ds:[esi+0x18] ; 获取.text节首地址,0x064801D0 00438E53 |. 8B48 14 mov ecx,dword ptr ds:[eax+0x14] ; .text节文件偏移地址 00438E56 |. 0348 10 add ecx,dword ptr ds:[eax+0x10] ; .text节文件偏移地址+.text节大小=.text节末尾偏移地址 00438E59 |. 3BF9 cmp edi,ecx ; 比较OEP是否在.text节中 00438E5B |. 0F82 95010000 jb upPEiD.00438FF6 ; 跳转到显示编译器版本处,此处即显示"Microsoft Visual C++ 6.0”
因为在第一部分对OEP的检测中,已经完成的跳转,实际上是不会执行这一段代码的,因此对于真正的文件判定代码,是会调用上面这段函数的。
要找到函数的调用处,因为函数在最后ret时,都会出栈函数调用处的调用地址,所以直接在函数结尾设置断点,执行观察栈区。
转到0x452F46
存放数据处
2.4 "真"文件分析函数
对上面分析函数进行分析
00452E90 /$ 64:A1 00000000 mov eax,dword ptr fs:[0] ; 入口地址 00452E96 |. 6A FF push -0x1 00452E98 |. 68 C8CD4600 push upPEiD.0046CDC8 ; 异常处理 00452E9D |. 50 push eax 00452E9E |. 64:8925 0000000>mov dword ptr fs:[0],esp 00452EA5 |. 83EC 10 sub esp,0x10 ; 局部变量空间 00452EA8 |. 56 push esi 00452EA9 |. 8B7424 24 mov esi,dword ptr ss:[esp+0x24] ; 第一个参数 00452EAD |. 8B46 14 mov eax,dword ptr ds:[esi+0x14] 00452EB0 |. 8B40 10 mov eax,dword ptr ds:[eax+0x10] ; 获取起始相对虚拟偏移地址 00452EB3 |. 57 push edi ; 压入参数一 00452EB4 |. 8BF9 mov edi,ecx ; 获取this指针 00452EB6 |. 50 push eax ; 压入代码起始RVA 00452EB7 |. 8BCE mov ecx,esi 00452EB9 |. E8 C2030000 call upPEiD.00453280 ; 检查PE文件格式,将OEP的RWA与RVA进行转换 00452EBE |. 3B46 04 cmp eax,dword ptr ds:[esi+0x4] ; 函数返回调整之后的OEP 00452EC1 |. 72 15 jb XupPEiD.00452ED8 ; 条件成立,跳转到分析阶段 00452EC3 |. 5F pop edi ; =============分析失败代码=========== 00452EC4 |. 32C0 xor al,al 00452EC6 |. 5E pop esi 00452EC7 |. 8B4C24 10 mov ecx,dword ptr ss:[esp+0x10] 00452ECB |. 64:890D 0000000>mov dword ptr fs:[0],ecx 00452ED2 |. 83C4 1C add esp,0x1C 00452ED5 |. C2 0800 retn 0x8 ; ======================================= 00452ED8 |> 53 push ebx 00452ED9 |. 8B5C24 30 mov ebx,dword ptr ss:[esp+0x30] 00452EDD |. 8943 20 mov dword ptr ds:[ebx+0x20],eax ; 保存调整之后的OEP 00452EE0 |. 8B4E 04 mov ecx,dword ptr ds:[esi+0x4] 00452EE3 |. 8B16 mov edx,dword ptr ds:[esi] 00452EE5 |. 2BC8 sub ecx,eax 00452EE7 |. 51 push ecx 00452EE8 |. 03D0 add edx,eax 00452EEA |. 52 push edx ; 载入内存后的程序入口地址 00452EEB |. 8D4C24 14 lea ecx,dword ptr ss:[esp+0x14] 00452EEF |. 51 push ecx 00452EF0 |. 8BCF mov ecx,edi 00452EF2 |. E8 E9740000 call upPEiD.0045A3E0 ; 将OEP代码与特征码进行对比--PEiD可以检查出分析程序是否在可识别的编译器范围内 00452EF7 |. 8B4424 14 mov eax,dword ptr ss:[esp+0x14] 00452EFB |. 8B4C24 10 mov ecx,dword ptr ss:[esp+0x10] 00452EFF |. 8BD0 mov edx,eax 00452F01 |. 2BD1 sub edx,ecx 00452F03 |. C1FA 02 sar edx,0x2 00452F06 |. 52 push edx 00452F07 |. 50 push eax 00452F08 |. 51 push ecx 00452F09 |. C74424 30 00000>mov dword ptr ss:[esp+0x30],0x0 00452F11 |. E8 9AF5FFFF call upPEiD.004524B0 ; 根据函数0x45A3E0对OEP处特征码的对比结果,将特征匹配的处理流程的函数指针,在数组中的下标值都存放在地址ESP+1C的数组中 00452F16 |. 8B7C24 1C mov edi,dword ptr ss:[esp+0x1C] 00452F1A |. 8B4424 20 mov eax,dword ptr ss:[esp+0x20] 00452F1E |. 83C4 0C add esp,0xC 00452F21 |. 3BF8 cmp edi,eax 00452F23 |. 74 37 je XupPEiD.00452F5C ; 没有匹配的特征函数,结束分析 00452F25 |> 8B07 /mov eax,dword ptr ds:[edi] 00452F27 |. 50 |push eax 00452F28 |. 56 |push esi 00452F29 |. 53 |push ebx 00452F2A |. FF15 8C1E4000 |call dword ptr ds:[0x401E8C] ; 检查.rdata节是否存在 00452F30 |. 83C4 0C |add esp,0xC 00452F33 |. 84C0 |test al,al 00452F35 |. 75 48 |jnz XupPEiD.00452F7F ; 如果不存在,结束查询分析 00452F37 |. 8B07 |mov eax,dword ptr ds:[edi] 00452F39 |. 50 |push eax 00452F3A |. 56 |push esi 00452F3B |. 8D0C40 |lea ecx,dword ptr ds:[eax+eax*2] 00452F3E |. 53 |push ebx 00452F3F |. FF148D 8C1E4000 |call dword ptr ds:[ecx*4+0x401E8C] ; 调用分析函数,存放数据的首地址在0x401E8C 00452F46 |. 83C4 0C |add esp,0xC 00452F49 |. 84C0 |test al,al 00452F4B |. 75 32 |jnz XupPEiD.00452F7F 00452F4D |. 8B4424 14 |mov eax,dword ptr ss:[esp+0x14] 00452F51 |. 83C7 04 |add edi,0x4 00452F54 |. 3BF8 |cmp edi,eax 00452F56 |.^ 75 CD \jnz XupPEiD.00452F25 ; 循环跳转。一直循环到匹配到对应的处理函数
上面的函数,整个过程:
- 对OEP的特征码比较
- 通过比较结果匹配储存函数指针的数组中的过程,将下标存储到数组
- 检测程序中是否存在.rdata节
- 从存储下标的数组中取出下标,调用对应的函数。
在第一步中,会产生一个使用OEP的哪些机器码作为特征码进行比较的问题(特征码的定义)。因此,我们进一步分析函数0x45A3E0
00452EF2 |. E8 E9740000 call upPEiD.0045A3E0 ; 将OEP代码与特征码进行对比--PEiD可以检查出分析程序是否在可识别的编译器范围内
3.特征码分析
0045A3E0 /$ 6A FF push -0x1 0045A3E2 |. 68 38D24600 push upPEiD.0046D238 ; SE 处理程序安装 0045A3E7 |. 64:A1 00000000 mov eax,dword ptr fs:[0] 0045A3ED |. 50 push eax 0045A3EE |. 64:8925 0000000>mov dword ptr fs:[0],esp 0045A3F5 |. 83EC 14 sub esp,0x14 0045A3F8 |. 53 push ebx 0045A3F9 |. 55 push ebp 0045A3FA |. 33DB xor ebx,ebx 0045A3FC |. 56 push esi 0045A3FD |. 57 push edi 0045A3FE |. 8BF1 mov esi,ecx ; 获取this指针 0045A400 |. 895C24 10 mov dword ptr ss:[esp+0x10],ebx ; 将数组清零 0045A404 |. 895C24 18 mov dword ptr ss:[esp+0x18],ebx 0045A408 |. 895C24 1C mov dword ptr ss:[esp+0x1C],ebx 0045A40C |. 895C24 20 mov dword ptr ss:[esp+0x20],ebx 0045A410 |. 8B7C24 38 mov edi,dword ptr ss:[esp+0x38] ; 获取OEP,保存到EDI 0045A414 |. 0FB607 movzx eax,byte ptr ds:[edi] ; 获取OEP地址处的数据 0045A417 |. 8B4486 14 mov eax,dword ptr ds:[esi+eax*4+0x14] ; 对this指针偏移计算 0045A41B |. 83F8 FF cmp eax,-0x1 0045A41E |. 8B6C24 3C mov ebp,dword ptr ss:[esp+0x3C] ; OEP差值 0045A422 |. 895C24 2C mov dword ptr ss:[esp+0x2C],ebx ; EBX=0,将局部变量清0 0045A426 |. 74 0F je XupPEiD.0045A437 0045A428 |. 55 push ebp 0045A429 |. 57 push edi 0045A42A |. 50 push eax 0045A42B |. 8D4C24 20 lea ecx,dword ptr ss:[esp+0x20] ; 获取数组首地址 0045A42F |. 51 push ecx 0045A430 |. 8BCE mov ecx,esi ; 将ECX赋值为this指针 0045A432 |. E8 99FDFFFF call upPEiD.0045A1D0 ; 检查OEP处代码是否与特征码相同(将OEP处的字节码与特征码对比,从而比较OEP处的机器码) 0045A437 |> 8B86 14040000 mov eax,dword ptr ds:[esi+0x414] 0045A43D |. 83F8 FF cmp eax,-0x1 0045A440 |. 74 0F je XupPEiD.0045A451 0045A442 |. 55 push ebp 0045A443 |. 57 push edi 0045A444 |. 50 push eax 0045A445 |. 8D5424 20 lea edx,dword ptr ss:[esp+0x20] 0045A449 |. 52 push edx 0045A44A |. 8BCE mov ecx,esi 0045A44C |. E8 7FFDFFFF call upPEiD.0045A1D0 ; 检查OEP处代码是否与特征码相同(将OEP处的字节码与特征码对比,从而比较OEP处的机器码)
机器码和特征码的介绍与关系:https://www.cnblogs.com/qiumingcheng/p/5400265.html
在上面的函数中通过0x45A1D0比较OEP的机器码与特征码,提取出具有相同特性的编译器版本。
例如
这是OEP的部分数据
05551634 55 8B EC 6A FF 68 F0 80 40 00 68 40 41 40 00 64 U嬱jh饊@[email protected]@.d 05551644 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 10 ?...Pd?....冹 05551654 53 56 57 89 65 E8 FF 15 0C 80 40 00 33 D2 8A D4 SVW塭?.€@.3見? 05551664 89 15 6C BA 40 00 8B C8 81 E1 FF 00 00 00 89 0D ?l篅.嬋佱...? 05551674 68 BA 40 00 C1 E1 08 03 CA 89 0D 64 BA 40 00 C1 h篅.玲蕢.d篅.?
使用数据拼接成机器码指令
0x55 0x8b 0xec 0x6a 0xff
0045A3E0 55 push ebp 0045A3E1 8BEC mov ebp,esp 0045A3E3 6A FF push -0x1
4.PEiD解析流程
- PEiD解析编译器的流程总结:
- 读取文件,分析出PE结构,保存。
- 检查OEP,修正OE,再次检查OEP
- 使用OEP处的机器码与特征码比较
- 通过比较结果匹配储存函数指针的数组中的过程,将下标存储到数组
- 检查文件是否存在rdata节
- 循环,从存储下标的数组中取出下标,调用对应的函数。
- 在处理函数中再次检查OEP的机器码与特征码
- 获取并显示编译器版本
5.开发环境伪造
在第一次文件判定中,我们知道会检测OEP是否在.text节中,因此,我们只需要将伪造OEP写入.text节后,使用HEX Editor改变原来OEP即可
55 8B EC 6A FF 68 F0 80 40 00 68 40 41 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 10 53 56 57 89 65 E8 5F 5E 5B 83 C4 10 58 64 A3 00 00 00 00 58 58 58 58 E8 76 FA FF FF 00 00 00 00
使用一个简单的Hello World程序进行伪造OEP
1.初始的OEP地址在0xF012C2处,写入伪造OEP数据
2.保存修改后的文件后,OD打开,起始偏移地址为1810
3.HEX Editor定位到偏移地址0x110处
将原OEP偏移地址0x12C2改为0x1810即可
原文地址:https://www.cnblogs.com/nongchaoer/p/12202515.html