Skip to content

Commit 473faf2

Browse files
authored
Merge pull request #604 from bet4it/gdbserver
Make gdbserver great again
2 parents a79bdf8 + e251478 commit 473faf2

File tree

7 files changed

+87
-83
lines changed

7 files changed

+87
-83
lines changed

qiling/arch/arm64.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def __init__(self, ql):
1515
super(QlArchARM64, self).__init__(ql)
1616

1717
register_mappings = [
18-
reg_map
18+
reg_map, reg_map_part
1919
]
2020

2121
for reg_maper in register_mappings:

qiling/arch/arm64_const.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@
3737
"x28": UC_ARM64_REG_X28,
3838
"x29": UC_ARM64_REG_X29,
3939
"x30": UC_ARM64_REG_X30,
40+
"sp": UC_ARM64_REG_SP,
41+
"pc": UC_ARM64_REG_PC,
42+
"lr": UC_ARM64_REG_LR,
43+
"cpacr_el1": UC_ARM64_REG_CPACR_EL1,
44+
"tpidr_el0": UC_ARM64_REG_TPIDR_EL0,
45+
}
46+
47+
reg_map_part = {
4048
"w0" : UC_ARM64_REG_W0,
4149
"w1" : UC_ARM64_REG_W1,
4250
"w2" : UC_ARM64_REG_W2,
@@ -68,9 +76,4 @@
6876
"w28" : UC_ARM64_REG_W28,
6977
"w29" : UC_ARM64_REG_W29,
7078
"w30" : UC_ARM64_REG_W30,
71-
"sp": UC_ARM64_REG_SP,
72-
"pc": UC_ARM64_REG_PC,
73-
"lr": UC_ARM64_REG_LR,
74-
"cpacr_el1": UC_ARM64_REG_CPACR_EL1,
75-
"tpidr_el0": UC_ARM64_REG_TPIDR_EL0,
7679
}

qiling/arch/register.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def arch_pc(self):
107107
def arch_pc(self, value):
108108
return self.ql.uc.reg_write(self.uc_pc, value)
109109

110+
@property
111+
def arch_pc_name(self):
112+
return self.ql.reg.reverse_mapping[self.uc_pc]
110113

111114
@property
112115
def arch_sp(self):

qiling/arch/x86.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def __init__(self, ql):
7070

7171
x64_register_mappings = [
7272
reg_map_8, reg_map_16, reg_map_32, reg_map_64,
73-
reg_map_cr, reg_map_st, reg_map_misc
73+
reg_map_cr, reg_map_st, reg_map_misc, reg_map_part
7474
]
7575

7676
for reg_maper in x64_register_mappings:

qiling/arch/x86_const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@
104104
"r14": UC_X86_REG_R14,
105105
"r15": UC_X86_REG_R15,
106106
"rip": UC_X86_REG_RIP,
107+
}
108+
109+
reg_map_part = {
107110
"r8b": UC_X86_REG_R8B,
108111
"r9b": UC_X86_REG_R9B,
109112
"r10b": UC_X86_REG_R10B,

qiling/debugger/gdb/gdb.py

Lines changed: 69 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -58,35 +58,25 @@ def __init__(self, ql, ip, port):
5858
else:
5959
port = int(port)
6060

61+
self.ip = ip
62+
self.port = port
63+
6164
if ql.shellcoder:
6265
load_address = ql.os.entry_point
6366
exit_point = load_address + len(ql.shellcoder)
6467
else:
6568
load_address = ql.loader.load_address
6669
exit_point = load_address + os.path.getsize(ql.path)
6770

68-
logging.info("gdb> Listening on %s:%u" % (ip, port))
6971
self.gdb.initialize(self.ql, exit_point=exit_point, mappings=[(hex(load_address))])
7072

71-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
72-
sock.bind((ip, port))
73-
sock.listen(1)
74-
clientsocket, addr = sock.accept()
75-
76-
self.clientsocket = clientsocket
77-
self.netin = clientsocket.makefile('r')
78-
self.netout = clientsocket.makefile('w')
79-
8073
if self.ql.ostype in (QL_OS.LINUX, QL_OS.FREEBSD) and not self.ql.shellcoder:
8174
self.entry_point = self.ql.os.elf_entry
8275
else:
8376
self.entry_point = self.ql.os.entry_point
84-
8577

8678
self.gdb.bp_insert(self.entry_point)
8779

88-
89-
9080
#Setup register tables, order of tables is important
9181
self.tables = {
9282
QL_ARCH.A8086 : list({**x86_reg_map_16, **x86_reg_map_misc}.keys()),
@@ -139,12 +129,28 @@ def incomplete_hex_check(hexchar):
139129

140130
return unhexlify(rawbin_escape)
141131

132+
def setup_server(self):
133+
logging.info("gdb> Listening on %s:%u" % (self.ip, self.port))
134+
135+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
136+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
137+
sock.bind((self.ip, self.port))
138+
sock.listen(1)
139+
clientsocket, addr = sock.accept()
140+
141+
self.sock = sock
142+
self.clientsocket = clientsocket
143+
self.netin = clientsocket.makefile('r')
144+
self.netout = clientsocket.makefile('w')
145+
142146
def close(self):
143147
self.netin.close()
144148
self.netout.close()
145149
self.clientsocket.close()
150+
self.sock.close()
146151

147152
def run(self):
153+
self.setup_server()
148154

149155
while self.receive() == 'Good':
150156
pkt = self.last_pkt
@@ -403,44 +409,48 @@ def handle_p(subcmd):
403409
def handle_P(subcmd):
404410
reg_index, reg_data = subcmd.split('=')
405411
reg_index = int(reg_index, 16)
412+
reg_name = self.tables[self.ql.archtype][reg_index]
406413

407414
if self.ql.archtype== QL_ARCH.A8086:
408415
reg_data = int(reg_data, 16)
409416
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='big')
410-
self.ql.reg.write(self.tables[QL_ARCH.A8086][reg_index], reg_data)
417+
self.ql.reg.write(reg_name, reg_data)
411418

412419
elif self.ql.archtype== QL_ARCH.X86:
413420
reg_data = int(reg_data, 16)
414421
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='big')
415-
self.ql.reg.write(self.tables[QL_ARCH.X86][reg_index], reg_data)
422+
self.ql.reg.write(reg_name, reg_data)
416423

417424
elif self.ql.archtype== QL_ARCH.X8664:
418425
if reg_index <= 17:
419426
reg_data = int(reg_data, 16)
420427
reg_data = int.from_bytes(struct.pack('<Q', reg_data), byteorder='big')
421-
self.ql.reg.write(self.tables[QL_ARCH.X8664][reg_index], reg_data)
428+
self.ql.reg.write(reg_name, reg_data)
422429
else:
423430
reg_data = int(reg_data[:8], 16)
424431
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='big')
425-
self.ql.reg.write(self.tables[QL_ARCH.X8664][reg_index], reg_data)
432+
self.ql.reg.write(reg_name, reg_data)
426433

427434
elif self.ql.archtype== QL_ARCH.ARM:
428435
reg_data = int(reg_data, 16)
429436
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='big')
430-
self.ql.reg.write(self.tables[QL_ARCH.ARM][reg_index], reg_data)
437+
self.ql.reg.write(reg_name, reg_data)
431438

432439
elif self.ql.archtype== QL_ARCH.ARM64:
433440
reg_data = int(reg_data, 16)
434441
reg_data = int.from_bytes(struct.pack('<Q', reg_data), byteorder='big')
435-
self.ql.reg.write(self.tables[QL_ARCH.ARM64][reg_index], reg_data)
442+
self.ql.reg.write(reg_name, reg_data)
436443

