feature: Import stub functions but don't overwrite their argument list

Ghidra might have auto-detected some arguments, so we don't want to overwrite that if the stub's argument list has not been verified

Closes #1009
This commit is contained in:
jonschz 2024-06-16 08:14:26 +02:00
parent 91dd9fed0d
commit bead9d1010
2 changed files with 22 additions and 14 deletions

View File

@ -88,7 +88,10 @@ def matches_ghidra_function(self, ghidra_function: Function) -> bool:
self.signature.call_type == ghidra_function.getCallingConventionName() self.signature.call_type == ghidra_function.getCallingConventionName()
) )
if thiscall_matches: if self.is_stub:
# We do not import the argument list for stubs, so it should be excluded in matches
args_match = True
elif thiscall_matches:
if self.signature.call_type == "__thiscall": if self.signature.call_type == "__thiscall":
args_match = self._matches_thiscall_parameters(ghidra_function) args_match = self._matches_thiscall_parameters(ghidra_function)
else: else:
@ -102,7 +105,7 @@ def matches_ghidra_function(self, ghidra_function: Function) -> bool:
name_match, name_match,
return_type_match, return_type_match,
thiscall_matches, thiscall_matches,
args_match, "ignored" if self.is_stub else args_match,
) )
return ( return (
@ -163,16 +166,25 @@ def overwrite_ghidra_function(self, ghidra_function: Function):
ghidra_function.setReturnType(self.return_type, SourceType.USER_DEFINED) ghidra_function.setReturnType(self.return_type, SourceType.USER_DEFINED)
ghidra_function.setCallingConvention(self.call_type) ghidra_function.setCallingConvention(self.call_type)
if self.is_stub:
logger.debug(
"%s is a stub, skipping parameter import", self.get_full_name()
)
return
ghidra_function.replaceParameters( ghidra_function.replaceParameters(
Function.FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, Function.FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
True, True, # force
SourceType.USER_DEFINED, SourceType.USER_DEFINED,
self.arguments, self.arguments,
) )
# When we set the parameters, Ghidra will generate the layout. self._import_parameter_names(ghidra_function)
# Now we read them again and match them against the stack layout in the PDB,
# both to verify and to set the parameter names. def _import_parameter_names(self, ghidra_function: Function):
# When we call `ghidra_function.replaceParameters`, Ghidra will generate the layout.
# Now we read the parameters again and match them against the stack layout in the PDB,
# both to verify the layout and to set the parameter names.
ghidra_parameters: list[Parameter] = ghidra_function.getParameters() ghidra_parameters: list[Parameter] = ghidra_function.getParameters()
# Try to add Ghidra function names # Try to add Ghidra function names
@ -186,7 +198,9 @@ def overwrite_ghidra_function(self, ghidra_function: Function):
# Appears to never happen - could in theory be relevant to __fastcall__ functions, # Appears to never happen - could in theory be relevant to __fastcall__ functions,
# which we haven't seen yet # which we haven't seen yet
logger.warning("Unhandled register variable in %s", self.get_full_name) logger.warning(
"Unhandled register variable in %s", self.get_full_name()
)
continue continue
def _rename_stack_parameter(self, index: int, param: Parameter): def _rename_stack_parameter(self, index: int, param: Parameter):

View File

@ -135,9 +135,7 @@ def get_function_list(self) -> list[PdbFunction]:
) )
return [signature for signature in handled if signature is not None] return [signature for signature in handled if signature is not None]
def handle_matched_function( def handle_matched_function(self, match_info: MatchInfo) -> Optional[PdbFunction]:
self, match_info: MatchInfo
) -> Optional[PdbFunction]:
assert match_info.orig_addr is not None assert match_info.orig_addr is not None
match_options = self.compare.get_match_options(match_info.orig_addr) match_options = self.compare.get_match_options(match_info.orig_addr)
assert match_options is not None assert match_options is not None
@ -172,8 +170,4 @@ def handle_matched_function(
is_stub = match_options.get("stub", False) is_stub = match_options.get("stub", False)
# TODO: Remove when implementing stubs
if is_stub:
return None
return PdbFunction(match_info, function_signature, is_stub) return PdbFunction(match_info, function_signature, is_stub)