一、节表
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //ASCII字符串 可自定义 只截取8个 可以8个字节都是名字
union { //Misc 双字 是该节在没有对齐前的真实尺寸,该值可以不准确
DWORD PhysicalAddress; //内存中的真实长度,这两个值是一个联合结构,可以使用其中的任何一个
DWORD VirtualSize; //一般是取后一个
} Misc;
DWORD VirtualAddress; //在内存中的偏移地址,加上ImageBase才是在内存中的真正地址
DWORD SizeOfRawData; //节在文件中对齐后的尺寸
DWORD PointerToRawData; //节区在文件中的偏移
DWORD PointerToRelocations; //调试相关
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics; //节的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
SizeOfRawData 和 联合体VirtualSize的值 的关系
联合体的大小可能大于 SizeOfRawData 。可能等于 也可能小于
没有初始化的变量在文件中是不分配内存的 ,如果没有初始化的全局变量特别多的话,联合体的值可能会比SizeOfRawData大,他们谁大 按谁的来
二、VirtualSize
如图是在硬盘中的节,A到B这段的真实长度
三、VirtualAddress
如图是在内存中的节,ImageBase到A这段长度是在内存中的偏移
四、SizeOfRawData
如图是在硬盘中的节,绿色部分就是节在文件中对齐后的大小
五、PointerToRawData
如图是在硬盘中的节,0到A这段的长度是节在文件中的偏移
六、Characteristics
七、节表个数
1、有几个节表,就有几个节
2、节表个数存储在标准PE头第二个成员中,WORD NumberOfSections;
八、打印节表
#include "stdafx.h"
#include <windows.h>
#include "stdlib.h"
#include "stdio.h"
#define FILEPATH_IN "C:/notepad.exe"
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer )
{
FILE *pFile = NULL;
DWORD fileSize = 0; //文件大小
LPVOID pTempFileBuffer = NULL; //缓冲区首地址
pFile = fopen(lpszFile,"rb"); //打开文件
if(!pFile)
{
printf("打开文件失败");
return NULL;
}
//读取文件大小
fseek(pFile,0,SEEK_END); //将指针从开始的位置移动到末尾
fileSize = ftell(pFile); //获取数据大小
//分配缓冲区(申请内存)
pTempFileBuffer = malloc(fileSize);
if(!pTempFileBuffer)
{
printf("分配空间失败");
fclose(pFile);
return NULL;
}
//将文件数据读取到缓冲区
fseek(pFile,0,SEEK_SET); //将指针指向开始
size_t n = fread(pTempFileBuffer,fileSize,1,pFile); //将数据读取到缓冲区中
if(!n)
{
printf("读取数据失败");
free(pTempFileBuffer); //释放内存
pTempFileBuffer = NULL;
fclose(pFile); //关闭文件
return NULL;
}
//关闭文件
*pFileBuffer = pTempFileBuffer;
pTempFileBuffer = NULL;
fclose(pFile); //关闭文件
return fileSize;
}
VOID Test()
{
DWORD Size = 0; //用来接收数据大小
LPVOID pFileBuffer = NULL; //用来接收缓冲区的首地址
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//File-> FileBuffer
Size = ReadPEFile(FILEPATH_IN,&pFileBuffer); //调用函数读取文件数据
if(!pFileBuffer || !Size)
{
printf("File-> FileBuffer失败");
return;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//判断 是否是PE标志
if(*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
free(pFileBuffer);
pFileBuffer = NULL;
return;
}
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x4);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
for(int i=0;i<pPEHeader->NumberOfSections;i++,pSectionHeader++)
{
printf("第%d个节的名字:%s\n",i+1,pSectionHeader->Name);
printf("第%d个节在内存中的真实长度:%x\n",i+1,pSectionHeader->Misc);
printf("第%d个节在内存中的偏移地址:%x\n",i+1,pSectionHeader->VirtualAddress);
printf("第%d个节在文件中对齐后的尺寸:%x\n",i+1,pSectionHeader->SizeOfRawData);
printf("第%d个节在文件中的偏移:%x\n",i+1,pSectionHeader->PointerToRawData);
printf("第%d个节属性:%x\n",i+1,pSectionHeader->Characteristics);
}
//释放内存
free(pFileBuffer);
pFileBuffer = NULL;
}
int main(int argc, char* argv[])
{
Test();
getchar();
return 0;
}