The Import Directory: Part 2

M33

[ Verified Seller ]
Staff member
Trusted Seller
Joined
11 yrs. 8 mth. 23 days
Messages
5,010
Reaction score
11,818
Wallet
13,191$
The Import Directory: Part 2

Dejan Lukan April 29, 2013

You can take a look at the previous article before reading this one. If you already understand the basics of IAT table, then you can skip the first article, but otherwise you should read that before continuing below.

Presenting the Example Import Directory

Let’s use the !dh command to dump the PE header. Below we can see that we’ve dumped the PE header that’s located at the 0×00400000 virtual address. Note that we presented only the Import Directory entry, because we’re interested only in that right now.

Code:
Please, Log in or Register to view codes content!

We can see that the RVA to the import directory is 0×18000 and is 0x3C bytes in size. The Import Directory points to the IMAGE_IMPORT_DESCRIPTOR structures, which is 20 bytes in size. Since the size of the Import Directory is 0x3C (60 bytes) and the size of the IMAGE_IMPORT_DESCRIPTOR structure is 0×14 (20 bytes), there are 3 structures available in the Import Directory.

Let’s dump the three structures contained in the Import Directory table. On the picture below we’ve calculated the address of the Import Table, which is 0×00400000+18000, and then we also added the relative offsets to the IMAGE_IMPORT_DESCRIPTOR structures. Since the size of each structure in an array is 0×14 bytes, we must add 0×14 bytes to the address to access the next element:

042413_1552_TheImportDi1.png




We can see that the array actually contains two elements and that the last one is set to zero to denote the end of the Import Directory. The names of both elements are denoted by the Name element in the IMAGE_IMPORT_DESCRIPTOR structure. The Name element holds the RVAs to the actual name of the library. In the next picture, we’ve dumped the memory at those RVAs as hex and ASCII representations:

042413_1552_TheImportDi2.png


Notice that we’ve actually printed the names of the loaded libraries, the msvcr100dl.dll and kernel32.dll? This proves that the executable is using the imported functions from those libraries.

Let’s now dump the OriginalFirstThunk array. We’ve seen that the RVA address to the OriginalFirstThunk array of the msvcr100d.dll library is 0x180FC. This is why we can use the command on the picture below to dump the four bytes of the IMAGE_THUNK_DATA structure.

042413_1552_TheImportDi3.png


The IMAGE_THUNK_DATA structure contains the element AddressOfData, which points to the IMAGE_IMPORT_BY_NAME structure. Let’s present that structure again for clarity:

042413_1552_TheImportDi4.png


If we now dump the IMAGE_IMPORT_BY_NAME structure from the address 0×00400000+000184fe, we’ll see the following:

042413_1552_TheImportDi5.png


Notice that the name presents only one character ‘_’. We’ve already established that the Name element actually contains a null terminated ASCII name, so it’s best if we dump the contents of memory on that address to see the actual name. We’ve dumped the contents of memory with the db command, which can be seen below:

042413_1552_TheImportDi6.png


The first type bytes are Hint, while the rest of the bytes, until the first NULL byte, are part of the Name element. Because of this, the actual name of this function is _crt_debugger_hook. We can also use the da command to dump only the ASCII characters, but we have to add an additional 0×2 bytes to the address to jump over the Hint element. We can see the same string dumped on the picture below:

042413_1552_TheImportDi7.png


We’ve seen that the OriginalFirstThunk array contains RVA addresses to the IMAGE_THUNK_DATA structures that in turn point to the IMAGE_IMPORT_BY_NAME structure that contains the name of the function of certain library. All of the RVA addresses that point to the IMAGE_THUNK_DATA can be seen on the picture below:

042413_1552_TheImportDi8.png


Notice that the last element is NULL element 0×00000000, which terminates the array. The rest of the dwords are RVA addresses to the IMAGE_THUNK_DATA structure. We can see that it would take a lot of work to traverse the entries manually, so we’ll just write a simple script that will do it for us. Let’s first check if the current expression evaluator is set to MASM. We can do this with the .expr command:

042413_1552_TheImportDi9.png


In order to write a script, we must first take a look at basic WinDbg scripting instructions. If we want to declare a variable, we must use the “r” prefix and the name must be $t0-$t19. If we want to obtain the value of the variable, we must use the prefix “@” like this: @$t0. We can use the script parameters as $arg1 – $argN in the script itself.

Whenever we want to execute the script, we need to use the following command:

Code:
Please, Log in or Register to view codes content!

I’ve coded a script that traverses the OriginalFirstThunk array and prints all the names from that array. The script can be seen below:

Code:
Please, Log in or Register to view codes content!

Let’s explain the script a little further. At first we calculate the actual address of the OriginalFirstThunk array: we add 0×00400000 (base address) to the first input argument. In our case, the input argument should be 0x180fc, so the whole address will be 0x004180fc, which is the address of the OriginalFirstThunk of the msvcr100d.dll library.

There’s no need to say that the script only works if the base address of the PE header is 0×00400000; if we would like to have a more versatile script, we only need to make small changes to find the PE header base address dynamically. We didn’t do this in our case, since it’s not important for this exercise.

