From 25252995582de490e468224a56785fdd775576a6 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Feb 2024 20:35:16 +0200 Subject: [PATCH 1/3] Let Unicorn know the invalid insn has been handled --- qiling/core_hooks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 58d4d736e..babd0e151 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -237,7 +237,7 @@ 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: + def _hook_insn_invalid_cb(self, uc: Uc, pack_data) -> bool: """Invalid instruction hooks dispatcher. """ @@ -257,6 +257,8 @@ def _hook_insn_invalid_cb(self, uc: Uc, pack_data) -> None: if not handled: raise QlErrorCoreHook("_hook_insn_invalid_cb : not handled") + return True + def _hook_addr_cb(self, uc: Uc, addr: int, size: int, pack_data): """Address hooks dispatcher. """ From 67ca97c1403acbf60184bbfa4267f40c2b299049 Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Feb 2024 20:36:18 +0200 Subject: [PATCH 2/3] Introduce hook_insn_invalid to hook invalid instructions --- qiling/core_hooks.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index babd0e151..2c819a7e0 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -120,6 +120,21 @@ def __call__(self, __ql: Qiling, intno: int, *__context: Any) -> Any: pass +class InvalidInsnHookCallback(Protocol): + def __call__(self, __ql: Qiling, *__context: Any) -> Any: + """Invalid instruction hook callback. + + Args: + __ql : the associated qiling instance + __context : additional context passed on hook creation. if no context was passed, this argument should be omitted + + Returns: + an integer with `QL_HOOK_BLOCK` mask set to block execution of remaining hooks + (if any) or `None` + """ + pass + + def hookcallback(ql: Qiling, callback: Callable): @wraps(callback) def wrapper(*args, **kwargs): @@ -650,6 +665,25 @@ 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_insn_invalid(self, callback: InvalidInsnHookCallback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: + """Intercept cases in which Unicorn reaches opcodes it does not recognize or support. + + Args: + callback : a method to call upon interception + user_data : an additional context to pass to callback (default: `None`) + begin : start of memory range to watch + end : end of memory range to watch + + Notes: + - The callback is responsible to advance the pc register, if needed. + - If `begin` and `end` are not specified, the entire memory space will be watched. + + Returns: + Hook handle + """ + + return self.ql_hook(UC_HOOK_INSN_INVALID, callback, user_data, begin, end) + def hook_del(self, hret: HookRet) -> None: """Unregister an existing hook and release its resources. From 96ebbc187171a1cf63dc99830942eff22692db2d Mon Sep 17 00:00:00 2001 From: elicn Date: Wed, 28 Feb 2024 20:36:41 +0200 Subject: [PATCH 3/3] Minor changes --- qiling/core_hooks.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 2c819a7e0..0b4b18a27 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -11,8 +11,7 @@ from __future__ import annotations from functools import wraps -from typing import Any, Callable, MutableMapping, MutableSequence, Protocol -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Protocol from unicorn.unicorn_const import ( UC_HOOK_INTR, @@ -152,14 +151,14 @@ class QlCoreHooks: def __init__(self, uc: Uc): self._h_uc = uc - self._hook: MutableMapping[int, MutableSequence[Hook]] = {} - self._hook_fuc: MutableMapping[int, int] = {} + self._hook: Dict[int, List[Hook]] = {} + self._hook_fuc: Dict[int, int] = {} - self._insn_hook: MutableMapping[int, MutableSequence[Hook]] = {} - self._insn_hook_fuc: MutableMapping[int, int] = {} + self._insn_hook: Dict[int, List[Hook]] = {} + self._insn_hook_fuc: Dict[int, int] = {} - self._addr_hook: MutableMapping[int, MutableSequence[HookAddr]] = {} - self._addr_hook_fuc: MutableMapping[int, int] = {} + self._addr_hook: Dict[int, List[HookAddr]] = {} + self._addr_hook_fuc: Dict[int, int] = {} ######################## # Callback definitions # @@ -229,7 +228,7 @@ 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): + def _hook_mem_cb(self, uc: Uc, access: int, addr: int, size: int, value: int, pack_data) -> bool: """Memory access hooks dispatcher. """ @@ -751,11 +750,11 @@ def clear_hooks(self): self.clear_ql_hooks() def clear_ql_hooks(self): - self._hook = {} - self._hook_fuc = {} + self._hook.clear() + self._hook_fuc.clear() - self._insn_hook = {} - self._insn_hook_fuc = {} + self._insn_hook.clear() + self._insn_hook_fuc.clear() - self._addr_hook = {} - self._addr_hook_fuc = {} + self._addr_hook.clear() + self._addr_hook_fuc.clear()