There are many articles about PE files, but I plan to write an article about the input table because it is useful for cracking.
The best way to explain it is to give an example. You can follow me step by step, step by step, and finally you will fully understand, I chose a small program that I just downloaded. It was compiled by tasm and has a small input table. So I think it should be a good example.
Okay. Let's get started. First, we need to find the input table. Its address is placed at 80 offset of the PE file header. Therefore, we need to use the hexadecimal editor to open our EXE file. First, we need to find the starting point of the PE file header, this is very simple, because it always starts with PE, 0, 0, and we can find it at the offset of 100. In general Win32 programs, the file header offset is placed at the file 0x3c. Then we can see that 00 01 00, because the data storage is low before, high after, so the flip is actually 00000100, as we mentioned above. Next, we can find our input table in the PE file. 100 + 80 = 180 at the offset of 180, we can see 0030 0000, flip, it should actually be 00003000, this indicates that the input table is 3000 in memory and must be converted to a file offset.
Generally, the input table is always at the beginning of a segment. We can use the PE editor to view the virtual offset, find 3000, and find the original offset. Very simple. Open and we can see:
-Codes 00001000 00001000 00000200 00000600
-Data 00001000 00002000 00000200 00000800
. Idata 00001000 00003000 00000200 00000a00
. Reloc 00001000 00004000 00000200 00000c00
Find out and find that the virtual offset of the. idata segment is 3000, the original offset is a00, 2600-a00 = 2600, and we need to remember so that we can convert other offsets later. If you cannot find the virtual offset of the input table, find the closest segment.
At the a00 offset, we can see the stuff called image_import_descriptors (IID). It uses five fields to indicate the information of each called DLL and ends with null.
**************************************** **********************************
(IID) the structure of image_import_descriptor contains the following five fields:
Originalfirstthunk, timedatestamp, forwarderchain, name, firstthunk
Originalfirstthunk
This field points to a 32-bit RVA offset address string ending with 00. Each address in this address string describes an input function, and its order in the input table remains unchanged.
Timedatestamp
A 32-bit time sign is of special use.
Forwarderchain
Enter a 32-bit index of the function list.
Name
The 32-bit RVA address of the DLL file name (an ASCII string ending with 00.
Firstthunk
This field points to a 32-bit RVA offset address string ending with 00. Each address in this address string describes an input function, and its order in the input table is variable.
**************************************** **********************************
Okay. Do you understand? Let's see how many IIDS we have, starting from the a00 offset.
3c30 0000/0000 0000/0000 0000/8 C30 0000/6430 0000
{Orignalfirstthunk} {timedatestamp} {forwardchain} {name} {First thunk}
5c30 0000/0000 0000/0000 0000/9930 0000/8430
{Orignalfirstthunk} {timedatestamp} {forwardchain} {name} {First thunk}
0000 0000/0000 0000/0000 0000/0000 0000/0000 0000
Every 1/3 is a demarcation. We know that each IID contains the call information of a DLL. Now we have two IIDS, So we estimate that this program calls two DLL. Even I bet you can guess what we will find.
The fourth field of each IID indicates the name, through which we can know the name of the called function. The name field of the first IID is 8c30 0000, which is the address 2017308c. If you subtract 2600, the original offset is obtained. 308c-2600 = a8c, and the file offset a8c is obtained, what do we see? Aha! The original call is kernel32.dll.
Now, we need to find the called function in kernel32.dll. Return to the first IID.
The firstthunk field contains the flag of the called function name. originalfirstthunk is only a backup of firstthunk, and even some programs do not exist. Therefore, we usually look at firstthunk, Which is initialized when the program is running.
The firstthunk field value of kernel32.dll is 6430 0000, And the flipped address is 00003064, minus A64 of 2600. At the A64 offset, it is our image_thunk_data, which stores a string of addresses, end with a string of 00. As follows:
A430 0000/b230 0000/c030 0000/ce30 0000/de30 0000/ea30 0000/f630 0000/0000 0000
These are usually included in a complete program. Now we have 7 function calls. Let's look at two of them:
After de30 0000 is flipped, It is 30de. After 2600 is subtracted, It is equal to Ade. The character string at the offset Ade is readfile,
Ea30 0000 is 30 EA after flip, minus 2600 is equal to AEA, see the string at the offset AEA is writefile,
You may have noticed that there are two 00 bytes before the function name, which is used as a prompt.
It's easy. You can try it on your own. Return to a00 and check the second DLL call.
5c30 0000/0000 0000/0000 0000/9930 0000/8430
{Orignalfirstthunk} {timedatestamp} {forwardchain} {name} {First thunk}
Find its DLL file name first. 9930 flip to 3099-2600 = a99, locate user32.dll at the a99 offset. Let's look at the firstthunk field value: 8430 flip to 3084-2600 = a84, the address saved at the offset a84 is 08310000, 3108-2600 = b08 after flip, and the string at the offset b08 is messageboxa. Now, you can use these files in your own EXE file.
Abstract:
The address of the input table is stored at the offset of the PE File Header + 80. The input table contains the function name and firstthunk of each function called by the DLL, usually including the forward chain and timestamp.
When the program is running, the system calls getprocaddress and uses the function name as a parameter in exchange for the real function entry address and writes it to the input table in the memory. When you shell a program, you may notice that you have an initialized firstthunk. For example, on Win98, the entry address of the getprocaddress function is ae6df7bf. On 98, the call address of all kernel32.dll functions looks like xxxxf7bf, if you see this in the input table, you can use orignal thunk to recreate it or the pe program.
The second instance:
If we need to protect our programs, we can modify the size and start position of the PE Header.
Download instance
Explanation:
Prerequisites: You need to use a hexadecimal editing tool, such as winhex, ultraedit, and cs32asm.
1. IfImage_nt_headersThe signature field value of is equal to "Pe \ 0 \ 0", which is a valid PE file. Here, the offset 0100 is 50 45, which indicates the offset header.
2. As we have mentioned earlier, one of the items in dosmz is used to specify the start position of the PE Header, so the value at 002c and 002d is 00 01, which in turn is 0100.
Start position of the PE Header
100 60 00
01 00
00 01
PE Header size:
224 bytes 00 E0. As we have mentioned above, we can see the size of its PE Header at 0114.
Modified PE Header:
24*16 = 384 bytes 180 in turn 80 01 offset moved to 0060
Modify the offset and size as needed to modify the PE Header.
Cracking software insights-Summary of PE file formats (V)