-
Notifications
You must be signed in to change notification settings - Fork 0
/
__init__.py
92 lines (69 loc) · 3.47 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from binaryninja import log_info, log_debug, log_error, log_warn
import binaryninja.interaction as interaction
from binaryninja.enums import MediumLevelILOperation
from binaryninja.plugin import PluginCommand
from binaryninja.types import Symbol
def discover_names(func, func_params):
param = func_params[0]
paramIndex = func.parameter_vars.vars.index(param)
identified_functions = {}
for caller in set(func.callers):
logged_names = set()
# Ensure that we only see one method used in this function
for mlil_inst in caller.mlil.instructions:
# Calls only
if mlil_inst.operation != MediumLevelILOperation.MLIL_CALL:
continue
# Ensure that we're only acting on our calls
# FIXME: There must be a better way to find the callee
if not hasattr(mlil_inst.operands[1], 'constant'):
continue
called_func = func.view.get_function_at(mlil_inst.operands[1].constant)
if called_func != func:
continue
call_site_param = caller.get_parameter_at(mlil_inst.address, func.function_type, paramIndex)
# FIXME: There must be a better way again
if str(call_site_param) == "<undetermined>":
call_site_param = None
logged_names.add(call_site_param)
if len(logged_names) != 1 or None in logged_names:
log_warn("Unable to determine method name for function %r: Identified method names: %r" % (caller, logged_names))
continue
logged_name_addr = list(logged_names)[0].value
method_name = func.view.get_string_at(logged_name_addr).value
if method_name not in identified_functions:
identified_functions[method_name] = set()
identified_functions[method_name].add(caller)
# Eliminate names with multiple callers
for name, callers in dict(identified_functions).items():
if len(callers) != 1:
log_debug("Eliminating name %r with callers %r" % (name, callers))
del identified_functions[name]
else:
identified_functions[name] = list(callers)[0]
return identified_functions
def do_discover_caller_names(bv, func):
param_name = interaction.get_text_line_input("Please enter the name of the parameter that contains the method name", "Parameter name")
# Docs says the above function returns a string with a link to the Python 3
# docs (e.g. a Py3 str), but it actually returns a bytes-object under Py3
param_name = param_name.decode("utf-8")
func_params = [param for param in func.parameter_vars if param.name == param_name]
force = False
if len(func_params) != 1:
log_error("Unable to determine method name argument")
return
for name, func in discover_names(func, func_params).items():
# Skip if named correctly
if func.symbol.name == name:
continue
# Skip if we're not forcing and the user has named this already
if not func.symbol.auto and not force:
log_debug("Skipped %r due to no auto symbol" % name)
continue
log_info("Renaming %r to %r" % (func, name))
func.view.define_auto_symbol(Symbol(func.symbol.type, func.symbol.address, short_name=name))
PluginCommand.register_for_function(
"Analysis\\Discover caller names by call parameters",
"Renames all unique callers based on call parameters to the current function",
do_discover_caller_names,
)