Deep Dive into the PE file format-build your own pe show

Source: Internet
Author: User

Deep Dive into the PE file format-create your own pe show
Author: winroot
//////////////////////////////////////// ////////////////////////////
// Start //
//////////////////////////////////////// ///////////////////////////
Hello everyone! I have been studying encryption and decryption for a while, but I am always confused about shell removal.
As a result, I started from the PE Structure. During the learning process, I found that to really understand the PE file structure, you must first understand it,
Feel him until you apply him .................. This is a bit of nonsense. The following are my study notes.
Here is a tip. please correct me if there is something wrong with this article. Thank you!
//////////////////////////////////////// //////////////////////////
// Prepare //
//////////////////////////////////////// /////////////////////////
Before the opening, I think you should have at least a few preparations:
1. Iczelion's Win32 Assembly Tutorial we mainly implement our function functions around his PE tutorial.
(In fact, win32asm tutorial Resource Kit v1.00 collected and packed by dreamtheater includes these
Or translated. Www. pediy. com)
Download it back. I hope you can check it out so that you can communicate with us :-)

2. A development environment. (I use VC ++ 6.0)
3. An environment suitable for your research.
//////////////////////////////////////// ////////////////////////
// Body //
//////////////////////////////////////// ///////////////////////

"PE means portable executable (portable executable ). It is the execution body file contained in the Win32 environment.
. Some of its features inherit from the Unix coff (Common Object File Format) file format. "Portable executable"
(Portable execution body) means that the file format is cross-Win32 platform:
Even if windows runs on a non-Intel CPU, the PE Loader on any Win32 platform can recognize and use this file format. Of course, do not
The PE execution body on the same CPU must have some changes. All Win32 execution bodies
(Except for VxD and 16-bit DLL) both use the PE file format, including the Kernel Mode Driver (kernel mode) of NT
Drivers ). Therefore, studying the PE file format gives us an opportunity to gain insight into the windows structure. "
Well, the above section is why we need to study the PE file structure.
See Figure 1,

I believe everyone is familiar with this picture. The first one is dos MZ header. What is this?
What does each part of this image mean?
From the aspect of programming, each part in the figure represents a struct, which contains different child blocks and some structs.
Each small part has its own function. I believe that the iczelion's tutorial has already been quite clear.
Let's start.
We want to design our own pe TOOLS----PE show
Main functions: 1. Determine whether the file is a PE file.
2. displays information about the PE file.

1. open the file with the following code:


If (false = pefile. Open (m_filename, cfile: typebinary & line; cfile: sharedenynone ))
& Leftsign;
MessageBox ("the file cannot be opened! ");
& Rightsign;

To use the cfile class, you need to search for the msdn
2. The file is opened in binary format. What should we do next?

Compile the first function-verify the validity of PE files
In the iczelion's tutorial, there is a passage like this:
"1. First, check whether the value of the first word in the file header is equal to image_dos_signature. If yes, the dos mz header is valid.
2. Once the file's dos header is valid, you can use e_lfanew to locate the PE Header.
3. Compare whether the value of the first word of the PE Header is equal to image_nt_header.
If both values match, the file is regarded as a valid PE file.
This is the process for verifying the effectiveness of PE files.
From the above section, we can see that the key to judgment is whether the value of the first word of the PE Header is equal to image_nt_header.
Until we find these.
What is the value of the first word of the PE Header?
Let me take a look at the image_nt_headers structure: (check winnt. h and find it)
Typedef struct _ image_nt_headers & leftsign;
DWORD signature;
Image_file_header fileheader;
Image_optional_header32 optionalheader;
& Rightsign; image_nt_headers32, * pimage_nt_headers32;
Signature-DWORD type, value: 50 h, 45 h, 00 h, 00 H (PE/0/0 ). This field is a PE tag. We can identify whether a given file is a valid PE file.
Fileheader: This structure field contains information about the physical distribution of PE files, such as the number of segments and the File Execution Machine.
Optionalheader this structure field contains information about the Logical Distribution of PE files. Although the domain name has the word "optional", the structure always exists.
Our goal is clear. If the signature field value of image_nt_headers is equal to "PE/0/0", it is a valid PE file. In fact, for convenience, Microsoft has defined the constant image_nt_signature for our use.
Image_dos_signature equ 5a4dh
Image_os2_signature equ 454eh
Image_os2_signature_le equ 454ch
Image_vxd_signature equ 454ch
Image_nt_signature equ 4550 H

