REVEN-Axion 2015v1.2.0
slicer.py

The slicer script make use of REVEN data tainting capabilities to display a list of instructions that manipulate tainted data.

It uses services run_search_tainted_instructions to retrieve the list of interesting instruction locations, then for each point, it prints the instructions themselves.

1 #!/usr/bin/env python
2 
3 import reven
4 import sys
5 
6 def query_connection():
7  rvn = None
8  host = raw_input('Enter the reven host [localhost]: ')
9  if not host:
10  host = "localhost"
11 
12  try:
13  port = int(raw_input('Enter the reven port [13370]: '))
14  except ValueError:
15  port = 13370
16 
17  try:
18  rvn = reven.reven_connection(host, port)
19  except:
20  print("[!] Reven not found on port %d" % port)
21  sys.exit(1)
22 
23  print("[+] Connected to reven on %s:%d" % (host, port))
24 
25  return rvn
26 
27 
28 def query_taint_range(rvn):
29  runs = rvn.run_get_all()
30 
31  if len(runs) == 0:
32  sys.stderr.write("[!] No run detected.\n")
33  sys.exit(1)
34 
35  # Usually the interesting run will always be the first one, unless we are using the fuzzer.
36  run = runs[0]
37 
38  try:
39  start_sequence = int(raw_input("Enter the initial sequence [0]: "))
40  except ValueError:
41  start_sequence = 0
42 
43  try:
44  start_instruction = int(raw_input("Enter the initial instruction [0]: "))
45  except ValueError:
46  start_instruction = 0
47 
48  try:
49  stop_sequence = int(raw_input("Enter the ending sequence [1]: "))
50  except ValueError:
51  stop_sequence = 1
52 
53  stop_instruction = 0
54 
55  start_point = reven.execution_point(run, start_sequence, start_instruction)
56  stop_point = reven.execution_point(run, stop_sequence, stop_instruction)
57 
58  return start_point, stop_point
59 
60 def query_initial_taint(rvn, point):
61 
62  reg = raw_input("Enter the initialy tainted register [eax]: ")
63  if not reg:
64  reg = "eax"
65 
66  # Here we only taint one register, we could create more of them if desired.
67  register_tainted = [reg]
68 
69  # We can also taint some memories by uncommenting the last part of the following lines:
70  # Memory range (last is excluded)
71  first_memory_tainted = reven.logical_address(0,0) #reven.logical_address(0x7b,0xbffff55c)
72  last_memory_tainted = reven.logical_address(0,0) #reven.logical_address(0x7b,0xbffff58c)
73 
74  initial_taint = reven.vector_of_symbolic()
75 
76  # Create the list of registers to taint. We just convert any item in register_tainted to the proper format.
77  for sym in register_tainted:
78  smem = reven.symbolic()
79  smem.name = reg
80  smem.type = reven.symbolic_type.register_all_purpose
81  initial_taint.append(smem)
82 
83  # We do exactly the same for memories. In the memories case, we also have to get their physical address
84  # because the tainter works by physical addresses.
85  segment = first_memory_tainted.segment
86  for offset in range(first_memory_tainted.offset, last_memory_tainted.offset):
87  smem = reven.symbolic()
88  # In the case of physical memory, name is irrevelant, its only used for pretty printing.
89  smem.name = "0x%x:0x%x" % (segment, offset)
90  smem.type = reven.symbolic_type.memory_physical
91  smem.physical_address = rvn.memory_get_physical_address(point, reven.logical_address(segment, offset))
92  smem.size = 1
93 
94  initial_taint.append(smem)
95 
96  return initial_taint
97 
98 def propagate(rvn, start_point, stop_point, initial_taint):
99 
100  # Propagate taint, may took some times
101  print "[*] Tainting ..."
102  runtime = 5000 # run for at most 5 seconds
103  tainted_points = rvn.run_search_tainted_instructions(start_point, stop_point, runtime, initial_taint, False)
104 
105  print("[*] Tracking ")
106  for i in initial_taint:
107  print("%s, " % (i.name), '', None)
108  print("from #%d:%d to #%d:%d" % (start_point.sequence_identifier,
109  start_point.instruction_index,
110  stop_point.sequence_identifier,
111  0))
112  print("-----------------------------------------------\n")
113 
114  return tainted_points
115 
116 def print_sliced_trace(rvn, tainted_points):
117  # Now, in tainted_points, we have all points where the taint is changed.
118  for entry in tainted_points:
119  k = entry.key()
120  v = entry.data()
121 
122  if not len(v.new) and not len(v.old):
123  # Ignore when the taint hasn't changed
124  continue
125 
126  # Request the instructions of the tainted point
127  sequences = rvn.run_get_instructions_range(reven.execution_range(k.run_name, k.sequence_identifier, 1, 0))
128  seq = sequences[0]
129  ins = seq.instructions[k.instruction_index]
130 
131  # Print the instruction itself
132  mnemonic = " "
133  if ins.prefixes: mnemonic = "%s " % ins.prefixes
134  mnemonic += ins.mnemonic
135  if ins.operand_one: mnemonic += " " + ins.operand_one
136  if ins.operand_two: mnemonic += ", " + ins.operand_two
137  if ins.operand_three: mnemonic += ", " + ins.operand_three
138 
139  symbol = "%s+%x" % (seq.sequence.symbol.name, seq.sequence.symbol.offset)
140  print("%-32s: #%d_%d: %s" % (symbol, k.sequence_identifier, k.instruction_index, mnemonic))
141 
142 if __name__ == '__main__':
143 
144  # Query connection info from the user
145  rvn = query_connection()
146 
147  # Query user for taint range
148  start_point, stop_point = query_taint_range(rvn)
149 
150  # Query user for initialy tainted data
151  initial_taint = query_initial_taint(rvn, start_point)
152 
153  # Propagate the taint
154  result = propagate(rvn, start_point, stop_point, initial_taint)
155 
156  # Display the sliced trace
157  print_sliced_trace(rvn, result)