Last active
November 4, 2021 22:45
-
-
Save vbe0201/acabc5c6dfc65b0ad0f44a9947d84a45 to your computer and use it in GitHub Desktop.
Ghidra script that finds unique signature patterns for selected functions
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
# Finds unique signature patterns for selected functions | |
# @author Valentin B. | |
# @category Binary | |
from itertools import chain | |
from ghidra.program.model.lang import OperandType | |
def getSelectedFunction(): | |
if currentSelection: | |
for addr in chain.from_iterable(currentSelection): | |
func = getFunctionContaining(addr) | |
if func is not None: | |
return func | |
else: | |
return getFunctionContaining(currentAddress) | |
def isPatternUnique(pattern): | |
# If more than one match for the pattern exists, it is not unique. | |
return len(findBytes(None, pattern, 2)) == 1 | |
# Modify this function if a custom pattern style is desired. | |
# The `pattern` input contains `.` for unknown/wildcard bytes and `\\xab` for static bytes. | |
def formatPattern(pattern): | |
pattern = pattern.replace(".", " ?? ") | |
return " ".join(pattern.split("\\x")).replace(" ", " ").strip() | |
def main(): | |
func = getSelectedFunction() | |
if not func: | |
raise RuntimeError("Please select a function with your cursor first") | |
func_body = func.getBody() | |
function_start_addr = func_body.getMinAddress() | |
function_end_addr = func_body.getMaxAddress().next() # Inclusive end. | |
print( | |
"Finding unique signature for %s (%s)" | |
% (func.getName(), func.getSignature().getPrototypeString()) | |
) | |
found = False | |
pattern = "" | |
addr = function_start_addr | |
while not monitor.isCancelled() and addr != function_end_addr: | |
insn = getInstructionAt(addr) | |
if insn: | |
insn_bytes = insn.getBytes() | |
for i in range(len(insn_bytes)): | |
# If the operand is dynamic, we use a wildcard pattern instead of a concrete byte. | |
if insn.getOperandType(i) & OperandType.DYNAMIC != 0: | |
pattern += "." | |
else: | |
pattern += "\\x%02x" % (insn_bytes[i] & 0xFF) | |
# Check if we already have a unique signature. | |
if isPatternUnique(pattern): | |
found = True | |
break | |
if found: | |
break | |
addr = addr.next() | |
if not found: | |
raise RuntimeError("Failed to find unique signature pattern") | |
if not monitor.isCancelled(): | |
# Print out the result only if the script was not cancelled. | |
print("Found signature pattern: %s" % formatPattern(pattern)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment