Last active
September 18, 2024 18:56
-
-
Save edeca/716c38cc78c5df17120583c203c1640d to your computer and use it in GitHub Desktop.
Find functions in IDA which are called by library functions and probably aren't user code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import idaapi | |
from idautils import * | |
######## | |
# Date: October 2019 | |
# Author: David Cannings (@edeca) | |
# | |
# Rename all functions that are called by library code as "__unknown_library_function_N". | |
# | |
# There is a high likelyhood these are less interesting to analyse than user | |
# code, therefore attention should probably be spent elsewhere. This works well | |
# when FLIRT detects some library functions but not all. Adding additional | |
# signatures (View -> Subviews -> Signatures) can often give enough clues for this | |
# script to make your life easier. | |
# | |
# The search is conducted in multiple passes, so any function called by something | |
# we already renamed as __unknown_library_function_N will also be treated as internal. | |
######## | |
MAX_PASSES = 16 | |
def rename_function(function_ea, name, max=999): | |
renamed = False | |
for n in range(0, max+1): | |
new_name = "{}_{}".format(name, n) | |
if idaapi.set_name(function_ea, new_name, idaapi.SN_NOWARN): | |
renamed = True | |
break | |
if not renamed: | |
print("[!] Couldn't rename, do you need to increase max?") | |
func = idaapi.get_func(function_ea) | |
func.flags |= FUNC_LIB | |
idaapi.update_func(func) | |
def is_thunk_function(function_ea): | |
func = idaapi.get_func(function_ea) | |
if not func or not (func.flags & idaapi.FUNC_THUNK): | |
return False | |
return True | |
def is_library_function(function_ea): | |
func = idaapi.get_func(function_ea) | |
if not func or not (func.flags & idaapi.FUNC_LIB): | |
return False | |
return True | |
def should_skip(function_ea): | |
return is_thunk_function(function_ea) | is_library_function(function_ea) | |
def main(): | |
renamed = 0 | |
for i in range(1, MAX_PASSES + 1): | |
renamed_this_pass = 0 | |
print("[+] Pass {}".format(i)) | |
for function_ea in Functions(): | |
name = idaapi.get_func_name(function_ea) | |
if should_skip(function_ea) : | |
#print "[+] {} is a library/thunk function, skipping".format(name) | |
continue | |
if not name.startswith("sub_"): | |
#print("[+] Skipping {} because it has been renamed".format(name)) | |
continue | |
called_by_lib = False | |
for ref in CodeRefsTo(function_ea, 1): | |
# The caller name can be None when it's not part of a function | |
caller_name = idaapi.get_func_name(ref) | |
if caller_name is None: | |
continue | |
if is_library_function(ref) or caller_name.startswith("__unknown_library_function_"): | |
res = is_library_function(ref) | |
called_by_lib = True | |
break | |
if called_by_lib: | |
print("[+] Xref to 0x{:08x} comes from library function {}".format(function_ea, caller_name)) | |
rename_function(function_ea, "__unknown_library_function") | |
renamed_this_pass += 1 | |
renamed += renamed_this_pass | |
print("[+] End of pass {}, renamed {} functions".format(i, renamed_this_pass)) | |
if renamed_this_pass == 0: | |
break | |
print("[+] Finished, renamed a total of {} functions".format(renamed)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment