Skip to content

Commit 2f604f4

Browse files
authored
Merge pull request #1577 from elicn/qdb-fixes
QDB and BLOB fixes
2 parents 81b847a + a2542f1 commit 2f604f4

File tree

15 files changed

+134
-70
lines changed

15 files changed

+134
-70
lines changed

examples/hello_arm_uboot.py

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,68 +8,82 @@
88

99
from qiling.core import Qiling
1010
from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE
11-
from qiling.os.const import STRING
11+
from qiling.os.const import STRING, SIZE_T, POINTER
1212

1313

14-
def get_kaimendaji_password():
15-
def my_getenv(ql: Qiling):
16-
env = {
17-
"ID" : b"000000000000000",
18-
"ethaddr" : b"11:22:33:44:55:66"
19-
}
14+
def my_getenv(ql: Qiling):
15+
env = {
16+
"ID" : b"000000000000000",
17+
"ethaddr" : b"11:22:33:44:55:66"
18+
}
2019

21-
params = ql.os.resolve_fcall_params({'key': STRING})
22-
value = env.get(params["key"], b"")
20+
params = ql.os.resolve_fcall_params({'key': STRING})
21+
value = env.get(params["key"], b"")
2322

24-
value_addr = ql.os.heap.alloc(len(value))
25-
ql.mem.write(value_addr, value)
23+
value_addr = ql.os.heap.alloc(len(value))
24+
ql.mem.write(value_addr, value)
2625

27-
ql.arch.regs.r0 = value_addr
28-
ql.arch.regs.arch_pc = ql.arch.regs.lr
26+
ql.arch.regs.r0 = value_addr
27+
ql.arch.regs.arch_pc = ql.arch.regs.lr
2928

30-
def get_password(ql: Qiling):
31-
password_raw = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2)
3229

33-
password = ''
34-
for item in password_raw:
35-
if 0 <= item <= 9:
36-
password += chr(item + 48)
37-
else:
38-
password += chr(item + 87)
30+
def get_password(ql: Qiling):
31+
# we land on a memcmp call, where the real password is being compared to
32+
# the one provided by the user. we can follow the arguments to read the
33+
# real password
3934

40-
print("The password is: %s" % password)
35+
params = ql.os.resolve_fcall_params({
36+
'ptr1': POINTER, # points to real password
37+
'ptr2': POINTER, # points to user provided password
38+
'size': SIZE_T # comparison length
39+
})
4140

42-
def partial_run_init(ql: Qiling):
43-
# argv prepare
44-
ql.arch.regs.arch_sp -= 0x30
45-
arg0_ptr = ql.arch.regs.arch_sp
46-
ql.mem.write(arg0_ptr, b"kaimendaji")
41+
ptr1 = params['ptr1']
42+
size = params['size']
4743

48-
ql.arch.regs.arch_sp -= 0x10
49-
arg1_ptr = ql.arch.regs.arch_sp
50-
ql.mem.write(arg1_ptr, b"000000") # arbitrary password
44+
password_raw = ql.mem.read(ptr1, size)
5145

52-
ql.arch.regs.arch_sp -= 0x20
53-
argv_ptr = ql.arch.regs.arch_sp
54-
ql.mem.write_ptr(argv_ptr, arg0_ptr)
55-
ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr)
46+
def __hex_digit(ch: int) -> str:
47+
off = ord('0') if ch in range(10) else ord('a') - 10
5648

57-
ql.arch.regs.r2 = 2
58-
ql.arch.regs.r3 = argv_ptr
49+
return chr(ch + off)
5950

60-
with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f:
61-
uboot_code = f.read()
51+
# should be: "013f1f"
52+
password = "".join(__hex_digit(ch) for ch in password_raw)
6253

63-
ql = Qiling(code=uboot_code[0x40:], archtype=QL_ARCH.ARM, ostype=QL_OS.BLOB, profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF)
54+
print(f'The password is: {password}')
6455

65-
image_base_addr = ql.loader.load_address
66-
ql.hook_address(my_getenv, image_base_addr + 0x13AC0)
67-
ql.hook_address(get_password, image_base_addr + 0x48634)
6856

