Skip to content

Commit 8aec76c

Browse files
committed
Merge branch 'dev' into qnx
2 parents da5ca7a + 9242ccc commit 8aec76c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1027
-921
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
5+
6+
import sys
7+
sys.path.append("..")
8+
9+
from qiling import Qiling
10+
from qiling.const import QL_VERBOSE
11+
12+
def dump(ql, *args, **kw):
13+
ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin")
14+
ql.emu_stop()
15+
16+
if __name__ == "__main__":
17+
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT)
18+
# load base address from profile file
19+
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
20+
# take a snapshot
21+
ql.hook_address(dump, X64BASE + 0x1094)
22+
ql.run()
23+
24+
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
25+
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
26+
ql.restore(snapshot="/tmp/snapshot.bin")
27+
# enable gdbserver to listen at localhost address, port 9999
28+
ql.debugger = "gdb:0.0.0.0:9999"
29+
begin_point = X64BASE + 0x109e
30+
end_point = X64BASE + 0x10bc
31+
ql.run(begin = begin_point, end = end_point)
32+
33+
'''
34+
Partial Execution: https://docs.qiling.io/en/latest/snapshot/
35+
36+
This example shows how to partially debug an elf file. First let the program run, hook at the main address and take a snapshot. Then resume the snapshot to construct a reasonable call_state (registers, memory mapping, dynamic library loading, etc) for our target piece of code, and directly assign the pc pointer to the beginning of the part you want to simulate.
37+
38+
Run it with:
39+
$ python3 hello_x8664_linux_part_debug.py
40+
41+
Then in a new terminal start gdb remote debug:
42+
$ gdb -q
43+
(gdb) target remote localhost:9999
44+
Remote debugging using localhost:9999
45+
Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target...
46+
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
47+
Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target...
48+
Reading symbols from target:/home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello...(no debugging symbols found)...done.
49+
warning: unable to open /proc file '/proc/42000/task/42000/maps'
50+
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
51+
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
52+
Reading symbols from target:/lib64/ld-linux-x86-64.so.2...Reading /lib64/ld-2.27.so from remote target...
53+
Reading /lib64/.debug/ld-2.27.so from remote target...
54+
(no debugging symbols found)...done.
55+
0x000055555555509e in ?? ()
56+
(gdb) x/8i $pc
57+
=> 0x55555555509e: lea 0xf83(%rip),%rdi # 0x555555556028
58+
0x5555555550a5: callq 0x555555555060
59+
0x5555555550aa: lea 0xf53(%rip),%rdi # 0x555555556004
60+
0x5555555550b1: callq 0x555555555060
61+
0x5555555550b6: xor %eax,%eax
62+
0x5555555550b8: add $0x8,%rsp
63+
0x5555555550bc: retq
64+
0x5555555550bd: nopl (%rax)
65+
66+
The source code of sleep_hello can be found at qiling/examples/src/linux/sleep_hello.c. As the above gdb output shows, we skipped the sleep function to directly debug the code afterwards.
67+
'''

examples/src/linux/getdents.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "stdio.h"
2+
#include <sys/types.h>
3+
#include <dirent.h>
4+
void main()
5+
{
6+
//int aa = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC;
7+
DIR *dirptr = NULL;
8+
struct dirent *ptr;
9+
dirptr = opendir("/");
10+
11+
while ((ptr = readdir(dirptr)) != NULL)
12+
{
13+
printf("%s\n", ptr->d_name);
14+
}
15+
16+
if (dirptr == NULL)
17+
{
18+
printf("Open dir error !\n");
19+
}
20+
else
21+
printf("Open Success!\n");
22+
close(dirptr);
23+
}

qiling/arch/utils.py

