联合体
1 2 3 4
| union TestUnion { char x; int y; };
|
特点:
- 共享空间:联合体的所有成员共享同一内存空间。
- 内存大小:联合体的大小由最大成员的大小决定。例如,以上例子中,联合体的大小为4字节(
int
类型)。
- 有效性:联合体中最多只有一个成员是有效的,但仍然可以访问所有成员。
1 2 3 4 5 6 7 8 9
| union TestUnion { char x; int y; };
union { char x; int y; } TestUnion;
|
节表(Section Table)
节表是Windows PE/COFF格式可执行文件中的一个重要数据结构,记录了各个代码段、数据段、资源段、重定向表等在文件中的位置和大小信息。操作系统通过节表进行各个段的映射和初始化。
在执行PE文件时,Windows不会立即将整个文件读入内存,而是由PE装载器建立虚拟地址与PE文件之间的映射关系。只有当执行到某个内存页中的指令或访问页中的数据时,才会将该页面从磁盘加载到内存。这种机制极大地节约了内存资源,并使文件的装入速度与文件大小无关。
程序中各种节的位置由节表决定,节表位于可选PE头之后。
找到节表的位置
在标准PE头中,有一个WORD SizeOfOptionalHeader,该值表示可选PE头的大小,32位文件的默认值为E0h,64位PE文件的默认值为F0h,大小可以自定义。因此,节表的内存地址为:
在标准PE头中,有一个WORD NumberOfSections,表示文件中存在的节的种数的数量。如果需要新增或合并节,必须修改此值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; };
|
- Name:段名,8字节的ASCII字符串,不足8字节用0补齐。
- VirtualSize:虚拟大小,标识节在内存中占用的大小,请勿与
PhysicalSize
(物理大小)混淆。此字段存储该节在未对齐时的真实尺寸,该值可能不准确(在内存中拉伸后的实际大小)。
- VirtualAddress:虚拟地址,标识节在内存中的偏移地址,实际加载的位置与此相关(节在内存中的偏移地址加上
ImageBase
即为在内存中的真实地址)。
- SizeOfRawData:物理大小,节在PE文件中占用的大小,若不足文件对齐单位则会进行填充(对齐后的长度)。
- PointerToRawData:物理地址,标识该段在文件中的偏移位置。
- PointerToRelocations:重定向表的偏移位置。
- PointerToLinenumbers:行号表的偏移位置。
- NumberOfRelocations:重定向表的数量。
- NumberOfLinenumbers:行号表的数量。
- Characteristics:标识该段的各种属性信息,包括常用属性:
IMAGE_SCN_MEM_READ
:可读;
IMAGE_SCN_MEM_WRITE
:可写;
IMAGE_SCN_MEM_EXECUTE
:可执行;
IMAGE_SCN_CNT_CODE
:代码段;
IMAGE_SCN_CNT_INITIALIZED_DATA
:已初始化数据段;
IMAGE_SCN_CNT_UNINITIALIZED_DATA
:未初始化数据段;
IMAGE_SCN_LNK_INFO
:包含附加信息。
Work
实例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
#include <iostream> #include <windows.h> #include <malloc.h>
char* ReadFilePe(const char* peFileName) { FILE* peFile = nullptr; fopen_s(&peFile, peFileName, "rb"); size_t peSize = NULL; char* peData = nullptr; if (peFile != NULL) { if (fseek(peFile, 0, SEEK_END) == 0) { peSize = ftell(peFile); fseek(peFile, 0, SEEK_SET); peData = (char*)malloc(peSize); if (peData != nullptr) { memset(peData, '\0', peSize); fread_s(peData, peSize, 1, peSize, peFile); } else { printf("申请内存空间失败!(%d)\n", __LINE__); } } else { printf("指针移动到数据末尾失败!(%d)\n", __LINE__); } } else { printf("文件打开失败!(%d)\n", __LINE__); }
if (peFile) fclose(peFile);
return peData; }
void printSectionTable(const char* peFileName) { char* peData = ReadFilePe(peFileName); char* tempData = peData; if (peData == nullptr) { printf("获取数据失败!"); return; }
WORD(*wp)[1]; wp = (WORD(*)[1])peData; DWORD(*dp)[1]; dp = (DWORD(*)[1])peData;
size_t docSize = 60; size_t fileSize = 20; size_t lfanew = *(*(dp) +15); size_t OptionalSize = *(*(wp)+(lfanew / 2) + 10); size_t NumberOfSection = *(*(wp)+(lfanew / 2) + 3);
tempData = &tempData[lfanew + 4]; tempData = &tempData[20]; tempData = &tempData[OptionalSize]; PIMAGE_SECTION_HEADER tempSectionHeader = nullptr; for (size_t i = 0; i < NumberOfSection; i++) { tempSectionHeader = (PIMAGE_SECTION_HEADER)tempData; tempData = &tempData[40]; printf(">>>>>>>>>> 节表:%d <<<<<<<<<<<\n", i); printf("Name = %s\n", tempSectionHeader->Name); printf("Misc = %x\n", tempSectionHeader->Misc.VirtualSize); printf("VirtualAddress = %x\n", tempSectionHeader->VirtualAddress); printf("SizeOfRawData = %x\n", tempSectionHeader->SizeOfRawData); printf("PointerToRawData = %x\n", tempSectionHeader->PointerToRawData); printf("PointerToRelocations = %x\n", tempSectionHeader->PointerToRelocations); printf("PointerToLinenumbers = %x\n", tempSectionHeader->PointerToLinenumbers); printf("NumberOfRelocations = %x\n", tempSectionHeader->NumberOfRelocations); printf("NumberOfLinenumbers = %x\n", tempSectionHeader->NumberOfLinenumbers); printf("Characteristics = %x\n", tempSectionHeader->Characteristics); }
free(peData); }
int main() { printSectionTable("C:\\Windows\\System32\\notepad.exe"); getchar(); return 0; }
|
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| >>>>>>>>>> 节表:0 <<<<<<<<<<< Name = .text Misc = 27900 VirtualAddress = 1000 SizeOfRawData = 27a00 PointerToRawData = 400 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = 60000020 >>>>>>>>>> 节表:1 <<<<<<<<<<< Name = .data Misc = 1ee0 VirtualAddress = 29000 SizeOfRawData = a00 PointerToRawData = 27e00 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = c0000040 >>>>>>>>>> 节表:2 <<<<<<<<<<< Name = .idata Misc = 2c7a VirtualAddress = 2b000 SizeOfRawData = 2e00 PointerToRawData = 28800 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = 40000040 >>>>>>>>>> 节表:3 <<<<<<<<<<< Name = .didat Misc = 7c VirtualAddress = 2e000 SizeOfRawData = 200 PointerToRawData = 2b600 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = c0000040 >>>>>>>>>> 节表:4 <<<<<<<<<<< Name = .rsrc Misc = 1e1d0 VirtualAddress = 2f000 SizeOfRawData = 1e200 PointerToRawData = 2b800 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = 40000040 >>>>>>>>>> 节表:5 <<<<<<<<<<< Name = .reloc Misc = 25b0 VirtualAddress = 4e000 SizeOfRawData = 2600 PointerToRawData = 49a00 PointerToRelocations = 0 PointerToLinenumbers = 0 NumberOfRelocations = 0 NumberOfLinenumbers = 0 Characteristics = 42000040
|