69-
partial_run_init(ql)
57+
def partial_run_init(ql: Qiling):
58+
# argv prepare
59+
ql.arch.regs.arch_sp -= 0x30
60+
arg0_ptr = ql.arch.regs.arch_sp
61+
ql.mem.write(arg0_ptr, b"kaimendaji")
62+
63+
ql.arch.regs.arch_sp -= 0x10
64+
arg1_ptr = ql.arch.regs.arch_sp
65+
ql.mem.write(arg1_ptr, b"000000") # arbitrary password
7066

71-
ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718)
67+
ql.arch.regs.arch_sp -= 0x20
68+
argv_ptr = ql.arch.regs.arch_sp
69+
ql.mem.write_ptr(argv_ptr, arg0_ptr)
70+
ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr)
71+
72+
ql.arch.regs.r2 = 2
73+
ql.arch.regs.r3 = argv_ptr
7274

7375

7476
if __name__ == "__main__":
75-
get_kaimendaji_password()
77+
with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f:
78+
uboot_code = f.read()
79+
80+
ql = Qiling(code=uboot_code[0x40:], archtype=QL_ARCH.ARM, ostype=QL_OS.BLOB, profile="uboot_bin.ql", verbose=QL_VERBOSE.DEBUG)
81+
82+
imgbase = ql.loader.images[0].base
83+
84+
ql.hook_address(my_getenv, imgbase + 0x13AC0)
85+
ql.hook_address(get_password, imgbase + 0x48634)
86+
87+
partial_run_init(ql)
88+
89+
ql.run(imgbase + 0x486B4, imgbase + 0x48718)

examples/uboot_bin.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[CODE]
22
ram_size = 0xa00000
3+
load_address = 0x80800000
34
entry_point = 0x80800000
45
heap_size = 0x300000
56

qiling/debugger/gdb/xml/arm/arm-m-profile.xml renamed to qiling/debugger/gdb/xml/cortex_m/arm-m-profile.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,10 @@
2525
<reg name="pc" bitsize="32" type="code_ptr"/>
2626

2727
<reg name="xpsr" bitsize="32" regnum="25"/>
28-
</feature>
28+
<reg name="msp" bitsize="32"/>
29+
<reg name="psp" bitsize="32"/>
30+
<reg name="primask" bitsize="32"/>
31+
<reg name="basepri" bitsize="32"/>
32+
<reg name="faultmask" bitsize="32"/>
33+
<reg name="control" bitsize="32"/>
34+
</feature>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<!-- Copyright (C) 2009-2016 Free Software Foundation, Inc.
3+
4+
*!Copying and distribution of this file, with or without modification,
5+
*!are permitted in any medium without royalty provided the copyright
6+
*!notice and this notice are preserved. -->
7+
8+
<!DOCTYPE target SYSTEM "gdb-target.dtd">
9+
<target xmlns:xi="http://www.w3.org/2001/XInclude">
10+
<architecture>armv7-m</architecture>
11+
<xi:include href="arm-m-profile.xml"/>
12+
</target>

qiling/debugger/gdb/xmlregs.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,21 @@
1313
reg_map_q as arm_regs_q,
1414
reg_map_s as arm_regs_s
1515
)
16+
17+
from qiling.arch.cortex_m_const import (
18+
reg_map as cortex_m_regs
19+
)
20+
1621
from qiling.arch.arm64_const import (
1722
reg_map as arm64_regs,
1823
reg_map_v as arm64_regs_v,
1924
reg_map_fp as arm64_reg_map_fp
2025
)
26+
2127
from qiling.arch.mips_const import (
2228
reg_map as mips_regs_gpr
2329
)
30+
2431
from qiling.arch.x86_const import (
2532
reg_map_32 as x86_regs_32,
2633
reg_map_64 as x86_regs_64,
@@ -133,7 +140,7 @@ def __load_regsmap(archtype: QL_ARCH, xmltree: ElementTree.ElementTree) -> Seque
133140
QL_ARCH.X86: dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm),
134141
QL_ARCH.X8664: dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm),
135142
QL_ARCH.ARM: dict(**arm_regs, **arm_regs_vfp, **arm_regs_q, **arm_regs_s),
136-
QL_ARCH.CORTEX_M: arm_regs,
143+
QL_ARCH.CORTEX_M: dict(**cortex_m_regs),
137144
QL_ARCH.ARM64: dict(**arm64_regs, **arm64_regs_v, **arm64_reg_map_fp),
138145
QL_ARCH.MIPS: dict(**mips_regs_gpr)
139146
}[archtype]

qiling/debugger/qdb/context.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def disasm(self, address: int, detail: bool = False) -> InsnLike:
5757
"""Helper function for disassembling.
5858
"""
5959

60-
insn_bytes = self.read_insn(address)
60+
insn_bytes = self.read_insn(address) or b''
6161
insn = None
6262

6363
if insn_bytes:
@@ -75,7 +75,7 @@ def disasm_lite(self, address: int) -> Tuple[int, int, str, str]:
7575
A tuple of: instruction address, size, mnemonic and operands
7676
"""
7777

78-
insn_bytes = self.read_insn(address)
78+
insn_bytes = self.read_insn(address) or b''
7979
insn = None
8080

8181
if insn_bytes:

qiling/debugger/qdb/qdb.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,7 @@ def __bp_handler(ql: Qiling, address: int, size: int):
136136
with self.__set_temp(self.ql, 'verbose', QL_VERBOSE.DISABLED):
137137
self.ql.os.run()
138138

139-
if self.ql.os.type is QL_OS.BLOB:
140-
self.ql.loader.entry_point = self.ql.loader.load_address
141-
142-
elif init_hook:
139+
if init_hook:
143140
for each_hook in init_hook:
144141
self.do_breakpoint(each_hook)
145142

qiling/loader/blob.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def __init__(self, ql: Qiling):
1515
self.load_address = 0
1616

1717
def run(self):
18-
self.load_address = self.ql.os.entry_point # for consistency
18+
self.load_address = self.ql.os.load_address
19+
self.entry_point = self.ql.os.entry_point
1920

2021
code_begins = self.load_address
2122
code_size = self.ql.os.code_ram_size
@@ -28,8 +29,10 @@ def run(self):
2829
self.images.append(Image(code_begins, code_ends, 'blob_code'))
2930

3031
# FIXME: heap starts above end of ram??
32+
# FIXME: heap should be allocated by OS, not loader
3133
heap_base = code_ends
3234
heap_size = int(self.ql.os.profile.get("CODE", "heap_size"), 16)
3335
self.ql.os.heap = QlMemoryHeap(self.ql, heap_base, heap_base + heap_size)
3436

37+
# FIXME: stack pointer should be a configurable profile setting
3538
self.ql.arch.regs.arch_sp = code_ends - 0x1000

qiling/os/blob/blob.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from qiling.os.fcall import QlFunctionCall
1010
from qiling.os.os import QlOs
1111

12+
1213
class QlOsBlob(QlOs):
1314
""" QlOsBlob for bare barines.
1415
@@ -21,7 +22,7 @@ class QlOsBlob(QlOs):
2122
type = QL_OS.BLOB
2223

2324
def __init__(self, ql: Qiling):
24-
super(QlOsBlob, self).__init__(ql)
25+
super().__init__(ql)
2526

2627
self.ql = ql
2728

@@ -39,11 +40,14 @@ def __init__(self, ql: Qiling):
3940
self.fcall = QlFunctionCall(ql, cc)
4041

4142
def run(self):
42-
if self.ql.entry_point:
43+
# if entry point was set explicitly, override the default one
44+
if self.ql.entry_point is not None:
4345
self.entry_point = self.ql.entry_point
4446

45-
self.exit_point = self.ql.loader.load_address + len(self.ql.code)
46-
if self.ql.exit_point:
47+
self.exit_point = self.load_address + len(self.ql.code)
48+
49+
# if exit point was set explicitly, override the default one
50+
if self.ql.exit_point is not None:
4751
self.exit_point = self.ql.exit_point
4852

4953
self.ql.emu_start(self.entry_point, self.exit_point, self.ql.timeout, self.ql.count)

qiling/os/os.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def __init__(self, ql: Qiling, resolvers: Mapping[Any, Resolver] = {}):
8989
if self.ql.code:
9090
# this shellcode entrypoint does not work for windows
9191
# windows shellcode entry point will comes from pe loader
92+
self.load_address = self.profile.getint('CODE', 'load_address')
9293
self.entry_point = self.profile.getint('CODE', 'entry_point')
9394
self.code_ram_size = self.profile.getint('CODE', 'ram_size')
9495

0 commit comments

Comments
 (0)