Source code for windows.hooks

import sys
import ctypes

import windows
import windows.utils as utils
from . import native_exec
from .generated_def import winfuncs
from .generated_def.windef import PAGE_EXECUTE_READWRITE
from .generated_def.winstructs import *

# TODO Not a big fan of importing 'meta' every load
# Should do an Hook API that take the winproxy function (not generate every hook possible)
import windows.generated_def.meta


[docs]class Callback(object): """Give type information to hook callback""" def __init__(self, *types): self.types = types def __call__(self, func): func._types_info = self.types return func
class KnownCallback(object): types = () def __call__(self, func): func._types_info = self.types return func def add_callback_to_module(callback): setattr(sys.modules[__name__], type(callback).__name__, callback) # Generate IATCallback decorator for all known functions for func in windows.generated_def.meta.functions: prototype = getattr(winfuncs, func + "Prototype") callback_name = func + "Callback" class CallBackDeclaration(KnownCallback): types = (prototype._restype_,) + prototype._argtypes_ CallBackDeclaration.__name__ = callback_name add_callback_to_module(CallBackDeclaration())
[docs]class IATHook(object): """Look at my hook <3""" def __init__(self, IAT_entry, callback, types=None): if types is None: if not hasattr(callback, "_types_info"): raise ValueError("Callback for IATHook has no type infomations") types = callback._types_info self.original_types = types self.callback_types = self.transform_arguments(self.original_types) self.entry = IAT_entry self.callback = callback ## No more circular ref -> but stub is destroyed -> segv :( self.stub = ctypes.WINFUNCTYPE(*self.callback_types)(self.hook_callback) # stub = ctypes.WINFUNCTYPE(*self.callback_types)(self.hook_callback) # self.stub_addr = ctypes.cast(stub, PVOID) # Same problem as keep stub... (GC..) self.stub_addr = ctypes.cast(self.stub, PVOID).value # Same problem as keep stub... (GC..) # IAT_entry.stub = stub self.realfunction = ctypes.WINFUNCTYPE(*types)(IAT_entry.nonhookvalue) self.is_enable = False def transform_arguments(self, types): res = [] for type in types: if type in (ctypes.c_wchar_p, ctypes.c_char_p): res.append(ctypes.c_void_p) else: res.append(type) return res
[docs] def enable(self): """Enable the IAT hook: you MUST keep a reference to the IATHook while the hook is enabled""" with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE): self.entry.value = self.stub_addr self.is_enable = True self.entry.enabled = True
[docs] def disable(self): """Disable the IAT hook""" with utils.VirtualProtected(self.entry.addr, ctypes.sizeof(PVOID), PAGE_EXECUTE_READWRITE): self.entry.value = self.entry.nonhookvalue self.is_enable = False self.entry.enabled = True
def hook_callback(self, *args): adapted_args = [] for value, type in zip(args, self.original_types[1:]): if type == ctypes.c_wchar_p: adapted_args.append(ctypes.c_wchar_p(value)) elif type == ctypes.c_char_p: adapted_args.append(ctypes.c_char_p((value))) else: adapted_args.append(value) def real_function(*args): if args == (): args = adapted_args return self.realfunction(*args) return self.callback(*adapted_args, real_function=real_function)
## New simple hook API based on winproxy def setup_hook(target, hook, dll_to_hook): "TODO: Test and doc :D" dll_name, api_name = windows.winproxy.get_target(target) prototype = target.prototype hook._types_info = (prototype._restype_,) + prototype._argtypes_ if not dll_name.endswith(".dll"): dll_name += ".dll" # Get the peb of our process peb = windows.current_process.peb # Get the dll_to_hook module_to_hook = [m for m in peb.modules if m.name.lower() == dll_to_hook.lower()][0] # Get the iat entries for DLL dll_name adv_imports = module_to_hook.pe.imports[dll_name] # Get RegOpenKeyExA iat entry iat = [n for n in adv_imports if n.name == api_name][0] iat.set_hook(hook) return iat