📦 Volatility3 : Import Address Table

Abstract Link to heading

Windows executable analysis is a key aspect of Digital Forensics and Reverse Malware Engineering. Identifying the capabilities of a program can help to target potential malicious code and orient the later reverse code analysis phase. In this blogpost, we will dive into the structure of the Windows Portable Executable (PE) and how we can extract the imported functions in the context of memory analysis.

Windows PE Format Link to heading

A portable executable (PE) 1 is a file format used by Windows to store executable programs, libraries (DLLs) and object files. It contains all the necessary information for the operating system to load and execute the program. The program is therefore well structured. Here is a representation of the PE structure for a Windows system 2:

alt text

The PE starts with the well-known DOS, Stub and NT headers. It is also composed of multiple sections. Each section as its own purpose, for example the .text section contains the byte codes corresponding to the instructions of the program. We will see that there are specific sections that exists which might help the analyst to identify the capabilities of an executable without starting the reverse code analysis phase. If you want to learn more about the PE format, the articles from 0xRick about the subject are very well explained 2.

Interactions with the memory Link to heading

In the context of memory analysis, we need to understand what is happening when a Windows executable is loaded. The operating system will map the PE file from the disk to memory by first creating a dedicated virtual address space. Then, the headers are parsed and loaded to learn about important information about the sections (entry point, size, …). Once parsed, the memory allocation is performed to load the actual content of the sections. The PE file often depends on external libraries, the operating system resolves the imports by looking up the required functions in the corresponding DLLs and update the memory addresses accordingly. A library can be “bound” to the PE which means it is directly integrated inside the code section. This is often used for better performances.

The Import Address Table (IAT) Link to heading

The Import Address Table is located inside the “.idata” Section 3 of a PE, it can be seen as a table of references indicating to the loader which functions are needed from the imported DLL by the program. This table is a copy of the Import Lookup Table (ILT), but once in memory, the IAT is overwritten with the actual addresses of the functions that are being imported which is interesting from the memory forensics standpoint.

Extracting the IAT using volatility3 Link to heading

Carving the IAT during memory forensics can be very valuable for the analyst to look for API call patterns associated with malware behavior. For example, the OpenProcess, VirtualAllocEx, CreateRemoteThread function present inside the IAT of a PE can be a good indicator for potential code injection 4. The analyst can also pivot on some of the functions to identify for example the arguments that can be passed.

A volatility3 plugin can be made to extract the IAT information from the memory. Below is an example output of the created plugin named “windows.iat.IAT”. For each process, the associated PE sections are parsed in order to find the IAT. Next, all of the imported functions are displayed to the analyst as well as if the associated DLL is bounded or not to the executable.

~» vol -r pretty -f Triage-Memory.mem windows.iat --pid 3496
Volatility 3 Framework 2.5.1
Formatting...0.00               PDB scanning finished                        
  |  PID |           Name |      Library | Bound |                        Function |  Address
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                            _iob | 0x80c0c8
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                _except_handler3 | 0x80c0cc
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                  __set_app_type | 0x80c0d0
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                      __p__fmode | 0x80c0d4
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                    __p__commode | 0x80c0d8
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                    _adjust_fdiv | 0x80c0dc
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                __setusermatherr | 0x80c0e0
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                       _initterm | 0x80c0e4
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                   __getmainargs | 0x80c0e8
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                   __p___initenv | 0x80c0ec
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                     _XcptFilter | 0x80c0f0
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                           _exit | 0x80c0f4
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         _onexit | 0x80c0f8
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                     __dllonexit | 0x80c0fc
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         strrchr | 0x80c100
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         wcsncmp | 0x80c104
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          _close | 0x80c108
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          wcslen | 0x80c10c
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          wcscpy | 0x80c110
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                        strerror | 0x80c114
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                            modf | 0x80c118
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          strspn | 0x80c11c
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         realloc | 0x80c120
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                    __p__environ | 0x80c124
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                   __p__wenviron | 0x80c128
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          _errno | 0x80c12c
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                            free | 0x80c130
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         strncmp | 0x80c134
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          strstr | 0x80c138
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                         strncpy | 0x80c13c
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                           _ftol | 0x80c140
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                           qsort | 0x80c144
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                           fopen | 0x80c148
* | 3496 | UWkpjFjDzM.exe |   MSVCRT.dll | False |                          perror | 0x80c14c
[TRUNCATED]

Conclusion Link to heading

The extraction of the IAT can be very useful for the analyst to identify the capabilities of a process in memory and gather context to better orient the reverse code analysis phase. When the analyst is willing to understand some of the Windows API functions, the Microsoft documentation is often explaining everything 5. Trying to look for some of the functions in the text section and extracting the value of the arguments can be the subject of a future blogpost. The pluging is available here and a pull request is in progress https://github.com/forensicxlab/volatility3/tree/feature/IAT

Do not hesitate to reach me at felix.guyard@forensicxlab.com to enhance this article or to comment on the integration to the volatility framework.