Detailed analysis of PE head

Detailed analysis of PE head

0x00 Preface

Recently, when I was studying Linux PWN and reading the book "self cultivation of programmers (loading - > link - > Library)", I came into contact with executable file formats, COFF, ELF and PE. Therefore, I also found the PE course in the video "dripping water reverse phase III" by Bilibili Shanghai East teacher. I just finished the PE class. Taking a note here can also be regarded as sorting out the learning results and sharing them with you for common learning. If there are mistakes, you are welcome to correct them.

0x01 PE file introduction

PE files are executable files on Windows. They are programs that can be run by double clicking the mouse. Of course, there are programs that can't be run by double clicking. Among them. exe,. dll,. sys are PE files, so readers may have a question. Can I double-click the. txt file to open and run it directly? Emmmmm... In fact, it is loaded and opened with Notepad Notepad, while the PE executable is loaded and run by the system.

PE files are stored in blocks. In the figure, we can see that the data will be different after being loaded into memory. When the PE file is loaded into memory (equivalent to a stretching process), the data is elongated.

However, the data in the block is still the same. We can see that the first fast is the data of PE header, followed by the data of other blocks such as section table, which will be introduced in subsequent articles.

0x02 detailed analysis of PE head

PE is mainly composed of three parts, (1), DOS head (2), NT head (standard PE head, Optional PE head).

Reference figure: (PE format figure on OpenRCE.org website. pdf)

DOS header parsing

The data in DOS header is as follows. The data marked with * is the more important data. The size of DOS header is 64 bytes.