We have solved the problem of judgment, and the new problem is how to locate the position of the image_nt_headers structure.
Ms is definitely a solution. What is the start of the PE file? Dos mz header structure. Let's take a look at its definition: Code

Typedef struct _ image_dos_header & leftsign; // dos. EXE Header
Word e_magic; // magic number
Word e_cblp; // bytes on last page of File
Word e_cp; // pages in file
Word e_crlc; // relocations
Word e_cparhdr; // size of header in paragraphs
Word e_minalloc; // minimum extra paragraphs needed
Word e_maxalloc; // maximum extra paragraphs needed
Word e_ss; // initial (relative) SS value
Word e_sp; // initial sp value
Word e_csum; // checksum
Word e_ip; // initial IP value
Word e_cs; // initial (relative) Cs value
Word e_lfarlc; // file address of relocation table
Word e_ovno; // overlay number
Word e_res [4]; // Reserved Words
Word e_oemid; // OEM identifier (for e_oeminfo)
Word e_oeminfo; // OEM information; e_oemid specific
Word e_res2 [10]; // Reserved Words
Long e_lfanew; // file address of New EXE Header
& Rightsign; image_dos_header, * pimage_dos_header;

Let's take a look at the last item !!!!!
Found? He points to the PE Header.
How can I determine the position of the DOS MZ header? He is the beginning of the file.
View code: Code

Pefile. Read (& stpedosheader, sizeof (_ image_dos_header ));
If (stpedosheader. e_magic! = Image_dos_signature) // "MZ"
& Leftsign;
MessageBox ("dos MZ header is invalid! ");
Pefile. Close ();
& Rightsign;
& Leftsign;
// Display dos Header
Updatedata (true );
M_magicnumber.format (_ T ("0x %. 4x"), stpedosheader. e_magic );
M_cblp.format (_ T ("0x %. 4x"), stpedosheader. e_cblp );
M_cp.format (_ T ("0x %. 4x"), stpedosheader. e_cp );
M_crlc.format (_ T ("0x %. 4x"), stpedosheader. e_crlc );
M_cparhdr.format (_ T ("0x %. 4x"), stpedosheader. e_cparhdr );
M_minalloc.format (_ T ("0x %. 4x"), stpedosheader. e_minalloc );
M_maxalloc.format (_ T ("0x %. 4x"), stpedosheader. e_maxalloc );
M_ss.format (_ T ("0x %. 4x"), stpedosheader. e_ss );
M_sp.format (_ T ("0x %. 4x"), stpedosheader. e_sp );
M_csum.format (_ T ("0x %. 4x"), stpedosheader. e_csum );
M_ip.format (_ T ("0x %. 4x"), stpedosheader. e_ip );
M_cs.format (_ T ("0x %. 4x"), stpedosheader. e_cs );
M_lfarlc.format (_ T ("0x %. 4x"), stpedosheader. e_lfarlc );
M_ovno.format (_ T ("0x %. 4x"), stpedosheader. e_ovno );
M_oemid.format (_ T ("0x %. 4x"), stpedosheader. e_oemid );
M_oeminfo.format (_ T ("0x %. 4x"), stpedosheader. e_oeminfo );
M_lfane1_format (_ T ("0x %. 8x"), stpedosheader. e_lfanew );
Updatedata (false );
& Rightsign;

