您的位置:首页 > 编程语言 > C语言/C++

PE文件之旅(C语言描述) -- 第一篇 Sections

2005-03-26 17:23 316 查看
无论是作为一名或者立志成为一名拥有真正技术的Top Cracker(当然我是属于后者啦,哈),对PE文件格式的熟悉绝对是必须要研究通透和掌握的技术,这一点相信应该没有什么争议吧(当然如果不研究Windows平台下解密那就另说了)?看过网上好多的PE文件教程,理论居多,只是看好象都明白,到了应用的时候,比如脱壳,对于IAT表在脑海中仍然是稀里糊涂一片(呵呵,至少我是这样D,菜啊~), 学习就是这样,只是学习原理,而没有去实践,好象是懂了,到真正去做的时候,却不知道从何下手。尤其是计算机这门实践性很强的学科,必须要辅以实践才能真正把知识学到手。这里要感谢 MengLong[DFCG],他的<>从编程实践的角度剖析PE文件格式,同时也让我有了研究下去的想法。
好了,罗嗦了这么多,忘了说了,纯属菜鸟教程,让高手贻笑大方了。

PE文件之旅(C语言描述) -- 第一篇 Sections

平台 : windows XP SP1
编译器 : VC++6.0
时间 : 2004.12 -- 2005.01
参考资料: 看雪<<加密解密II>>,MengLong[DFCG]<>,<>.
Coded by: prince
E-mail : Cracker_prince@163.com

注意:这篇教程直接从Sections开始讲解,前面的知识和代码请参阅<>.以下列出的仅是核心部分代码,完整代码见后续篇幅。

首先请大家直观地看一下PE文件格局。这也是PE文件存放在磁盘上的格局。

offset 0 -------------------------------
| IMAGE_DOS_HEADER | <-- Dos部首
PE Signature ------------------------------- /
| 'PE',0,0 | <-- PE文件标志 |
------------------------------- |
| IMAGE_FILE_HEADER | <-- 映像文件头 | -- IMAGE_NT_HEADERS
------------------------------- |
| IMAGE_OPTIONAL_HEADER32 | <-- 映像可选头 |
------------------------------- /
------------| Section Table | <-- 节表 -- IMAGE_SECTION_HEADER (Array)
| | | | | -------------------------------
| | | | /-->| .text | <-- 代码区段
| | | | -------------------------------
| | | /---->| .data | <-- 数据区段
| | | -------------------------------
| | /------>| .idata | <-- 输入表
| | -------------------------------
| /-------->| .edata | <-- 输出表
| -------------------------------
/---------->| .reloc | <-- 重定位表区段
-------------------------------
| .... |
-------------------------------
| 调试信息 |
-------------------------------

我们由IMAGE_DOS_HEADER.e_lfanew得到PE文件头在PE文件中的偏移,即IMAGE_NT_HEADERS结构,如下:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; **PE文件标识 "PE",0,0
IMAGE_FILE_HEADER FileHeader; **映像文件头 (其中的NumberOfSections成员指定了Sections的个数)
IMAGE_OPTIONAL_HEADER32 OptionalHeader; **映像可选头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

核心代码:

IMAGE_DOS_HEADER myDosHeader;
LONG e_lfanew;
FILE *pFile;
pFile = fopen("文件路径", r+b);

fread(&myDosHeader, sizeof(IMAGE_DOS_HEADER), 1, pFile); // pFile 为打开的文件指针
e_lfanew = myDosHeader.e_lfanew; // 保存PE文件头偏移

IMAGE_FILE_HEADER myFileHeader;
int nSectionCount;

fseek(pFile, (e_lfanew + sizeof(DWORD)), SEEK_SET);
fread(&myFileHeader, sizeof(IMAGE_FILE_HEADER), 1, pFile);
nSectionCount = myFileHeader.NumberOfSections; // 保存Section个数

// 过了IMAGE_NT_HEADERS结构就是IMAGE_SECTION_HEADER结构数组了,注意是结构数组,有几个Section该结构就有几个元素
// 这里动态开辟NumberOfSections个内存来存储不同的Section信息
IMAGE_SECTION_HEADER *pmySectionHeader = (IMAGE_SECTION_HEADER *)calloc(nSectionCount, sizeof(IMAGE_SECTION_HEADER));
fseek(pFile, (e_lfanew + sizeof(IMAGE_NT_HEADERS)), SEEK_SET);
fread(pmySectionHeader, sizeof(IMAGE_SECTION_HEADER), nSectionCount, pFile);

// 打印Sections信息
for (int i = 0; i < nSectionCount; i++, pmySectionHeader++)
{
printf("Name: %s/n", pmySectionHeader->Name);
printf("union_PhysicalAddress: %08x/n", pmySectionHeader->Misc.PhysicalAddress);
printf("union_VirtualSize: %04x/n", pmySectionHeader->Misc.VirtualSize);
printf("VirtualAddress: %08x/n", pmySectionHeader->VirtualAddress);
printf("SizeOfRawData: %08x/n", pmySectionHeader->SizeOfRawData);
printf("PointerToRawData: %04x/n", pmySectionHeader->PointerToRawData);
printf("PointerToRelocations: %04x/n", pmySectionHeader->PointerToRelocations);
printf("PointerToLinenumbers: %04x/n", pmySectionHeader->PointerToLinenumbers);
printf("NumberOfRelocations: %04x/n", pmySectionHeader->NumberOfRelocations);
printf("NumberOfLinenumbers: %04x/n", pmySectionHeader->NumberOfLinenumbers);
printf("Charateristics: %04x/n", pmySectionHeader->Characteristics);
}

// 恢复指针
pmySectionHeader -= m_nSectionCount;

if (pmySectionHeader != NULL) // 释放内存
{
free(pmySectionHeader);
pmySectionHeader = NULL;
}

// 最后不要忘记关闭文件
fclose(pFile);

我将以上代码改写了一个Win32程序,可以很方便地查看PE文件的Section信息。本人菜鸟,错误及不妥之处难免存在,如果大家发现有什么问题,不要吝啬啊,请告之。那么关于PE文件格式Section的C语言描述到此就结束了,下一篇将继续我们的PE文件研究,DLL的秘密 -- 输出表。

prince 2005.01.06
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: