diff --git a/qiling/arch/arm.py b/qiling/arch/arm.py index c03d0d8c0..394258f79 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' @@ -53,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: diff --git a/qiling/arch/evm/evm.py b/qiling/arch/evm/evm.py index a402e0d35..81ce642c5 100644 --- a/qiling/arch/evm/evm.py +++ b/qiling/arch/evm/evm.py @@ -3,10 +3,13 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework +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 monkeypath_core_hooks class QlArchEVM(QlArch): type = QL_ARCH.EVM @@ -16,7 +19,8 @@ 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) + 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/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/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' diff --git a/qiling/core.py b/qiling/core.py index 0c5cb929e..1a42d3e7e 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -30,18 +30,18 @@ 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, 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, *, @@ -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 @@ -540,17 +537,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, code=None): + 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 + 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 = count - - if self.interpreter: - return self.arch.run(code) + self.count = count # init debugger (if set) debugger = select_debugger(self._debugger) @@ -565,7 +566,7 @@ def run(self, begin=None, end=None, timeout=0, count=0, code=None): 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 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] 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 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 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] 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