Skip to content

Commit 43d413d

Browse files
authored
Merge pull request #4 from qilingframework/dev
Dev
2 parents f9c5f1a + b0bd49f commit 43d413d

File tree

10 files changed

+169
-53
lines changed

10 files changed

+169
-53
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE
11+
from qiling.os.const import STRING
12+
13+
def my_puts_onenter(ql: Qiling):
14+
params = ql.os.resolve_fcall_params({'s': STRING})
15+
16+
print(f'puts("{params["s"]}")')
17+
return QL_CALL_BLOCK
18+
19+
def my_printf_onenter(ql: Qiling):
20+
params = ql.os.resolve_fcall_params({'s': STRING})
21+
22+
print(f'printf("{params["s"]}")')
23+
return QL_CALL_BLOCK
24+
25+
def my_puts_onexit(ql: Qiling):
26+
print(f'after puts')
27+
return QL_CALL_BLOCK
28+
29+
if __name__ == "__main__":
30+
ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx")
31+
ql.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER)
32+
ql.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER)
33+
ql.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT)
34+
ql.run()

examples/mem_invalid_access.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
def mem_crash(ql: Qiling, access: int, address: int, size: int, value: int):
1212
print(f'got crash')
1313

14-
PAGE_SIZE = 0x1000
15-
aligned = address & ~(PAGE_SIZE - 1)
14+
PAGE_SIZE = ql.mem.pagesize
15+
aligned = ql.mem.align(address)
1616

1717
# map the entire page containing the invalid address and fill it with 'Q's
1818
ql.mem.map(aligned, PAGE_SIZE)

qiling/extensions/idaplugin/qilingida.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from PyQt5.QtWidgets import (QPushButton, QHBoxLayout)
4343

4444
# Qiling
45-
from qiling import *
45+
from qiling import Qiling
4646
from qiling.const import *
4747
from qiling.arch.x86_const import reg_map_32 as x86_reg_map_32
4848
from qiling.arch.x86_const import reg_map_64 as x86_reg_map_64
@@ -1269,7 +1269,7 @@ def ql_show_mem_view(self, addr=get_screen_ea(), size=0x10):
12691269
ok = ask_yn(1, "Memory [%X:%X] is not mapped!\nDo you want to map it?\n YES - Load Binary\n NO - Fill page with zeroes\n Cancel - Close dialog" % (mem_addr, mem_addr + mem_size))
12701270
if ok == 0:
12711271
self.qlemu.ql.mem.map(mem_addr, mem_size)
1272-
self.qlemu.ql.mem.write(self.qlemu.ql.mem.align(mem_addr), b"\x00"*mem_size)
1272+
self.qlemu.ql.mem.write(mem_addr, b"\x00"*mem_size)
12731273
elif ok == 1:
12741274
# TODO: map_binary
12751275
return
@@ -1568,16 +1568,16 @@ def _guide_hook(self, ql, addr, size):
15681568
self.paths[start_bb_id].append(cur_bb.id)
15691569
ql.emu_stop()
15701570

1571-
def _skip_unmapped_rw(self, ql, type, addr, size, value):
1572-
alignment = 0x1000
1573-
# Round down
1574-
map_addr = addr & (~(alignment - 1))
1575-
# Round up
1576-
map_size = ((size + (alignment - 1)) & (~(alignment - 1)))
1571+
def _skip_unmapped_rw(self, ql: Qiling, type, addr, size, value):
1572+
map_addr = ql.mem.align(addr)
1573+
map_size = ql.mem.align_up(size)
1574+
15771575
if not ql.mem.is_mapped(map_addr, map_size):
15781576
logging.warning(f"Invalid memory R/W, trying to map {hex(map_size)} at {hex(map_addr)}")
1577+
15791578
ql.mem.map(map_addr, map_size)
1580-
ql.mem.write(map_addr, b'\x00'*map_size)
1579+
ql.mem.write(map_addr, b'\x00' * map_size)
1580+
15811581
return True
15821582

