-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
gdb.py
142 lines (113 loc) · 4.97 KB
/
gdb.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import os
import re
import logging
import claripy
import binascii
from .plugin import SimStatePlugin
from ..errors import SimStateError
l = logging.getLogger(name=__name__)
#global heap_location
class GDB(SimStatePlugin):
"""
Initialize or update a state from gdb dumps of the stack, heap, registers and data (or arbitrary) segments.
"""
def __init__(self, omit_fp=False, adjust_stack=False):
"""
:param omit_fp: The frame pointer register is used for something else. (i.e. --omit_frame_pointer)
:param adjust_stack: Use different stack addresses than the gdb session (not recommended).
"""
SimStatePlugin.__init__(self)
# The stack top from gdb's session
self.real_stack_top = 0
# Is the binary compiled with --omit_frame_pointer ?
self.omit_fp = omit_fp
# Adjust the stack w.r.t. the real stack (from the gdb session)
self.adjust_stack = adjust_stack
def set_stack(self, stack_dump, stack_top):
"""
Stack dump is a dump of the stack from gdb, i.e. the result of the following gdb command :
``dump binary memory [stack_dump] [begin_addr] [end_addr]``
We set the stack to the same addresses as the gdb session to avoid pointers corruption.
:param stack_dump: The dump file.
:param stack_top: The address of the top of the stack in the gdb session.
"""
data = self._read_data(stack_dump)
self.real_stack_top = stack_top
addr = stack_top - len(data) # Address of the bottom of the stack
l.info("Setting stack from 0x%x up to %#x", addr, stack_top)
#FIXME: we should probably make we don't overwrite other stuff loaded there
self._write(addr, data)
def set_heap(self, heap_dump, heap_base):
"""
Heap dump is a dump of the heap from gdb, i.e. the result of the
following gdb command:
``dump binary memory [stack_dump] [begin] [end]``
:param heap_dump: The dump file.
:param heap_base: The start address of the heap in the gdb session.
"""
# We set the heap at the same addresses as the gdb session to avoid pointer corruption.
data = self._read_data(heap_dump)
self.state.heap.heap_location = heap_base + len(data)
addr = heap_base
l.info("Set heap from 0x%x to %#x", addr, addr+len(data))
#FIXME: we should probably make we don't overwrite other stuff loaded there
self._write(addr, data)
def set_data(self, addr, data_dump):
"""
Update any data range (most likely use is the data segments of loaded objects)
"""
data = self._read_data(data_dump)
l.info("Set data from 0x%x to %#x", addr, addr+len(data))
self._write(addr, data)
def set_regs(self, regs_dump):
"""
Initialize register values within the state
:param regs_dump: The output of ``info registers`` in gdb.
"""
if self.real_stack_top == 0 and self.adjust_stack is True:
raise SimStateError("You need to set the stack first, or set"
"adjust_stack to False. Beware that in this case, sp and bp won't be updated")
data = self._read_data(regs_dump)
rdata = re.split(b"\n", data)
for r in rdata:
if r == b"":
continue
reg = re.split(b" +", r)[0].decode()
val = int(re.split(b" +", r)[1],16)
try:
self.state.registers.store(reg, claripy.BVV(val, self.state.arch.bits))
# Some registers such as cs, ds, eflags etc. aren't supported in angr
except KeyError as e:
l.warning("Reg %s was not set", e)
self._adjust_regs()
def _adjust_regs(self):
"""
Adjust bp and sp w.r.t. stack difference between GDB session and angr.
This matches sp and bp registers, but there is a high risk of pointers inconsistencies.
"""
if not self.adjust_stack:
return
bp = self.state.arch.register_names[self.state.arch.bp_offset]
sp = self.state.arch.register_names[self.state.arch.sp_offset]
stack_shift = self.state.arch.initial_sp - self.real_stack_top
self.state.registers.store(sp, self.state.regs.sp + stack_shift)
if not self.omit_fp:
self.state.registers.store(bp, self.state.regs.bp + stack_shift)
@staticmethod
def _read_data(path):
if not os.path.exists(path):
raise SimStateError("File does not exist")
f = open(path, "rb")
return f.read()
def _write(self, addr, data):
self.state.memory.store(addr, data)
@staticmethod
def _to_bvv(data):
sz = len(data)
num = int(binascii.hexlify(data), 16)
return claripy.BVV(num, sz)
@SimStatePlugin.memo
def copy(self, memo): # pylint: disable=unused-argument
return GDB()
from angr.sim_state import SimState
SimState.register_default('gdb', GDB)