Skip to content

Instantly share code, notes, and snippets.

@jthuraisamy
Last active July 13, 2020 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jthuraisamy/7142c40e03e32892a02e3f0329f6355f to your computer and use it in GitHub Desktop.
Save jthuraisamy/7142c40e03e32892a02e3f0329f6355f to your computer and use it in GitHub Desktop.
#Recover function names from logger function calls.
#@author @Jackson_T
#@category _NEW_
#@keybinding
#@menupath
#@toolbar
import re
from ghidra.program.model.symbol import SourceType
from ghidra.util.exception import InvalidInputException
'''
Example logger function prototype:
void sub_140001000(int log_level,
char* function_name,
char* file_name,
char* format_str,
...);
'''
logger_addr = 0x140001000 # CHANGE THIS TO THE ADDRESS OF THE LOGGER FUNCTION
logger_regx = re.compile(r'.*\(.*,"(?P<name>.*?)","(?P<file>.*?)".*\)') # CHANGE THIS REGEX TO MATCH THE FUNCTION PROTOTYPE
logger_name = getFunctionContaining(toAddr(logger_addr)).getName()
# Initialize decompiler.
flat_program_api = ghidra.program.flatapi.FlatProgramAPI(getCurrentProgram(), getMonitor())
decompiler_api = ghidra.app.decompiler.flatapi.FlatDecompilerAPI(flat_program_api)
decompiler_api.initialize()
decompiler = decompiler_api.getDecompiler()
def get_functions_referencing_logger():
functions = []
references_to_logger = getReferencesTo(toAddr(logger_addr))
for reference in references_to_logger:
function = getFunctionContaining(reference.getFromAddress())
if function:
functions.append(function)
# Return list without duplicates.
return list(set(functions))
def extract_function_name_from_token(function_metadata, function, node):
if type(node) == ghidra.app.decompiler.ClangStatement:
if str(node).startswith(logger_name):
if function not in function_metadata:
call_str = str(node)
print((call_str[:100] + '...') if len(call_str) > 100 else call_str)
function_metadata[function] = logger_regx.match(str(node)).groupdict()
return
else:
for i in range(node.numChildren()):
extract_function_name_from_token(function_metadata, function, node.Child(i))
def collect_function_metadata_from_logger_call():
function_metadata = {}
functions = get_functions_referencing_logger()
getMonitor().initialize(len(functions))
for function in functions:
node = decompiler.decompileFunction(function, 0, None).getCCodeMarkup()
extract_function_name_from_token(function_metadata, function, node)
getMonitor().incrementProgress(1)
getMonitor().setMessage('Recovering name of {0}...'.format(function))
return function_metadata
def rename_functions():
function_metadata = collect_function_metadata_from_logger_call()
for function, metadata in function_metadata.items():
print('(I): Renaming {0} to {1}...'.format(function, metadata['name']))
# Account for class name if there is one.
if '::' in metadata['name']:
function_name = metadata['name'].split('::')[-1]
class_name = metadata['name'].split('::')[-2]
namespace = getNamespace(None, class_name)
# Create a namespace for the class if there isn't one.
if not namespace:
namespace = getCurrentProgram().getSymbolTable().createClass(
None,
class_name,
SourceType.USER_DEFINED)
# If there isn't a class name, use the global namespace.
else:
function_name = metadata['name']
namespace = None
# Set the namespace.
if namespace:
function.setParentNamespace(namespace)
# Set the function name.
try:
function.setName(function_name, SourceType.USER_DEFINED)
except InvalidInputException as e:
print('(E): {0}'.format(e))
rename_functions()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment