滴水逆向第三期-节表

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值