437444
elif self.ql.archtype== QL_ARCH.MIPS:
438445
reg_data = int(reg_data, 16)
439446
if self.ql.archendian == QL_ENDIAN.EL:
440447
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='little')
441448
else:
442449
reg_data = int.from_bytes(struct.pack('<I', reg_data), byteorder='big')
443-
self.ql.reg.write(self.tables[QL_ARCH.MIPS][reg_index], reg_data)
450+
self.ql.reg.write(reg_name, reg_data)
451+
452+
if reg_name == self.ql.reg.arch_pc_name:
453+
self.gdb.current_address = reg_data
444454

445455
logging.info("gdb> Write to register %s with %x\n" % (self.tables[self.ql.archtype][reg_index], reg_data))
446456
self.send('OK')
@@ -462,6 +472,9 @@ def handle_Q(subcmd):
462472
elif subcmd.startswith('PassSignals'):
463473
self.send('OK')
464474

475+
elif subcmd.startswith('qemu'):
476+
self.send('')
477+
465478
def handle_D(subcmd):
466479
self.send('OK')
467480

@@ -479,9 +492,9 @@ def handle_q(subcmd):
479492
xfercmd_file = os.path.join(xfercmd_abspath,"xml",xml_folder, xfercmd_file)
480493

481494
if os.path.exists(xfercmd_file) and self.ql.ostype is not QL_OS.WINDOWS:
482-
f = open(xfercmd_file, 'r')
483-
file_contents = f.read()
484-
self.send("l%s" % file_contents)
495+
with open(xfercmd_file, 'r') as f:
496+
file_contents = f.read()
497+
self.send("l%s" % file_contents)
485498
else:
486499
logging.info("gdb> Platform is not supported by xml or xml file not found: %s\n" % (xfercmd_file))
487500
self.send("l")
@@ -522,7 +535,7 @@ def handle_q(subcmd):
522535
AT_HWCAP2 = "0000000000000000"
523536
ID_AT_EXECFN = "1f00000000000000"
524537
AT_EXECFN = "0000000000000000" # File name of executable
525-
ID_AT_PLATFORM = "f000000000000000"
538+
ID_AT_PLATFORM = "0f00000000000000"
526539
ID_AT_NULL = "0000000000000000"
527540
AT_NULL = "0000000000000000"
528541

@@ -550,7 +563,7 @@ def handle_q(subcmd):
550563
AT_HWCAP2 = "00000000"
551564
ID_AT_EXECFN = "1f000000"
552565
AT_EXECFN = "00000000" # File name of executable
553-
ID_AT_PLATFORM = "f0000000"
566+
ID_AT_PLATFORM = "0f000000"
554567
ID_AT_NULL = "00000000"
555568
AT_NULL = "00000000"
556569

@@ -666,65 +679,42 @@ def handle_v(subcmd):
666679
self.send("")
667680

668681
elif subcmd.startswith('File:open'):
669-
self.lib_path = subcmd.split(':')[-1].split(',')[0]
670-
self.lib_path = unhexlify(self.lib_path).decode(encoding='UTF-8')
682+
(file_path, flags, mode) = subcmd.split(':')[-1].split(',')
683+
file_path = unhexlify(file_path).decode(encoding='UTF-8')
684+
flags = int(flags, base=16)
685+
mode = int(mode, base=16)
686+
if file_path.startswith(self.rootfs_abspath):
687+
file_abspath = file_path
688+
else:
689+
file_abspath = self.ql.os.transform_to_real_path(file_path)
671690

672-
if self.lib_path != "just probing":
673-
if self.lib_path.startswith(self.rootfs_abspath):
674-
self.lib_abspath = self.lib_path
675-
else:
676-
self.lib_abspath = self.ql.os.transform_to_real_path(self.lib_path)
677-
678-
logging.debug("gdb> target file: %s" % (self.lib_abspath))
679-
680-
if os.path.exists(self.lib_abspath):
681-
self.send("F5")
682-
else:
683-
self.send("F0")
691+
logging.debug("gdb> target file: %s" % (file_abspath))
692+
if os.path.exists(file_abspath) and not (file_path).startswith("/proc"):
693+
fd = os.open(file_abspath, flags, mode)
694+
self.send("F%x" % fd)
684695
else:
685-
self.send("F0")
696+
self.send("F-1")
686697

