/
gdb.py
141 lines (108 loc) · 3.52 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
import subprocess
count = 0
prompt = ""
subproc = None
_arch = None
def drain():
str_buffer = ""
while not str_buffer.endswith(prompt):
c = subproc.stdout.read(1)
str_buffer += c
return str_buffer[: -len(prompt)]
def start(arch, argv, port=1234, _prompt="(gdb) "):
global prompt, subproc
prompt = _prompt
gdb = "gdb-multiarch"
try:
subproc = subprocess.Popen(
[gdb, argv[0]], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
except OSError:
msg = f"'{gdb}' binary not found in PATH (needed for tracing)"
raise RuntimeError(msg)
drain()
# correspond(f'set architecture {arch}\n')
correspond(f"file {argv[0]}\n")
correspond(f"target remote :{port}\n")
correspond("set pagination off\n")
def correspond(text):
"""Communicate with the child process without closing stdin."""
subproc.stdin.write(text)
subproc.stdin.flush()
return drain()
def getInstruction():
return correspond("x/i $pc\n").split("\n")[0]
def getR(reg):
reg = "$" + reg
if "XMM" in reg:
reg = reg + ".uint128"
val = correspond(f"p {reg.lower()}\n").split("=")[-1].split("\n")[0]
if "0x" in val:
return int(val.split("0x")[-1], 16)
else:
return int(val)
if "FLAG" in reg:
reg = "(unsigned) " + reg
if reg in [f"$R{i}B" for i in range(16)]:
reg = reg[:-1] + "&0xff"
if reg in [f"$R{i}W" for i in range(16)]:
reg = reg[:-1] + "&0xffff"
val = correspond(f"p /x {reg.lower()}\n")
val = val.split("0x")[-1]
return int(val.split("\n")[0], 16)
def getCanonicalRegisters():
reg_output = correspond("info reg\n")
registers = {}
for line in reg_output.split("\n"):
line = line.strip()
if not line:
continue
name, hex_val = line.split()[:2]
if name != "cpsr":
registers[name] = int(hex_val, 0)
else:
# We just want the NZCV flags
registers[name] = int(hex_val, 0) & 0xF0000000
return registers
def setR(reg, value):
correspond(f"set ${reg.lower()} = {int(value)}\n")
def stepi():
# print subproc.correspond("x/i $pc\n")
correspond("stepi\n")
def getM(m):
try:
return int(correspond(f"x/xg {m}\n").strip().split("\t")[-1], 0)
except Exception as e:
raise e
def getPid():
return int(correspond("info proc\n").split("\n")[0].split(" ")[-1])
def getStack():
p = correspond("info proc\n").split("\n")[0].split(" ")[-1]
with open(f"/proc/{p}/maps") as f:
maps = f.read().split("\n")
i, o = [int(x, 16) for x in maps[-3].split(" ")[0].split("-")]
def setByte(addr, val):
cmdstr = f"set {{char}}{addr} = {ord(val)}"
correspond(cmdstr + "\n")
def getByte(m):
arch = get_arch()
mask = {"i386": 0xFFFFFFFF, "armv7": 0xFFFFFFFF, "amd64": 0xFFFFFFFFFFFFFFFF}[arch]
return int(correspond(f"x/1bx {m & mask}\n").split("\t")[-1].split("\n")[0][2:], 16)
def get_entry():
a = correspond("info target\n")
return int(a[a.find("Entry point:") :].split("\n")[0].split(" ")[-1][2:], 16)
def get_arch():
global _arch
if _arch is not None:
return _arch
infotarget = correspond("info target\n")
if "elf32-i386" in infotarget:
_arch = "i386"
elif "elf64-x86-64" in infotarget:
_arch = "amd64"
elif "elf32-littlearm" in infotarget:
_arch = "armv7"
else:
print(infotarget)
raise NotImplementedError
return _arch