After that, we have a for loop which counts from 0 to 1000, increasing the counter by t 4 and executing the for loop body each time. In the loop body, we calculate the address of each element in the OriginalFirstThunk array and read the value from that address. If the address contains the value 0, then we’ve come to the end of the array and we terminate the loop. Otherwise, we take that value and add 0×400002, which constructs the whole address to the actual null-terminated ASCII name. Then we print that value to the output and repeat the loop.

Let’s see what happens when we run the script. We saved the script into C:\scripts\ directory as importnames.wds script, but the extension can be anything we like, even.txt. We’re passing one argument 0x180fc to the script, which is the RVA to the OriginalFirstThunk.

Code:
Please, Log in or Register to view codes content!

Let’s also dump all the names from the FirstThunk array in the msvcr100d.dll library, which has a RVA of 0x1827c. In order to do that, we have to change the script a little bit, because the OriginalFirstThunk and FirstThunk don’t actually use the same data structures. The new script is very similar to the previous one and can be seen below:

Code:
Please, Log in or Register to view codes content!

We won’t explain the script in detail, since it’s very similar to the previous one. The only difference is the else conditional body, where we print the read value to the stdout, where in the previous case we printed the value pointed to by the current value and there was one more pointer in the hierarchy.

When we run the script, the following will be printed to the screen:

Code:
Please, Log in or Register to view codes content!

Notice that we passed the RVA of the OriginalFirstThunk 0x1827c to the new script. The script printed the same number of elements as before, but now the function addresses were printed, instead of the function names in the previous script.

Let’s verify that the printed address actually belongs to the function we’ve identified. The last element printed in both cases is “getchar” and “1025f660″, which means that the getchar() function must be located at address 0x1025f660. We can check whether this is true by simply using the u command. The picture below shows us that our script works and that we’ve correctly identified the address of the getchar() function:

042413_1552_TheImportDi10.png


In the beginning of the article we’ve identified that the executable uses two libraries, the msvcr100d.dll and the kernel32.dll library. Previously, we’ve dumped the names and addresses of the functions in the msvcr100d.dll library. Now let’s dump all the function names of the kernel32.dll library. We can see all the names below:

Code:
Please, Log in or Register to view codes content!

Notice that this time we had to use the RVA of the kernel32.dll’s OriginalFirstThunk, which is 0x1803c. To print the appropriate addresses, we must use the RVA of kernel32.dll’s FirstThunk, which is 0x181bc. We can see all of the functions’ addresses printed below:

Code:
Please, Log in or Register to view codes content!

Let’s also verify that the function addresses are correct by checking whether the last element matches.

042413_1552_TheImportDi11.png


The address 0x7c810cd9 matches the CreateFileW function, which means that our scripts work as intended.

If we now dump the PE header with the !dh command, we’ll see that the RVA to the Import Address Table Directory is 0x181BC, which is exactly the RVA of the kernel32.dll’s FirstThunk.

Code:
Please, Log in or Register to view codes content!

This proves that the IAT table must be traversed through the Import Directory structures as we saw in this tutorial. If we dumped the contents of the memory at IAT (RVA0x181BC), we would see that we’re actually accessing the same functions that we already identified.

Conclusion

We’ve seen the distinction between load-time and run-time dynamic linking. With load-time dynamic linking, we must specify the required libraries that we’ll be using during the program compilation, and of course the used functions are written to the program’s IAT table. With run-time dynamic linking, the IAT is not used, because we’ll know the function that we’re referencing at run-time and not at compile-time. We can bring a library to the current process’s address space by running the LoadLibrary() function and then scanning through its exported functions.

The IAT table is used to support dynamic linking, which needs to be done when the application is run. Since the application uses functions from standard libraries, we must write them into the IAT table, so that the operating system knows which libraries to load into the process’s address space when the process is being executed. Alternatively, we could use run-time linking, in which case the IAT table won’t be necessary, because we have to load the library and execute its functions at run-time.

References:

[1] Import Address Table, accessible at
Please, Log in or Register to view URLs content!
.

[2] Dynamic-link library, accessible at
Please, Log in or Register to view URLs content!
.

[3] CreateFile function, accessible at
Please, Log in or Register to view URLs content!
.

[4] Linker Options, accessible at
Please, Log in or Register to view URLs content!
.

[5] PE File Structure, accessible at
Please, Log in or Register to view URLs content!
.

[6] Tutorial 6: Import Table, accessible at
Please, Log in or Register to view URLs content!
.

[7] What’s the difference between “Import Table address” and “Import Address Table address” in Date Directories of PE?, accessible at
Please, Log in or Register to view URLs content!
.

sursa:
Please, Log in or Register to view URLs content!
 
Paid adv. expire in 2 months
CLICK to buy Advertisement !
westernunion carding Verified & Trusted WesternUnion | MoneyGram | Bank - Transferring [299$ BTC for 2000$ WU]
electronics carding Verified & Trusted Electronics Carding, Carding iPhone, Samsung Carding, MacBook Carding, Laptops Carding
Top Bottom