Method name detection with assert in IDAPython

January 18, 2016

This post is a tutorial for creating an IDAPython script to identify unnamed functions. Some functions leak their original function names in assert calls or other error information. For this example, I’m using the home router TL-WDR3500’s firmware, and a call to the __assert function as an example.

Identifying method names

Several unnammed methods in this firmware use the __assert method. For example, the method sub_4205C8 below calls __assert if a protocol value is invalid.

IDA Pro sub_4205C8 disassembly

The second parameter to __assert holds the source file’s name ($a1 = "httpOutput.c"), and the fourth parameter holds the calling method’s name ($a3 = "httpStatusLine"). In code, this looks something like this:

int parser_parse_entity(request_id *reqId) {
  if (reqId->sProtocol < 2) {
     __assert("reqId->sProtocol < 2", "httpOutput.c", 0x48, "httpStatusLine");
  }
  // ...
}

Writing the script

The goal is to write a script that

  • Identifies unnamed methods (sub_*) that call __assert
  • Find the value of string containing the method name (stored in $a3)
  • Print out all identified methods

Identify unnamed methods

First, create a script file for IDAPython code. I’m calling mine name-asserted-functions.py.

To run the script, go to File -> Script File... in IDA Pro

Open file menul

Select the name-asserted-functions.py file:

Choose file dialog

The script may pause for a bit then dump the names of discovered sub_* functions:

IDAPython evaluated output of unnamed functions

Find functions that call __assert

Next, use IDAPython’s NextHead to iterate through instructions in each function. On each function, look for code cross-references to __assert using IDAPython’s CodeRefsFrom and GetFunctionName.

The output is a handful of functions that use __assert:

IDAPython evaluated output of functions with __assert references

Find the methodName argument for __assert

__assert’s function call looks like this:

void __assert(char *message, char *file, int code, char *methodName);
// e.g.
__assert("reqId->sProtocol < 2", "httpOutput.c", 0x48, "httpStatusLine");

In order to find what’s in the methodName argument, the script needs to determine what’s stored in the fourth argument register, $a3. The code below steps backwards through the code using IDAPython’s PrevHead, then uses GetOpnd to determine if a value is being loaded into $a3. Finally, the code uses IDAPython’s GetOperandValue and GetString functions to find the value of the string and associate it with the unnamed function.

Running this script produces:

Final output of function names passed to __assert for each unnammed function

Success!

Bulk renaming

To have the script automatically rename each function, IDAPython’s MakeName function can be used with arguments for the function’s address and the new name. I haven’t included it in the code above.

MakeName(function_address, function_new_name);
// e.g.
MakeName(0x4224D8, "httpReqLineParse");