首页
论坛
课程
招聘
[原创]PE学习笔记-利用C语言实现PE头解析
2022-7-23 17:24 3552

[原创]PE学习笔记-利用C语言实现PE头解析

2022-7-23 17:24
3552

自学了C语言,自己实现LordPE, PeViewer等工具的控制台版本

程序主界面

打印DOS头信息

打印NT头信息

数据目录

打印节区头信息


以下是实现功能的代码,由于是自学,所以可能有些代码对大佬来说会非常奇怪,还请大家多指教。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <conio.h>  //提供getch(),用于无回显输入

void Print_Hex_Data(FILE* fp, unsigned char des[], int n);  //截取二进制数据,会将小端序转换成正常序
void Print_Hex_Char(FILE* fp, unsigned char des[], int n); //截取二进制数据,不会将小端序转换成正常序
void Print_Dos_Header(FILE* fp);	//打印DOS头
void Print_Nt_Header(FILE* fp);	//打印NT头
void Print_Sec_Header(FILE* fp);     //打印节区头
int HtoD(char* str);		//将16进制的字符串数字转换成10进制的整型数字

int main(int argc, char* argv[]) {
	int opt = 0;
	char pe_name[FILENAME_MAX] = { 0 };
next:	puts("请输入PE名:");
	scanf("%s", pe_name);
	getchar();
	FILE* fp = fopen(pe_name, "rb");
	if (fp == NULL)
	{
		perror("打开文件失败");
		exit(0);
	}
	puts("******输入数字选择******");
	puts("*1.DOS头               *");
	puts("*2.NT头                *");
	puts("*3.节区头              *");
	puts("*4.打开另一个PE文件    *");
	puts("*按其他键退出          *");
	puts("************************");
	while (1)
	{
		opt=getch()-48;    //getch()获取的是字符的ASCII码值
		switch (opt)
		{
		case 1:
			Print_Dos_Header(fp);
			break;
		case 2:
			Print_Nt_Header(fp);
			break;
		case 3:
			Print_Sec_Header(fp);
			break;
		case 4:
			goto next;		
		default:
			return 0;
		}

	}
	fclose(fp);
	return 0;
}

int HtoD(char* str)		//将16进制的字符串数字转换成10进制的整形数字
{
	int i = 0;
	int exp = 0;
	int res = 0;
	int temp = 0;
	while (str[i] != '\0') {
		++i;
	}
	exp = i - 1;
	i = 0;
	while (str[i] != '\0') {
		if (str[i] >= '0' && str[i] <= '9')   //'0'-'9'时应刚减去48, '0'的ASCII码值为48(0x30)
		{
			temp = str[i] - 48;
		}
		else 						//'A'-'F'时应减去55, 'A'的ASCII码为65(0x41)
		{
			temp = str[i] - 55;
		}

		res += temp * pow(16, exp);
		exp--;
		i++;
	}
	return res;
}

//将二进制数据转换成可显示的十六进制值, 会将小端序转换成正常顺序
/*
参数说明:fp-文件指针
		des-缓冲区
		n-读取字节数
*/
void Print_Hex_Data(FILE* fp, unsigned char des[], int n) {

	char str[20] = { 0 };
	fread(str, sizeof(char), n, fp);
	int j = 0;
	for (int i = n - 1; i >= 0; i--)     //这里从读取的缓冲最后一个字符开始取,倒序
	{
		unsigned char ch = str[i];
		unsigned char high_ch = ch >> 4;  //取高4位,转换时类型要统一
		unsigned char low_ch = ch & 15; //取低4位,15的二进制数是00001111

		//将数字转成对应的ASCII码值
		if (high_ch < 10) {
			high_ch += 0x30;
		}
		else {
			high_ch += 0x37;
		}
		if (low_ch < 10) {
			low_ch += 0x30;
		}
		else {
			low_ch += 0x37;
		}
		des[j] = high_ch;
		++j;

		des[j] = low_ch;
		++j;

	}
	des[j] = '\0';
}

