# Understanding the Import Table: Your Guide to Program Dependencies
Ever wondered how programs manage to do all those fancy things like showing message boxes or accessing the internet? They're not doing it alone! These programs are actually borrowing pre-built functions from Windows itself - think of them as ready-made building blocks that handle common tasks. But how does a program know where to find these functions? That's where the Import Table comes in - it's like a program's contact list, keeping track of all these borrowed functions and where to find them. If you're just starting out in malware analysis or reverse engineering, understanding the Import Table is like getting the keys to decode what programs are really up to.
## What's an Import Table Anyway?
Imagine you're cooking dinner. Sure, you could make everything from scratch, but sometimes it's easier to use pre-made ingredients. Programs work the same way. Instead of writing code for every little task, they use pre-built functions that Windows provides through things called Dynamic Link Libraries (DLLs).
The Import Table is like a recipe book that lists all these "borrowed ingredients" - it tells Windows:
- Which DLLs the program needs (like kernel32.dll or user32.dll)
- Which functions it wants to use from each DLL
- Where to put the addresses of these functions so the program can find them
When you're analysing malware, the Import Table is often your first stop. It's like checking someone's browser history - it gives you a pretty good idea of what they've been up to!
## The Parts That Make It Work
The Import Table isn't just one big list - it's more like a filing cabinet with different drawers for different things. Let's break it down:
### The Import Directory: Your Master Index
This is like the table of contents in your recipe book. Each entry (called an IMAGE_IMPORT_DESCRIPTOR) points to:
<div style="font-family: monospace;">
<strong style="color: #5F98DC;">Import Directory Entry</strong><br>
├── <strong style="color: #D9B27C;">OriginalFirstThunk</strong> -> <span style="color: #C2E5A0;">Points to function names/numbers</span><br>
├── <strong style="color: #D98A8A;">TimeDateStamp</strong> -> <span style="color: #FFD9B5;">When was this DLL last updated?</span><br>
├── <strong style="color: #E6CD7F;">ForwarderChain</strong> -> <span style="color: #A4E2E9;">Any function redirects?</span><br>
├── <strong style="color: #C7DFFC;">Name</strong> -> <span style="color: #D3B6F5;">What's this DLL called?</span><br>
└── <strong style="color: #E4A983;">FirstThunk</strong> -> <span style="color: #E3B3C7;">Where to store the real addresses</span><br>
</div>
Let's break down each part with some real-world examples:
#### OriginalFirstThunk
This points to a list of the functions your program wants to use. It's like your program's wish list. But here's where it gets interesting - programs can ask for functions in two ways:
##### Function Names vs Ordinals
###### By Name
Most legitimate programs ask for functions by their actual names:
```C
GetProcAddress(hModule, "CreateFileA"); // Using the function name
```
###### By Ordinal
> [!warning] Malware often prefers using ordinals because
>
> - They're harder to spot in static analysis
> - The numbers are meaningless without context
> - They can make reverse engineering more difficult
>
> If you see a lot of ordinal usage, especially in seemingly simple programs, that's a red flag!
>
Programs can also ask for functions by their number (ordinal) in the DLL:
```C
GetProcAddress(hModule, (LPCSTR)15); // Using the ordinal number
```
Think of it like this - in a phonebook, you can find someone by their name (easy to understand) or by their number (harder to know who you're calling). Ordinals are just numbers that represent a function's position in the DLL's export table.
<div style="font-family: monospace;">
<strong style="color: #A0B9D8;">Example OriginalFirstThunk entries:</strong><br>
├── <strong style="color: #B3CDE3;">"CreateFileA"</strong> <span style="color: #D9A6A6;">(from kernel32.dll)</span><br>
├── <strong style="color: #C5B4E3;">"MessageBoxA"</strong> <span style="color: #E3B680;">(from user32.dll)</span><br>
├── <strong style="color: #B3CDE3;">"CreateFileA"</strong> <span style="color: #A6D9A6;">(function referenced by name)</span><br>
├── <strong style="color: #E6AFAF;">Ordinal #15</strong> <span style="color: #B3D9E6;">(function referenced by its position number in the DLL)</span><br>
└── <strong style="color: #D3A6E3;">"#7 - ReadFile"</strong> <span style="color: #E6B6B6;">(often malware uses ordinals to be sneaky!)</span><br>
</div>
#### TimeDateStamp
This field shows when the DLL was bound (linked) to your program. It helps Windows know if it needs to update the function addresses:
<div style="font-family: monospace;">
<strong style="color: #A0B9D8;">TimeDateStamp examples:</strong><br>
├── <strong style="color: #B3CDE3;">0x00000000</strong> <span style="color: #D9A6A6;">-> Not bound (most common)</span><br>
└── <strong style="color: #C5B4E3;">0x507B2F1A</strong> <span style="color: #E3B680;">-> Bound at a specific time</span><br>
</div>
#### ForwarderChain
Sometimes a function in one DLL actually lives in another DLL. *ForwarderChain* helps track these redirects:
<div style="font-family: monospace;">
<strong style="color: #A0B9D8;">Example forwarding:</strong><br>
├── <strong style="color: #B3CDE3;">kernel32.dll</strong> -> <span style="color: #D9A6A6;">CreateFile</span><br>
│ <span style="color: #A6D9A6;">actually forwards to -></span><br>
└── <strong style="color: #C5B4E3;">kernelbase.dll</strong> -> <span style="color: #E3B680;">CreateFileImplementation</span><br>
</div>
#### Name
Simply the name of the DLL your program needs. You'll often see familiar names here:
<div style="font-family: monospace;">
<strong style="color: #A0B9D8;">Common DLL names:</strong><br>
├── <strong style="color: #B3CDE3;">kernel32.dll</strong> <span style="color: #D9A6A6;">(core Windows functions)</span><br>
├── <strong style="color: #C5B4E3;">user32.dll</strong> <span style="color: #E3B680;">(user interface functions)</span><br>
└── <strong style="color: #D3A6E3;">ws2_32.dll</strong> <span style="color: #A6D9A6;">(networking functions)</span><br>
</div>
#### FirstThunk
> [!tip] When analysing malware, pay special attention to the FirstThunk addresses. Malware often modifies these addresses to hijack function calls - it's like changing the phone numbers in someone's contact list to redirect their calls!
This becomes the Import Address Table (IAT) - where Windows puts the actual memory addresses of the functions:
<div style="font-family: monospace;">
<strong style="color: #A0B9D8;">Before loading:</strong><br>
├── <strong style="color: #B3CDE3;">FirstThunk</strong> -> <span style="color: #D9A6A6;">0x00000000</span> <span style="color: #A6D9A6;">(empty address)</span><br>
<strong style="color: #A0B9D8;">After loading:</strong><br>
├── <strong style="color: #C5B4E3;">FirstThunk</strong> -> <span style="color: #E3B680;">0x77D507EA</span> <span style="color: #D3A6E3;">(real address of CreateFileA)</span><br>
</div>
### The Import Lookup Table (ILT): Your Shopping List
Think of this as your shopping list before you go to the store. It lists everything you need, but you haven't got it yet. Each entry can be either:
- An ordinal (like saying "I want item #5 from the shop")
- A function name (like saying "I want tomato sauce")
Just remember that many legitimate programs use function names, while malware often prefers ordinals because they're harder to spot. It's like using a code name instead of the real thing.
### The Import Address Table (IAT): Your Pantry
This is where the magic happens! When Windows loads your program, it looks at your shopping list (ILT), finds all the functions you asked for, and puts their addresses in the IAT. It's like turning your shopping list into a map showing exactly where everything is stored.
## How Malware Messes With It
Just like a magician uses misdirection, malware authors love to play tricks with the Import Table. Here are some of their favourite moves:
### API Hashing: The Secret Code
Instead of writing function names clearly, malware might use hashes, there a many types of hashing algorithms out there, common hashing algorithms include XOR-based hashes, CRC32, DJB2, or MurmurHash.
```C
// Instead of this (easy to spot):
GetProcAddress(kernel32, "CreateFileA");
// They might do this (harder to detect):
GetProcAddress(kernel32, hash("CreateFileA"));
```
### How It Works
1. **API Hashing**
- Malware authors calculate a hash (using algorithms like XOR-based hashing, CRC32, DJB2, or MurmurHash, etc.) for an API function name, e.g., `"CreateFileA"`.
- The hash value is hardcoded in the malware.
2. **Hash Matching**
- At runtime, the malware uses the hash value to resolve the corresponding function name dynamically.
- The process involves enumerating through available exports of loaded modules (like `kernel32.dll`) and comparing each exported function's hash to the precomputed hash
```c
// Hash calculation function (example with DJB2)
unsigned long hash(const char *str) {
unsigned long hash = 5381;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c; // hash * 33 + c
}
return hash;
}
// Usage
unsigned long targetHash = 0x12345678; // Precomputed hash for "CreateFileA"
for (PIMAGE_EXPORT_DIRECTORY exportDir = getExportDirectory("kernel32.dll");
hasMoreExports(exportDir);
exportDir++) {
if (hash(getFunctionName(exportDir)) == targetHash) {
// We've found our function, now get its address
void *functionAddress = getFunctionAddress(exportDir);
break;
}
}
```
3. **Invoke the Function**: Once the hash matches, the malware can resolve and invoke the API function using its address and pass them onto the ILT, which will be written to the IAT at runtime.
### Dynamic Loading: The Sleight of Hand
Some malware doesn't show all its cards at once. It might start with a nearly empty Import Table and then load functions on the fly:
```c
HMODULE hDll = LoadLibrary("kernel32.dll");
FARPROC pFunc = GetProcAddress(hDll, "CreateFileA");
// Now use pFunc instead of calling CreateFileA directly
```
## Common Functions to Watch For
>[!warning] Remember: Just because a program uses these functions doesn't automatically make it malicious. It's all about context.
When you're analysing malware, knowing which API calls to look out for is crucial. Think of it like being a detective - certain clues immediately catch your attention.
### The Usual Suspects
Here are some functions that should make you take a closer look:
| Function | What It Does | Why It's Suspicious |
|----------|-------------|-------------------|
| CreateRemoteThread | Starts code in another process | Often used for injection |
| VirtualAllocEx | Allocates memory in another process | Could be making room for bad stuff |
| WriteProcessMemory | Writes to another process | Might be injecting code |
| RegCreateKeyEx | Creates registry keys | Could be setting up persistence |
### Resources for API Analysis
One of the most brilliant tools in your analysis toolkit is [malapi.io](https://malapi.io). Think of it as the MITRE ATT&CK Framework meets GTFOBins, but specifically for Windows APIs. Here's why it's so valuable:
- Maps APIs to malicious usage patterns
- Shows you real-world malware samples that use each API
- Provides detailed documentation and usage examples
- Links APIs to specific MITRE ATT&CK techniques
For example, if you're analysing a sample and spot a suspicious `VirtualAllocEx` call, you can hop over to malapi.io and see:
- Exactly how malware authors typically abuse this API
- Which malware families are known to use it
- What legitimate uses look like versus suspicious patterns
- Related APIs you should be watching for
> [!tip] When you're analysing a new piece of malware, keep `malapi.io` open in another window. As you spot API calls, quickly cross-reference them to see if they match known malicious patterns.
### Other Essential Resources
>[!tip] Start with `ProcMon` for a broad view of what's happening, then zoom in with API Monitor when you spot something interesting. It's like having both binoculars and a microscope!
When you're diving into API analysis, having the right resources at your fingertips can make all the difference. Here's what you'll want in your toolkit:
1. **MSDN Documentation**:
- Your API encyclopedia! When you're wondering "what's this function supposed to do?", this is where you'll find out
- Perfect for understanding what "normal" looks like - after all, you can't spot weird behaviour if you don't know what's normal
- Pro tip: bookmark the Windows API reference pages, you'll be visiting them a lot!
2. **Process Monitor (ProcMon)**:
- Think of this as your real-time API detective - it shows you exactly what's happening on your system as it happens
- Want to know what files a program's touching? What registry keys it's poking at? ProcMon's got your back
- The filtering is brilliant - you can zero in on exactly what you want to see and ignore the rest
3. **API Monitor**:
- Your front-row seat to watching APIs in action - it's like having x-ray vision for program behaviour
- Works with both old (32-bit) and modern (64-bit) programs - no need to switch tools
- The best part? You can see whole sequences of API calls, perfect for understanding how malware pieces its attacks together
## Tools You'll Want in Your Kit
Ready to start poking around Import Tables? Here are some tools to get you started:
1. **PE Bear**: Great for visualising PE structures
2. **DIE (Detect It Easy)**: Helps spot packed or obfuscated files
3. **PEStudio**: Perfect for malware analysis
4. **CFF Explorer**: Detailed PE file examination
Remember, analysing Import Tables is like learning to read - it takes practice, but once you get it, a whole new world opens up!
## Want to Learn More?
This is just the beginning! Check out:
- [[PE File Format Foundations]] to understand how programs are structured
- [[Windows API Basics]] to learn about the functions programs can use
- [[CPU Registers Building Blocks]] to see how programs actually run these functions
- [[Advanced Register Techniques]] for more complex analysis