Calculating API hashes with IDA Pro
Many times when debugging malware you discover that the malware does not import any function, replaces API names by hashes and tries to resolve the addresses by looking up which API name has the desired hash!
In this blog post we are going to demonstrate how to use IDA Pro to solve this problem and uncover all API hashes.
To illustrate the problem, imagine this piece of code:
After tracing this code, we discovered that the call at 0x405DA4 should be renamed as ‘call_by_hash’ because it takes the first argument as the HASH of the API to be called followed by the actual parameters to the desired function.
The call_by_hash() starts by reading the PEB from pointer from the TIB, locates the LDR_MODULE structure of kernel32.dll, parses its PE structure and finally retrieves the IMAGE_EXPORT_DIRECTORY in order to get both the AddressOfFunctions and AddressOfNames fields:
With this information, the malware will then iterate through all the exported names trying to match the hash of the given exported name against the passed hash value using the calc_hash() function:
We notice that this function is self-contained and is easy to extract out of the code, reassemble and use in an external program to calculate the hashes. Instead of going through this hassle, we will write an IDAPython script that will make use of this function to calculate the hashes of all the exported names in this debugging session.
Writing the script
Before writing the script, let us break down into smaller steps:
- Extract the calc_hash function body and make it available for use from our script
- Find all exported names
- Pass each name to the calc_hash() and remember the result
- Display all the hashes in a nice chooser window
Using calc_hash() from the IDAPython script
Since the calc_hash() is self-contained, we can directly extract its body from the database and use ctypes to call it:
(Remember to free the memory when done)
Or we can use the Appcall mechanism to do just the same thing:
Because we will be calling calc_hash() at least 9000 times, we opt for the first solution because it is much much faster (Gladly we have another solution because it is not always a luxury to have a self-contained function that we can map into the Python host and execute as is).
Finding exported names and calculating their hashes
Everytime a debugging session starts, the IDA Pro debugger asks the debugger module to provide a set of debug names. The debug names are essentially the exported names of all loaded modules. To retrieve this list programmatically, we resort to using idaapi.get_debug_names():
Each returned debug name has the following format ‘Modulename_ApiName’. This is why we had to split (after the first underscore character) the returned debug name.
Now to calculate the hashes of all the names, it is sufficient to loop through the list like this:
Putting it all together
Now that we solved all the issues, we will present the results in a nice chooser and provide two facilities: one to import the hashes into IDA Pro’s enumeration window and the other to export the API hash list to a text file for external processing.
Writing a Chooser window is trivial (please refer to the source code or the ex_choose2 sample in the IDAPython package).
This is how the end result looks like:
The chooser window displays the module name, the hash value and the API name. A popup menu is created so that one can either export the list to a text file or import the values as enums:
Using the script
Now to use the script, launch the debugger, trace until/locate the function that calculates the hash and name it as calc_func.
If the function is not self-contained you need to prototype the function properly (by pressing ‘y’ in IDA Pro) and use the Appcall method instead of the ctypes method.
If you want to enhance the disassembly listing, then after you run the script, select “Import as Enum”.
Later when you encounter something like this:
You may simply press ‘m’ and select the appropriate hash constant, for example:
And after that you will get something like this:
Hope you found this blog post useful.
This script has been tested with IDA Pro 6.0 and may be downloaded from here.
Your comments and suggestions are welcome.