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.
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.