Skip to content

Commit

Permalink
🎨 refactor: move 'hook_switch' to 'experimental' folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul2803k committed Nov 27, 2024
1 parent 8d23479 commit a88f2c9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 40 deletions.
28 changes: 1 addition & 27 deletions qiling/core_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
14 changes: 1 addition & 13 deletions qiling/core_hooks_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
64 changes: 64 additions & 0 deletions qiling/extensions/hookswitch/hook_switch.py
Original file line number Diff line number Diff line change
@@ -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
)

0 comments on commit a88f2c9

Please sign in to comment.