union联合体
union TestUnion
{
char x;
int y;
};
1、联合体共享内存空间
2、联合体的内存空间大小是其成员中内存最大成员的大小
3、上图中两个联合体的意义不一样,第一个联合体的类型名是TestUnion;而第二个相当于创建了一个匿名的联合体,这个联合体声明了一个变量,变量名为TestUnion
节表结构
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER{
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //该节的名字
union{
DWORD PhysicalAddress;
DWORD VirtualSize;
}Misc; //该节在内存中对齐前的大小,用到了联合体
DWORD VirtualAddress; //该节在ImageBuffer中的偏移
DWORD SizeOfRawData; //该节在文件中对齐后的大小
DWORD PointerToRawData; //该节在在文件中的偏移
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics; //该节的属性(比如是否可读,是否可写...)
}IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
1.Name:它占8个字节,一般情况下是以"\0"结尾的ASCII码字符串来标识的名称,内容可以修改。存在一种极端情况——当Name是八个字节,那么数组后面不能继续加”\0”,会导致用char*的时候,会一直往后面找,直到找到0为止
2.Misc:双字,该节在没有对齐前的真实尺寸
3.VirtualAddress :节区在内存中的偏移地址,加上ImageBase才是在内存中的真正地址
4.SizeOfRawData : 节在文件中对齐后的尺寸
5.PointerToRawData :节区在文件中的偏移
6.PointerToRelocations:在obj文件中使用,对exe无意义
7.PointerToLinenumbers:行号表的位置,调试时使用
8.NumberOfRelocations:在obj文件中使用,对exe无意义
9.NumberOfLinenumbers:行号表中行号的位置,调试时使用
10.Characteristics: 节的属性
节表的位置
e_lfanew尾部+4字节(NT头的Signature标记)+20字节(标准PE头)+E0字节(32位可选PE头默认大小,64位默认为F0个字节,可修改)
打印节表
下面附上代码
//#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#define FILE_PATH "C:\\Users\\Allure_Love\\Desktop\\notepad.exe"
LPVOID ReadPEFile(LPCSTR lpszFile) //const char[]相当于const char*,LPSTR相当于char*,两者不兼容,所以可以把LPSTR改成LPCSTR
{
FILE *pFile;
DWORD fileSize = 0;
LPVOID pFileBuffer = NULL;
//打开文件
errno_t err;
err = fopen_s(&pFile,lpszFile,"rb"); //"rb"只读
if (!pFile)
{
printf("无法打开.exe文件!");
}
//读取文件大小
fseek(pFile,0,SEEK_END);
//fseek(FILE * stream, long offset, int fromwhere); //函数设置文件指针stream的位置,以fromwhere为基址,偏移offset个字节的位置
fileSize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
//分配缓冲区
pFileBuffer = malloc(fileSize);
if (!pFileBuffer)
{
printf("分配文件失败!");
fclose(pFile); //关闭文件
return NULL;
}
//将文件数据读取到缓冲区
size_t n = fread(pFileBuffer, fileSize, 1, pFile); //size_t无符号整数,sieof()返回的结果类型
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流stream读取nmemb个size大小的数据到ptr所指向的数组中
if (!n)
{
printf("读取数据失败!");
free(pFileBuffer);
fclose(pFile);
return NULL;
}
//关闭文件
fclose(pFile);
return pFileBuffer;
}
void PrintNTHeaders()
{
//初始化
LPVOID pFileBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL; //DOS头指针
PIMAGE_NT_HEADERS pNTHeader = NULL; //NT头指针
PIMAGE_FILE_HEADER pPEHeader = NULL; //标准PE头指针
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL; //可选PE头指针ReadPEFile(FILE_PATH)
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pFileBuffer = ReadPEFile(FILE_PATH);
if (!pFileBuffer)
{
printf("文件读取失败!");
return;
}
if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不是有效的MZ标志!");
free(pFileBuffer); //释放指针内存
return;
}
//打印DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
printf("***************DOS头****************\n");
printf("MZ标志:%x\n",pDosHeader->e_magic);
printf("PE偏移:%x\n", pDosHeader->e_lfanew);
//判断是否是有效的PE标志
if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志!");
free(pFileBuffer);
return;
}
//打印NT头
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
printf("***************NT头****************\n");
printf("NT:%x\n", pNTHeader->Signature);
//打印标准PE头
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
printf("*************标准PE头****************\n");
printf("PE:%x\n", pPEHeader->Machine);
printf("节的数量:%x\n", pPEHeader->NumberOfSections);
printf("可选PE头的大小:%x\n", pPEHeader->SizeOfOptionalHeader);
//打印可选PE头
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeader)+ IMAGE_SIZEOF_FILE_HEADER); //const IMAGE_SIZEOF_FILE_HEADER = 20 标准PE头大小
printf("*************可选PE头****************\n");
printf("Optional_PE:%x\n", pOptionalHeader->Magic);
//打印节表
pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pOptionalHeader)+ pPEHeader->SizeOfOptionalHeader);
char Name[IMAGE_SIZEOF_SHORT_NAME + 1];
//防止Name为8字节时没有存放'\0'的空间
memset(Name, 0, sizeof(Name));
printf("***************节表******************\n");
while (pPEHeader->NumberOfSections--)
{
memcpy(Name, pSectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME);
printf("节表名:%x\n", pSectionHeader->Name);
printf("内存对齐前大小:%x\n", pSectionHeader->Misc);
printf("内存中偏移:%x\n", pSectionHeader->VirtualAddress);
printf("文件对齐前大小:%x\n", pSectionHeader->SizeOfRawData);
printf("文件中偏移:%x\n", pSectionHeader->PointerToRawData);
printf("节表属性:%x\n", pSectionHeader->Characteristics);
pSectionHeader ++;
}
//释放内存
free(pFileBuffer);
}
int main()
{
PrintNTHeaders();
return 0;
}