Buf = stpedosheader. e_lfanew; // you can specify the _ image_dos_header offset.
Try & leftsign; pefile. Seek (BUF, cfile: Begin); & rightsign;
Catch (...)
& Leftsign;
MessageBox ("_ image_dos_header.e_lfanew is incorrect! ");
Pefile. Close ();
& Rightsign;
Pefile. Read (& stpeheader, sizeof (_ image_nt_headers); // ---------- nt Header
If (stpeheader. signature! = Image_nt_signature) // "PE/0/0"
& Leftsign;
MessageBox ("this file is not in PE format! ");
Pefile. Close ();
& Rightsign;
& Leftsign;
MessageBox ("this file is in PE format! ");
Pefile. Close ();
& Rightsign;


Now we have determined whether the file is a valid PE file. By the way, the structure members of image_dos_header are displayed.
We have written a function.
Next we will continue to look down:
The end of the image_dos_header structure is image_nt_headers. We have already introduced the structure member information.
Let's extract them: Code

// Display the image_file_header Structure
Updatedata (true );
M_machine.format (_ T ("0x %. 4x"), stpeheader. fileheader. Machine );
M_numberofsections.format (_ T ("0x %. 4x"), stpeheader. fileheader. numberofsections );
M_timedatestamp.format (_ T ("0x %. 8x"), stpeheader. fileheader. timedatestamp );
M_pointertosymboltable.format (_ T ("0x %. 8x"), stpeheader. fileheader. pointertosymboltable );
M_numberofsymbols.format (_ T ("0x %. 8x"), stpeheader. fileheader. numberofsymbols );
M_sizeofoptionalheader.format (_ T ("0x %. 4x"), stpeheader. fileheader. sizeofoptionalheader );
M_characteristics.format (_ T ("0x %. 4x"), stpeheader. fileheader. characteristics );
Updatedata (false );

This is a member of image_file_header fileheader. We have extracted them.
After reading the tutorial, we will continue to look for the image_optional_header member. It is the struct In the struct and we will follow it. Code

Typedef struct _ image_optional_header & leftsign;
// Standard fields.

Word magic;
Byte majorlinkerversion;
Byte minorlinkerversion;
DWORD sizeofcode;
DWORD sizeofinitializeddata;
DWORD sizeofuninitializeddata;
DWORD addressofentrypoint;
DWORD baseofcode;
DWORD baseofdata;

// Nt additional fields.

DWORD imagebase;
DWORD sectionalignment;
DWORD filealignment;
Word majoroperatingsystemversion;
Word minoroperatingsystemversion;
Word majorimageversion;
Word minorimageversion;
Word majorsubsystemversion;
Word minorsubsystemversion;
DWORD win32versionvalue;
DWORD sizeofimage;
DWORD sizeofheaders;
DWORD checksum;
Word subsystem;
Word dllcharacteristics;
DWORD sizeofstackreserve;
DWORD sizeofstackcommit;
DWORD sizeofheapreserve;
DWORD sizeofheapcommit;
DWORD loaderflags;
DWORD numberofrvaandsizes;
Image_data_directory datadirectory [image_numberof_directory_entries];
& Rightsign; image_optional_header32, * pimage_optional_header32;


All these members are displayed.


// Display image_optional_header
Updatedata (true );
M_magic.format (_ T ("0x %. 4x"), stpeheader. optionalheader. Magic );
M_majorlinkerversion.format (_ T ("0x %. 2x"), stpeheader. optionalheader. majorlinkerversion );
M_minorlinkerversion.format (_ T ("0x %. 2x"), stpeheader. optionalheader. minorlinkerversion );
M_sizeofcode.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofcode );
M_sizeofinitializeddata.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofinitializeddata );
M_sizeofuninitializeddata.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofuninitializeddata );
M_addressofentrypoint.format (_ T ("0x %. 8x"), stpeheader. optionalheader. addressofentrypoint );
M_baseofcode.format (_ T ("0x %. 8x"), stpeheader. optionalheader. baseofcode );
M_baseofdata.format (_ T ("0x %. 8x"), stpeheader. optionalheader. baseofdata );
M_imagebase.format (_ T ("0x %. 8x"), stpeheader. optionalheader. imagebase );
M_sectionalignment.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sectionalignment );
M_filealignment.format (_ T ("0x %. 8x"), stpeheader. optionalheader. filealignment );
M_majoroperatingsystemversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. majoroperatingsystemversion );
M_minoroperatingsystemversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. minoroperatingsystemversion );
M_majorimageversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. majorimageversion );
M_minorimageversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. minorimageversion );
M_majorsubsystemversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. majorsubsystemversion );
M_minorsubsystemversion.format (_ T ("0x %. 4x"), stpeheader. optionalheader. minorsubsystemversion );
M_win32versionvalue.format (_ T ("0x %. 8x"), stpeheader. optionalheader. win32versionvalue );
M_sizeofimage.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofimage );
M_sizeofheaders.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofheaders );
M_checksum.format (_ T ("0x %. 8x"), stpeheader. optionalheader. checksum );
M_subsystem.format (_ T ("0x %. 4x"), stpeheader. optionalheader. subsystem );
M_dllcharacteristics.format (_ T ("0x %. 4x"), stpeheader. optionalheader. dllcharacteristics );
M_sizeofstackreserve.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofstackreserve );
M_sizeofstackcommit.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofstackcommit );
M_sizeofheapreserve.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofheapreserve );
M_sizeofheapcommit.format (_ T ("0x %. 8x"), stpeheader. optionalheader. sizeofheapcommit );
M_loaderflags.format (_ T ("0x %. 8x"), stpeheader. optionalheader. loaderflags );
M_numberofrvaandsizes.format (_ T ("0x %. 8x"), stpeheader. optionalheader. numberofrvaandsizes );
Updatedata (false );

