节表( IMAGE_SECTION_HEADER )
作用:描述PE文件与内存之间的映射关系,说明PE文件的指定内容拷贝至内存的哪个位置、拷贝大小及内存属性的设置。
一个结构体总大小: 0x 28 (40) 字节
节表位置: 置于选项头之后,位置 = 选项头( IMAGE_OPTIONAL_HEADER) 的地址 + 选项头( IMAGE_OPTIONAL_HEADER)的大小。
// IMAGE_SECTION_HEADER 节表结构体,大小40B
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称:描述性字段 2个字节, 这个段写了区段名字(.text .rdata ....),但是系统不承认这个名字,名字随便改
// 重要的是内存属性 不是名字, 调试器查看内存有区段显示,是从这里获取的
// 下方4个字段:从文件S1处开始,拷贝S2大小的数据,到内存S3处,有效数据占用内存S4大小
union {
DWORD PhysicalAddress;
DWORD VirtualSize; // S4:在内存中的大小
} Misc;
DWORD VirtualAddress; // S3:内存地址:基于模块基址,与SectionAlignment对齐(0x1000)
DWORD SizeOfRawData; // S2:文件大小(从文件中取SizeOfRawData字节到VirtualAddress地址),与FileAlignment对齐(0x200)
DWORD PointerToRawData; // S1:文件偏移,与FileAlignment对齐(0x200)
//跟调试相关
DWORD PointerToRelocations; // 无用
DWORD PointerToLinenumbers; // 无用
WORD NumberOfRelocations; // 无用
WORD NumberOfLinenumbers; // 无用
DWORD Characteristics; // 节内存属性(可读 可写 可执行),取值IMAGE_SCN_...系列宏 分低位和高位
//32位: inter芯片 无法让一个内存不可读 无法让一段代码不可执行 芯片手册有这个表
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
把节表放到内存里的过程:
开头:从开头0到选项头的字段SizeOfHeaders(0x400),映射到这段内存 400000h ~ 00401000, 把节表也放进去了,节表就在内存里了;
检测总大小:遍历内存,内存里拿到节表,先把所有节的文件大小加起来(算的对齐值),判断是否超过选项头的SizeOfImage ,如果够了,开始映射
检测连续性:malloc申请地址 010Editor上看到没有数据,显示都是0,为什么? OS申请内存会初始化为0 是定义了一个未初始化的数据区 410000h ~ 00411000,
每个节的内存必须是连续的,否则系统拒绝加载
表搬到内存: 从PE的SizeOfHeaders(0x400)到PE的节表SizeOfRawData(56000) 搬到
0~SizeOfHeaders 400000h ~ 00401000
XXXX 00401000h ~ 00411000
400~5200 00411000 ~00417000
节在文件中是连续的,在内存中不是连续的(因为对齐的原因)
验证一下映射的流程:
ImageBase = 00400000
0x0000 – 0x0200 => 00400000 = 00401000 文件头映射
0x0200 – 0x0400 => 00401000 = 00402000 遍历节表,从0x0200开始,第一个表SizeOfRawData是200h,内存地址保持连续
0x0400 – 0x0600 => 00402000 = 00403000
0x0600 – 0x0800 => 00403000 = 004040000x0200 – 0x0400 => 00401000 = 00402000
这个映射关系不对应,内存中前面多了一些东西,是全局变量,全局变量被修改了
常量区也能改,修改节表属性Characteristics
010Editor的脚本, myPE.BT
typedef UINT64 ULONGLONG;
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic <format=hex,fgcolor=cRed> ; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew <format=hex,fgcolor=cRed>; // File address of new exe header
} IMAGE_DOS_HEADER;
//枚举 需要加上类型 写上具体的数字大小
enum <ushort> FILE_MACHINE {
IMAGE_FILE_MACHINE_UNKNOWN=0,
IMAGE_FILE_MACHINE_I386=0x014c,
IMAGE_FILE_MACHINE_AMD64=0x8664
};
enum <ushort> OPTIONAL_MACHINE {
IMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b,
IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b,
IMAGE_ROM_OPTIONAL_HDR_MAGIC=0x107
};
typedef struct _IMAGE_FILE_HEADER {
FILE_MACHINE Machine <format=hex,fgcolor=cRed>;
WORD NumberOfSections <format=hex,fgcolor=cRed>;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader <format=hex,fgcolor=cRed>;
WORD Characteristics <format=hex,fgcolor=cRed>;
} IMAGE_FILE_HEADER;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
OPTIONAL_MACHINE Magic <format=hex,fgcolor=cRed>;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint <format=hex,fgcolor=cRed>;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase <format=hex,fgcolor=cRed>;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER64 {
OPTIONAL_MACHINE Magic <format=hex,fgcolor=cRed>;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint <format=hex,fgcolor=cRed>;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
local WORD Magic = ReadShort(FTell()); // 往后读两个字节
if (Magic == 0x10b)
{
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}
else if (Magic == 0x20b)
{
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
}
} IMAGE_NT_HEADERS;
#define IMAGE_SIZEOF_SHORT_NAME 8
//使用位段的方式来表示,更加清晰
typedef struct
{
DWORD res:28;
DWORD IMAGE_SCN_MEM_SHARED:1;
DWORD IMAGE_SCN_MEM_EXECUTE:1;
DWORD IMAGE_SCN_MEM_READ:1;
DWORD IMAGE_SCN_MEM_WRITE:1;
}IMAGE_SCN_MEM;
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
DWORD VirtualSize;
DWORD VirtualAddress <format=hex,fgcolor=cRed>;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
if(PointerToRawData!=0)
{
local int old = FTell();
FSeek(PointerToRawData);
char data[SizeOfRawData];
FSeek(old);
}
} IMAGE_SECTION_HEADER <read=ShowSectionName>;
string ShowSectionName(IMAGE_SECTION_HEADER& s)
{
local string msg;
local char buf[10] = {0};
SPrintf(buf,"%8s",s.Name);
msg = buf;
msg += " ";
if (s.Characteristics & 0x10000000)
msg += "S";
if (s.Characteristics & 0x20000000)
msg += "E";
if (s.Characteristics & 0x40000000)
msg += "R";
if (s.Characteristics & 0x80000000)
msg += "W";
return msg;
}
IsLittleEndian();
IMAGE_DOS_HEADER DosHeader;
char DosStub[DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER)];
IMAGE_NT_HEADERS NtHeader;
IMAGE_SECTION_HEADER SectionHeades[NtHeader.FileHeader.NumberOfSections]; // 从文件头拿到节的数量