首页
社区
课程
招聘
[原创]提取嵌入文件中的 PE 文件
发表于: 2010-11-29 17:12 21784

[原创]提取嵌入文件中的 PE 文件

2010-11-29 17:12
21784
有时候会遇到某些程序把整个 PE 文件(就像整个 .exe, .dll, .sys, ...)嵌入到数据段中,在需要的时候才释放出来。
要提取这类程序中的文件,只有动态调试或者手工静态提取。

Exeinfo 本身带有提取功能,但是它的提取方法是找到一个有效的文件头之后就从文件头一直提取到整个文件的末尾。
这样虽然拨出了萝卜,但是带出了不少泥。

只好自己动手写一个程序了。
原理:
标准的 PE 文件结构是:Dos头|PE头|区段表|区段1,区段2,区段3,...
这样要提取出完整的文件,就是从Dos头开始,一直到最后一个区段的末尾。
思路:
先把目标文件映射到内存,获取文件在内存中的指针,遍历整个文件内容。
把所有疑似 PE 文件的内容都保存出来。

相关代码如下:

把文件映射到内存之后,通过内存指针来判断是否是一个 PE 文件,通过简单的判断 DOS 头和 PE 头来确定。

[font=Comic Sans MS][color=#008000]// 是否疑似 PE 文件?
[/color][/font][font=Fixedsys][color=#000000]BOOL IsPeLike[/color][color=#000080]([/color][color=#000000]LPVOID lpImageBase[/color][color=#000080])
{
    [/color][color=#000000]PIMAGE_DOS_HEADER    pDosHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_NT_HEADERS    pNtHeader[/color][color=#000080];

    [/color][color=#000000]pDosHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_DOS_HEADER[/color][color=#000080])[/color][color=#000000]lpImageBase[/color][color=#000080];
    
    [/color][color=#0000FF]if [/color][color=#000080]([/color][color=#000000]IMAGE_DOS_SIGNATURE [/color][color=#000080]!= [/color][color=#000000]pDosHeader[/color][color=#000080]->[/color][color=#000000]e_magic[/color][color=#000080])    [/color][color=#0000FF]return    [/color][color=#000000]FALSE[/color][color=#000080];

    [/color][color=#000000]pNtHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_NT_HEADERS[/color][color=#000080])(([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]pDosHeader [/color][color=#000080]+ [/color][color=#000000]pDosHeader[/color][color=#000080]->[/color][color=#000000]e_lfanew[/color][color=#000080]);
    [/color][/font][font=Comic Sans MS][color=#008000]// 如果偏移落在结构体范围之外,说明数据是错误的。跳过。
    [/color][/font][font=Fixedsys][color=#0000FF]if[/color][color=#000080](([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]pDosHeader[/color][color=#000080]->[/color][color=#000000]e_lfanew [/color][color=#000080]> (([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]lpImageBase [/color][color=#000080]+ [/color][color=#0000FF]sizeof[/color][color=#000080]([/color][color=#000000]IMAGE_DOS_HEADER[/color][color=#000080]) + [/color][color=#0000FF]sizeof[/color][color=#000080]([/color][color=#000000]IMAGE_NT_HEADERS[/color][color=#000080])))    [/color][color=#0000FF]return    [/color][color=#000000]FALSE[/color][color=#000080];
    [/color][color=#0000FF]if [/color][color=#000080](([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]pNtHeader [/color][color=#000080]> (([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]lpImageBase [/color][color=#000080]+ [/color][color=#0000FF]sizeof[/color][color=#000080]([/color][color=#000000]IMAGE_DOS_HEADER[/color][color=#000080]) + [/color][color=#0000FF]sizeof[/color][color=#000080]([/color][color=#000000]IMAGE_NT_HEADERS[/color][color=#000080])))    [/color][color=#0000FF]return    [/color][color=#000000]FALSE[/color][color=#000080];

    [/color][color=#0000FF]if [/color][color=#000080]([/color][color=#000000]IMAGE_NT_SIGNATURE [/color][color=#000080]!= [/color][color=#000000]pNtHeader[/color][color=#000080]->[/color][color=#000000]Signature[/color][color=#000080])    [/color][color=#0000FF]return    [/color][color=#000000]FALSE[/color][color=#000080];

    [/color][color=#0000FF]return    [/color][color=#000000]TRUE[/color][color=#000080];
}[/color][/font]


如果通过判断,那么说明找到的数据可能是一个 PE 文件,接下来获取这个文件的真实大小,真实大小是从 DOS 头开始,直到最后一个区段末尾的总大小,不包含附加数据。

[font=Comic Sans MS][color=#008000]// 获取 PE 文件真实大小
[/color][/font][font=Fixedsys][color=#000000]DWORD WINAPI GetRealSize[/color][color=#000080]([/color][color=#000000]LPVOID    lpImageBase[/color][color=#000080])
{
    [/color][color=#000000]PIMAGE_DOS_HEADER    pDosHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_NT_HEADERS    pNtHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_FILE_HEADER    pFileHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_SECTION_HEADER    pSectionHeader[/color][color=#000080];

    [/color][color=#000000]pDosHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_DOS_HEADER[/color][color=#000080])[/color][color=#000000]lpImageBase[/color][color=#000080];
    [/color][color=#000000]pNtHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_NT_HEADERS[/color][color=#000080])(([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]pDosHeader [/color][color=#000080]+ [/color][color=#000000]pDosHeader[/color][color=#000080]->[/color][color=#000000]e_lfanew[/color][color=#000080]);
    [/color][color=#000000]pSectionHeader    [/color][color=#000080]=    [/color][color=#000000]IMAGE_FIRST_SECTION[/color][color=#000080]([/color][color=#000000]pNtHeader[/color][color=#000080]);
    [/color][color=#000000]pFileHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_FILE_HEADER[/color][color=#000080])&[/color][color=#000000]pNtHeader[/color][color=#000080]->[/color][color=#000000]FileHeader[/color][color=#000080];
    [/color][color=#000000]pSectionHeader    [/color][color=#000080]+=    ([/color][color=#000000]pFileHeader[/color][color=#000080]->[/color][color=#000000]NumberOfSections [/color][color=#000080]- [/color][color=#800080]1[/color][color=#000080]);    [/color][/font][font=Comic Sans MS][color=#008000]//定位到最后一个区块表的开头

    [/color][/font][font=Fixedsys][color=#0000FF]return [/color][color=#000080]([/color][color=#000000]pSectionHeader[/color][color=#000080]->[/color][color=#000000]PointerToRawData [/color][color=#000080]+ [/color][color=#000000]pSectionHeader[/color][color=#000080]->[/color][color=#000000]SizeOfRawData[/color][color=#000080]); [/color][/font][font=Comic Sans MS][color=#008000]// 文件实际大小 = 文件结尾偏移 = 最后一个区段的磁盘偏移 + 最后一个区段的磁盘大小

[/color][/font][font=Fixedsys][color=#000080]}[/color][/font]


在保存到磁盘之前先判断一下 PE 的类型,根据判断结果来决定文件的扩展名,如果不能确定类型,则默认为.bin。
[color=#000000]LPTSTR    WINAPI GetRealType[/color][color=#000080]([/color][color=#000000]LPVOID lpImageBase[/color][color=#000080])
{
    [/color][color=#000000]PIMAGE_DOS_HEADER    pDosHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_NT_HEADERS    pNtHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_FILE_HEADER    pFileHeader[/color][color=#000080];
    [/color][color=#000000]PIMAGE_OPTIONAL_HEADER    pOptionalHeader[/color][color=#000080];

    [/color][color=#000000]pDosHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_DOS_HEADER[/color][color=#000080])[/color][color=#000000]lpImageBase[/color][color=#000080];
    [/color][color=#000000]pNtHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_NT_HEADERS[/color][color=#000080])(([/color][color=#000000]DWORD[/color][color=#000080])[/color][color=#000000]pDosHeader [/color][color=#000080]+ [/color][color=#000000]pDosHeader[/color][color=#000080]->[/color][color=#000000]e_lfanew[/color][color=#000080]);
    [/color][color=#000000]pFileHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_FILE_HEADER[/color][color=#000080])&[/color][color=#000000]pNtHeader[/color][color=#000080]->[/color][color=#000000]FileHeader[/color][color=#000080];
    [/color][color=#000000]pOptionalHeader    [/color][color=#000080]=    ([/color][color=#000000]PIMAGE_OPTIONAL_HEADER[/color][color=#000080])&[/color][color=#000000]pNtHeader[/color][color=#000080]->[/color][color=#000000]OptionalHeader[/color][color=#000080];
    
    [/color][/font][font=Comic Sans MS][color=#008000]// 判断映像类型
    [/color][/font][font=Fixedsys][color=#0000FF]if [/color][color=#000080]([/color][color=#000000]IMAGE_FILE_DLL [/color][color=#000080]& [/color][color=#000000]pFileHeader[/color][color=#000080]->[/color][color=#000000]Characteristics[/color][color=#000080])    [/color][color=#0000FF]return    [/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]".dll"[/color][color=#000080]);
    [/color][color=#0000FF]if [/color][color=#000080](([/color][color=#000000]IMAGE_FILE_EXECUTABLE_IMAGE [/color][color=#000080]& [/color][color=#000000]pFileHeader[/color][color=#000080]->[/color][color=#000000]Characteristics[/color][color=#000080]) && ([/color][color=#000000]IMAGE_SUBSYSTEM_NATIVE [/color][color=#000080]& [/color][color=#000000]pOptionalHeader[/color][color=#000080]->[/color][color=#000000]Subsystem[/color][color=#000080]))    [/color][color=#0000FF]return    [/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]".sys"[/color][color=#000080]);
    [/color][color=#0000FF]if [/color][color=#000080]([/color][color=#000000]IMAGE_FILE_EXECUTABLE_IMAGE [/color][color=#000080]& [/color][color=#000000]pFileHeader[/color][color=#000080]->[/color][color=#000000]Characteristics[/color][color=#000080])    [/color][color=#0000FF]return    [/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]".exe"[/color][color=#000080]);

    [/color][color=#0000FF]return    [/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]".bin"[/color][color=#000080]); [/color][/font][font=Comic Sans MS][color=#008000]//默认返回后缀 .bin
[/color][/font][font=Fixedsys][color=#000080]}[/color][/font]

剩下的工作就是遍历文件内容了,我使用的是效率最低的逐字节遍历,所以只能对付小文件。
[font=Fixedsys][color=#000000]    [/color][color=#0000FF]for [/color][color=#000080]([/color][color=#000000]DWORD dwPos [/color][color=#000080]= [/color][color=#800080]0[/color][color=#000080]; [/color][color=#000000]dwPos [/color][color=#000080]< [/color][color=#000000]dwFileSize[/color][color=#000080]; [/color][color=#000000]dwPos[/color][color=#000080]++, [/color][color=#000000]lpByte[/color][color=#000080]++)
    {
        [/color][color=#0000FF]if [/color][color=#000080](![/color][color=#000000]IsPeLike[/color][color=#000080]([/color][color=#000000]lpByte[/color][color=#000080]) || ([/color][color=#000000]dwPos [/color][color=#000080]== [/color][color=#800080]0[/color][color=#000080]))    [/color][color=#0000FF]continue[/color][color=#000080];
        
        [/color][color=#000000]dwRealSize    [/color][color=#000080]=    [/color][color=#000000]GetRealSize[/color][color=#000080]([/color][color=#000000]lpByte[/color][color=#000080]);
        [/color][color=#000000]csFileToSave[/color][color=#000080].[/color][color=#000000]Format[/color][color=#000080]([/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]"%s_~0x%08X%s"[/color][color=#000080]),[/color][color=#000000]m_csFile[/color][color=#000080], [/color][color=#000000]dwPos[/color][color=#000080], [/color][color=#000000]GetRealType[/color][color=#000080]([/color][color=#000000]lpByte[/color][color=#000080])); [/color][/font][font=Comic Sans MS][color=#008000]// 以在文件中的偏移地址为文件名称
        [/color][/font][font=Fixedsys][color=#000000]hFile    [/color][color=#000080]=    [/color][color=#000000]CreateFile[/color][color=#000080]([/color][color=#000000]csFileToSave[/color][color=#000080].[/color][color=#000000]GetBuffer[/color][color=#000080]([/color][color=#000000]MAX_PATH[/color][color=#000080]), [/color][color=#000000]GENERIC_WRITE[/color][color=#000080], [/color][color=#000000]FILE_SHARE_READ[/color][color=#000080], [/color][color=#000000]NULL[/color][color=#000080], [/color][color=#000000]CREATE_ALWAYS[/color][color=#000080], [/color][color=#000000]FILE_ATTRIBUTE_NORMAL[/color][color=#000080], [/color][color=#000000]NULL[/color][color=#000080]);
        [/color][color=#000000]csFileToSave[/color][color=#000080].[/color][color=#000000]ReleaseBuffer[/color][color=#000080]();

        [/color][color=#0000FF]if [/color][color=#000080]([/color][color=#000000]INVALID_HANDLE_VALUE [/color][color=#000080]== [/color][color=#000000]hFile[/color][color=#000080])    [/color][color=#0000FF]continue[/color][color=#000080];

        [/color][color=#000000]WriteFile[/color][color=#000080]([/color][color=#000000]hFile[/color][color=#000080], [/color][color=#000000]lpByte[/color][color=#000080], [/color][color=#000000]dwRealSize[/color][color=#000080], &[/color][color=#000000]dwWrited[/color][color=#000080], [/color][color=#000000]NULL[/color][color=#000080]);
        [/color][color=#000000]CloseHandle[/color][color=#000080]([/color][color=#000000]hFile[/color][color=#000080]);
        [/color][color=#000000]bFound    [/color][color=#000080]=    [/color][color=#000000]TRUE[/color][color=#000080];
        ++[/color][color=#000000]dwCounter[/color][color=#000080];
        [/color][color=#000000]csTmp[/color][color=#000080].[/color][color=#000000]Format[/color][color=#000080]([/color][color=#000000]_T[/color][color=#000080]([/color][color=#808080]"文件名称:%s\r\n文件偏移:0x%08X (%d)\r\n文件大小:%d (字节)\r\n"[/color][color=#000080]), [/color][color=#000000]csFileToSave[/color][color=#000080], [/color][color=#000000]dwPos[/color][color=#000080], [/color][color=#000000]dwPos[/color][color=#000080], [/color][color=#000000]dwRealSize[/color][color=#000080]);
        [/color][color=#000000]csLog    [/color][color=#000080]+=    [/color][color=#000000]csTmp[/color][color=#000080];
    }[/color][/font]


附件是我写的演示程序,用于演示提取和写入文件。

附上效果图:
XueTr 0.37

SOD 0.35


*有些程序加密了PE头,或采用压缩的方法存储,对于这类程序是没办法的。
*添加拖放功能,方便测试。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 7
支持
分享
最新回复 (34)
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错
很 强大 的
搬个沙发坐着 玩玩啦
2010-11-29 17:39
0
雪    币: 412
活跃值: (30)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
多谢分享。。。
2010-11-29 21:13
0
雪    币: 291
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持一下~呵呵  不错~
2010-11-29 21:21
0
雪    币: 191
活跃值: (335)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
5
只要萝卜,不要泥.
2010-11-29 21:33
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
6
现在大多数那啥里的包含的pe文件都会把dosheader的放在其他地方存在~
2010-11-30 00:07
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我下下来怎么没有可执行程序啊,也没有源码啊,楼主是否能共享下
2010-11-30 17:28
0
雪    币: 149
活跃值: (126)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
这贴也解决了我不少疑惑。
2010-11-30 19:42
0
雪    币: 291
活跃值: (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
干坏事的好东东
2010-11-30 20:36
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
10
谢谢分享~~
2010-11-30 20:40
0
雪    币: 1149
活跃值: (833)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
11
学习了。。。。。。
2010-12-1 02:36
0
雪    币: 7992
活跃值: (2566)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
学习了.好文章..谢谢分享.
2010-12-1 08:59
0
雪    币: 95
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
学习.....
2010-12-1 10:45
0
雪    币: 72
活跃值: (52)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
谢谢分享  打把dota 一会慢慢欣赏
2010-12-1 12:26
0
雪    币: 303
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
又见PE  支持LZ好文。
2010-12-1 14:16
0
雪    币: 45
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
good article thanks
2010-12-2 08:17
0
雪    币: 384
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
强人啊 学习 谢谢分享
2010-12-2 16:06
0
雪    币: 57
活跃值: (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
有个地方不明白,还请大大解释下:

在判断疑似PE文件时,下面这一句没搞明白……
if ((DWORD)pNtHeader > ((DWORD)lpImageBase + sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS)))    return    FALSE;

IMAGE_DOS_HEADER与IMAGE_NT_HEADERS之间不是还有个DOS STUB吗?如果将DOS STUB调的很大,它也是满足这个条件的,但还是一个pe呀……
2010-12-2 17:23
0
雪    币: 411
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
非常感谢,很不错的文章。
2010-12-2 19:53
0
雪    币: 289
活跃值: (67)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
学习中..............................
2010-12-2 22:33
0
雪    币: 40
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
如果嵌入的PE是加密过的,就只有动态调试的时候dump出来了...
2010-12-3 14:33
0
雪    币: 534
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
学习了 谢谢楼主发帖
2010-12-3 15:57
0
雪    币: 242
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
好文齐分享~
2010-12-3 20:35
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
24
这个值不是很靠谱,一般的软件都是只显示一条消息。
2010-12-3 20:52
0
雪    币: 301
活跃值: (300)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
25
收藏,感谢
2010-12-4 07:40
0
游客
登录 | 注册 方可回帖
返回
//