Lines changed: 54 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,100 +7,87 @@
77
This module is intended for general purpose functions that are only used in qiling.arch
88
"""
99

10-
from unicorn import UcError, UC_ERR_READ_UNMAPPED, UC_ERR_FETCH_UNMAPPED
11-
from keystone import *
12-
from capstone import *
10+
from capstone import Cs, CS_ARCH_ARM, CS_ARCH_ARM64, CS_ARCH_X86, CS_ARCH_MIPS, CS_MODE_16, CS_MODE_32, CS_MODE_64, CS_MODE_ARM, CS_MODE_THUMB, CS_MODE_MIPS32 ,CS_MODE_BIG_ENDIAN, CS_MODE_LITTLE_ENDIAN
11+
from keystone import Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_X86, KS_ARCH_MIPS, KS_MODE_16, KS_MODE_32, KS_MODE_64, KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32 ,KS_MODE_BIG_ENDIAN, KS_MODE_LITTLE_ENDIAN
1312

14-
from qiling.const import QL_ARCH, QL_ENDIAN, QL_OS, QL_DEBUGGER, QL_ARCH_32BIT, QL_ARCH_64BIT, QL_ARCH_16BIT
15-
from qiling.exception import *
13+
from qiling.const import QL_ARCH, QL_ENDIAN
14+
from qiling.exception import QlErrorArch
1615

16+
__cs_endian = {
17+
QL_ENDIAN.EL : CS_MODE_LITTLE_ENDIAN,
18+
QL_ENDIAN.EB : CS_MODE_BIG_ENDIAN
19+
}
1720

18-
def ql_create_disassembler(archtype, archendian, reg_cpsr=None):
19-
if archtype == QL_ARCH.ARM: # QL_ARM
20-
mode = CS_MODE_ARM
21-
if archendian == QL_ENDIAN.EB:
22-
# TODO: Test for big endian.
23-
reg_cpsr_v = 0b100000
24-
# reg_cpsr_v = 0b000000
25-
else:
26-
reg_cpsr_v = 0b100000
21+
__ks_endian = {
22+
QL_ENDIAN.EL : KS_MODE_LITTLE_ENDIAN,
23+
QL_ENDIAN.EB : KS_MODE_BIG_ENDIAN
24+
}
2725

28-
if reg_cpsr & reg_cpsr_v != 0:
29-
mode = CS_MODE_THUMB
26+
__reg_cpsr_v = {
27+
QL_ENDIAN.EL : 0b100000,
28+
QL_ENDIAN.EB : 0b100000 # FIXME: should be: 0b000000
29+
}
3030

31-
if archendian == QL_ENDIAN.EB:
32-
md = Cs(CS_ARCH_ARM, mode)
33-
# md = Cs(CS_ARCH_ARM, mode + CS_MODE_BIG_ENDIAN)
34-
else:
35-
md = Cs(CS_ARCH_ARM, mode)
36-
37-
elif archtype == QL_ARCH.ARM_THUMB:
38-
md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
39-
40-
elif archtype == QL_ARCH.X86: # QL_X86
31+
def ql_create_disassembler(archtype: QL_ARCH, archendian: QL_ENDIAN, reg_cpsr=None) -> Cs:
32+
if archtype == QL_ARCH.X86:
4133
md = Cs(CS_ARCH_X86, CS_MODE_32)
4234

43-
elif archtype == QL_ARCH.X8664: # QL_X86_64
35+
elif archtype == QL_ARCH.X8664:
4436
md = Cs(CS_ARCH_X86, CS_MODE_64)
4537

46-
elif archtype == QL_ARCH.ARM64: # QL_ARM64
38+
elif archtype == QL_ARCH.ARM:
39+
mode = CS_MODE_THUMB if reg_cpsr & __reg_cpsr_v[archendian] else CS_MODE_ARM
40+
41+
md = Cs(CS_ARCH_ARM, mode) # FIXME: should be: mode + __cs_endian[archendian]
42+
43+
elif archtype == QL_ARCH.ARM_THUMB:
44+
md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
45+
46+
elif archtype == QL_ARCH.ARM64:
4747
md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)
4848

49-
elif archtype == QL_ARCH.A8086: # QL_A8086
49+
elif archtype == QL_ARCH.MIPS:
50+
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + __cs_endian[archendian])
51+
52+
elif archtype == QL_ARCH.A8086:
5053
md = Cs(CS_ARCH_X86, CS_MODE_16)
5154

52-
elif archtype == QL_ARCH.MIPS: # QL_MIPS32
53-
if archendian == QL_ENDIAN.EB:
54-
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
55-
else:
56-
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
55+
elif archtype == QL_ARCH.EVM:
56+
raise NotImplementedError('evm')
5757

5858
else:
59-
raise QlErrorArch("Unknown arch defined in utils.py (debug output mode)")
59+
raise QlErrorArch(f'{archtype:d}')
6060

6161
return md
6262

63-
def ql_create_assembler(archtype, archendian, reg_cpsr=None):
64-
if archtype == QL_ARCH.ARM: # QL_ARM
65-
mode = KS_MODE_ARM
66-
if archendian == QL_ENDIAN.EB:
67-
# TODO: Test for big endian.
68-
reg_cpsr_v = 0b100000
69-
# reg_cpsr_v = 0b000000
70-
else:
71-
reg_cpsr_v = 0b100000
72-
73-
if reg_cpsr & reg_cpsr_v != 0:
74-
mode = KS_MODE_THUMB
75-
76-
if archendian == QL_ENDIAN.EB:
77-
ks = Ks(KS_ARCH_ARM, mode)
78-
# md = Cs(CS_ARCH_ARM, mode + CS_MODE_BIG_ENDIAN)
79-
else:
80-
ks = Ks(KS_ARCH_ARM, mode)
81-
82-
elif archtype == QL_ARCH.ARM_THUMB:
83-
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
84-
85-
elif archtype == QL_ARCH.X86: # QL_X86
63+
def ql_create_assembler(archtype: QL_ARCH, archendian: QL_ENDIAN, reg_cpsr=None) -> Ks:
64+
if archtype == QL_ARCH.X86:
8665
ks = Ks(KS_ARCH_X86, KS_MODE_32)
8766

88-
elif archtype == QL_ARCH.X8664: # QL_X86_64
67+
elif archtype == QL_ARCH.X8664:
8968
ks = Ks(KS_ARCH_X86, KS_MODE_64)
9069

91-
elif archtype == QL_ARCH.ARM64: # QL_ARM64
70+
elif archtype == QL_ARCH.ARM:
71+
mode = KS_MODE_THUMB if reg_cpsr & __reg_cpsr_v[archendian] else KS_MODE_ARM
72+
73+
ks = Ks(KS_ARCH_ARM, mode) # FIXME: should be: mode + __ks_endian[archendian]
74+
75+
elif archtype == QL_ARCH.ARM_THUMB:
76+
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
77+
78+
elif archtype == QL_ARCH.ARM64:
9279
ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
9380

94-
elif archtype == QL_ARCH.A8086: # QL_A8086
81+
elif archtype == QL_ARCH.MIPS:
82+
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + __ks_endian[archendian])
83+
84+
elif archtype == QL_ARCH.A8086:
9585
ks = Ks(KS_ARCH_X86, KS_MODE_16)
9686

97-
elif archtype == QL_ARCH.MIPS: # QL_MIPS32
98-
if archendian == QL_ENDIAN.EB:
99-
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + KS_MODE_BIG_ENDIAN)
100-
else:
101-
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + KS_MODE_LITTLE_ENDIAN)
87+
elif archtype == QL_ARCH.EVM:
88+
raise NotImplementedError('evm')
10289

10390
else:
104-
raise QlErrorArch("Unknown arch defined in utils.py (debug output mode)")
91+
raise QlErrorArch(f'{archtype:d}')
10592

10693
return ks

qiling/const.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6-
from enum import IntEnum
6+
from enum import EnumMeta, IntEnum
7+
from typing import Mapping
78

89
class QL_ENDIAN(IntEnum):
910
EL = 1
1011
EB = 2
1112

12-
1313
class QL_ARCH(IntEnum):
1414
X86 = 101
1515
X8664 = 102
@@ -42,7 +42,6 @@ class QL_DEBUGGER(IntEnum):
4242
IDAPRO = 2
4343
QDB = 3
4444

45-
4645
class QL_INTERCEPT(IntEnum):
4746
CALL = 1
4847
ENTER = 2
@@ -65,38 +64,21 @@ class QL_INTERCEPT(IntEnum):
6564
QL_HOOK_BLOCK = 0b0001
6665
QL_CALL_BLOCK = 0b0010
6766

68-
debugger_map = {
69-
"gdb" : QL_DEBUGGER.GDB,
70-
"ida" : QL_DEBUGGER.IDAPRO,
71-
"qdb" : QL_DEBUGGER.QDB
72-
}
67+
def __reverse_enum(e: EnumMeta) -> Mapping[str, int]:
68+
'''Create a reverse mapping for an enum.
69+
'''
7370

74-
arch_map = {
75-
"x86" : QL_ARCH.X86,
76-
"x8664" : QL_ARCH.X8664,
77-
"mips" : QL_ARCH.MIPS,
78-
"arm" : QL_ARCH.ARM,
79-
"arm_thumb" : QL_ARCH.ARM_THUMB,
80-
"arm64" : QL_ARCH.ARM64,
81-
"a8086" : QL_ARCH.A8086,
82-
"evm" : QL_ARCH.EVM,
83-
}
71+
return dict((k.lower(), v.value) for k, v in e.__members__.items())
8472

85-
os_map = {
86-
"linux" : QL_OS.LINUX,
87-
"macos" : QL_OS.MACOS,
88-
"freebsd" : QL_OS.FREEBSD,
89-
"qnx" : QL_OS.QNX,
90-
"windows" : QL_OS.WINDOWS,
91-
"uefi" : QL_OS.UEFI,
92-
"dos" : QL_OS.DOS,
93-
"evm" : QL_OS.EVM,
94-
}
73+
debugger_map = __reverse_enum(QL_DEBUGGER)
74+
arch_map = __reverse_enum(QL_ARCH)
75+
os_map = __reverse_enum(QL_OS)
76+
verbose_map = __reverse_enum(QL_VERBOSE)
9577

9678
loader_map = {
9779
QL_OS.LINUX : "ELF",
9880
QL_OS.FREEBSD : "ELF",
99-
QL_OS.QNX : "QNX",
81+
QL_OS.QNX : "ELF",
10082
QL_OS.MACOS : "MACHO",
10183
QL_OS.WINDOWS : "PE",
10284
QL_OS.UEFI : "PE_UEFI",

qiling/core.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .os.memory import QlMemoryManager
1717
from .loader.loader import QlLoader
1818

19-
from .const import QL_ARCH_ENDIAN, QL_ENDIAN, QL_OS, QL_CUSTOM_ENGINE
19+
from .const import QL_ARCH_ENDIAN, QL_ENDIAN, QL_OS, QL_VERBOSE, QL_CUSTOM_ENGINE
2020
from .exception import QlErrorFileNotFound, QlErrorArch, QlErrorOsType, QlErrorOutput
2121
from .utils import *
2222
from .core_struct import QlCoreStructs
@@ -35,7 +35,7 @@ def __init__(
3535
ostype=None,
3636
archtype=None,
3737
bigendian=False,
38-
verbose=1,
38+
verbose=QL_VERBOSE.DEFAULT,
3939
profile=None,
4040
console=True,
4141
log_file=None,
@@ -563,7 +563,8 @@ def verbose(self):
563563
def verbose(self, v):
564564
self._verbose = v
565565
self.log.setLevel(ql_resolve_logger_level(self._verbose))
566-
self.os.utils.setup_output()
566+
if not self._custom_engine:
567+
self.os.utils.setup_output()
567568

568569
@property
569570
def patch_bin(self) -> list:

qiling/core_hooks.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,20 @@ def _hook_insn_cb(self, uc, *args):
7474
ql, hook_type = args[-1]
7575

7676
if hook_type in self._insn_hook.keys():
77+
retval = None
78+
7779
for h in self._insn_hook[hook_type]:
7880
if h.bound_check(ql.reg.arch_pc):
7981
ret = h.call(ql, *args[ : -1])
80-
if isinstance(ret, int) == True and ret & QL_HOOK_BLOCK != 0:
82+
83+
if type(ret) is tuple:
84+
ret, retval = ret
85+
86+
if type(ret) is int and ret & QL_HOOK_BLOCK:
8187
break
8288

89+
# use the last return value received
90+
return retval
8391

8492
def _callback_type4(self, uc, addr, size, pack_data):
8593
ql, user_data, callback = pack_data

qiling/debugger/gdb/gdb.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ def __init__(self, ql, ip, port):
6565
else:
6666
self.entry_point = self.ql.os.entry_point
6767

68+
# Only part of the binary file will be debugged.
69+
if self.ql.entry_point is not None and self.ql.exit_point is not None:
70+
self.entry_point = self.ql.entry_point
71+
exit_point = self.ql.exit_point
72+
6873
self.gdb.initialize(self.ql, self.entry_point, exit_point=exit_point, mappings=[(hex(load_address))])
6974

7075
#Setup register tables, order of tables is important

qiling/debugger/qdb/frontend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def context_reg(ql, saved_states=None, *args, **kwargs):
149149

150150
for idx in range(8):
151151
_addr = ql.reg.arch_sp + idx * 4
152-
_val = ql.mem.read(_addr, ql.archbit // 8)
152+
_val = ql.mem.read(_addr, ql.pointersize)
153153
print(f"$sp+0x{idx*4:02x}|[0x{_addr:08x}]=> 0x{ql.unpack(_val):08x}", end="")
154154

155155
try: # try to deference wether its a pointer

0 commit comments

Comments
 (0)