From c3ef41121fa0a5d5220d91300f2ef3c8dac8e119 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 22 May 2022 19:45:28 +0300 Subject: [PATCH 01/12] Fix #1157 --- qiling/os/posix/posix.py | 2 +- qiling/os/posix/syscall/fcntl.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index 73278057a..6f5041c9e 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -72,7 +72,7 @@ def __init__(self): def __len__(self): return len(self.__fds) - def __getitem__(self, idx: int): + def __getitem__(self, idx: Union[slice, int]): return self.__fds[idx] def __setitem__(self, idx: int, val: Optional[IO]): diff --git a/qiling/os/posix/syscall/fcntl.py b/qiling/os/posix/syscall/fcntl.py index 9c1182105..54b00555e 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -131,8 +131,8 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): if arg not in range(NR_OPEN): regreturn = -EINVAL - for idx, val in enumerate(ql.os.fd, arg): - if val is None: + for idx in range(arg, len(ql.os.fd)): + if ql.os.fd[idx] is None: ql.os.fd[idx] = f.dup() regreturn = idx break @@ -173,11 +173,13 @@ def ql_syscall_fcntl64(ql: Qiling, fd: int, cmd: int, arg: int): if arg not in range(NR_OPEN): regreturn = -1 - for idx, val in enumerate(ql.os.fd, arg): - if val is None: + for idx in range(arg, len(ql.os.fd)): + if ql.os.fd[idx] is None: ql.os.fd[idx] = f.dup() regreturn = idx break + else: + regreturn = -1 elif cmd == F_GETFL: regreturn = 2 From 2fafbeef960d6bbc629fc5103150918ee59c899b Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 22 May 2022 19:47:24 +0300 Subject: [PATCH 02/12] Tweak brk syscall --- qiling/os/posix/syscall/unistd.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index 942ac4140..fe0c01ca6 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -210,13 +210,14 @@ def ql_syscall_brk(ql: Qiling, inp: int): # otherwise, just return current brk_address if inp: - new_brk_addr = ((inp + 0xfff) // 0x1000) * 0x1000 + cur_brk_addr = ql.loader.brk_address + new_brk_addr = ql.mem.align_up(inp) - if inp > ql.loader.brk_address: # increase current brk_address if inp is greater - ql.mem.map(ql.loader.brk_address, new_brk_addr - ql.loader.brk_address, info="[brk]") + if inp > cur_brk_addr: # increase current brk_address if inp is greater + ql.mem.map(cur_brk_addr, new_brk_addr - cur_brk_addr, info="[brk]") - elif inp < ql.loader.brk_address: # shrink current bkr_address to inp if its smaller - ql.mem.unmap(new_brk_addr, ql.loader.brk_address - new_brk_addr) + elif inp < cur_brk_addr: # shrink current bkr_address to inp if its smaller + ql.mem.unmap(new_brk_addr, cur_brk_addr - new_brk_addr) ql.loader.brk_address = new_brk_addr From 4b46d6f752690a3fcc9fa57072882967d2ed94a2 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 00:39:17 +0300 Subject: [PATCH 03/12] Correct typos --- qiling/arch/evm/evm.py | 4 ++-- qiling/arch/evm/hooks.py | 4 ++-- qiling/os/memory.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qiling/arch/evm/evm.py b/qiling/arch/evm/evm.py index a402e0d35..2d77956d1 100644 --- a/qiling/arch/evm/evm.py +++ b/qiling/arch/evm/evm.py @@ -6,7 +6,7 @@ from qiling.const import * from ..arch import QlArch from .vm.evm import QlArchEVMEmulator -from .hooks import monkeypath_core_hooks +from .hooks import monkeypatch_core_hooks class QlArchEVM(QlArch): type = QL_ARCH.EVM @@ -16,7 +16,7 @@ def __init__(self, ql) -> None: super(QlArchEVM, self).__init__(ql) self.evm = QlArchEVMEmulator(self.ql) - monkeypath_core_hooks(self.ql) + monkeypatch_core_hooks(self.ql) def run(self, msg): return self.evm.vm.execute_message(msg) diff --git a/qiling/arch/evm/hooks.py b/qiling/arch/evm/hooks.py index 2c429a6a5..c2354c713 100644 --- a/qiling/arch/evm/hooks.py +++ b/qiling/arch/evm/hooks.py @@ -63,8 +63,8 @@ def __evm_hook_del(ql, hret): if not hooks_list: del evm_hooks_info.hook_addr_dict[h.addr] -def monkeypath_core_hooks(ql): - """Monkeypath core hooks for evm +def monkeypatch_core_hooks(ql): + """Monkeypatch core hooks for evm """ ql.hook_code = types.MethodType(__evm_hook_code, ql) diff --git a/qiling/os/memory.py b/qiling/os/memory.py index 228d07d0a..21d461e65 100644 --- a/qiling/os/memory.py +++ b/qiling/os/memory.py @@ -35,7 +35,7 @@ def __init__(self, ql: Qiling): } if ql.arch.bits not in bit_stuff: - raise QlErrorStructConversion("Unsupported Qiling archtecture for memory manager") + raise QlErrorStructConversion("Unsupported Qiling architecture for memory manager") max_addr = bit_stuff[ql.arch.bits] From af3ee3270fb1a11901294767990fb40115cced43 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 00:44:50 +0300 Subject: [PATCH 04/12] Let EVM patch ql.run --- qiling/arch/evm/evm.py | 14 ++++++++++++++ qiling/core.py | 5 +---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/qiling/arch/evm/evm.py b/qiling/arch/evm/evm.py index 2d77956d1..bd8245177 100644 --- a/qiling/arch/evm/evm.py +++ b/qiling/arch/evm/evm.py @@ -3,6 +3,9 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework +import types + +from qiling.arch.evm.vm.message import Message from qiling.const import * from ..arch import QlArch from .vm.evm import QlArchEVMEmulator @@ -17,6 +20,7 @@ def __init__(self, ql) -> None: self.evm = QlArchEVMEmulator(self.ql) monkeypatch_core_hooks(self.ql) + monkeypatch_core_methods(self.ql) def run(self, msg): return self.evm.vm.execute_message(msg) @@ -40,3 +44,13 @@ def uc(self): @property def endian(self) -> QL_ENDIAN: return QL_ENDIAN.EL + + +def __evm_run(self, code: Message): + return self.arch.run(code) + +def monkeypatch_core_methods(ql): + """Monkeypatch core methods for evm + """ + + ql.run = types.MethodType(__evm_run, ql) diff --git a/qiling/core.py b/qiling/core.py index 0c5cb929e..5dec03418 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -542,16 +542,13 @@ def write_exit_trap(self): # Emulate the binary from begin until @end, with timeout in @timeout and # number of emulated instructions in @count - def run(self, begin=None, end=None, timeout=0, count=0, code=None): + def run(self, begin=None, end=None, timeout=0, count=0): # replace the original entry point, exit point, timeout and count self.entry_point = begin self.exit_point = end self.timeout = timeout self.count = count - if self.interpreter: - return self.arch.run(code) - # init debugger (if set) debugger = select_debugger(self._debugger) From 04c7943777662afa40d5db9860f4b22000a0ad99 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 00:52:48 +0300 Subject: [PATCH 05/12] Annotate and document ql.run --- qiling/core.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 5dec03418..2e7513c3c 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -540,14 +540,21 @@ def write_exit_trap(self): # Qiling APIS # ############### - # Emulate the binary from begin until @end, with timeout in @timeout and - # number of emulated instructions in @count - def run(self, begin=None, end=None, timeout=0, count=0): + def run(self, begin: Optional[int] = None, end: Optional[int] = None, timeout: int = 0, icount: int = 0): + """Start binary emulation. + + Args: + begin : emulation starting address + end : emulation ending address + timeout : limit emulation to a specific amount of time (microseconds); unlimited by default + icount : limit emulation to a specific amount of instructions; unlimited by default + """ + # replace the original entry point, exit point, timeout and count self.entry_point = begin self.exit_point = end self.timeout = timeout - self.count = count + self.count = icount # init debugger (if set) debugger = select_debugger(self._debugger) @@ -562,7 +569,7 @@ def run(self, begin=None, end=None, timeout=0, count=0): if self.count <= 0: self.count = -1 - self.arch.run(count=self.count, end=self.exit_point) + self.arch.run(count=self.count, end=self.exit_point) else: self.write_exit_trap() # emulate the binary From 7b08cedd5f31b3d0805b71d3ee704dd1d3c1515b Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 00:54:04 +0300 Subject: [PATCH 06/12] Annotations and import fixes --- qiling/arch/evm/evm.py | 6 +++--- qiling/os/windows/windows.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qiling/arch/evm/evm.py b/qiling/arch/evm/evm.py index bd8245177..81ce642c5 100644 --- a/qiling/arch/evm/evm.py +++ b/qiling/arch/evm/evm.py @@ -5,11 +5,11 @@ import types +from qiling.arch.arch import QlArch +from qiling.arch.evm.hooks import monkeypatch_core_hooks +from qiling.arch.evm.vm.evm import QlArchEVMEmulator from qiling.arch.evm.vm.message import Message from qiling.const import * -from ..arch import QlArch -from .vm.evm import QlArchEVMEmulator -from .hooks import monkeypatch_core_hooks class QlArchEVM(QlArch): type = QL_ARCH.EVM diff --git a/qiling/os/windows/windows.py b/qiling/os/windows/windows.py index a0e615ac2..6c115d99c 100644 --- a/qiling/os/windows/windows.py +++ b/qiling/os/windows/windows.py @@ -4,13 +4,13 @@ # import ntpath -from typing import Callable, TextIO +from typing import Callable, TextIO, Type from unicorn import UcError from qiling import Qiling from qiling.arch.x86_const import GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, FS_SEGMENT_ADDR, FS_SEGMENT_SIZE -from qiling.arch.x86_utils import GDTManager, SegmentManager86, SegmentManager64 +from qiling.arch.x86_utils import GDTManager, SegmentManager, SegmentManager86, SegmentManager64 from qiling.cc import intel from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT from qiling.exception import QlErrorSyscallError, QlErrorSyscallNotFound, QlMemoryMappedError @@ -137,7 +137,7 @@ def load(self): def setupGDT(self): gdtm = GDTManager(self.ql) - segm_class = { + segm_class: Type[SegmentManager] = { 32 : SegmentManager86, 64 : SegmentManager64 }[self.ql.arch.bits] From 02a27cacd5d14a75c1218124caf68bf479b925e3 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 16:42:45 +0300 Subject: [PATCH 07/12] Better handling of rootfs default --- qiling/core.py | 7 ++----- qltool | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 2e7513c3c..e8bf7f468 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -30,7 +30,7 @@ class Qiling(QlCoreHooks, QlCoreStructs): def __init__( self, argv: Sequence[str] = None, - rootfs: str = None, + rootfs: str = r'.', env: MutableMapping[AnyStr, AnyStr] = {}, code: bytes = None, ostype: Union[str, QL_OS] = None, @@ -100,10 +100,7 @@ def __init__( ################ # rootfs setup # ################ - if rootfs is None: - rootfs = '.' - - elif not os.path.exists(rootfs): + if not os.path.exists(rootfs): raise QlErrorFileNotFound(f'Target rootfs not found: "{rootfs}"') self._rootfs = rootfs diff --git a/qltool b/qltool index 2ce8fa3c2..861bbbae3 100755 --- a/qltool +++ b/qltool @@ -187,7 +187,7 @@ if __name__ == '__main__': code_parser.add_argument('--thumb', action='store_true', help='specify thumb mode for ARM') code_parser.add_argument('--endian', choices=('little', 'big'), default='little', help='specify endianess for bi-endian archs') code_parser.add_argument('--os', required=True, choices=os_map) - code_parser.add_argument('--rootfs', help='emulated root filesystem, that is where all libraries reside') + code_parser.add_argument('--rootfs', default='.', help='emulated root filesystem, that is where all libraries reside') code_parser.add_argument('--format', choices=('asm', 'hex', 'bin'), default='bin', help='input file format') # set "examples" subcommand @@ -223,7 +223,7 @@ if __name__ == '__main__': handle_examples(parser) # ql file setup - if options.subcommand == 'run': + elif options.subcommand == 'run': ql = handle_run(options) # ql code setup From 806aa29f8b0d30cfc76987f53e2656d85cd2c9d4 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 16:45:37 +0300 Subject: [PATCH 08/12] A few more annotations --- qiling/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index e8bf7f468..701b64820 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -37,11 +37,11 @@ def __init__( archtype: Union[str, QL_ARCH] = None, verbose: QL_VERBOSE = QL_VERBOSE.DEFAULT, profile: str = None, - console=True, + console: bool = True, log_file=None, log_override=None, - log_plain=False, - multithread = False, + log_plain: bool = False, + multithread: bool = False, filter = None, stop: QL_STOP = QL_STOP.NONE, *, From 073ee3b85c7cbc6989b1dc969a7f7cd06e52aa2f Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 24 May 2022 17:03:13 +0300 Subject: [PATCH 09/12] Reverting arg name change --- qiling/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 701b64820..1a42d3e7e 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -537,21 +537,21 @@ def write_exit_trap(self): # Qiling APIS # ############### - def run(self, begin: Optional[int] = None, end: Optional[int] = None, timeout: int = 0, icount: int = 0): + def run(self, begin: Optional[int] = None, end: Optional[int] = None, timeout: int = 0, count: int = 0): """Start binary emulation. Args: begin : emulation starting address end : emulation ending address timeout : limit emulation to a specific amount of time (microseconds); unlimited by default - icount : limit emulation to a specific amount of instructions; unlimited by default + count : limit emulation to a specific amount of instructions; unlimited by default """ # replace the original entry point, exit point, timeout and count self.entry_point = begin self.exit_point = end self.timeout = timeout - self.count = icount + self.count = count # init debugger (if set) debugger = select_debugger(self._debugger) From f0f5cb338091d84dca568173d4f1a0c303107745 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 30 May 2022 18:30:21 +0300 Subject: [PATCH 10/12] Add missing ARM regs --- qiling/arch/arm.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qiling/arch/arm.py b/qiling/arch/arm.py index c03d0d8c0..130d93e8e 100644 --- a/qiling/arch/arm.py +++ b/qiling/arch/arm.py @@ -41,7 +41,11 @@ def uc(self) -> Uc: @cached_property def regs(self) -> QlRegisterManager: - regs_map = arm_const.reg_map + regs_map = dict( + **arm_const.reg_map, + **arm_const.reg_vfp + ) + pc_reg = 'pc' sp_reg = 'sp' From bf5f26f566a3ba7d9db7c9d70042019660d4b7fa Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 30 May 2022 18:30:49 +0300 Subject: [PATCH 11/12] Remove ARM endian workaround --- qiling/arch/arm.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/qiling/arch/arm.py b/qiling/arch/arm.py index 130d93e8e..394258f79 100644 --- a/qiling/arch/arm.py +++ b/qiling/arch/arm.py @@ -57,17 +57,7 @@ def is_thumb(self) -> bool: @property def endian(self) -> QL_ENDIAN: - # FIXME: ARM is a bi-endian architecture which allows flipping core endianess - # while running. endianess is tested in runtime through CPSR[9], however unicorn - # doesn't reflect the endianess correctly through that bit. - # @see: https://github.com/unicorn-engine/unicorn/issues/1542 - # - # we work around this by using the initial endianess configuration, even though - # it might have been changed since. - # - # return QL_ENDIAN.EB if self.regs.cpsr & (1 << 9) else QL_ENDIAN.EL - - return self._init_endian + return QL_ENDIAN.EB if self.regs.cpsr & (1 << 9) else QL_ENDIAN.EL @property def effective_pc(self) -> int: From becf79985b626e58d614286248c3350873bbaa7c Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 30 May 2022 18:56:44 +0300 Subject: [PATCH 12/12] Add missing x86-64 regs --- qiling/arch/x86.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qiling/arch/x86.py b/qiling/arch/x86.py index 97850ef66..0a787e8b9 100644 --- a/qiling/arch/x86.py +++ b/qiling/arch/x86.py @@ -109,7 +109,10 @@ def regs(self) -> QlRegisterManager: **x86_const.reg_map_64_b, **x86_const.reg_map_64_w, **x86_const.reg_map_64_d, - **x86_const.reg_map_seg_base + **x86_const.reg_map_seg_base, + **x86_const.reg_map_xmm, + **x86_const.reg_map_ymm, + **x86_const.reg_map_zmm ) pc_reg = 'rip'