687698
elif subcmd.startswith('File:pread:'):
699+
(fd, count, offset) = subcmd.split(':')[-1].split(',')
688700

689-
offset = subcmd.split(',')[-1]
690-
count = subcmd.split(',')[-2]
691-
offset = ((int(offset, base=16)))
692-
count = ((int(count, base=16)))
693-
694-
if os.path.exists(self.lib_abspath) and not (self.lib_path).startswith("/proc"):
695-
696-
with open(self.lib_abspath, "rb") as f:
697-
preadheader = f.read()
698-
699-
if offset != 0:
700-
shift_count = offset + count
701-
read_offset = preadheader[offset:shift_count]
702-
else:
703-
read_offset = preadheader[offset:count]
704-
705-
preadheader_len = len(preadheader)
706-
707-
read_offset = self.bin_to_escstr(read_offset)
701+
fd = int(fd, base=16)
702+
offset = int(offset, base=16)
703+
count = int(count, base=16)
708704

709-
if count == 1 and (preadheader_len >= offset):
710-
if read_offset:
711-
self.send(b'F1;' + (read_offset))
712-
else:
713-
self.send('F1;\x00')
705+
data = os.pread(fd, count, offset)
706+
size = len(data)
707+
data = self.bin_to_escstr(data)
714708

715-
elif count > 1:
716-
self.send(("F%x;" % len(read_offset)).encode() + (read_offset))
717-
718-
else:
719-
self.send("F0;")
720-
721-
elif re.match("\/proc\/.*\/maps", self.lib_abspath):
722-
self.send("F0;")
723-
709+
if data:
710+
self.send(("F%x;" % size).encode() + (data))
724711
else:
725712
self.send("F0;")
726713

727714
elif subcmd.startswith('File:close'):
715+
fd = subcmd.split(':')[-1]
716+
fd = int(fd, base=16)
717+
os.close(fd)
728718
self.send("F0")
729719

730720
elif subcmd.startswith('Kill'):
@@ -758,6 +748,10 @@ def handle_s(subcmd):
758748
self.send('S%.2x' % GDB_SIGNAL_TRAP)
759749

760750

751+
def handle_X(subcmd):
752+
self.send('')
753+
754+
761755
def handle_Z(subcmd):
762756
data = subcmd
763757
ztype = data[data.find('Z') + 1:data.find(',')]
@@ -807,6 +801,7 @@ def handle_exclaim(subcmd):
807801
'Q': handle_Q,
808802
's': handle_s,
809803
'v': handle_v,
804+
'X': handle_X,
810805
'Z': handle_Z,
811806
'z': handle_z
812807
}
@@ -870,4 +865,4 @@ def send(self, msg):
870865

871866
def send_raw(self, r):
872867
self.netout.write(r)
873-
self.netout.flush()
868+
self.netout.flush()

tests/test_debugger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_gdbdebug_file_server(self):
3636

3737
# some random command test just to make sure we covered most of the command
3838
def gdb_test_client():
39-
time.sleep(DELAY)
39+
time.sleep(DELAY * 2)
4040
gdb_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
4141
netout = gdb_client.makefile('w')
4242
gdb_client.connect(('127.0.0.1',9999))
@@ -89,7 +89,7 @@ def test_gdbdebug_shellcode_server(self):
8989
ql.debugger = "gdb:127.0.0.1:9998"
9090

9191
def gdb_test_client():
92-
time.sleep(DELAY)
92+
time.sleep(DELAY * 2)
9393
gdb_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
9494
netout = gdb_client.makefile('w')
9595
gdb_client.connect(('127.0.0.1',9998))

0 commit comments

Comments
 (0)