15831583
def _find_branch_in_real_block(self, bb):

qiling/loader/pe.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def load_dll(self, name: bytes, driver: bool = False) -> int:
9696
data = cached.data
9797

9898
image_base = cached.ba
99-
image_size = self.ql.mem.align(len(data), 0x1000)
99+
image_size = self.ql.mem.align_up(len(data))
100100

101101
# verify whether we can load the dll to the same address it was loaded when it was cached.
102102
# if not, the dll will have to be realoded in order to have its symbols relocated using the
@@ -126,7 +126,7 @@ def load_dll(self, name: bytes, driver: bool = False) -> int:
126126
data = bytearray(dll.get_memory_mapped_image())
127127

128128
image_base = dll.OPTIONAL_HEADER.ImageBase or self.dll_last_address
129-
image_size = self.ql.mem.align(len(data), 0x1000)
129+
image_size = self.ql.mem.align_up(len(data))
130130

131131
self.ql.log.debug(f'DLL preferred base address: {image_base:#x}')
132132

@@ -514,7 +514,7 @@ def load(self):
514514
if self.path and not self.ql.code:
515515
# for simplicity, no image base relocation
516516
self.pe_image_address = self.pe.OPTIONAL_HEADER.ImageBase
517-
self.pe_image_address_size = self.ql.mem.align(self.pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)
517+
self.pe_image_address_size = self.ql.mem.align_up(self.pe.OPTIONAL_HEADER.SizeOfImage)
518518

519519
if self.pe_image_address + self.pe_image_address_size > self.ql.os.heap_base_address:
520520
# pe reloc
@@ -599,7 +599,7 @@ def load(self):
599599
self.ql.os.fcall.writeParams(((POINTER, self.ql.loader.driver_object_address), (POINTER, self.ql.loader.regitry_path_address)))
600600

601601
# mmap PE file into memory
602-
self.ql.mem.map(self.pe_image_address, self.align(self.pe_image_address_size, 0x1000), info="[PE]")
602+
self.ql.mem.map(self.pe_image_address, self.ql.mem.align_up(self.pe_image_address_size), info="[PE]")
603603
self.pe.parse_data_directories()
604604
data = bytearray(self.pe.get_memory_mapped_image())
605605
self.ql.mem.write(self.pe_image_address, bytes(data))

qiling/loader/pe_uefi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ def map_and_load(self, path: str, exec_now: bool=False):
9797

9898
# use image base only if it does not point to NULL
9999
image_base = pe.OPTIONAL_HEADER.ImageBase or self.next_image_base
100-
image_size = ql.mem.align(pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)
100+
image_size = ql.mem.align_up(pe.OPTIONAL_HEADER.SizeOfImage)
101101

102-
assert (image_base % 0x1000) == 0, 'image base is expected to be page-aligned'
102+
assert (image_base % ql.mem.pagesize) == 0, 'image base is expected to be page-aligned'
103103

104104
if image_base != pe.OPTIONAL_HEADER.ImageBase:
105105
pe.relocate_image(image_base)

qiling/os/memory.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -195,21 +195,45 @@ def show_mapinfo(self):
195195
def get_lib_base(self, filename: str) -> int:
196196
return next((s for s, _, _, info, _ in self.map_info if os.path.split(info)[1] == filename), -1)
197197