//将二进制数据转换成可显示的十六进制值, 不会转换字节顺序
void Print_Hex_Char(FILE* fp, unsigned char des[], int n)
{
	char str[20] = { 0 };
	fread(str, sizeof(char), n, fp);

	int j = 0;
	for (int i = 0; i < n; i++)     //顺序读取,不会调整顺序
	{
		unsigned char ch = str[i];
		unsigned char high_ch = ch >> 4;  //取高4位,转换时类型要统一
		unsigned char low_ch = ch & 15; //取低4位,15的二进制数是00001111

		//将数字转成对应的ASCII码值
		if (high_ch < 10) {
			high_ch += 0x30;
		}
		else {
			high_ch += 0x37;
		}
		if (low_ch < 10) {
			low_ch += 0x30;
		}
		else {
			low_ch += 0x37;
		}
		des[j] = high_ch;
		++j;

		des[j] = low_ch;
		++j;

	}
	des[j] = '\0';
}

//打印DOS头信息
void Print_Dos_Header(FILE* fp)
{
	rewind(fp);
	char str[100];

	printf("--DOS头\n");
	puts("   |  ");
	Print_Hex_Char(fp, str, 2);
	printf("   |----0x%.8X---->e_magic(魔数)-->%s\n", 0, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_cblp(文件最后一页字节数)-->%s\n", 2, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_cp(文件页数)-->%s\n", 4, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_crlc(重定位)-->%s\n", 6, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_cparhdr(段中头的大小)-->%s\n", 8, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_minalloc(需要的最少额外段)-->%s\n", 10, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_maxalloc(需要的最多额外段)-->%s\n", 12, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_ss(初始的SS寄存器的值)-->%s\n", 14, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_sp(初始的SP寄存器的值)-->%s\n", 16, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_csum(校验和)-->%s\n", 18, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_ip(初始的IP寄存器的值)-->%s\n", 20, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_cs(初始的CS寄存器的值)-->%s\n", 22, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_lfarlc(重定位表在文件中的地址)-->%s\n", 24, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_ovno(交叠数)-->%s\n", 26, str);
	Print_Hex_Data(fp, str, 8);
	printf("   |----0x%.8X---->e_res[4](保留字)-->%s\n", 28, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_oemid(OEM识别符)-->%s\n", 36, str);
	Print_Hex_Data(fp, str, 2);
	printf("   |----0x%.8X---->e_oeminfo(OEM信息)-->%s\n", 38, str);
	Print_Hex_Data(fp, str, 20);
	printf("   |----0x%.8X---->e_res2[10](O保留字)-->%s\n", 40, str);
	Print_Hex_Data(fp, str, 4);
	printf("   |----0x%.8X---->e_lfanew(NT头起始地址)-->%s\n", 60, str);
	puts("   |  ");
}

//打印NT头
void Print_Nt_Header(FILE* fp)
{
	rewind(fp);
	fseek(fp, 60, SEEK_SET);
	char str[20] = { 0 };
	Print_Hex_Data(fp, str, 4);
	long int nt_begin_offset = 0;

	//将字符串地址,转换成十进制的地址
	nt_begin_offset = HtoD(str);

	fseek(fp, nt_begin_offset, SEEK_SET);
	printf("--NT头\n");
	puts("   |  ");
	Print_Hex_Char(fp, str, 4);
	printf("   |----0x%.8X---->Magic(魔数)-->%s\n", nt_begin_offset, str);

	//文件头
	{
		puts("   |----文件头  ");
		Print_Hex_Char(fp, str, 2);
		printf("   |     |----0x%.8X---->Machine(处理器型号)-->%s\n", nt_begin_offset + 4, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->NumberOfSections(节区数)-->%s\n", nt_begin_offset + 6, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->TimeDateStamp(时间戳)-->%s\n", nt_begin_offset + 10, str);
		Print_Hex_Char(fp, str, 4);
		printf("   |     |----0x%.8X---->PointerToSymbolTable(符号表指针,调试用,一般为0)-->%s\n", nt_begin_offset + 14, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->NumberOfSymbols(符号数,调试用,一般为0)-->%s\n", nt_begin_offset + 18, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->SizeOfOptionalHeader(可选头大小)-->%s\n", nt_begin_offset + 20, str);
		Print_Hex_Char(fp, str, 2);
		printf("   |     |----0x%.8X---->Characteristics(文件属性)-->%s\n", nt_begin_offset + 22, str);
		puts("   |  ");
	}

	//可选头
	puts("   |----可选头  ");
	Print_Hex_Data(fp, str, 2);
	printf("   |     |----0x%.8X---->Magic(魔数,判断32或64位)-->%s\n", nt_begin_offset + 24, str);
	if (!strcmp(str, "010B"))  //打印32位PE文件可选头
	{
		Print_Hex_Data(fp, str, 1);
		printf("   |     |----0x%.8X---->MajorLinkerVersion(链接器主版本号)-->%s\n", nt_begin_offset + 26, str);
		Print_Hex_Data(fp, str, 1);
		printf("   |     |----0x%.8X---->MinorLinkerVersion(链接器次版本号)-->%s\n", nt_begin_offset + 27, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfCode(代码段大小)-->%s\n", nt_begin_offset + 28, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfInitializedData(已初始化的数据大小)-->%s\n", nt_begin_offset + 32, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfUninitializedData(未初始化的数据大小)-->%s\n", nt_begin_offset + 36, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->AddressOfEntryPoint(程序入口点)-->%s\n", nt_begin_offset + 40, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->BaseOfCode(代码地址)-->%s\n", nt_begin_offset + 44, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->BaseOfData(数据地址)-->%s\n", nt_begin_offset + 48, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->ImageBase(映像基址)-->%s\n", nt_begin_offset + 52, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SectionAlignment(内存中单元块的大小)-->%s\n", nt_begin_offset + 56, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->FileAlignment(文件中单元块的大小)-->%s\n", nt_begin_offset + 60, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorOperatingSystemVersion(操作系统主版本号)-->%s\n", nt_begin_offset + 64, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorOperatingSystemVersion(操作系统次版本号)-->%s\n", nt_begin_offset + 66, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorImageVersion(映像文件主版本号)-->%s\n", nt_begin_offset + 68, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorImageVersion(映像文件次版本号)-->%s\n", nt_begin_offset + 70, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorSubsystemVersion(子系统主版本号)-->%s\n", nt_begin_offset + 72, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorSubsystemVersion(子系统次版本号)-->%s\n", nt_begin_offset + 74, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->Win32VersionValue(保留项)-->%s\n", nt_begin_offset + 76, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfImage(映像文件大小)-->%s\n", nt_begin_offset + 80, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfHeaders(所有头大小)-->%s\n", nt_begin_offset + 84, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->CheckSum(校验和)-->%s\n", nt_begin_offset + 88, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->Subsystem(子系统,区分文件类别,1-系统驱动 2-GUI程序 3-CGI程序)-->%s\n", nt_begin_offset + 92, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->DllCharacteristics(DLL特性,已废弃)-->%s\n", nt_begin_offset + 94, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfStackReserves(保留的栈大小)-->%s\n", nt_begin_offset + 96, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfStackCommit(交付使用的栈大小)-->%s\n", nt_begin_offset + 100, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfHeapReserve(保留的堆大小)-->%s\n", nt_begin_offset + 104, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfHeapCommit(交付使用的堆大小)-->%s\n", nt_begin_offset + 108, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->LoaderFlags(加载器标志,已废弃)-->%s\n", nt_begin_offset + 112, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->NumberOfRvaAndSizes(数据目录个数)-->%s\n", nt_begin_offset + 116, str);
	}
	else  		//打印64位PE文件可选头
	{
		Print_Hex_Data(fp, str, 1);
		printf("   |     |----0x%.8X---->MajorLinkerVersion(链接器主版本号)-->%s\n", nt_begin_offset + 26, str);
		Print_Hex_Data(fp, str, 1);
		printf("   |     |----0x%.8X---->MinorLinkerVersion(链接器次版本号)-->%s\n", nt_begin_offset + 27, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfCode(代码段大小)-->%s\n", nt_begin_offset + 28, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfInitializedData(已初始化的数据大小)-->%s\n", nt_begin_offset + 32, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfUninitializedData(未初始化的数据大小)-->%s\n", nt_begin_offset + 36, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->AddressOfEntryPoint(程序入口点)-->%s\n", nt_begin_offset + 40, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->BaseOfCode(代码地址)-->%s\n", nt_begin_offset + 44, str);
		Print_Hex_Data(fp, str, 8);
		printf("   |     |----0x%.8X---->ImageBase(映像基址)-->%s\n", nt_begin_offset + 48, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SectionAlignment(内存中单元块的大小)-->%s\n", nt_begin_offset + 56, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->FileAlignment(文件中单元块的大小)-->%s\n", nt_begin_offset + 60, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorOperatingSystemVersion(操作系统主版本号)-->%s\n", nt_begin_offset + 64, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorOperatingSystemVersion(操作系统次版本号)-->%s\n", nt_begin_offset + 66, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorImageVersion(映像文件主版本号)-->%s\n", nt_begin_offset + 68, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorImageVersion(映像文件次版本号)-->%s\n", nt_begin_offset + 70, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MajorSubsystemVersion(子系统主版本号)-->%s\n", nt_begin_offset + 72, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->MinorSubsystemVersion(子系统次版本号)-->%s\n", nt_begin_offset + 74, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->Win32VersionValue(保留项)-->%s\n", nt_begin_offset + 76, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfImage(映像文件大小)-->%s\n", nt_begin_offset + 80, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->SizeOfHeaders(所有头大小)-->%s\n", nt_begin_offset + 84, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->CheckSum(校验和)-->%s\n", nt_begin_offset + 88, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->Subsystem(子系统,区分文件类别,1-系统驱动 2-GUI程序 3-CGI程序)-->%s\n", nt_begin_offset + 92, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |     |----0x%.8X---->DllCharacteristics(DLL特性,已废弃)-->%s\n", nt_begin_offset + 94, str);
		Print_Hex_Data(fp, str, 8);
		printf("   |     |----0x%.8X---->SizeOfStackReserves(保留的栈大小)-->%s\n", nt_begin_offset + 96, str);
		Print_Hex_Data(fp, str, 8);
		printf("   |     |----0x%.8X---->SizeOfStackCommit(交付使用的栈大小)-->%s\n", nt_begin_offset + 104, str);
		Print_Hex_Data(fp, str, 8);
		printf("   |     |----0x%.8X---->SizeOfHeapReserve(保留的堆大小)-->%s\n", nt_begin_offset + 112, str);
		Print_Hex_Data(fp, str, 8);
		printf("   |     |----0x%.8X---->SizeOfHeapCommit(交付使用的堆大小)-->%s\n", nt_begin_offset + 120, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->LoaderFlags(加载器标志,已废弃)-->%s\n", nt_begin_offset + 128, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |     |----0x%.8X---->NumberOfRvaAndSizes(数据目录个数)-->%s\n", nt_begin_offset + 132, str);
	}

	//数据目录
	{
		int datadirectory_offset = 0;
		fseek(fp, nt_begin_offset + 24, SEEK_SET);
		Print_Hex_Data(fp, str, 2);
		if (!strcmp(str, "010B"))
		{
			datadirectory_offset = nt_begin_offset + 120;  //32位程序数据目录较nt头起始地址偏移120字节
		}
		else {
			datadirectory_offset = nt_begin_offset + 136;  //64位程序数据目录较nt头起始地址偏移136字节
		}

		fseek(fp, datadirectory_offset, SEEK_SET);  //将文件流置于数据目录起始处

		char str_add[20] = { 0 };
		printf("   |     |\n");
		printf("   |     |----数据目录\n");
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->输出表(Export Table)		地址: 0x%s	大小: 0x%s\n", datadirectory_offset, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->输入表(Import Table)		地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 8, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->资源(Resource)		        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 16, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->异常数据(Exception)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 24, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->安全数据(Security)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 32, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->重定位表(Relocation)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 40, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->调试数据(Debug)	                地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 48, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->版权数据(Copyright)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 56, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->全局指针Globalptr)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 64, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->TLS表		      	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 72, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->载入配置(Load Config)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 80, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->绑定输入(Bound Import)            地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 88, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->输入地址表(Import Address Table)  地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 96, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->延迟装入表(Delay Import)	        地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 104, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->COM		                地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 112, str, str_add);
		Print_Hex_Data(fp, str, 4);
		Print_Hex_Data(fp, str_add, 4);
		printf("   |             |---->0x%.8X---->保留字段		                地址: 0x%s	大小: 0x%s\n", datadirectory_offset + 120, str, str_add);
	}

}

//打印节区头
void Print_Sec_Header(FILE* fp)
{
	//确定节区头的偏移量
	int sec_header_offset = 0;
	char str[20] = { 0 };	//先获取NT头偏移量
	fseek(fp, 60, SEEK_SET);
	Print_Hex_Data(fp, str, 4);
	int nt_begin_offset = HtoD(str);

	fseek(fp, nt_begin_offset + 24, SEEK_SET); //获取可选头magic数
	Print_Hex_Data(fp, str, 2);
	if (!strcmp(str, "010B"))
	{
		sec_header_offset = nt_begin_offset + 248; //32位NT头大小为248
	}
	else
	{
		sec_header_offset = nt_begin_offset + 264; //64位NT头大小为264
	}

	//获取节区个数
	fseek(fp, nt_begin_offset + 6, SEEK_SET);   //文件头的第二个最字段(word型)
	Print_Hex_Data(fp, str, 2);
	int section_num = HtoD(str);

	fseek(fp, sec_header_offset, SEEK_SET);  //将文件流置于节区头起始位置

	printf("--节区头\n");


	for (int i = 0; i < section_num; i++)
	{
		puts("   |  ");
		fread(str, sizeof(char), 8, fp);
		printf("   |----0x%.8X---->Name[8](节名):			 %s\n", sec_header_offset * (i + 1), str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->VirtualSize(在内存中的大小):     %s\n", sec_header_offset * (i + 1) + 8, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->VirtualAddress(在内存中的地址):  %s\n", sec_header_offset * (i + 1) + 12, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->SizeOfRawData(在文件中的大小):   %s\n", sec_header_offset * (i + 1) + 16, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->PointerToRawData(在文件中的地址):%s\n", sec_header_offset * (i + 1) + 20, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->PointerToRelocations(重定位指针):%s\n", sec_header_offset * (i + 1) + 24, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->PointerToLinenumbers(行数指针):  %s\n", sec_header_offset * (i + 1) + 28, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |----0x%.8X---->NumberOfRelocations(重定位数目): %s\n", sec_header_offset * (i + 1) + 32, str);
		Print_Hex_Data(fp, str, 2);
		printf("   |----0x%.8X---->NumberOfLinenumbers(行数数目):   %s\n", sec_header_offset * (i + 1) + 34, str);
		Print_Hex_Data(fp, str, 4);
		printf("   |----0x%.8X---->Characteristics(节区属性):       %s\n", sec_header_offset * (i + 1) + 36, str);
	}

}



[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

收藏
点赞0
打赏
分享
最新回复 (1)
雪    币: 59
活跃值: 活跃值 (943)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
HotPower 活跃值 2022-9-2 05:14
2
0
顶一个,学习了
游客
登录 | 注册 方可回帖
返回