PEBundle3.2的高级捆缚分析

【文章标题】: PEBundle3.2的高级捆缚分析
【文章作者】: iawen
【软件名称】: EdrTest.exe
【下载地址】: 见附件
【使用工具】: OD、LoadPE、ImportRec
【操作平台】: Xp Sp3
【软件介绍】: 一个UnpackMe,呵呵
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
——————————————————————————–
【详细过程】
  先用PEid查一下壳,显示为:PEBundle 2.0b5 – 3.0x -> Jeremy Collake
  因为朋友自己加的,所以知道是PEBundle 3.2版的,呵呵!
  
  主要是分2步:
  1、Dump出完整的主程序
  2、Dump出捆绑的DLL
  
  好了,不多说了,直接用OD载入,先来Dump出主程序吧:
  


  00418000 Ed>  9C              pushfd
  00418001      60              pushad
  00418002      E8 02000000     call EdrTest.00418009
  00418007      33C0            xor eax,eax
  00418009      8BC4            mov eax,esp
  

  
  我们单步到00418002时,看一下ESP,下断点:hr 0013FFA0
  然后F9运行,就到了这里:
  


  004181A7      9D              popfd
  004181A8      68 4F154000     push EdrTest.0040154F
  004181AD      C3              retn
  

  
  
  F8单步几下,很快就到了OEP位置了,呵呵,VC写的程序:
  


  0040154F      55              push ebp
  00401550      8BEC            mov ebp,esp
  00401552      6A FF           push -1
  00401554      68 58714000     push EdrTest.00407158
  00401559      68 D0264000     push EdrTest.004026D0
  0040155E      64:A1 00000000  mov eax,dword ptr fs:[0]
  00401564      50              push eax
  00401565      64:8925 0000000>mov dword ptr fs:[0],esp
  0040156C      83EC 58         sub esp,58
  0040156F      53              push ebx
  00401570      56              push esi
  00401571      57              push edi
  00401572      8965 E8         mov dword ptr ss:[ebp-18],esp
  00401575      FF15 A0704000   call dword ptr ds:[4070A0]             ; kernel32.GetVersion
  

  
  
  我们先看一下IAT,在00401575上,右键--数据窗口跟随--内存地址,发现有IAT加密:
  


  00407098  7C801EF2  kernel32.GetStartupInfoA
  0040709C  00419377  EdrTest.00419377================加密了的
  004070A0  7C81126A  kernel32.GetVersion
  004070A4  00419501  EdrTest.00419501================加密了的
  004070A8  00418F79  EdrTest.00418F79================加密了的
  004070AC  7C801E1A  kernel32.TerminateProcess
  004070B0  7C80DE85  kernel32.GetCurrentProcess
  

  
  我们重新载入程序,下断:hr 0040709C,然后F9运行,中断在了:
  


  00418E14      8B19            mov ebx,dword ptr ds:[ecx]
  00418E16      83C1 04         add ecx,4
  00418E19      85DB            test ebx,ebx
  00418E1B      74 33           je short EdrTest.00418E50
  00418E1D      8BC3            mov eax,ebx
  00418E1F      F7C3 00000080   test ebx,80000000
  00418E25      74 08           je short EdrTest.00418E2F
  00418E27      81E3 FFFF0000   and ebx,0FFFF
  00418E2D      EB 04           jmp short EdrTest.00418E33
  00418E2F      43              inc ebx
  00418E30      43              inc ebx
  00418E31      03DA            add ebx,edx
  00418E33      51              push ecx
  00418E34      52              push edx
  00418E35      899D C2214000   mov dword ptr ss:[ebp+4021C2],ebx
  00418E3B      53              push ebx
  00418E3C      FFB5 BA214000   push dword ptr ss:[ebp+4021BA]
  00418E42      E8 32010000     call EdrTest.00418F79
  00418E47      5A              pop edx
  00418E48      59              pop ecx
  00418E49      85C0            test eax,eax
  00418E4B      74 05           je short EdrTest.00418E52
  00418E4D      AB              stos dword ptr es:[edi]
  00418E4E    ^ EB C4           jmp short EdrTest.00418E14=========中断在这里了,呵呵
  

  
  这是一个循环,我们耐心的单步,单步这里:
  


  00418E3C      FFB5 BA214000   push dword ptr ss:[ebp+4021BA]         ; 这里是DLL的基址
  00418E42      E8 32010000     call EdrTest.00418F79
  

  
  我们发现dword ptr ss:[ebp+4021BA]里加载的是DLL的基址,于是我们跟进去看:
  


  00418F79      C8 000000       enter 0,0
  00418F7D      55              push ebp
  00418F7E      56              push esi
  00418F7F      E8 00000000     call EdrTest.00418F84
  00418F84      5E              pop esi
  00418F85      81EE 842F4000   sub esi,EdrTest.00402F84
  00418F8B      8B86 B2214000   mov eax,dword ptr ds:[esi+4021B2]
  00418F91      3945 08         cmp dword ptr ss:[ebp+8],eax
  00418F94      75 1B           jnz short EdrTest.00418FB1
  00418F96      55              push ebp
  00418F97      51              push ecx
  00418F98      52              push edx
  00418F99      57              push edi
  00418F9A      53              push ebx
  00418F9B      FF75 0C         push dword ptr ss:[ebp+C]
  00418F9E      FF75 08         push dword ptr ss:[ebp+8]
  00418FA1      E8 AEFEFFFF     call EdrTest.00418E54
  00418FA6      5B              pop ebx
  00418FA7      5F              pop edi
  00418FA8      5A              pop edx
  00418FA9      59              pop ecx
  00418FAA      5D              pop ebp
  00418FAB      5E              pop esi
  00418FAC      5D              pop ebp
  00418FAD      C9              leave
  00418FAE      C2 0800         retn 8
  00418FB1      5E              pop esi
  00418FB2      5D              pop ebp
  00418FB3      FF75 0C         push dword ptr ss:[ebp+C]
  00418FB6      FF75 08         push dword ptr ss:[ebp+8]              ; 这里加载函数名
  00418FB9      FF15 E9884100   call dword ptr ds:[<&KERNEL32.GetProcA>; kernel32.GetProcAddress
  00418FBF      85C0            test eax,eax                           ; 这里开始获取函数的地址了
  00418FC1      74 25           je short EdrTest.00418FE8              ; 地址为0则返回
  00418FC3      51              push ecx
  00418FC4      56              push esi
  00418FC5      50              push eax
  00418FC6      E8 00000000     call EdrTest.00418FCB
  00418FCB      5E              pop esi
  00418FCC      81EE CB2F4000   sub esi,EdrTest.00402FCB
  00418FD2      8D8E 2B234000   lea ecx,dword ptr ds:[esi+40232B]
  00418FD8      50              push eax                               ; EAX里是真实的函数地址
  00418FD9      51              push ecx                               ; ECX里则是一个将要加密的地址
  00418FDA      E8 97FBFFFF     call EdrTest.00418B76
  00418FDF      85C0            test eax,eax
  00418FE1      74 02           je short EdrTest.00418FE5
  00418FE3      59              pop ecx
  00418FE4      50              push eax
  00418FE5      58              pop eax
  00418FE6      5E              pop esi
  00418FE7      59              pop ecx
  00418FE8      C9              leave
  00418FE9      C2 0800         retn 8
  

  
  然后我们继续跟进 call EdrTest.00418B76:
  


  00418B76      C8 040000       enter 4,0
  00418B7A      53              push ebx
  00418B7B      57              push edi
  00418B7C      56              push esi
  00418B7D      E8 00000000     call EdrTest.00418B82
  00418B82      5B              pop ebx
  00418B83      81EB 822B4000   sub ebx,EdrTest.00402B82
  00418B89      C745 FC 0000000>mov dword ptr ss:[ebp-4],0
  00418B90      8B75 08         mov esi,dword ptr ss:[ebp+8]
  00418B93      833E 00         cmp dword ptr ds:[esi],0
  00418B96      74 34           je short EdrTest.00418BCC
  00418B98      56              push esi
  00418B99      8B7E 08         mov edi,dword ptr ds:[esi+8]
  00418B9C      03FB            add edi,ebx
  00418B9E      8B76 0C         mov esi,dword ptr ds:[esi+C]
  00418BA1      03F3            add esi,ebx
  00418BA3      8B45 0C         mov eax,dword ptr ss:[ebp+C]
  00418BA6      833F FF         cmp dword ptr ds:[edi],-1
  00418BA9      74 13           je short EdrTest.00418BBE
  00418BAB      8B0F            mov ecx,dword ptr ds:[edi]
  00418BAD      85C9            test ecx,ecx
  00418BAF      74 05           je short EdrTest.00418BB6
  00418BB1      390419          cmp dword ptr ds:[ecx+ebx],eax         ; kernel32.FreeEnvironmentStringsW
  00418BB4      74 0E           je short EdrTest.00418BC4              ; 注意这个比较,EAX里真实的IAT地址
  00418BB6      83C7 04         add edi,4                              ; 而ds:[ecx+ebx]里是什么呢?
  00418BB9      83C6 04         add esi,4
  00418BBC    ^ EB E8           jmp short EdrTest.00418BA6
  00418BBE      5E              pop esi
  00418BBF      83C6 10         add esi,10
  00418BC2    ^ EB CF           jmp short EdrTest.00418B93
  00418BC4      8B06            mov eax,dword ptr ds:[esi]
  00418BC6      03C3            add eax,ebx
  00418BC8      8945 FC         mov dword ptr ss:[ebp-4],eax
  00418BCB      5E              pop esi
  00418BCC      5E              pop esi
  00418BCD      5F              pop edi
  00418BCE      5B              pop ebx
  00418BCF      8B45 FC         mov eax,dword ptr ss:[ebp-4]
  00418BD2      C9              leave
  00418BD3      C2 0800         retn 8
  

  
  关键在于这个比较了: cmp dword ptr ds:[ecx+ebx],eax
  EAX里真实的IAT地址,而ds:[ecx+ebx]里是什么呢?我们右键跟随,在数据窗口里,我们看到了这些:
  


  004188B9  00000000
  004188BD >7C809BD7  kernel32.CloseHandle
  004188C1 >7C801A28  kernel32.CreateFileA
  004188C5 >7C8106C7  kernel32.CreateThread
  004188C9 >7C831EC5  kernel32.DeleteFileA
  004188CD >7C81CAFA  kernel32.ExitProcess
  004188D1 >7C80C0E8  kernel32.ExitThread
  004188D5 >7C80AC6E  kernel32.FreeLibrary
  004188D9 >7C80DE85  kernel32.GetCurrentProcess
  004188DD >7C8099B0  kernel32.GetCurrentProcessId
  004188E1 >7C80B55F  kernel32.GetModuleFileNameA
  004188E5 >7C80B731  kernel32.GetModuleHandleA
  004188E9 >7C80AE30  kernel32.GetProcAddress
  004188ED >7C861807  kernel32.GetTempFileNameA
  004188F1 >7C835DE2  kernel32.GetTempPathA
  004188F5 >7C812B6E  kernel32.GetVersionExA
  004188F9 >7C801D7B  kernel32.LoadLibraryA
  004188FD >7C801D53  kernel32.LoadLibraryExA
  00418901 >7C8309D1  kernel32.OpenProcess
  00418905 >7C802213  kernel32.WriteProcessMemory
  00418909 >7C809AE1  kernel32.VirtualAlloc
  0041890D >7C809B74  kernel32.VirtualFree
  00418911 >7C810E17  kernel32.WriteFile
  00418915  00000000
  

  
  这里都是要加密的函数了!
  所以我们只需要把这句:00418B96      74 34           je short EdrTest.00418BCC
  改成无条件跳转,跳过就OK了:jmp short EdrTest.00418BCC
  
  好了,我们重新载入程序,直接来到刚刚找到位置,把je改成jmp,然后用ESP快速来到OEP
  然后查看一下IAT:
  


  00407098  7C801EF2  kernel32.GetStartupInfoA
  0040709C  7C812FAD  kernel32.GetCommandLineA
  004070A0  7C81126A  kernel32.GetVersion
  004070A4  7C81CAFA  kernel32.ExitProcess
  004070A8  7C80AE30  kernel32.GetProcAddress
  004070AC  7C801E1A  kernel32.TerminateProcess
  004070B0  7C80DE85  kernel32.GetCurrentProcess
  004070B4  7C863E6A  kernel32.UnhandledExceptionFilter
  

  
  好了,我用LoadPE来Dump出程序,然后修复IAT(有一个无效指针,我们直接CUT掉就行了),一切OK,程序也能跑起来了,呵呵!
  难道就此OVER了??也没见什么捆绑的DLL啊!我发朋友一看,XP SP2的,NO,NO,直接出错~!
  原来是没有DLL,导致跨平台出错!
  所以我们现在就是提取出DLL了,哈,我们再次载入OD,Alt+M打开内存镜像:
  
  
  如图,大家看到了那些区段了吧,呵呵!这个壳很有意思,把DLL的所有区段,连名称都没变,就直接捆绑到主程序的区段里了!
  好了,我们也不先运行了,直接DUMP吧,用LoadPE的部分Dump功能,地址填写:0040B000,大小是C000,大家可以自己累加一下!
  
  然后将DUMP的文件名直接改成DLL名:EdrLib.dll
  这个DLL名,我们可以通过下:bp GetModuleHandleA断点来找到,如下:
  


  0013FF7C   00419196  /CALL 到 GetModuleHandleA 来自 EdrTest.00419190
  0013FF80   00407954  \pModule = "EdrLib.dll"
  

  
  我找了一个需要DLL 的主程序来测试,运行,NO,提示EdrLib.dll无效!看来DLL有修改!
  好了,我们在.pe区段上双击进去,然后指定用PE头的格式来查看,一个个看下去,发现(如图):
  
  
  .text区段的PointerToRawData怎么会是1200??应该是1000啊,因为PE头占了1000字节
  继续往下看:发现.rdata、data、reloc等区段都多了200字节!而且reloc的虚拟地址也不对,多了1000字节!
  
  先不管了,我们把这些修改过来:
  1000、7000、 8000、B000后,再BDUMP一份,测试运行,依然NO!这是为什么??
  想到了.reloc区段的虚拟地址多出了1000,这样我们在Dump时,因为大小是C000,所以没有包含上这个地址!
  用HexWork打开一个,果然,全部是0!
  
  好了,知道原因了,我们先好着手DUMP出DLL了,将上面的值一一修改过来!
  注意.reloc的PointerToRawData是C000,呵呵!不能只简单的改为B000哦!
  
  然后再部分Dump,如图:
  
  
  大小增加了1000字节!
  测试OK了,哈!
  
——————————————————————————–
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年01月30日 20:36:46

附件为目标程序:
PEBundle3.2%E7%9A%84%E9%AB%98%E7%BA%A7%E6%8D%86%E7%BC%9A.rar

发表评论