|
6 | 6 | # gdbserver --remote-debug 0.0.0.0:9999 /path/to binary |
7 | 7 | # documentation: according to https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol |
8 | 8 |
|
9 | | -from unicorn import * |
10 | | - |
11 | | -import struct, os, re, socket |
| 9 | +import struct, os, socket |
12 | 10 | from binascii import unhexlify |
| 11 | +from typing import Iterator, Literal |
13 | 12 |
|
14 | | -from .utils import QlGdbUtils |
| 13 | +from qiling import Qiling |
15 | 14 | from qiling.const import * |
16 | 15 | from qiling.utils import * |
17 | 16 | from qiling.debugger import QlDebugger |
|
25 | 24 | from qiling.arch.mips_const import reg_map as mips_reg_map |
26 | 25 | from qiling.loader.elf import AUX |
27 | 26 |
|
| 27 | +from .utils import QlGdbUtils |
| 28 | + |
28 | 29 | GDB_SIGNAL_INT = 2 |
29 | 30 | GDB_SIGNAL_SEGV = 11 |
30 | 31 | GDB_SIGNAL_GILL = 4 |
|
35 | 36 |
|
36 | 37 | class QlGdb(QlDebugger, object): |
37 | 38 | """docstring for Debugsession""" |
38 | | - def __init__(self, ql, ip, port): |
| 39 | + def __init__(self, ql: Qiling, ip: str = '127.0.01', port: int = 9999): |
39 | 40 | super(QlGdb, self).__init__(ql) |
| 41 | + |
40 | 42 | self.ql = ql |
41 | 43 | self.last_pkt = None |
42 | | - self.exe_abspath = (os.path.abspath(self.ql.argv[0])) |
43 | | - self.rootfs_abspath = (os.path.abspath(self.ql.rootfs)) |
| 44 | + self.exe_abspath = os.path.abspath(self.ql.argv[0]) |
| 45 | + self.rootfs_abspath = os.path.abspath(self.ql.rootfs) |
44 | 46 | self.gdb = QlGdbUtils() |
45 | 47 |
|
46 | | - if ip == None: |
47 | | - ip = '127.0.0.1' |
48 | | - |
49 | | - if port == None: |
50 | | - port = 9999 |
51 | | - else: |
52 | | - port = int(port) |
| 48 | + if type(port) is str: |
| 49 | + port = int(port, 0) |
53 | 50 |
|
54 | 51 | self.ip = ip |
55 | 52 | self.port = port |
@@ -83,18 +80,23 @@ def __init__(self, ql, ip, port): |
83 | 80 | QL_ARCH.MIPS : list({**mips_reg_map}.keys()), |
84 | 81 | } |
85 | 82 |
|
86 | | - def addr_to_str(self, addr, short=False, endian="big"): |
87 | | - if self.ql.archbit == 64 and short == False: |
88 | | - addr = (hex(int.from_bytes(self.ql.pack64(addr), byteorder=endian))) |
89 | | - addr = '{:0>16}'.format(addr[2:]) |
90 | | - elif self.ql.archbit == 32 or short == True: |
91 | | - addr = (hex(int.from_bytes(self.ql.pack32(addr), byteorder=endian))) |
92 | | - addr = ('{:0>8}'.format(addr[2:])) |
93 | | - elif self.ql.archbit == 16 or short == True: |
94 | | - addr = (hex(int.from_bytes(self.ql.pack32(addr), byteorder=endian))) |
95 | | - addr = ('{:0>8}'.format(addr[2:])) |
96 | | - addr = str(addr) |
97 | | - return addr |
| 83 | + def addr_to_str(self, addr: int, short: bool = False, endian: Literal['little', 'big'] = 'big') -> str: |
| 84 | + # a hacky way to divide archbits by 2 if short, and leave it unchanged if not |
| 85 | + nbits = self.ql.archbit // (int(short) + 1) |
| 86 | + |
| 87 | + if nbits == 64: |
| 88 | + s = f'{int.from_bytes(self.ql.pack64(addr), byteorder=endian):016x}' |
| 89 | + |
| 90 | + elif nbits == 32: |
| 91 | + s = f'{int.from_bytes(self.ql.pack32(addr), byteorder=endian):08x}' |
| 92 | + |
| 93 | + elif nbits == 16: |
| 94 | + s = f'{int.from_bytes(self.ql.pack16(addr), byteorder=endian):04x}' |
| 95 | + |
| 96 | + else: |
| 97 | + raise RuntimeError |
| 98 | + |
| 99 | + return s |
98 | 100 |
|
99 | 101 | def bin_to_escstr(self, rawbin): |
100 | 102 | rawbin_escape = "" |
@@ -221,13 +223,13 @@ def handle_g(subcmd): |
221 | 223 | s += tmp |
222 | 224 |
|
223 | 225 | elif self.ql.archtype == QL_ARCH.ARM: |
224 | | - mode = self.ql.arch.check_thumb() |
| 226 | + |
225 | 227 |
|
226 | 228 | # r0-r12,sp,lr,pc,cpsr ,see https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/arch/arm.h;h=fa589fd0582c0add627a068e6f4947a909c45e86;hb=HEAD#l127 |
227 | 229 | for reg in self.tables[QL_ARCH.ARM][:16] + [self.tables[QL_ARCH.ARM][25]]: |
228 | | - r = self.ql.reg.read(reg) |
229 | | - if mode == UC_MODE_THUMB and reg == "pc": |
230 | | - r += 1 |
| 230 | + # if reg is pc, make sure to take thumb mode into account |
| 231 | + r = self.ql.arch.get_pc() if reg == "pc" else self.ql.reg.read(reg) |
| 232 | + |
231 | 233 | tmp = self.addr_to_str(r) |
232 | 234 | s += tmp |
233 | 235 |
|
@@ -505,106 +507,43 @@ def handle_q(subcmd): |
505 | 507 | elif subcmd.startswith('Xfer:auxv:read::'): |
506 | 508 | if self.ql.code: |
507 | 509 | return |
508 | | - if self.ql.ostype in (QL_OS.LINUX, QL_OS.FREEBSD) : |
509 | | - if self.ql.archbit == 64: |
510 | | - ANNEX = "00000000000000" |
511 | | - AT_SYSINFO_EHDR = "0000000000000000" # System-supplied DSO's ELF header |
512 | | - ID_AT_HWCAP = "1000000000000000" |
513 | | - ID_AT_PAGESZ = "0600000000000000" |
514 | | - ID_AT_CLKTCK = "1100000000000000" |
515 | | - AT_CLKTCK = "6400000000000000" # Frequency of times() 100 |
516 | | - ID_AT_PHDR = "0300000000000000" |
517 | | - ID_AT_PHENT = "0400000000000000" |
518 | | - ID_AT_PHNUM = "0500000000000000" |
519 | | - ID_AT_BASE = "0700000000000000" |
520 | | - ID_AT_FLAGS = "0800000000000000" |
521 | | - ID_AT_ENTRY = "0900000000000000" |
522 | | - ID_AT_UID = "0b00000000000000" |
523 | | - ID_AT_EUID = "0c00000000000000" |
524 | | - ID_AT_GID = "0d00000000000000" |
525 | | - ID_AT_EGID = "0e00000000000000" |
526 | | - ID_AT_SECURE = "1700000000000000" |
527 | | - AT_SECURE = "0000000000000000" |
528 | | - ID_AT_RANDOM = "1900000000000000" |
529 | | - ID_AT_HWCAP2 = "1a00000000000000" |
530 | | - AT_HWCAP2 = "0000000000000000" |
531 | | - ID_AT_EXECFN = "1f00000000000000" |
532 | | - AT_EXECFN = "0000000000000000" # File name of executable |
533 | | - ID_AT_PLATFORM = "0f00000000000000" |
534 | | - ID_AT_NULL = "0000000000000000" |
535 | | - AT_NULL = "0000000000000000" |
536 | | - |
537 | | - elif self.ql.archbit == 32: |
538 | | - ANNEX = "000000" |
539 | | - AT_SYSINFO_EHDR = "00000000" # System-supplied DSO's ELF header |
540 | | - ID_AT_HWCAP = "10000000" |
541 | | - ID_AT_PAGESZ = "06000000" |
542 | | - ID_AT_CLKTCK = "11000000" |
543 | | - AT_CLKTCK = "64000000" # Frequency of times() 100 |
544 | | - ID_AT_PHDR = "03000000" |
545 | | - ID_AT_PHENT = "04000000" |
546 | | - ID_AT_PHNUM = "05000000" |
547 | | - ID_AT_BASE = "07000000" |
548 | | - ID_AT_FLAGS = "08000000" |
549 | | - ID_AT_ENTRY = "09000000" |
550 | | - ID_AT_UID = "0b000000" |
551 | | - ID_AT_EUID = "0c000000" |
552 | | - ID_AT_GID = "0d000000" |
553 | | - ID_AT_EGID = "0e000000" |
554 | | - ID_AT_SECURE = "17000000" |
555 | | - AT_SECURE = "00000000" |
556 | | - ID_AT_RANDOM = "19000000" |
557 | | - ID_AT_HWCAP2 = "1a000000" |
558 | | - AT_HWCAP2 = "00000000" |
559 | | - ID_AT_EXECFN = "1f000000" |
560 | | - AT_EXECFN = "00000000" # File name of executable |
561 | | - ID_AT_PLATFORM = "0f000000" |
562 | | - ID_AT_NULL = "00000000" |
563 | | - AT_NULL = "00000000" |
564 | | - |
565 | | - AT_HWCAP = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_HWCAP]) # mock cpuid 0x1f8bfbff |
566 | | - AT_PAGESZ = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_PAGESZ]) # System page size, fixed in qiling |
567 | | - AT_PHDR = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_PHDR]) # Program headers for program |
568 | | - AT_PHENT = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_PHENT]) # Size of program header entry |
569 | | - AT_PHNUM = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_PHNUM]) # Number of program headers |
570 | | - AT_BASE = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_BASE]) # Base address of interpreter |
571 | | - AT_FLAGS = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_FLAGS]) |
572 | | - AT_ENTRY = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_ENTRY]) # Entry point of program |
573 | | - AT_UID = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_UID]) # UID from ql.profile |
574 | | - AT_EUID = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_EUID]) # UID from ql.profile |
575 | | - AT_GID = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_GID]) # UID from ql.profile |
576 | | - AT_EGID = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_EGID]) # UID from ql.profile |
577 | | - AT_RANDOM = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_RANDOM]) # Address of 16 random bytes |
578 | | - AT_PLATFORM = self.addr_to_str(self.ql.loader.aux_vec[AUX.AT_PLATFORM]) # String identifying platform |
579 | | - |
580 | | - auxvdata_c = ( |
581 | | - ANNEX + AT_SYSINFO_EHDR + |
582 | | - ID_AT_HWCAP + AT_HWCAP + |
583 | | - ID_AT_PAGESZ + AT_PAGESZ + |
584 | | - ID_AT_CLKTCK + AT_CLKTCK + |
585 | | - ID_AT_PHDR + AT_PHDR + |
586 | | - ID_AT_PHENT + AT_PHENT + |
587 | | - ID_AT_PHNUM + AT_PHNUM + |
588 | | - ID_AT_BASE + AT_BASE + |
589 | | - ID_AT_FLAGS + AT_FLAGS + |
590 | | - ID_AT_ENTRY + AT_ENTRY + |
591 | | - ID_AT_UID + AT_UID + |
592 | | - ID_AT_EUID + AT_EUID + |
593 | | - ID_AT_GID + AT_GID + |
594 | | - ID_AT_EGID + AT_EGID + |
595 | | - ID_AT_SECURE + AT_SECURE + |
596 | | - ID_AT_RANDOM + AT_RANDOM + |
597 | | - ID_AT_HWCAP2 + AT_HWCAP2 + |
598 | | - ID_AT_EXECFN + AT_EXECFN + |
599 | | - ID_AT_PLATFORM + AT_PLATFORM + |
600 | | - ID_AT_NULL + AT_NULL |
601 | | - ) |
602 | | - |
603 | | - auxvdata = self.bin_to_escstr(unhexlify(auxvdata_c)) |
604 | | - #self.send(b'l!%s' % auxvdata) |
| 510 | + |
| 511 | + if self.ql.ostype in (QL_OS.LINUX, QL_OS.FREEBSD): |
| 512 | + def __read_auxv() -> Iterator[int]: |
| 513 | + auxv_entries = ( |
| 514 | + AUX.AT_HWCAP, |
| 515 | + AUX.AT_PAGESZ, |
| 516 | + AUX.AT_CLKTCK, |
| 517 | + AUX.AT_PHDR, |
| 518 | + AUX.AT_PHENT, |
| 519 | + AUX.AT_PHNUM, |
| 520 | + AUX.AT_BASE, |
| 521 | + AUX.AT_FLAGS, |
| 522 | + AUX.AT_ENTRY, |
| 523 | + AUX.AT_UID, |
| 524 | + AUX.AT_EUID, |
| 525 | + AUX.AT_GID, |
| 526 | + AUX.AT_EGID, |
| 527 | + AUX.AT_SECURE, |
| 528 | + AUX.AT_RANDOM, |
| 529 | + AUX.AT_HWCAP2, |
| 530 | + AUX.AT_EXECFN, |
| 531 | + AUX.AT_PLATFORM, |
| 532 | + AUX.AT_NULL |
| 533 | + ) |
| 534 | + |
| 535 | + for e in auxv_entries: |
| 536 | + yield e.value |
| 537 | + yield self.ql.loader.aux_vec[e] |
| 538 | + |
| 539 | + annex = self.addr_to_str(0)[:-2] |
| 540 | + sysinfo_ehdr = self.addr_to_str(0) |
| 541 | + |
| 542 | + auxvdata_c = unhexlify(''.join([annex, sysinfo_ehdr] + [self.addr_to_str(val) for val in __read_auxv()])) |
| 543 | + auxvdata = self.bin_to_escstr(auxvdata_c) |
605 | 544 | else: |
606 | 545 | auxvdata = b"" |
607 | | - |
| 546 | + |
608 | 547 | self.send(b'l!%s' % auxvdata) |
609 | 548 |
|
610 | 549 | elif subcmd.startswith('Xfer:exec-file:read:'): |
|
0 commit comments