Last active
July 13, 2020 01:48
-
-
Save jthuraisamy/7142c40e03e32892a02e3f0329f6355f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#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