From 491a6c89c6c6fe50753f8bc84d1bbd66272cb05e Mon Sep 17 00:00:00 2001 From: Paul2803k Date: Fri, 11 Oct 2024 21:53:00 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20feature:=20add=20new=20HookSwit?= =?UTF-8?q?ch=20hook=20type.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qiling/core_hooks.py | 29 ++++++++++++++++++++++++++++- qiling/core_hooks_types.py | 13 +++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 0b4b18a27..c5cbf4f08 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -43,7 +43,7 @@ UC_HOOK_INSN_INVALID ) -from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet +from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet, HookSwitch from .const import QL_HOOK_BLOCK from .exception import QlErrorCoreHook @@ -397,6 +397,12 @@ def ql_hook(self, hook_type: int, callback: Callable, user_data: Any = None, beg return HookRet(self, hook_type, hook) + def ql_switch_hook(self, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: + hook = HookSwitch(callback, user_data, begin, end) + self._ql_hook(UC_HOOK_CODE, hook) + + return HookRet(self, UC_HOOK_CODE, 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. @@ -419,6 +425,27 @@ def hook_code(self, callback: TraceHookCalback, user_data: Any = None, begin: in 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_switch(self, callback: TraceHookCalback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: + """Intercept assembly instructions before they get executed. + + Args: + callback : a method to call upon interception + user_data : an additional context to pass to callback (default: `None`) + begin : the memory address from when to start watching + end : the memory address from when to stop watching + + Notes: + If `begin` and `end` are not specified, the hook will never execute, use + `hook_code` instead. + If 'begin' and 'end' are the same address, the hook will never execute, use + `hook_address` instead. + + Returns: + Hook handle + """ + + return self.ql_switch_hook(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. diff --git a/qiling/core_hooks_types.py b/qiling/core_hooks_types.py index 896d70a0e..03b7512e4 100644 --- a/qiling/core_hooks_types.py +++ b/qiling/core_hooks_types.py @@ -54,3 +54,16 @@ def __init__(self, ql, hook_type: int, hook_obj: Hook): def remove(self) -> None: self.__remove(self) + + +class HookSwitch(Hook): + def __init__(self, callback, user_data=None, begin: int = 1, end: int = 0): + super().__init__(callback, user_data, begin, end) + self.switch = False + + def bound_check(self, pc: int, size: int = 1) -> bool: + if self.begin == pc and not self.switch: + self.switch = True + if self.end == pc and self.switch: + self.switch = False + return self.switch \ No newline at end of file From a88f2c929aa8f5325923cc8761a48d39b1319ec8 Mon Sep 17 00:00:00 2001 From: Paul2803k Date: Wed, 27 Nov 2024 10:10:21 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8E=A8=20refactor:=20move=20'hook=5Fs?= =?UTF-8?q?witch'=20to=20'experimental'=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qiling/core_hooks.py | 28 +-------- qiling/core_hooks_types.py | 14 +---- qiling/extensions/hookswitch/hook_switch.py | 64 +++++++++++++++++++++ 3 files changed, 66 insertions(+), 40 deletions(-) create mode 100644 qiling/extensions/hookswitch/hook_switch.py diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index c5cbf4f08..e8a9bdca4 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -43,7 +43,7 @@ UC_HOOK_INSN_INVALID ) -from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet, HookSwitch +from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet from .const import QL_HOOK_BLOCK from .exception import QlErrorCoreHook @@ -397,12 +397,6 @@ def ql_hook(self, hook_type: int, callback: Callable, user_data: Any = None, beg return HookRet(self, hook_type, hook) - def ql_switch_hook(self, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: - hook = HookSwitch(callback, user_data, begin, end) - self._ql_hook(UC_HOOK_CODE, hook) - - return HookRet(self, UC_HOOK_CODE, 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. @@ -425,26 +419,6 @@ def hook_code(self, callback: TraceHookCalback, user_data: Any = None, begin: in 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_switch(self, callback: TraceHookCalback, user_data: Any = None, begin: int = 1, end: int = 0) -> HookRet: - """Intercept assembly instructions before they get executed. - - Args: - callback : a method to call upon interception - user_data : an additional context to pass to callback (default: `None`) - begin : the memory address from when to start watching - end : the memory address from when to stop watching - - Notes: - If `begin` and `end` are not specified, the hook will never execute, use - `hook_code` instead. - If 'begin' and 'end' are the same address, the hook will never execute, use - `hook_address` instead. - - Returns: - Hook handle - """ - - return self.ql_switch_hook(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. diff --git a/qiling/core_hooks_types.py b/qiling/core_hooks_types.py index 03b7512e4..157446f01 100644 --- a/qiling/core_hooks_types.py +++ b/qiling/core_hooks_types.py @@ -5,6 +5,7 @@ from typing import Any, Callable + class Hook: def __init__(self, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0): self.callback = callback @@ -54,16 +55,3 @@ def __init__(self, ql, hook_type: int, hook_obj: Hook): def remove(self) -> None: self.__remove(self) - - -class HookSwitch(Hook): - def __init__(self, callback, user_data=None, begin: int = 1, end: int = 0): - super().__init__(callback, user_data, begin, end) - self.switch = False - - def bound_check(self, pc: int, size: int = 1) -> bool: - if self.begin == pc and not self.switch: - self.switch = True - if self.end == pc and self.switch: - self.switch = False - return self.switch \ No newline at end of file diff --git a/qiling/extensions/hookswitch/hook_switch.py b/qiling/extensions/hookswitch/hook_switch.py new file mode 100644 index 000000000..d66d7aaf2 --- /dev/null +++ b/qiling/extensions/hookswitch/hook_switch.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from typing import Any, Callable + +from unicorn.unicorn_const import ( + UC_HOOK_CODE, +) + +from qiling import Qiling +from qiling.core_hooks import TraceHookCalback +from qiling.core_hooks_types import Hook, HookRet + + +class HookSwitch(Hook): + def __init__(self, callback, user_data=None, begin: int = 1, end: int = 0) -> None: + super().__init__(callback=callback, user_data=user_data, begin=begin, end=end) + self.switch = False + + def bound_check(self, pc: int, size: int = 1) -> bool: + if self.begin == pc and not self.switch: + self.switch = True + if self.end == pc and self.switch: + self.switch = False + return self.switch + + +def ql_hook_switch( + ql: Qiling, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0 +) -> HookRet: + hook = HookSwitch(callback=callback, user_data=user_data, begin=begin, end=end) + ql._ql_hook(UC_HOOK_CODE, hook) + + return HookRet(ql=ql, hook_type=UC_HOOK_CODE, hook_obj=hook) + + +def hook_switch( + ql: Qiling, + callback: TraceHookCalback, + user_data: Any = None, + begin: int = 1, + end: int = 0, +) -> HookRet: + """Intercept assembly instructions before they get executed. + + Args: + ql : an instance of the Qiling class + callback : a method to call upon interception + user_data : an additional context to pass to callback (default: `None`) + begin : the memory address from when to start watching + end : the memory address from when to stop watching + + Notes: + If `begin` and `end` are not specified, the hook will never execute, use + `hook_code` instead. + If 'begin' and 'end' are the same address, the hook will never execute, use + `hook_address` instead. + + Returns: + Hook handle + """ + + return ql_hook_switch( + ql=ql, callback=callback, user_data=user_data, begin=begin, end=end + ) From d1ab4088ea6d6c40e4337e4c2564a6cb46527327 Mon Sep 17 00:00:00 2001 From: Paul2803k Date: Wed, 27 Nov 2024 10:12:55 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20ref:=20remove=20extra=20whit?= =?UTF-8?q?espaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qiling/core_hooks.py | 1 - qiling/core_hooks_types.py | 1 - 2 files changed, 2 deletions(-) diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index e8a9bdca4..0b4b18a27 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -419,7 +419,6 @@ def hook_code(self, callback: TraceHookCalback, user_data: Any = None, begin: in 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. diff --git a/qiling/core_hooks_types.py b/qiling/core_hooks_types.py index 157446f01..896d70a0e 100644 --- a/qiling/core_hooks_types.py +++ b/qiling/core_hooks_types.py @@ -5,7 +5,6 @@ from typing import Any, Callable - class Hook: def __init__(self, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0): self.callback = callback