iawen 发表于 2009-1-30 20:48

PEBundle3.2的高级捆缚分析

【文章标题】: PEBundle3.2的高级捆缚分析
【文章作者】: iawen
【作者主页】: www.iawen.com
【软件名称】: 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 00000000mov eax,dword ptr fs:
00401564      50            push eax
00401565      64:8925 0000000>mov dword ptr fs:,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:,esp
00401575      FF15 A0704000   call dword ptr ds:             ; kernel32.GetVersion
我们先看一下IAT,在00401575上,右键--数据窗口跟随--内存地址,发现有IAT加密:
004070987C801EF2kernel32.GetStartupInfoA
0040709C00419377EdrTest.00419377================加密了的
004070A07C81126Akernel32.GetVersion
004070A400419501EdrTest.00419501================加密了的
004070A800418F79EdrTest.00418F79================加密了的
004070AC7C801E1Akernel32.TerminateProcess
004070B07C80DE85kernel32.GetCurrentProcess
我们重新载入程序,下断:hr 0040709C,然后F9运行,中断在了:
00418E14      8B19            mov ebx,dword ptr ds:
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:,ebx
00418E3B      53            push ebx
00418E3C      FFB5 BA214000   push dword ptr ss:
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:
00418E4E    ^ EB C4         jmp short EdrTest.00418E14=========中断在这里了,呵呵
这是一个循环,我们耐心的单步,单步这里:
00418E3C      FFB5 BA214000   push dword ptr ss:         ; 这里是DLL的基址
00418E42      E8 32010000   call EdrTest.00418F79
我们发现dword ptr ss:里加载的是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:
00418F91      3945 08         cmp dword ptr ss:,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:
00418F9E      FF75 08         push dword ptr ss:
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:
00418FB6      FF75 08         push dword ptr ss:            ; 这里加载函数名
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:
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:,0
00418B90      8B75 08         mov esi,dword ptr ss:
00418B93      833E 00         cmp dword ptr ds:,0
00418B96      74 34         je short EdrTest.00418BCC
00418B98      56            push esi
00418B99      8B7E 08         mov edi,dword ptr ds:
00418B9C      03FB            add edi,ebx
00418B9E      8B76 0C         mov esi,dword ptr ds:
00418BA1      03F3            add esi,ebx
00418BA3      8B45 0C         mov eax,dword ptr ss:
00418BA6      833F FF         cmp dword ptr ds:,-1
00418BA9      74 13         je short EdrTest.00418BBE
00418BAB      8B0F            mov ecx,dword ptr ds:
00418BAD      85C9            test ecx,ecx
00418BAF      74 05         je short EdrTest.00418BB6
00418BB1      390419          cmp dword ptr ds:,eax         ; kernel32.FreeEnvironmentStringsW
00418BB4      74 0E         je short EdrTest.00418BC4            ; 注意这个比较,EAX里真实的IAT地址
00418BB6      83C7 04         add edi,4                              ; 而ds:里是什么呢?
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:
00418BC6      03C3            add eax,ebx
00418BC8      8945 FC         mov dword ptr ss:,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:
00418BD2      C9            leave
00418BD3      C2 0800         retn 8
关键在于这个比较了: cmp dword ptr ds:,eax
EAX里真实的IAT地址,而ds:里是什么呢?我们右键跟随,在数据窗口里,我们看到了这些:
004188B900000000
004188BD >7C809BD7kernel32.CloseHandle
004188C1 >7C801A28kernel32.CreateFileA
004188C5 >7C8106C7kernel32.CreateThread
004188C9 >7C831EC5kernel32.DeleteFileA
004188CD >7C81CAFAkernel32.ExitProcess
004188D1 >7C80C0E8kernel32.ExitThread
004188D5 >7C80AC6Ekernel32.FreeLibrary
004188D9 >7C80DE85kernel32.GetCurrentProcess
004188DD >7C8099B0kernel32.GetCurrentProcessId
004188E1 >7C80B55Fkernel32.GetModuleFileNameA
004188E5 >7C80B731kernel32.GetModuleHandleA
004188E9 >7C80AE30kernel32.GetProcAddress
004188ED >7C861807kernel32.GetTempFileNameA
004188F1 >7C835DE2kernel32.GetTempPathA
004188F5 >7C812B6Ekernel32.GetVersionExA
004188F9 >7C801D7Bkernel32.LoadLibraryA
004188FD >7C801D53kernel32.LoadLibraryExA
00418901 >7C8309D1kernel32.OpenProcess
00418905 >7C802213kernel32.WriteProcessMemory
00418909 >7C809AE1kernel32.VirtualAlloc
0041890D >7C809B74kernel32.VirtualFree
00418911 >7C810E17kernel32.WriteFile
0041891500000000
这里都是要加密的函数了!
所以我们只需要把这句:00418B96      74 34         je short EdrTest.00418BCC
改成无条件跳转,跳过就OK了:jmp short EdrTest.00418BCC

好了,我们重新载入程序,直接来到刚刚找到位置,把je改成jmp,然后用ESP快速来到OEP
然后查看一下IAT:
004070987C801EF2kernel32.GetStartupInfoA
0040709C7C812FADkernel32.GetCommandLineA
004070A07C81126Akernel32.GetVersion
004070A47C81CAFAkernel32.ExitProcess
004070A87C80AE30kernel32.GetProcAddress
004070AC7C801E1Akernel32.TerminateProcess
004070B07C80DE85kernel32.GetCurrentProcess
004070B47C863E6Akernel32.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

ximo 发表于 2009-1-30 21:39

dump下0040B000,大小为D000的文件后,保存为dll
然后把最后一个区段的Roffset的值加1000,也就是C200,保存
然后,由于偏移的值为200,所以在0x1000前插入0x200字节的00值,保存后,同样OK!

wgz001 发表于 2009-1-30 21:49

膜拜大牛好好学习    :D

iawen 发表于 2009-1-30 21:59

原帖由 ximo 于 2009-1-30 21:39 发表 http://www.52pojie.cn/images/common/back.gif
dump下0040B000,大小为D000的文件后,保存为dll
然后把最后一个区段的Roffset的值加1000,也就是C200,保存
然后,由于偏移的值为200,所以在0x1000前插入0x200字节的00值,保存后,同样OK!

感觉这样都不是很好,不能还原到原DLL一样!

到DLL的text段下断,再DUMP,然后手工复制relox数据覆盖到DUMP下来的0xB000后的1000字节,再修改那4个指针,能完美再现原版DLL!

zapline 发表于 2009-1-30 22:04

不懂
顶了再说
向大牛学习

xie83544109 发表于 2009-1-30 23:37

学习中
多谢分享:lol

决战破解 发表于 2009-1-31 00:22

高呀!!!要向LZ学习

小生我怕怕 发表于 2009-1-31 01:55

支持老鸦的文章!

天骄 发表于 2009-1-31 03:06

实在是强!!!谢谢!!!

fyll 发表于 2009-1-31 06:50

没怎么看明白。。。。究极新手。。。。
   呵呵。偶要好好学习天天向上。:lol
页: [1] 2 3 4
查看完整版本: PEBundle3.2的高级捆缚分析