The percent script simulates the % key in VI command mode, more stack memory items. Basically this means that for a push, this makes you jump to the associated pop. For a call, this makes you jump to the corresponding ret, and so on.
It is built as an Axion script, so this also shows the use of a callback in Axion.
1 from axion_api
import axion
2 from PythonQt.Qt
import *
6 def pick_memory_access(client, point):
7 "Return first non null logical address accessed by instruction at given execution point or None"
8 null_logical = reven.logical_address(0, 0)
11 accesses = client.memory_get_history_instruction(point)
12 for access
in accesses:
13 if access.logical != null_logical:
14 if not (result
and result.write
and not access.write):
18 def get_matching_instruction(client, point):
19 "Return execution point of matching instruction for given execution point or None if not found."
22 point_range = reven.execution_range(point.run_name, point.sequence_identifier, 1, point.instruction_index)
24 context = client.run_get_running_context_between(point_range, reven.vector_of_logical_address_range())
27 ss_before = context.before.numeric_registers[
'ss'].value
28 ss_after = context.after.numeric_registers[
'ss'].value
31 if ss_before != ss_after:
33 return client.run_search_next_register_use(point, forward=(ss_before > ss_after), read=
False, write=
True, register_name=
"ss")
36 access = pick_memory_access(client, point)
39 return client.run_search_next_memory_use(point, forward=
True, read=
True, write=
False, address=access.logical)
42 return client.run_search_next_memory_use(point, forward=
False, read=
False, write=
True, address=access.logical)
45 esp_before = context.before.numeric_registers[
'esp'].value
46 esp_after = context.after.numeric_registers[
'esp'].value
49 if esp_before != esp_after:
50 if esp_before > esp_after:
51 stack = reven.logical_address(ss_after, esp_after)
52 return client.run_search_next_memory_use(point, forward=
True, read=
True, write=
False, address=stack)
54 if esp_before < esp_after:
55 stack = reven.logical_address(ss_before, esp_before)
56 return client.run_search_next_memory_use(point, forward=
False, read=
False, write=
True, address=stack)
62 run, seq, instr = axion.selected_sequence()
65 host, port = axion.connection_info()
66 client = reven.reven_connection(host.encode(), port)
69 point = reven.execution_point(run.encode(), seq, instr)
72 result = get_matching_instruction(client, point)
74 if result ==
None or not result.valid():
75 axion.status_message(
"No matching instruction recorded for [%s@%d:%d]" % (run, seq, instr))
78 axion.select_sequence(result.run_name, result.sequence_identifier, result.instruction_index)
79 axion.status_message(
"Jumped to matching instruction at [%s@%d:%d] from [%s@%d:%d]" % (result.run_name, result.sequence_identifier, result.instruction_index, run, seq, instr))