WinUnpack 0.39 Final的分析和手动脱壳[分析]
压缩软件WinUnpack 0.39 Final的特点是:压缩率高,无保护功能。由于其压缩率比较高,被一些病毒程序编写者青睐;但正因为其无保护功能,所以相对来讲,比较好脱壳。程序的下载地址可至http://www.PEArmor.com
下面,我们以WinRAR.exe V3.71为对象进行分析。未压缩前的原文件表示为A,大小为915KB,压缩后的文件表示为B,大小为370KB。在下文中PA表示物理地址,RVA表示相对虚拟地址,AVA表示绝对虚拟地址,地址值均用十六进制表示。
WinUnpack对于文件头部的处理,显示出程序作者对于PE格式和windows装载机制深刻的理解。在此对程序作者表示敬意。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 4D 5A 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 00 MZKERNEL32.DLL..
00000010 50 45 00 00 4C 01 03 00 BE B0 11 40 00 AD 50 FF PE..L...景.@.璓
00000020 76 34 EB 7C 48 01 0F 01 0B 01 4C 6F 61 64 4C 69 v4雦H.....LoadLi
00000030 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 braryA..........
00000040 00 40 0A 00 00 00 40 00 00 10 00 00 00 02 00 00 .@....@.........
00000050 04 00 00 00 00 00 39 00 04 00 00 00 00 00 00 00 ......9.........
00000060 00 F0 18 00 00 02 00 00 00 00 00 00 02 00 00 00 .?.............
00000070 00 00 10 00 00 20 00 00 00 00 10 00 00 10 00 00 ..... ..........
00000080 00 00 00 00 0A 00 00 00 F1 61 18 00 5F 00 00 00 ........馻.._...
00000090 EE E1 18 00 14 00 00 00 00 A0 12 00 0A 5F 00 00 钺.......?.._..
000000A0 FF 76 38 AD 50 8B 3E BE F0 E0 58 00 6A 27 59 F3 v8璓?攫郮.j'Y?
000000B0 A5 FF 76 04 83 C8 FF 8B DF AB EB 1C 00 00 00 00 ?v.內嬤.....
000000C0 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 GetProcAddress..
000000D0 D9 61 18 00 18 00 00 00 40 AB 40 B1 04 F3 AB C1 賏......@獲?螳?
000000E0 E0 0A B5 1C F3 AB 8B 7E 0C 57 51 E9 DB 51 18 00 ??螳媬.WQ檑Q..
000000F0 56 10 E2 E3 B1 04 D3 E0 03 E8 8D 53 18 33 C0 55 V.忏?余.鑽S.3繳
00000100 40 51 D3 E0 8B EA 91 FF 56 4C 99 59 D1 E8 13 D2 @Q余嬯?VL橸谚.?
00000110 E2 FA 5D 03 EA 45 59 89 6B 08 56 8B F7 2B F5 F3 恸].闑Y塳.V嬿+躞
00000120 A4 AC 5E B1 80 AA 3B 7E 34 0F 82 AC FE FF FF 58 が^眬?~4.偓?X
00000130 5F 59 E3 1B 8A 07 47 04 18 3C 02 73 F7 8B 07 3C _Y??G..<.s鲖.<
00000140 11 75 F3 B0 00 0F C8 03 46 38 2B C7 AB E2 E5 5E .u蟀..?F8+谦忮^
00000150 5D 59 46 AD 85 C0 74 1F 51 56 97 FF D1 93 AC 84 ]YF瓍纓.QV?褤瑒
00000160 C0 75 FB 38 06 74 EA 8B C6 79 05 46 33 C0 66 AD 纔?.t陭苰.F3纅?
00000170 50 53 FF D5 AB EB E7 C3 00 90 12 00 00 10 00 00 PS斋腌??.....
00000180 F0 01 00 00 10 00 00 00 0A FF 52 00 83 62 58 00 ?.......R.僢X.
00000190 C6 51 00 00 60 00 00 E0 00 10 40 00 B8 62 58 00 芉..`..?.@.竍X.
000001A0 00 40 06 00 00 A0 12 00 E0 C3 05 00 00 02 00 00 .@...?.嗝......
000001B0 00 10 40 00 FF 7F 52 00 E0 63 58 00 60 00 00 E0 ..@.R.郼X.`..?
000001C0 9F 97 52 00 FC 0F 40 00 00 10 00 00 00 E0 18 00 煑R.?@......?.
000001D0 F0 01 00 00 10 00 00 00 50 62 58 00 53 62 58 00 ?......PbX.SbX.
000001E0 62 62 58 00 60 00 00 E0 28 00 00 00 BE 00 00 00 bbX.`..?...?..
000001F0 00 00 00 00 00 00 00 00 00 00 02 00 00 00 E8 11 ..............?
图(1)B文件的前200个字节
在Windows下,DOS EXE Stub对于PE文件的执行并无用处,有意义的只限于两处:PA00-01处的标记e_magic和PA3c-3f处、指向NT头的指针e_lfanew。B中的e_lfanew指向位于PA0010处的IMAGE_NT_HEADER。这就是说,经winunpack压缩的程序,IMAGE_NT_HEADER覆盖在DOS EXE Stub上,已经不再可能在DOS下运行、打印出一个出错信息。
同理,IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER中有一些域对于程序的运行没有多大用处,可以另作它用。比如B中SizeOfCode, SizeOfInitializedData, SizeOfUninitializedData被用来存放函数字符串“LoadLibraryA”。
继续前行,0170-01E7处是三个节头,每一个节头占0x28个字节。
VA Size PA Size
0x00001000 0x00129000 0x00000010 0x000001F0
0x0012A000 0x00064000 0x00000200 0x0005C3E0
0x0018E000 0x00001000 0x00000010 0x000001F0
图(2)
Windows在按照节头加载节时,会按照FileAlignment(B为200)和SectionAlignment(B为1000)将这些值进行调整。
RVA Size PA Size
0x00001000 0x00129000 0x00000000 0x00000200
0x0012A000 0x00064000 0x00000200 0x0005C400
0x0018E000 0x00001000 0x00000000 0x00000200
图(3)
如果你在压缩时没有选择“清除输出表”,输出数据目录会和原程序A相同,没有更改。输入数据目录位于PA 0x01EE-0x01FF处,在文件中实际只有0x12个字节,还有两个字节在哪里?因为Windows加载时会用零初始化没有文件数据映射的内存,所以后两个字节值为0x0000,位于用零初始化的内存AVA 0x0018E200-0x0018E201。
00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 E8 11
->
00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 E8 11 00 00
总结一下,前200个字节的文件头。
0000 - 0001 e_magic
0002 - 000E 字符串"kernel32.dll"
0010 - 0013 IMAGE_NT_SIGANATURE
0014 - 0027 IMAGE_FILE_HEADER,有意义、可信的域有Machine(0x014C), NumberOfSections(03), SizeOfOptionalHeader(0x0148), Characteristics(0x010F)
0018 - 0023 B的入口点
0028 - 016F IMAGE_OPTIONAL_HEADER,有意义、可信的域有Magic(0x010B), AddressOfEntryPoint(0x00001018), ImageBase(0x00400000), SectionAlignment(0x00001000), FileAlignment(0x00000200), MajorOperatingSystemVersion(0x0004), MinorOperatingSystemVersion(0x0000), MajorSubsystemVersion(0x0004), MinorSubsystemVersion(0x0000), Win32VersionValue(0x0000), SizeOfImage(随着程序大小的不同而变化), SizeOfHeaders(0x00000200), Subsystem
002A - 0037 字符串"LoadLibraryA"
0170 - 01E7 三个节头
VA Size PA Size
? ? 0x00000010 0x000001F0
? ? 0x00000200 SizeB-0x0200
? ? 0x00000010 0x000001F0
注I.?表示可变量,其它量为固定值;II.SizeB表示B文件的大小
01E8 - 01F3 FirstThunk
01EE - 01FF 输入数据目录,有意义、可信的域有Name(0x0020), FirstThunk(0x11E8)
输入两个函数两个:kernel32!GetProcAddress, kernel32!LoadLibraryA
现在开始分析程序体,从入口点开始。解压缩部分大致分为:入栈,初始化,解压缩,修补Call调用,加载输入函数。
入口点处,先后入栈的三个数依次是:OEP, LoadLibraryA()指针, GetAddress()指针。
注意哦!OEP是最先入栈的。
PS______:00401018 mov esi, offset OEP
PS______:0040101D lodsd
PS______:0040101E push eax ; OEP
PS______:0040101F push dword ptr [esi+34h] ; LoadLibraryA()指针
PS______:00401022 jmp short loc_4010A0
PS______:004010A0 push dword ptr [esi+38h] ; GetAddress()指针
用0xFFFFFFFF, 0x00000000, 0x00000001初始化某些内存段,然后进入解压缩循环。下面是解压缩循环完成后的代码段。
00586415 loc_586415: ; CODE XREF: start:loc_58631E j
00586415 stosb
00586416 cmp edi, [esi+34h] ; [esi+34h]是解压缩循环结束时应该到达的地址
00586419 jb loc_5862CB
; 解压缩循环结束处,修补call调用开始处
0058641F pop eax
00586420 pop edi ; 起址
00586421 pop ecx ; 修补的次数
00586422 jecxz short loc_58643F
00586424
00586424 FixCall:
00586424 mov al, [edi]
00586426 inc edi
00586427 add al, 18h
00586429 cmp al, 2
0058642B jnb short FixCall
0058642D mov eax, [edi]
0058642F cmp al, 11h
00586431 jnz short loc_586426
00586433 mov al, 0
00586435 bswap eax
00586437 add eax, [esi+38h]
0058643A sub eax, edi
0058643C stosd
0058643D loop FixCall
; 修补Call调用结束,加载输入函数开始
0058643F pop esi ; esi
00586440 pop ebp ; ebp - GetProcAddress()函数指针出栈
00586441 pop ecx ; ecx - LoadLibraryA()函数指针出栈
00586442 inc esi
00586443 lodsd ; eax - FirstThunk
00586444 test eax, eax
00586446 jz short locret_586467
00586448 push ecx
00586449 push esi ; DLL Name
0058644A xchg eax, edi ; edi - FirstThunk
0058644B call ecx
0058644D xchg eax, ebx ; ebx – DLL Handle
0058644E
0058644E loc_58644E: ; CODE XREF: seg018:00586451 j seg018:00586465 j
0058644E lodsb
0058644F test al, al
00586451 jnz short loc_58644E
00586453 cmp [esi], al
00586455 jz short loc_586441
00586457 mov eax, esi
00586459 jns short loc_586460
0058645B inc esi ; 以顺序号,不是以函数名引用DLL函数时
0058645C xor eax, eax
0058645E lodsw
00586460
00586460 loc_586460: ; CODE XREF: seg018:00586459 j
00586460 push eax
00586461 push ebx
00586462 call ebp
00586464 stosd
00586465 jmp short loc_58644E
00586467 retn ; 返回OEP
[手工脱壳]
因为B是动态解压缩,所以不能直接在返回点处下断点,你可以在开头0x00401018下断点,然后在FixCall代码段之前下断点,返回处下断点。最后程序中断到此处0x00586467。转储:打开WinHex,起址为0x00400000,大小为0x0018F000,终址为0x0058EFFF,保存。
修复文件头。重建DOS EXE Stub,可以以下面的这个为模板。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ?..........
00000010 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ?......@.......
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 88 00 00 00 ............?..
00000040 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ..?.???L?Th
00000050 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno
00000060 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS
00000070 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......
00000080 00 00 00 00 00 00 00 00 50 45 00 00 00 00 00 00 ........PE......
依上图所示从PA 000088开始重建IMAGE_NT_HEADER,以B的文件头为模板,可信的域不变,不可信的域清零。IMAGE_OPTIONAL_HEADER中可信的域中需要修改的有:AddressOfEntryPoint设为0x401000(从B中获得的OEP),FileAlignment改成和SectionAlignment一样,SizeOfHeaders改为0x001000,其它多处不一一赘述。改完的文件头,如下图所示。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ?..........
00000010 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ?......@.......
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 88 00 00 00 ............?..
00000040 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ..?.???L?Th
00000050 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno
00000060 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS
00000070 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......
00000080 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 03 00 ........PE..L...
00000090 00 00 00 00 00 00 00 00 00 00 00 00 48 01 0F 01 ............H...
000000A0 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000000B0 00 10 00 00 00 00 00 00 00 00 00 00 00 00 40 00 ..............@.
000000C0 00 10 00 00 00 10 00 00 04 00 00 00 00 00 00 00 ................
000000D0 04 00 00 00 00 00 00 00 00 30 19 00 00 10 00 00 .........0......
000000E0 00 00 00 00 02 00 00 00 00 00 10 00 00 20 00 00 ............. ..
000000F0 00 00 10 00 00 10 00 00 00 00 00 00 0A 00 00 00 ................
00000100 F1 61 18 00 5F 00 00 00 00 E0 18 00 00 50 00 00 馻.._....?..P..
00000110 00 A0 12 00 0A 5F 00 00 00 00 00 00 00 00 00 00 .?.._..........
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000140 00 00 00 00 00 00 00 00 D9 61 18 00 18 00 00 00 ........賏......
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001E0 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00 ........1.......
000001F0 00 90 12 00 00 10 00 00 00 90 12 00 00 10 00 00 .?......?.....
00000200 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 E0 ............`..?
00000210 32 00 00 00 00 00 00 00 00 40 06 00 00 A0 12 00 2........@...?.
00000220 00 40 06 00 00 A0 12 00 00 00 00 00 00 00 00 00 .@...?.........
00000230 00 00 00 00 60 00 00 E0 33 00 00 00 00 00 00 00 ....`..?.......
00000240 00 50 00 00 00 E0 18 00 00 50 00 00 00 E0 18 00 .P...?..P...?.
00000250 00 00 00 00 00 00 00 00 00 00 00 00 60 00 00 E0 ............`..?
00000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
输出目录和资源目录,winunpack在压缩时都没有改动。为了方便修改输入目录,我将最后一个节由1000扩大为5000,空间足够了。下图是完整的输入目录
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
0018E000 00 00 00 00 00 00 00 00 00 00 00 00 00 E6 18 00 .............?.
0018E010 04 21 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 .!..............
0018E020 80 E8 18 00 D8 23 0F 00 00 00 00 00 00 00 00 00 €?.?..........
0018E030 00 00 00 00 A0 FC 18 00 88 26 0F 00 00 00 00 00 ....狘..?......
0018E040 00 00 00 00 00 00 00 00 00 FE 18 00 CC 26 0F 00 .........?.?..
0018E050 00 00 00 00 00 00 00 00 00 00 00 00 C0 FE 18 00 ............俐..
0018E060 64 27 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 d'..............
0018E070 C0 02 19 00 2C 28 0F 00 00 00 00 00 00 00 00 00 ?..,(..........
0018E080 00 00 00 00 00 05 19 00 D4 2A 0F 00 00 00 00 00 ........?......
0018E090 00 00 00 00 00 00 00 00 00 18 19 00 4C 2D 0F 00 ............L-..
0018E0A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
图
下图是部分advapi32.dll的函数名字表。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
0018E600 41 44 56 41 50 49 33 32 2E 44 4C 4C 00 00 00 00 ADVAPI32.DLL....
0018E610 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0018E620 00 00 41 64 6A 75 73 74 54 6F 6B 65 6E 50 72 69 ..AdjustTokenPri
0018E630 76 69 6C 65 67 65 73 00 00 00 00 00 00 00 00 00 vileges.........
0018E640 00 00 47 65 74 46 69 6C 65 53 65 63 75 72 69 74 ..GetFileSecurit
0018E650 79 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 yA..............
0018E660 00 00 47 65 74 46 69 6C 65 53 65 63 75 72 69 74 ..GetFileSecurit
0018E670 79 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 yW..............
0018E680 00 00 47 65 74 53 65 63 75 72 69 74 79 44 65 73 ..GetSecurityDes
0018E690 63 72 69 70 74 6F 72 4C 65 6E 67 74 68 00 00 00 criptorLength...
0018E6A0 00 00 4C 6F 6F 6B 75 70 50 72 69 76 69 6C 65 67 ..LookupPrivileg
0018E6B0 65 56 61 6C 75 65 41 00 00 00 00 00 00 00 00 00 eValueA.........
在修复完数据目录后,程序便可以正常运行了。不想弄些什么按多少多少次到哪里,知道了程序里代码段都是干什么的,自然知道断点在哪里下。
Enjoy it. By TNTTOOLS
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法