3

i am trying to work on easyhook in python and here is my code

# Hook/EasyHook.py
from ctypes import *
from ctypes.util import find_library
from pathlib import Path

c_ulong_p = POINTER(c_ulong)
c_void_pp=POINTER(c_void_p)

res_path = str(Path(__file__).parent / 'res' / 'EasyHook64.dll')
lib_path = find_library(res_path)
clib = cdll.LoadLibrary(lib_path)


class TRACED_HOOK_HANDLE(Structure):
    _fields_ = [("Link", c_void_p)]


lh_install_hook = clib.LhInstallHook
lh_install_hook.restype = c_ulong
lh_install_hook.argtypes = [c_void_p, c_void_p, c_void_p, TRACED_HOOK_HANDLE]

# some definition of other functions...

if __name__ == '__main__':
    from ctypes.wintypes import *

    t_dll = CDLL('User32.dll')
    test=lambda:t_dll.MessageBoxW(None, 'hi content!', 'hi title!', 0)
    test()

    interface=CFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)

    def fake_function(handle, title, message, flag):
        return t_original(handle, "hooked "+title, "hooked "+message, flag)


    t_hook_info = TRACED_HOOK_HANDLE(None)
    if lh_install_hook(t_dll.MessageBoxW, interface(fake_function), None, byref(t_hook_info)):
        raise Exception("Hook error[%s]:\n%s" % (rtl_get_last_error(), rtl_get_last_error_string()))
    # error occur here and the program terminate
    # some other tests...

after a try, it exit on code 0xC0000005 when running to lh_install_hook calling and without any exception printed

then I tried to use those Api after inject into a C++ program by

lh_install_hook(func_address, interface(hook_function), None, byref(hook_info))

where func_address is the actual address of target call,and it cause

python38.dll+24174
_ctypes.pyd+A48D
python38.dll+33E00
python38.dll+3DA6E
_ctypes.pyd+3C69
_ctypes.pyd+38AB
python38.dll+507F5
python38.dll+491C8

is there any way to make it run?

Edit: here is my code inject and run in the c++ programe

# Hook/__init__.py
from .EasyHook import *


class Hook(object):
    def __init__(self, func_address: int):
        self.enabled = False
        self.hook_info = TRACED_HOOK_HANDLE(None)
        self._ACLEntries = (c_ulong * 1)(0)
        self.ACLEntries = cast(self._ACLEntries, POINTER(c_ulong))
        interface = CFUNCTYPE(self.restype, *self.argtypes)

        def hook_function(*args):
            return self.hook_function(*args)

        if lh_install_hook(func_address, interface(hook_function), None, byref(self.hook_info)):
            raise LocalHookError()
        # error occur here and the program terminate
        # some other codes...

    restype = c_void_p
    argtypes = []

    def hook_function(self, *args):
        return self.original(*args)
# main.py
from Hook import Hook
from ctypes import *
from ctypes.wintypes import *

class kernel32_beep_hook(Hook):
    restype = c_bool
    argtypes = [DWORD,DWORD]

    def hook_function(self, a1, a2):
        if logger is not None:
            logger.log('beep_hook','%s,%s'%(a1,a2))
        return self.original(a1,a2)

# some skip codes
addr=kernel32.GetProcAddress(kernel32_module,b"Beep")
ctypes.windll.kernel32.Beep(500,500)
hook=kernel32_beep_hook(addr)
# error occur here and the program terminate
nyao
  • 81
  • 1
  • 1
  • 5
  • 1
    I don't know if you have any interface definition errors, but one thing to watch out for is in `lh_install_hook(func_address, interface(hook_function), None, byref(hook_info))`. `interface(hook_function)` has to exist for the lifetime that `hook_function` may be called, but it goes out of scope right after `lh_install_hook` is called. Store it in a variable to maintain a reference. – Mark Tolonen Mar 20 '21 at 16:37
  • @MarkTolonen thanks for comment, I think this wont be the current problem, the program is terminate before "install", I try to look at the memory page by cheat engine and find that the memory where the function is havn't change when it terminate. – nyao Mar 20 '21 at 21:48
  • `hook_f = interface(fake_function) lh_install_hook(t_dll.MessageBoxW, hook_f, None, byref(t_hook_info))`# this ok `lh_install_hook(t_dll.MessageBoxW, interface(fake_function), None, byref(t_hook_info)) ` # not work, why? – CS QGB Mar 25 '21 at 08:59
  • 1
    @CSQGB it is because the gc system in python, which when a piece of memory is not be used by function (or store by a PYTHON variable), it will be free, so when the hooked function is call, it try to access a freed/another used memory as a function] – nyao Mar 29 '21 at 17:26

1 Answers1

1

According to [GitHub]: EasyHook/EasyHook - (master) EasyHook/Public/easyhook.h:

typedef struct _HOOK_TRACE_INFO_
{
    PLOCAL_HOOK_INFO        Link;
}HOOK_TRACE_INFO, *TRACED_HOOK_HANDLE;

TRACED_HOOK_HANDLE is actually a pointer (although its name suggests the opposite), therefore your lh_install_hook.argtypes (1st snippet) is incorrect. It should be:

lh_install_hook.argtypes = [c_void_p, c_void_p, c_void_p, POINTER(TRACED_HOOK_HANDLE)]

Technically, you ran into [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer).

Regarding no exception being thrown, maybe [SO]: Python exception thrown by libtidy is amusingly impossible to catch (@CristiFati's answer) should shed some light.

This should get past the problem, at least the main one. I'm not sure whether there are others, as I didn't install (or build) the .lib, so I didn't run your code.
My knowledge is very limited (so this might be complete nonsense), but one potential spot to generate problems is TRACED_HOOK_HANDLE->Link being initialized to NULL.

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • 1
    Very thanks for your answer! although there are still some coding mistake other than what you point out in my code, but you help me to find out the biggest mistake :) – nyao Mar 21 '21 at 19:17
  • You're welcome! It's better to handle each (major) mistake in a separate question to make it easier for whoever runs into one of them. – CristiFati Mar 21 '21 at 20:01
  • @nyao can you show me the fixed code. I meet the same problem – CS QGB Mar 24 '21 at 06:23
  • @CSQGB i put an example code in my github https://github.com/nyaoouo/PyEzH/ – nyao Mar 24 '21 at 15:48