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
|
import lldb
from angr.errors import SimConcreteMemoryError, \
SimConcreteRegisterError
from angr_targets.concrete import ConcreteTarget
from angr_targets.memory_map import MemoryMap
class LLDBConcreteTarget(ConcreteTarget):
def __init__(self, executable: str, args: list[str] = []):
# Prepend the executable's path to argv, as is convention
args.insert(0, executable)
self.debugger = lldb.SBDebugger.Create()
self.debugger.SetAsync(False)
self.target = self.debugger.CreateTargetWithFileAndArch(executable,
lldb.LLDB_ARCH_DEFAULT)
self.module = self.target.FindModule(self.target.GetExecutable())
self.interpreter = self.debugger.GetCommandInterpreter()
# Set up objects for process execution
self.error = lldb.SBError()
self.listener = self.debugger.GetListener()
self.process = self.target.Launch(self.listener,
args, None, None,
None, None, None, 0,
True, self.error)
if not self.process.IsValid():
raise RuntimeError(f'[In LLDBConcreteTarget.__init__]: Failed to'
f' launch process.')
def set_breakpoint(self, addr, **kwargs):
command = f'b -a {addr} -s {self.module.GetFileSpec().GetFilename()}'
result = lldb.SBCommandReturnObject()
self.interpreter.HandleCommand(command, result)
def remove_breakpoint(self, addr, **kwargs):
command = f'breakpoint delete {addr}'
result = lldb.SBCommandReturnObject()
self.interpreter.HandleCommand(command, result)
def is_running(self):
return self.process.GetState() == lldb.eStateRunning
def is_exited(self):
"""Not part of the angr interface, but much more useful than
`is_running`.
:return: True if the process has exited. False otherwise.
"""
return self.process.GetState() == lldb.eStateExited
def wait_for_running(self):
while self.process.GetState() != lldb.eStateRunning:
pass
def wait_for_halt(self):
while self.process.GetState() != lldb.eStateStopped:
pass
def run(self):
state = self.process.GetState()
if state == lldb.eStateExited:
raise RuntimeError(f'Tried to resume process execution, but the'
f' process has already exited.')
assert(state == lldb.eStateStopped)
self.process.Continue()
def stop(self):
self.process.Stop()
def exit(self):
self.debugger.Terminate()
print(f'Program exited with status {self.process.GetState()}')
def read_register(self, regname: str) -> int:
frame = self.process.GetThreadAtIndex(0).GetFrameAtIndex(0)
reg = frame.FindRegister(regname)
if reg is None:
raise SimConcreteRegisterError(
f'[In LLDBConcreteTarget.read_register]: Register {regname}'
f' not found.')
val = reg.GetValue()
if val is None:
raise SimConcreteRegisterError(
f'[In LLDBConcreteTarget.read_register]: Register has an'
f' invalid value of {val}.')
return int(val, 16)
def read_memory(self, addr, size):
err = lldb.SBError()
content = self.process.ReadMemory(addr, size, err)
if not err.success:
raise SimConcreteMemoryError(f'Error when reading {size} bytes at'
f' address {hex(addr)}: {err}')
return content
def write_memory(self, addr, value):
err = lldb.SBError()
res = self.process.WriteMemory(addr, value, err)
if not err.success or res != len(value):
raise SimConcreteMemoryError(f'Error when writing to address'
f' {hex(addr)}: {err}')
def get_mappings(self):
mmap = []
region_list = self.process.GetMemoryRegions()
for i in range(region_list.GetSize()):
region = lldb.SBMemoryRegionInfo()
region_list.GetMemoryRegionAtIndex(i, region)
perms = f'{"r" if region.IsReadable() else "-"}' \
f'{"w" if region.IsWritable() else "-"}' \
f'{"x" if region.IsExecutable() else "-"}' \
mmap.append(MemoryMap(region.GetRegionBase(),
region.GetRegionEnd(),
0, # offset?
"<no-name>", # name?
perms))
return mmap
|