2

is there a way to get a listing of all called APIs in a function via IDAPython. For example I have the below code from a function.

.text:003A33D9                 call    esi ; _snwprintf
.text:003A33DB                 add     esp, 1Ch
.text:003A33DE                 mov     eax, 3A4336h
.text:003A33E3                 push    ebx             ; dwReserved
.text:003A33E4                 mov     [ebp+var_C], eax
.text:003A33E7                 mov     [ebp+var_8], eax
.text:003A33EA                 push    0Ch             ; dwBufferLength
.text:003A33EC                 lea     eax, [ebp+pBuffer]
.text:003A33EF                 push    eax             ; pBuffer
.text:003A33F0                 push    26h             ; dwOption
.text:003A33F2                 mov     [ebp+pBuffer], 1
.text:003A33F9                 call    ds:UrlMkSetSessionOption
.text:003A33FF                 lea     eax, [ebp+szUrlName]
.text:003A3405                 push    eax             ; lpszUrlName
.text:003A3406                 call    ds:DeleteUrlCacheEntryW

I'd like to get all the API calls ( _snwprintf, UrlMkSetSessionOption, DeleteUrlCacheEntryW, etc). The following IDAPython function can be used to get most of them.

def get_apis(func_addr):
        calls = 0
        apis = []
        flags = GetFunctionFlags(func_addr)
        # ignore library functions
        if flags & FUNC_LIB or flags & FUNC_THUNK:
            logging.debug("get_apis: Library code or thunk")
            return None
        # list of addresses
        dism_addr = list(FuncItems(func_addr))
        for instr in dism_addr:
            tmp_api_address = ""
            if idaapi.is_call_insn(instr):
                # In theory an API address should only have one xrefs
                # The xrefs approach was used because I could not find how to
                # get the API name by address.
                for xref in XrefsFrom(instr, idaapi.XREF_FAR):
                    if xref.to == None:
                        calls += 1
                        continue
                    tmp_api_address = xref.to
                    break
                # get next instr since api address could not be found
                if tmp_api_address == "":
                    calls += 1
                    continue
                api_flags = GetFunctionFlags(tmp_api_address)
                # check for lib code (api)
                if api_flags & idaapi.FUNC_LIB == True or api_flags & idaapi.FUNC_THUNK:
                    tmp_api_name = NameEx(0, tmp_api_address)
                    if tmp_api_name:
                        apis.append(tmp_api_name)
                else:
                    calls += 1
        return (calls, apis

Output

Python>get_apis(here())
(18, ['UrlMkSetSessionOption', 'DeleteUrlCacheEntryW', 'URLDownloadToFileW', 'GetModuleFileNameW', 'CreateProcessW', 'Sleep', 'ExitProcess', 'RtlGetLastWin32Error', 'byte_3A3E45', 'RtlGetLastWin32Error'])        

The issue I'm having is call esi ; _snwprintf is not present. I understand I could use backtracing to find the value of ESI but I'd like to find another approach. Is there a more reliable technique for getting all APIs in a function? Similar data is present in the proximity browser.

  • Maybe exhaustive emulation? – fileoffset Jul 15 '15 at 5:40
  • Whenever you detect a register call, you can use idaapi.is_tilcmt to check if the comment is automatically propagated by IDA. If it is, it is pretty safe to assume that it is the name of the function being called. Would be able to help more as soon as I get to a computer with IDA on it. – tmr232 Jul 16 '15 at 19:28
1

an idc script that scans for Register calls and prints them
( this script is using text search because ida wild card ? appears to be useless for masking
ie we cant search binary like FF D? so that all binary sequences "ff d0","ff d1","ff d2",etc can be searched at once)

#include <idc.idc>
static main (void) {
  auto offset,count;
  count = 1;
  offset= MinEA();
  while(offset != BADADDR) {
    offset = FindText(offset+2,3,0,0,"call    e");
    Message(
    "%03d %08x %s %s %s\n",
    count++,
    offset,
    GetMnem(offset),
    GetOpnd(offset,0),
    Name(Dfirst(offset))
    );
  }
}

result on calc.exe xp sp3 x86

Compiling file 'C:\Documents and Settings\Admin\My Documents\callreg.idc'...
Executing function 'main'...
001 01001682 call esi CharNextW
002 010016ba call esi CharNextW
003 01001713 call esi 
004 01001740 call esi 
005 0100178b call esi 
006 010017b4 call esi 
007 01001a74 call esi GetProfileStringW
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
069 01007b5d call esi LoadLibraryA
070 01007ba0 call eax 
071 0101248a call edi GetModuleHandleA
072 010125e1 call edi GetModuleHandleA
073 ffffffff   
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.