198-
def align(self, addr: int, alignment: int = None) -> int:
199-
"""Round up to nearest alignment.
198+
def align(self, value: int, alignment: int = None) -> int:
199+
"""Align a value down to the specified alignment boundary.
200200
201201
Args:
202-
addr: address to align
203-
alignment: alignment granularity, must be a power of 2
202+
value: a value to align
203+
alignment: alignment boundary; must be a power of 2. if not specified
204+
value will be aligned to page size
205+
206+
Returns: aligned value
207+
"""
208+
209+
if alignment is None:
210+
alignment = self.pagesize
211+
212+
# make sure alignment is a power of 2
213+
assert alignment & (alignment - 1) == 0
214+
215+
# round down to nearest alignment
216+
return value & ~(alignment - 1)
217+
218+
def align_up(self, value: int, alignment: int = None) -> int:
219+
"""Align a value up to the specified alignment boundary.
220+
221+
Args:
222+
value: value to align
223+
alignment: alignment boundary; must be a power of 2. if not specified
224+
value will be aligned to page size
225+
226+
Returns: aligned value
204227
"""
205228

206229
if alignment is None:
207230
alignment = self.pagesize
208231

209-
# rounds up to nearest alignment
210-
mask = self.max_mem_addr & -alignment
232+
# make sure alignment is a power of 2
233+
assert alignment & (alignment - 1) == 0
211234

212-
return (addr + (alignment - 1)) & mask
235+
# round up to nearest alignment
236+
return (value + alignment - 1) & ~(alignment - 1)
213237

214238
def save(self):
215239
"""Save entire memory content.
@@ -431,7 +455,7 @@ def find_free_space(self, size: int, minaddr: int = None, maxaddr: int = None, a
431455
gaps = zip(gaps_lbounds, gaps_ubounds)
432456

433457
for lbound, ubound in gaps:
434-
addr = self.align(lbound, align)
458+
addr = self.align_up(lbound, align)
435459
end = addr + size
436460

437461
# is aligned range within gap and satisfying min / max requirements?
@@ -457,18 +481,19 @@ def map_anywhere(self, size: int, minaddr: int = None, maxaddr: int = None, alig
457481
if align is None:
458482
align = self.pagesize
459483

484+
size = self.align_up(size)
460485
addr = self.find_free_space(size, minaddr, maxaddr, align)
461486

462-
self.map(addr, self.align(size), perms, info)
487+
self.map(addr, size, perms, info)
463488

464489
return addr
465490

466491
def protect(self, addr: int, size: int, perms):
467492
# mask off perms bits that are not supported by unicorn
468493
perms &= UC_PROT_ALL
469494

470-
aligned_address = addr & ~(self.pagesize - 1)
471-
aligned_size = self.align((addr & (self.pagesize - 1)) + size)
495+
aligned_address = self.align(addr)
496+
aligned_size = self.align_up((addr & (self.pagesize - 1)) + size)
472497

473498
self.ql.uc.mem_protect(aligned_address, aligned_size, perms)
474499
self.change_mapinfo(aligned_address, aligned_address + aligned_size, mem_p = perms)
@@ -590,7 +615,7 @@ def alloc(self, size: int) -> int:
590615
# is new chunk going to exceed currently allocated heap space?
591616
# in case it does, allocate additional heap space
592617
if self.current_use + size > self.current_alloc:
593-
real_size = self.ql.mem.align(size)
618+
real_size = self.ql.mem.align_up(size)
594619

595620
# if that additional allocation is going to exceed heap upper bound, fail
596621
if self.start_address + self.current_use + real_size > self.end_address:

qiling/os/posix/syscall/mman.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ def syscall_mmap_impl(ql: Qiling, addr: int, mlen: int, prot: int, flags: int, f
8484

8585
need_mmap = True
8686
mmap_base = addr
87-
mmap_size = (mlen - (addr & (pagesize - 1)) + pagesize - 1) & ~(pagesize - 1)
87+
mmap_size = ql.mem.align_up(mlen - (addr & (pagesize - 1)))
8888

8989
if ql.ostype != QL_OS.QNX:
90-
mmap_base &= ~(pagesize - 1)
91-
if (flags & MAP_FIXED) > 0 and mmap_base != addr:
90+
mmap_base = ql.mem.align(mmap_base)
91+
92+
if (flags & MAP_FIXED) and mmap_base != addr:
9293
return MAP_FAILED
9394

9495
# initial ql.loader.mmap_address

qiling/os/qnx/message.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def ql_qnx_msg_io_connect(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, **
9898
else:
9999
# TODO: Can we throw this exception here?
100100
# raise NotImplementedError(f'msg_io_connect(_IO_CONNECT_COMBINE) for type 0x{x_type:x} not implemented')
101-
ql.log.warn(f'msg_io_connect(_IO_CONNECT_COMBINE) for type 0x{x_type:x} not implemented')
101+
ql.log.warning(f'msg_io_connect(_IO_CONNECT_COMBINE) for type 0x{x_type:x} not implemented')
102102
elif subtype == 2: # == _IO_CONNECT_OPEN
103103
ql.log.debug(f'open(path = {path}, openflags = 0x{ioflag:x}, openmode = 0x{real_mode:x})')
104104
ql.os.connections[coid].fd = ql_syscall_open(ql, ql.unpack32(ql.mem.read(smsg + 8, 4)), ioflag, real_mode)
@@ -127,7 +127,7 @@ def ql_qnx_msg_io_connect(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, **
127127
elif os.path.isfile(real_path):
128128
umask = file_stats['_S_IFREG']
129129
else:
130-
ql.log.warn("msg_io_connect(): type of {real_path} not handled properly?")
130+
ql.log.warning("msg_io_connect(): type of {real_path} not handled properly?")
131131
umask = 0
132132
# struct _io_connect_link_reply in lib/c/public/sys/iomsg.h
133133
ql.mem.write(iov_base, pack("<IIBBHIHH", 0, file_type, eflag, 0, 0, umask, 0, 0))
@@ -190,7 +190,7 @@ def ql_qnx_msg_mem_ctrl(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw
190190
if not subtype in mem_ctrl_subtypes:
191191
raise NotImplementedError(f'MEM_CTRL subtype {subtype} not implemented')
192192

193-
ql.log.warn(f'msg_mem_ctrl(subtype = {mem_ctrl_subtypes[subtype]}, flags = 0x{flags:x}, addr = 0x{addr:x}, len = 0x{len:x}) not implemented')
193+
ql.log.warning(f'msg_mem_ctrl(subtype = {mem_ctrl_subtypes[subtype]}, flags = 0x{flags:x}, addr = 0x{addr:x}, len = 0x{len:x}) not implemented')
194194
# TODO: implement mem_ctrl
195195
return -1
196196

qiling/os/qnx/qnx.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6+
from typing import Callable
67
import os
78

89
from typing import Callable
@@ -13,6 +14,7 @@
1314
from qiling.os.qnx.const import NTO_SIDE_CHANNEL, SYSMGR_PID, SYSMGR_CHID, SYSMGR_COID
1415
from qiling.os.qnx.helpers import QnxConn
1516
from qiling.os.qnx.structs import _thread_local_storage
17+
1618
from qiling.cc import QlCC, intel, arm, mips, riscv
1719
from qiling.const import QL_ARCH, QL_INTERCEPT
1820
from qiling.os.fcall import QlFunctionCall
@@ -44,6 +46,18 @@ def __init__(self, ql: Qiling):
4446
self.function_after_load_list = []
4547
self.elf_mem_start = 0x0
4648
self.load()
49+
50+
cc: QlCC = {
51+
QL_ARCH.X86 : intel.cdecl,
52+
QL_ARCH.X8664 : intel.amd64,
53+
QL_ARCH.ARM : arm.aarch32,
54+
QL_ARCH.ARM64 : arm.aarch64,
55+
QL_ARCH.MIPS : mips.mipso32,
56+
QL_ARCH.RISCV : riscv.riscv,
57+
QL_ARCH.RISCV64: riscv.riscv,
58+
}[ql.archtype](ql)
59+
60+
self.fcall = QlFunctionCall(ql, cc)
4761

4862
# use counters to get free Ids
4963
self.channel_id = 1
@@ -87,7 +101,7 @@ def run_function_after_load(self):
87101
f()
88102

89103

90-
def hook_sigtrap(self, intno= None, int = None):
104+
def hook_sigtrap(self, intno= None, int = None):
91105
self.ql.log.info("Trap Found")
92106
self.emu_error()
93107
exit(1)

0 commit comments

Comments
 (0)