//-->DOS header (_image_dos_header)<--
struct _IMAGE_DOS_HEADER
{
	WORD  e_magic;   //*DOS Magic number*
	WORD  e_cblp;    //[Bytes on last page]
	WORD  e_cp;      //[Pages in file]
	WORD  e_crlc;    //[Relocations]
	WORD  e_cparhdr; //[Size of header]
	WORD  e_minalloc;//[Minium memory]
	WORD  e_maxalloc;//[Maxium Memory]
	WORD  e_ss;      //[Inital SS value]
	WORD  e_sp;      //[Inital SP value]
	WORD  e_csum;    //[Checksum]
	WORD  e_ip;      //[Inital IP value]
	WORD  e_cs;      //[Inital CS value]
	WORD  e_lfarlc;  //[Table offset]
	WORD  e_ovno;    //[Overlay number]
	WORD  e_res[4];  //[Reserved words]
	WORD  e_oemid;   //[OEM id]
	WORD  e_oeminfo; //[OEM infomation]
	WORD  e_res2[10];//[Reserved words]
	DWORD e_lfanew;  //*NT header address*
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

NT header parsing

NT header is mainly composed of 3 parts, including mark, standard PE header and Optional PE header. The magic number of NT header is the PE string, as shown in the figure above.

//-->NT headers (_image_nt_headers)<--
struct _IMAGE_NT_HREADERS
{
	DWORD Signature;//*NT head magic number
	_IMAGE_FILE_HEADER FileHeader;//Standard PE head
	_IMAGE_OPTIONAL_HEADER OptionalHeader;//Optional PE head
}IMAGE_NT_HREADERS,*PIMAGE_NT_HREADERS;

Standard PE header parsing

The fixed size of the flag PE header is 20 bytes, in which we can see the data of the number of sections.

Another focus is the timestamp, which we can use in the article https://www.cnblogs.com/17bdw/p/6412158.html The method in is converted to the file creation time.

Finally, we should also pay attention to the feature data, because it can be used to judge many feature information of PE files, such as whether they are DLL files, whether relocation information has been removed, whether they are system files, etc.

//-->Standard PE header (_image_file_header)<--
struct _IMAGE_FILE_HEADER
{
	WORD Machine;//*Operation platform
	WORD NumberOfSections;//*Number of sections
	DWORD TimeDateStamp;//*Time stamp
	DWORD PointerToSymbolTable;//[Pointer to COFF]
	DWORD NumberOfSymbols;//[COFF table size]
	WORD SizeOfOptionalHeader;//*Optional PE head size
	WORD Characteristics;//*Characteristics
}IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;

Optional PE header parsing

Optional PE head structure

//-->Optional PE header (_image_optional_header)<--
struct _IMAGE_OPTIONAL_HEADER
{
	WORD Magic;//[Optional PE head magic number]
	BYTE MajorLinkerVersion;//[Master linker version]
	BYTE MinorLinkerVersion;//[sub linker version]
	DWORD SizeOfCode;//[code segment size]
	DWORD SizeOfInitializedData;//[initialize data size]
	DWORD SizeOfUninitializedData;//[uninitialized data size]
	DWORD AddressOfEntryPoint;//*[program entry point]
	DWORD BaseOfCode;//*[code snippet address]
	DWORD BaseOfData;//*[segment address]
	DWORD ImageBase;// *[start address of loading into memory] - > generally seems to be 0x400000
	DWORD SectionAlignment;//*[memory page size]
	DWORD FileAlignment;//[file size]
	WORD MajorOperatingSystemVersion;//*[major version number of operating system]
	WORD MinjorOperatingSystemVersion;//*[minor version number of operating system]
	WORD MajorImageVersion;//[program major version number]
	WORD MinorImageVersion;//[program minor version number]
	WORD MajorSubsystemVersion;//[subsystem major version number]
	WORD MinorSubsystemVersion;//[subsystem minor version number]
	DWORD Win32VersionValue;//[default reserved]
	DWORD SizeOfImage;//*[size loaded into memory image]
	DWORD SizeOfHeaders;//[DOS header PE header combination size]
	DWORD CheckSum;//*[get hash loaded into memory image]
	WORD Subsystem;//[subsystem name required to run this image]
	WORD DllCharacteristics;//[characteristics of DLL image]
	DWORD SizeOfStackReserve;//*[get size of reserved stack]
	DWORD SizeOfStackCommit;//*[get size of stack to commit]
	DWORD SizeOfHeapReserve;//*[get size of reserved heap space]
	DWORD SizeOfHeapCommit;//*[get local heap space size to commit]
	DWORD LoaderFlags;//[previously reserved members]
	DWORD NumberOfRvaAndSizes;//*[get the number, location and size of data directory entries in the rest of PEHeader]
	_IMAGE_DATA_DIRECTORY DataDirectory[16];//[pointer to the first IMAGE_DATA_DIRECTORY structure in the data directory.]
}IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;

It can be seen that the Optional PE header data is the most, but this is a good thing. There are also a lot of data useful to us. For example, the information marked in red below is usually useful in reverse, shelling and cracking.

Base address

First of all, we won't talk about the first magic number 0x010B. It should be mainly to distinguish 32-bit and 64 bit programs.

Then we look at the program base address 0x01000000, which means the location of the PE file when the program is loaded into memory. Windows will allocate a virtual 4GB space for each program.

Some readers here will ask why the base address must be so large, why not 0? Because Windows has a memory for protection, usually when we write C + + code, for example, when we refer to a null (null pointer) whose memory address is 0, the program will crash and report an error!, Yes, this is what Windows designed to protect programs.

We can also use Winhex to open the data of Notepad.exe loaded in memory. We can find that its first address is the program base address.

Code segment address

Next, let's look at the address 0x001000 of the code segment, that is, the PE file starts storing program code here, which is of course converted into assembly code at the bottom.

We can use rasm2 in the radare2 suite to convert hexadecimal into assembly code.

rasm2 -a x86 -b 32 -d "hexadecimal"
#-a stands for x86 architecture platform
#-b-bit 32-bit
#-d decoding and parsing into assembly

Segment address

Next, look at the address 0x009000 of the data segment. The data segment mainly stores data, such as string and other data. You can see that Notepad string is stored in the following figure.

OEP program entry point

OEP is the data of the seventh member AddressOfEntryPoint in the Optional PE header structure. As the name suggests, it refers to the first line of code where the program starts to execute.

Since the program is loaded into memory, we also need to add the base address to be the real program entry point.

Namely: base address + OEP = 0x01000000 + 0x739D = 0x0100739D.

We can use tools to convert it into assembly and see what the first line of assembly code is?

We can also use od to load the program. The OD loader will be automatically loaded to the OEP by default. So we can verify the location we're looking for.

Well, the introduction of optional header PE ends here. Among them, the Optional PE header also has the most structure data_ IMAGE_DATA_DIRECTORY, this will not be introduced for the time being, but will be explained in detail when introducing other contents later.

0x03 written by PE header parsing tool

After knowing the PE header structure, the code is also very convenient to write, and Microsoft has its own PE header structure. We can directly open() file and read the content directly to the structure for parsing.

/*******************************************************
*
* Learning PE structure analysis code exercise
*
* Haidong teacher Bilibili: phase III
*********************************************************/

//Header file definition
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <Windows.h>
using namespace std;

//--------------------------PE structure----------------------------------
//-->DOS header (_image_dos_header)<--
struct _IMAGE_DOS_HEADER_2
{
	WORD  e_magic;   //*DOS Magic number*
	WORD  e_cblp;    //[Bytes on last page]
	WORD  e_cp;      //[Pages in file]
	WORD  e_crlc;    //[Relocations]
	WORD  e_cparhdr; //[Size of header]
	WORD  e_minalloc;//[Minium memory]
	WORD  e_maxalloc;//[Maxium Memory]
	WORD  e_ss;      //[Inital SS value]
	WORD  e_sp;      //[Inital SP value]
	WORD  e_csum;    //[Checksum]
	WORD  e_ip;      //[Inital IP value]
	WORD  e_cs;      //[Inital CS value]
	WORD  e_lfarlc;  //[Table offset]
	WORD  e_ovno;    //[Overlay number]
	WORD  e_res[4];  //[Reserved words]
	WORD  e_oemid;   //[OEM id]
	WORD  e_oeminfo; //[OEM infomation]
	WORD  e_res2[10];//[Reserved words]
	DWORD e_lfanew;  //*PE file header address*
} IMAGE_DOS_HEADER_2, *PIMAGE_DOS_HEADER_2;
//-->NT headers (_image_nt_headers)<--
struct _IMAGE_NT_HREADERS_2
{
	DWORD Signature;
	_IMAGE_FILE_HEADER FileHeader;
	_IMAGE_OPTIONAL_HEADER OptionalHeader;
}IMAGE_NT_HREADERS_2,*PIMAGE_NT_HREADERS_2;
//-->Standard PE header (_image_file_header)<--
struct _IMAGE_FILE_HEADER_2
{
	WORD Machine;
	WORD NumberOfSections;
	DWORD TimeDateStamp;
	DWORD PointerToSymbolTable;
	DWORD NumberOfSymbols;
	WORD SizeOfOptionalHeader;
	WORD Characteristics;
}IMAGE_FILE_HEADER_2,*PIMAGE_FILE_HEADER_2;
//-->Optional PE header (_image_optional_header)<--
struct _IMAGE_OPTIONAL_HEADER_2
{
	WORD Magic;//[Optional PE head magic number]
	BYTE MajorLinkerVersion;//[Master linker version]
	BYTE MinorLinkerVersion;//[sub linker version]
	DWORD SizeOfCode;//[code segment size]
	DWORD SizeOfInitializedData;//[initialize data size]
	DWORD SizeOfUninitializedData;//[uninitialized data size]
	DWORD AddressOfEntryPoint;//*[program entry point]
	DWORD BaseOfCode;//*[code snippet address]
	DWORD BaseOfData;//*[segment address]
	DWORD ImageBase;// *[start address of loading into memory] - > generally seems to be 0x400000
	DWORD SectionAlignment;//*[memory page size]
	DWORD FileAlignment;//[file size]
	WORD MajorOperatingSystemVersion;//*[major version number of operating system]
	WORD MinjorOperatingSystemVersion;//*[minor version number of operating system]
	WORD MajorImageVersion;//[program major version number]
	WORD MinorImageVersion;//[program minor version number]
	WORD MajorSubsystemVersion;//[subsystem major version number]
	WORD MinorSubsystemVersion;//[subsystem minor version number]
	DWORD Win32VersionValue;//[default reserved]
	DWORD SizeOfImage;//*[size loaded into memory image]
	DWORD SizeOfHeaders;//[DOS header PE header combination size]
	DWORD CheckSum;//*[get hash loaded into memory image]
	WORD Subsystem;//[subsystem name required to run this image]
	WORD DllCharacteristics;//[characteristics of DLL image]
	DWORD SizeOfStackReserve;//*[get size of reserved stack]
	DWORD SizeOfStackCommit;//*[get size of stack to commit]
	DWORD SizeOfHeapReserve;//*[get size of reserved heap space]
	DWORD SizeOfHeapCommit;//*[get local heap space size to commit]
	DWORD LoaderFlags;//[previously reserved members]
	DWORD NumberOfRvaAndSizes;//*[get the number, location and size of data directory entries in the rest of PEHeader]
	_IMAGE_DATA_DIRECTORY DataDirectory[16];//[pointer to the first IMAGE_DATA_DIRECTORY structure in the data directory.]
}IMAGE_OPTIONAL_HEADER_2,*PIMAGE_OPTIONAL_HEADER_2;
//-----------------------------------------------------------------


int main(int args,char *argv[])
{
	if (args < 2)
	{
		printf("Parameter error,Please call this program in the following format!\n");
		printf("PEAnysis.exe Program name.exe\n");
		return 0;
	}
	//Initialize colorable terminal Handle
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//
	printf("===================PE Anysis-PE File analyzer tool!==========================\n\n");
	FILE* fp = fopen(argv[1], "rb");
	if (fp != NULL)
	{
		//Read DOS header
		fread(&IMAGE_DOS_HEADER_2, sizeof(IMAGE_DOS_HEADER_2), 1, fp);
		//Jump to NT header
		fseek(fp, IMAGE_DOS_HEADER_2.e_lfanew, 0);
		//Read NT header
		fread(&IMAGE_NT_HREADERS_2, sizeof(IMAGE_NT_HREADERS_2), 1, fp);

		printf("---------------PE Header data----------------\n");
		//Output DOS header information
		cout << "--> DOS head(_IMAGE_DOS_HEADER ) <--" << endl;
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		char szMagic[3] = { 0 };
		memcpy(szMagic, &IMAGE_DOS_HEADER_2.e_magic, 2);
		printf("*DOS Head magic number:0x%x|%s\n", IMAGE_DOS_HEADER_2.e_magic, szMagic);
		SetConsoleTextAttribute(handle, 0x07);
		printf("[Bytes on last page]:0x%x\n", IMAGE_DOS_HEADER_2.e_cblp);
		printf("[Pages in file]:0x%x\n", IMAGE_DOS_HEADER_2.e_cp);
		printf("[Relocations]:0x%x\n", IMAGE_DOS_HEADER_2.e_crlc);
		printf("[Size of header]:0x%x\n", IMAGE_DOS_HEADER_2.e_cparhdr);
		printf("[Minium memory]:0x%x\n", IMAGE_DOS_HEADER_2.e_minalloc);
		printf("[Maxium Memory]:0x%x\n", IMAGE_DOS_HEADER_2.e_maxalloc);
		printf("[Inital SS value]:0x%x\n", IMAGE_DOS_HEADER_2.e_ss);
		printf("[Inital SP value]:0x%x\n", IMAGE_DOS_HEADER_2.e_sp);
		printf("[Checksum]:0x%x\n", IMAGE_DOS_HEADER_2.e_csum);
		printf("[Inital IP value]:0x%x\n", IMAGE_DOS_HEADER_2.e_ip);
		printf("[Inital CS value]:0x%x\n", IMAGE_DOS_HEADER_2.e_cs);
		printf("[Table offset]:0x%x\n", IMAGE_DOS_HEADER_2.e_lfarlc);
		printf("[Overlay number]:0x%x\n", IMAGE_DOS_HEADER_2.e_ovno);
		printf("[Reserved words]:", IMAGE_DOS_HEADER_2.e_res);
		for (size_t i = 0; i < 4; i++)
		{
			printf("0x%x, ", IMAGE_DOS_HEADER_2.e_res[0]);
		}
		cout << endl;
		printf("[OEM id]:0x%x\n", IMAGE_DOS_HEADER_2.e_oemid);
		printf("[OEM infomation]:0x%x\n", IMAGE_DOS_HEADER_2.e_oeminfo);
		printf("[Reserved words]:", IMAGE_DOS_HEADER_2.e_res2);
		for (size_t i = 0; i < 10; i++)
		{
			printf("0x%x, ", IMAGE_DOS_HEADER_2.e_res2[0]);
		}
		cout << endl;
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*PE File header address:0x%x\n", IMAGE_DOS_HEADER_2.e_lfanew);
		SetConsoleTextAttribute(handle, 0x07);
		cout << "DOS Head size:" << sizeof(IMAGE_DOS_HEADER_2) << endl;
		cout << endl;

		//Output standard PE header information
		cout << "--> standard PE head(_IMAGE_FILE_HEADER) <--" << endl;
		char szNTSignature[3] = { 0 };
		memcpy(szNTSignature, &IMAGE_NT_HREADERS_2.Signature, 2);
		printf("[NT Header identification]:%s\n", szNTSignature);
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*[Operation platform]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.Machine);
		printf("*[Number of sections]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections);
		printf("*[time stamp]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.TimeDateStamp);
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
		struct  tm test_gmtime_s;
		errno_t err = gmtime_s(&test_gmtime_s, (time_t*)&IMAGE_NT_HREADERS_2.FileHeader.TimeDateStamp);
		printf("  File creation time:%d year%d month%d day %02d Time:%02d branch:%02d second(week%d)\n", test_gmtime_s.tm_year + 1900, test_gmtime_s.tm_mon, test_gmtime_s.tm_mday,
			test_gmtime_s.tm_hour + 8, test_gmtime_s.tm_min, test_gmtime_s.tm_sec, test_gmtime_s.tm_wday);
		SetConsoleTextAttribute(handle, 0x07);
		printf("[Pointer to COFF]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.PointerToSymbolTable);
		printf("[COFF table size]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.NumberOfSections);
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*[Optional header size]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.SizeOfOptionalHeader);
		printf("*[features/characteristic]:0x%x\n", IMAGE_NT_HREADERS_2.FileHeader.Characteristics);
		SetConsoleTextAttribute(handle, 0x07);
		cout << "standard PE Head size:" << sizeof(IMAGE_NT_HREADERS_2.FileHeader) << endl;
		cout << endl;

		//Output Optional PE header information
		cout << "--> Optional PE head(_IMAGE_OPTIONAL_HEADER) <--" << endl;
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*[Program memory entry point]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.AddressOfEntryPoint + IMAGE_NT_HREADERS_2.OptionalHeader.ImageBase);
		printf("*[Optional PE Head magic number]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.Magic);
		printf("*[Master linker version]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MajorLinkerVersion);
		printf("*[Secondary linker version]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MinorLinkerVersion);
		printf("*[Code segment size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfCode);
		printf("*[Initialize data size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfInitializedData);
		printf("*[Uninitialized data size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfUninitializedData);
		printf("*[Code segment address]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.BaseOfCode);
		printf("*[Segment address]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.BaseOfData);
		printf("*[PE File base address]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.ImageBase);
		printf("*[Program entry point]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.AddressOfEntryPoint);
		SetConsoleTextAttribute(handle, 0x07);
		printf("[Memory to its size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SectionAlignment);
		printf("[File size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.FileAlignment);
		printf("[Major version number of the operating system]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MajorOperatingSystemVersion);
		printf("[Minor version number of the operating system]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MinorOperatingSystemVersion);
		printf("[Program major version number]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MajorImageVersion);
		printf("[Program minor version number]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MinorImageVersion);
		printf("[Subsystem major version number]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MajorSubsystemVersion);
		printf("[Subsystem minor version number]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.MinorSubsystemVersion);
		printf("[Win32 Version value]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.Win32VersionValue);
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*[Memory image size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfImage);
		printf("*[DOS|PE|Node size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfHeaders);
		printf("*[memory-mapped hash]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.CheckSum);
		SetConsoleTextAttribute(handle, 0x07);
		printf("[A system in which programs can run]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.Subsystem);
		SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("*[DLL Characteristics of image]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.DllCharacteristics);
		printf("*[Gets the size of the reserved stack]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfStackReserve);
		printf("*[Gets the size of the stack to commit]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfStackCommit);
		printf("*[Gets the size of the reserved heap space]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfHeapReserve);
		printf("*[Gets the size of the local heap space to commit]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.SizeOfHeapCommit);
		SetConsoleTextAttribute(handle, 0x07);
		printf("[Load flag(obsolete )]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.LoaderFlags);
		printf("[obtain PEHeader Remaining data,Location and size]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.NumberOfRvaAndSizes);
		printf("[point IMAGE_DATA_DIRECTORY Structure pointer]:0x%x\n", IMAGE_NT_HREADERS_2.OptionalHeader.DataDirectory);
		cout << "Optional PE Head size:" << sizeof(IMAGE_NT_HREADERS_2.OptionalHeader) << endl;
		cout << endl;
		printf("---------------Section table data----------------\n");

		printf("===========================================================================\n\n");

	}
	else 
	{
		printf("File open failed,Please check whether it is occupied!\n");
		return 0;
	}


	int x;
	cin >> x;

	return 0;
}

Posted by Draicone on Tue, 02 Nov 2021 19:11:13 -0700