Format of hook library (Hooks.dll) ---------------------------------- All constants, structures and macros are in ApiHooks.inc file. DLL can be written in any language and must export ApiHookChain as the 1st exported function (ord 1). ApiHookChain is array of API_HOOK structures. ApiHookChain must be terminated by HOOKS_END (-1) dword. I recommend to use MkHook macro for building API_HOOK structures. API_HOOK structure: ModuleName LPCSTR ? ;pointer to Ansi name of PE which exports wanted ;API; NULL for main (.exe) module ApiNameOrOrd LPCSTR ? ;ordinal number of API or pointer to the Ansi ;name of API dwFlags DWORD ? ;specifies how to hook, can be combination of: HOOK_EXPORT ;changes export item of ModuleName, so GetProcAddress ;will return HookAddress (useful for packed/crypted files) ;item is found according to ApiNameOrOrd HOOK_IMPORT ;changes import item of ModuleImport, item is found ;according to ApiNameOrOrd HOOK_BY_ADDRESS ;changes import items of ModuleImport, items are found ;according to current API address ;HOOK_BY_ADDRESS mustn't be used together with HOOK_IMPORT HOOK_HARD ;ignored under NT; when you want to hook modules laying in ;kernel space (system DLLs) of Windows 9x you must use this ;option (see 9xGlobal.txt) ;combined constants: HOOK_EXACT ;= HOOK_EXPORT + HOOK_IMPORT ;EXACT means that if I want to hook lstrcmpi, this and only ;this will be hooked in both ModuleName and ModuleImport HOOK_ALL ;= HOOK_EXPORT + HOOK_BY_ADDRESS ;ALL means that if I want to hook lstrcmpi, this and only ;this will be hooked in ModuleName but in ModuleImport ;will be hooked lstcmpiA in addition (the same addresses) ;there are also shortcuts: H_E, H_I, H_B, H_EXACT, H_ALL ModuleImport LPCSTR ? ;pointer to PE which imports wanted API, ;NULL for main (.exe) module ;ALL_MODULES for all modules in the process UnhookAddresses LPVOID ? ;pointer to UNHOOK_API structure for storing ;addresses for unhooking ;can be NULL ;UNHOOK_API structure has the following format: COMMON_NO_ADDR = 2 UNHOOK_API STRUCT DWORD MaxNoAddr DWORD COMMON_NO_ADDR CurNoAddr DWORD 0 WhereWhat ADDR_CONTENTS COMMON_NO_ADDR DUP <> UNHOOK_API ENDS ;MaxNoAddr is maximum number of dwords for storing unhook ;addresses ;CurNoAddr is current number of unhook addresses ;so the final size of UNHOOK_API structure must be: 4+4+MaxNoAddr*SIZEOF WhereWhat ;WhereWhat is array of ADDR_CONTENTS structures ADDR_CONTENTS STRUCT DWORD ReturnWhere LPDWORD ? ReturnWhat DWORD ? ADDR_CONTENTS ENDS ;ReturnWhere is address which was modified in ;during hooking process, ReturnWhat is the ;original contents of ReturnWhere ;to unhook: [ReturnWhere] := ReturnWhat ;I recommend to use MkUnhook macro for building UNHOOK_API ;structures HookAddress LPVOID ? ;pointer to hook procedure ;------------------------------------------------------------------------------- MkUnhook MACRO __procedure, __maxunhooks MkUnhook WantedApi, 2 Macro defined UNHOOK_API structure named UnhookWantedApi and reserved space for 2 ADDR_CONTENTS structures. MkUnhook 21, 1 Macro defined UNHOOK_API structure named Unhook21 and reserved space for 1 ADDR_CONTENTS structure. ;------------------------------------------------------------------------------- MkHook MACRO __module, __procedure, __method, __mod_with_import MkHook USER32, MessageBoxA, HOOK_IMPORT Macro defined API_HOOK structure with: ModuleName = sUSER32 ApiNameOrOrd = sMessageBoxA dwFlags = HOOK_IMPORT ModuleImport = NULL UnhookAddresses = NULL if UnhookMessageBoxA doesn't exist = OFFSET UnhookMessageBoxA if UnhookMessageBoxA exists HookAddress = NewMessageBoxA ;Import item of main (.exe) module for MessageBoxA is changed: ;If UnhookMessageBoxA exists, address (position) of item and item itself ;will be stored in UNHOOK_API structure ;Import item will be replaced with NewMessageBoxA address ;If the main module lays in kernel space import will not be changed MkHook , 145 Macro defined API_HOOK structure with: ModuleName = sKERNEL32 ApiNameOrOrd = 145 dwFlags = HOOK_BY_ADDRESS+HOOK_EXPORT ModuleImport = NULL UnhookAddresses = NULL if Unhook145 doesn't exist = OFFSET Unhook1 if Unhook1 exists HookAddress = New145 ;Import items of main (.exe) module which are equal to current address of the ;KERNEL32.145 are changed: ;If Unhook145 exists, addresses (positions) of items and items themselves ;will be stored in UNHOOK_API structure ;Import items will be replaced with New145 address ;If the main module lays in kernel space import will not be changed ;Export item of KERNEL32 for 145th function is changed: ;If Unhook145 exists, address (position) of item and item itself ;will be stored in UNHOOK_API structure ;Export item will be changed to point to New145 ;If KERNEL32 lays in kernel space export will not be changed MkHook , Sleep, H_E+H_B+H_H, USER32 Macro defined API_HOOK structure with: ModuleName = sKERNEL32 ApiNameOrOrd = sSleep dwFlags = HOOK_EXPORT+HOOK_BY_ADDRESS ModuleImport = sUSER32 UnhookAddresses = NULL if UnhookSleep doesn't exist = OFFSET UnhookSleep if UnhookSleep exists HookAddress = NewSleep ;Import items of USER32 which are equal to current address of Sleep ;of KERNEL32 are changed: ;If UnhookSleep exists, addresses (positions) of items and items themselves ;will be stored in UNHOOK_API structure ;Import items will be replaced with NewSleep address ;Even if USER32 lays in kernel space import will be changed ;Export item of KERNEL32 for Sleep function is changed: ;If UnhookSleep exists, address (position) of item and item itself ;will be stored in UNHOOK_API structure ;Export item will be changed to point to NewSleep ;Even if KERNEL32 lays in kernel space import will be changed MkHook , CreateFileA, H_E+H_B+H_H, ALL_MODULES Macro defined API_HOOK structure with: ModuleName = sKERNEL32 ApiNameOrOrd = sCreateFileA dwFlags = HOOK_EXPORT+HOOK_BY_ADDRESS+HOOK_HARD ModuleImport = ALL_MODULES UnhookAddresses = NULL if UnhookCreateFileA doesn't exist = OFFSET UnhookCreateFileA if UnhookCreateFileA exists HookAddress = NewCreateFileA ;Import items of all modules in the process which are equal to current address ;of CreateFileA of KERNEL32 are changed: ;If UnhookCreateFileA exists, addresses (positions) of items and items ;themselves will be stored in UNHOOK_API structure ;Import items will be replaced with NewCreateFileA address ;Even if some modules lay in kernel space their import will be changed ;Export item of KERNEL32 for CreateFileA function is changed: ;If UnhookCreateFileA exists, address (position) of item and item itself ;will be stored in UNHOOK_API structure ;Export item will be changed to point to NewCreateFileA ;Even if KERNEL32 lays in kernel space import will be changed ApiHookChain example: --------------------- BeginOfHooks MyHooks ;defines public variable, which must be exported API_HOOK ;API_HOOK above defined EXACT hook of kernel32!GetVersion in shell32.dll ;The contents and address of kernel32 export item for GetVersionExW will be ;stored in UNHOOK_API structure pointed by UnhookGetVersionExW ;The contents of kernel32 export will be replaced with NewGetVersionExW ;only if kernel32 lays in user space ;The contents and address of shell32 import item for GetVersionExW will be ;stored in UNHOOK_API structure pointed by UnhookGetVersionExW ;The contents of shell32 import will be replaced with NewGetVersionExW ;only if user32 lays in user space MkHook ADVAPI32, RegOpenKeyExA ;Above is ALL hook of advapi32!RegOpenKeyExA in main module ;The contents and address of advapi32 export item for RegOpenKeyExA will be ;stored in UNHOOK_API structure pointed by UnhookRegOpenKeyExA if it exists ;The contents of advapi32 export item will be changed to point to ;NewRegOpenKeyExA only if advapi32 lays in user space ;The contents and address of main module import items with address= ;RegOpenKeyExA will be stored in UNHOOK_API structure pointed by ;UnhookRegOpenKeyExA if it exists ;The contents of main module import items with address=RegOpenKeyExA will be ;replaced with NewRegOpenKeyExA only if main module lays in user space MkHook , CreateFileA ;Above is ALL hook of kernel32!CreateFileA in main module API_HOOK ;API_HOOK above defined EXACT hook of kernel32.50 (ordinal) in main module MkHook , FindFirstFileW, H_I, COMDLG32 ;API_HOOK above defined IMPORT hook of kernel32!FindFirstFileW in comdlg32.dll MkHook USER32, DialogBoxParamA, H_ALL ;above is ALL hook of user32!DialogBoxParamA in main module EndOfHooks ;HOOKS_END terminator On the LINK command line should be switch: /EXPORT:MyHooks,@1,NONAME or /EXPORT:MyHooks,@1 or DEF file should contain: NAME MyHooks.dll EXPORTS MyHooks @1 NONAME Dynamic hooks ------------- are ApiHookChain preceded by DYNAMIC_HOOKS constant. See AHasDLL for more. Use macro MkHookD for building Dynamic hooks. Unhooking --------- Hooks vanish automatically with exit of process. To unhook you have to specify pointer to UNHOOK_API structure in API_HOOK definition or to declare UnhookMyAPI (for example by MkUnhook MyApi, 3) and use MkHook macro with MyApi as __procedure. When unhooking is required then simply read ADDR_CONTENTS structures in UNHOOK_API structure, apply VirtualProtect on ReturnWhere to make it writeable, put ReturnWhat to ReturnWhere and return page attributes again with VP as is showed in Unhook example. Unhooking is required before exit of process where is hooks.dll located and some of hooks were used with HOOK_HARD option.