We have learned a lot about DOS headers and PE headers. The next step is the section table.
The Section Table is actually a structure array next to the PE Header. The number of members of this array is determined by File Header (image_file_header)
The value of the numberofsections field in the structure. The table structure is also named image_section_header. Code

Typedef struct _ image_section_header & leftsign;
Byte name [image_sizeof_short_name];
Union & leftsign;
DWORD physicaladdress;
DWORD virtualsize;
& Rightsign; MISC;
DWORD virtualaddress;
DWORD sizeofrawdata;
DWORD pointertorawdata;
DWORD pointertorelocations;
DWORD pointertolinenumbers;
Word numberofrelocations;
Word numberoflinenumbers;
DWORD characteristics;
& Rightsign; image_section_header, * pimage_section_header

The node name length cannot exceed 8 bytes. Remember that the node name is only a flag. You can select any name or even leave it empty. The name is not an asciiz string, so it does not end with null.
Virtualaddress in this section, RVA (relative virtual address ). The PE Loader will read this value when ing the section to the memory. Therefore, if the Domain value is 1000 h and the PE file is packed at 401000 H, this section will be loaded to H.
After file alignment, the PE Loader extracts the local value to understand the number of bytes to be mapped into the memory. Assume that the size of an object is 0x200.
The virtualsize field indicates that the length of this section is 0x400, indicating that the length of this section is 0 x bytes ).
Pointertorawdata: This section is based on the file offset. The PE Loader uses this field value to locate the position of the section data in the file.
Characteristics contains tags to indicate the attributes of a section, such as whether the section contains executable code, initialized data, uninitialized data, writable, and readable data.

Now we know the image_section_header structure. Let's simulate the PE Loader's work:

1. Read the numberofsections field of image_file_header and know the number of file sections.
2. The sizeofheaders field value is used as the file offset of the section table, and this is used to locate the section table.
3. traverse the entire structure array and check the Member values.
For each structure, we read the value of the pointertorawdata field and locate the file offset. Then read the sizeofrawdata Domain value to determine the number of bytes mapped to the memory.
Add the virtualaddress Domain value and the imagebase Domain value to the virtual address starting from the node. Then you are ready to map the section to the memory, and according to characteristics
Set the attribute of the Domain value.
5. traverse the entire array until all sections have been processed.
The Code is as follows:

// Display the section structure
Nsection = stpeheader. fileheader. numberofsections;
Stsectionheader = new _ image_section_header [nsection];
M_listctrl.deleteallitems ();
For (INT I = 0; I & leftsign;

Pefile. Read (& stsectionheader [I], sizeof (_ image_section_header); // ----- Section Table
// No
Sztemp. Format (_ T ("%. 2d"), I + 1 );
M_listctrl.insertitem (I, sztemp, I );
// Sectionname
Strcpy (chsectionname, (lpcstr) stsectionheader [I]. Name );
M_listctrl.setitemtext (I, 1, chsectionname );
// Virtualsize
Sztemp. Format (_ T ("0x %. 8x"), stsectionheader [I]. Misc. virtualsize );
M_listctrl.setitemtext (I, 2, sztemp );
// Virtualaddress
Sztemp. Format (_ T ("0x %. 8x"), stsectionheader [I]. virtualaddress );
M_listctrl.setitemtext (I, 3, sztemp );
// Sizeofrawdata
Sztemp. Format (_ T ("0x %. 8x"), stsectionheader [I]. sizeofrawdata );
M_listctrl.setitemtext (I, 4, sztemp );
// Sizeoffset
Sztemp. Format (_ T ("0x %. 8x"), stsectionheader [I]. pointertorawdata );
M_listctrl.setitemtext (I, 5, sztemp );
// Characteristics
Sztemp. Format (_ T ("0x %. 8x"), stsectionheader [I]. characteristics );
M_listctrl.setitemtext (I, 6, sztemp );

& Rightsign;
Delete stsectionheader;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.