ApiHooks 3.1: Structures.txt

 Structures for EstablishApiHooks:
  a) for unhooking (optional) ADDR_CONTENTS, API_UNHOOK
  b) for hooking (required) API_HOOK

 Structure for GetLastStatus information: AH_LAST_STATUS
----------------------------------------------------------------------------------
ADDR_CONTENTS:

 typedef struct  _ADDR_CONTENTS      {
  DWORD         *ReturnWhere;
  DWORD          ReturnWhat;
 } ADDR_CONTENTS, *PADDR_CONTENTS;

Has sense in unhooking, must be loacated in writeable memory,
is filled by EstablishApiHooks or HookApi functions.
 ReturnWhere - address where to write (=return) ReturnWhat.
               VirtualProtect must be used to make ReturnWhere writeable.
 ReturnWhat  - contents of ReturnWhere before hooking.

You can use ReturnWhat as address of original API address only if
HOOK_EXPORT was NOT among dwFlags. See Examples\Delphi\Generic\Exe.dpr
----------------------------------------------------------------------------------- 
API_UNHOOK:

 typedef  struct _API_UNHOOK  {
  DWORD          MaxNoAddr;
  DWORD          CurNoAddr;
  PADDR_CONTENTS WhereWhat; 
 } API_UNHOOK, *PAPI_UNHOOK;

Has sense in unhooking, must be located in writeable memory,
is partially filled by EstablishApiHooks or HookApi functions.
  MaxNoAddr   - must be specified by user. Number of available ADDR_CONTENTS
                structures pointed by WhereWhat
  CurNoAddr   - should be 0. It is updated by AH. Current number of filled
                ADDR_CONTENTS structures.
  WhereWhat   - must be specified by user. Pointer to array of ADDR_CONTENTS
                structures. Array must contain at least MaxNoAddr ADDR_CONTENTS
                structures.

  See example of unhooking in Examples\C\Unhook.c
----------------------------------------------------------------------------------- 
API_HOOK:

 typedef struct  _API_HOOK   {
  LPCSTR       ModuleExport;
  LPCSTR       ApiNameOrOrd;
  DWORD        dwFlags;
  LPCSTR       ModuleImport;
  PAPI_UNHOOK  UnhookAddresses;
  LPVOID       HookAddress;
 } API_HOOK, *PAPI_HOOK;

Contains information for EstablishApiHooks function. Specifies API to hook, method,
address of new routine and optionally pointer to API_UNHOOK structure.

"Replace ModuleExport.ApiNameOrOrd imported by ModuleImport with HookAddress,
 do it according to dwFlags, optionally change ModuleExport too and
 optionally save changed dwords and addresses in UnhookAddresses."


  ModuleExport -  pointer to ANSI name of module which exports wanted API.
                  Can be specified with PathTo. It doesn't have to be present
                  in Target. 
                  Special values: MAIN_MODULE for main (.exe) module.
                                  HOOKS_END marks end of ApiHookChain.
                                  DYNAMIC_HOOKS marks dynamic hooks.
                  

  ApiNameOrOrd -  ordinal number (1..65535) of wanted API or
                  pointer to the ANSI name of wanted API.
                  It can be nonexisting (not exported by ModuleExport) name
                  or ordinal.

  dwFlags      -  specifies how to hook, see "dwFlags.txt".
 
  ModuleImport -  pointer to module which import wanted API.
                  Can be specified with PathTo. If it isn't present in Target,
                  ModuleImport isn't hooked. However, you can preload
                  ModuleImport immediatelly before hooking via HOOK_LOAD_IMPORT
                  dwFlag. 
                  Special values: MAIN_MODULE for main (.exe) module.
                                  ALL_MODULES for all modules in Target.

  UnhookAddresses pointer to API_UNHOOK structure for storing addresses for
                  unhooking.
                  If it is not used, set it to NULL.

  HookAddress  -  pointer to your hook procedure.
                  If you are using C, your procedure should have format:

                  ResultType CallType MyApi(Par0, Par1,...) {
                     ResultType result;
                     // pre-orig-call actions: modify parameters, bufers
                     result = OrigApi(Par0, Par1,...);  // optional
                     lasterr = GetLastError(); 
                     // post-orig-call actions: modify parameters, buffers, result
                     SetLastError(lasterr); 
                     return(result);
                  }

                  if you are using ASM or __declspec(naked) there are no limits.
----------------------------------------------------------------------------------- 
ApiHookChain is array of API_HOOK structures. It must end with API_HOOK structure
which has ModuleExport == HOOKS_END.

NOTE: You can always change ApiHookChain during DllMain(DLL_PROCESS_ATTACH),,).

Hooks can be exported (statically from .dll) by 3 ways:
   1) Hooks_DLL exports function "GetApiHookChain" which returns pointer
      to array of API_HOOK structures.
   2) Hooks_DLL exports array of API_HOOK structures "ApiHookChain".
   3) Hooks_DLL exports array of API_HOOK structures by ordinal number 1.

  Ad 1)----------------------------------------------------------
      API_HOOK ApiHookChain[9] = {
	{"KERNEL32.DLL", "WriteConsoleA",    HOOK_ALL,                          ALL_MODULES,   NULL,                  NewWriteConsoleA},
	{"USER32.DLL",   "FindWindowA",      HOOK_BY_ADDRESS,                   "MSVCRT.DLL",  NULL,                  NewWriteConsoleW},
	{NULL,           NULL,               0},
	{"GDI32.DLL",    "Pie",              HOOK_NY_ADDRESS|HOOK_BY_NAME,      "Display.drv", &UnhookPie,            NewPie},
	{"COMDLG32.DLL", "GetSaveFileNameA", HOOK_NY_ADDRESS|HOOK_BY_NAME,      MAIN_MODULE,   NULL,                  NewGetSaveFileNameA},
	{"KERNEL32.DLL", "GetProcAddress",   HOOK_ALL|HOOK_NOT_NT,              ALL_MODULES,   &UnhookGetProcAddress, NewGetProcAddress},
	{"MAIN_MODULE",  "MyExeExportedAPI", HOOK_ALL,                          ALL_MODULES,   NULL,                  NewMyExeExportedAPI},
	{"KERNEL32.DLL", 7,                  HOOK_EXPORT|HOOK_HARD|HOOK_NOT_NT, NULL,          &Unhook7,              New7},
	{HOOKS_END}
      };
      
      __EXPORT PAPI_HOOK GetApiHookChain(void) {
           return ApiHookChain;
      }

  Ad 2)----------------------------------------------------------
      __EXPORT API_HOOK ApiHookChain[6] = {
	{"KERNEL32.DLL", "WriteConsoleA",  HOOK_ALL,             ALL_MODULES, NULL, NewWriteConsoleA},
	{"KERNEL32.DLL", "WriteConsoleW",  HOOK_ALL,             ALL_MODULES, NULL, NewWriteConsoleW},
	{"KERNEL32.DLL", "GetStdHandle",   HOOK_ALL,             ALL_MODULES, NULL, NewGetStdHandle},
	{"KERNEL32.DLL", "WriteFile",      HOOK_ALL,             ALL_MODULES, NULL, NewWriteFile},
	{"KERNEL32.DLL", "GetProcAddress", HOOK_ALL|HOOK_NOT_NT, ALL_MODULES, NULL, NewGetProcAddress},
	{HOOKS_END}
      };    
----------------------------------------------------------------------------------
 There is also possibility to build ApiHookChain on the fly. Dynamic ApiHookChain
must begin with API_HOOK structure which has ModuleExport == HOOK_DYNAMIC. UnhookAddresses
member of this 1st structure can point to ExcludeModules - NULL terminated list of
HMODULEs to exclude from hooking.

      API_HOOK DynamicApiHookChain[7] = {
	{HOOKS_DYNAMIC},
	{"KERNEL32.DLL", "WriteConsoleA",  HOOK_ALL,             ALL_MODULES, NULL, NewWriteConsoleA},
	{"KERNEL32.DLL", "WriteConsoleW",  HOOK_ALL,             ALL_MODULES, NULL, NewWriteConsoleW},
	{"KERNEL32.DLL", "GetStdHandle",   HOOK_ALL,             ALL_MODULES, NULL, NewGetStdHandle},
	{"KERNEL32.DLL", "WriteFile",      HOOK_ALL,             ALL_MODULES, NULL, NewWriteFile},
	{"KERNEL32.DLL", "GetProcAddress", HOOK_ALL|HOOK_NOT_NT, ALL_MODULES, NULL, NewGetProcAddress},
	{HOOKS_END}
      };    

Following 2 examples do the same thing:
1)
  HANDLE ExcludeThem[6], hDll;
  int i = 0;
  DWORD status;
  ExcludeThem[i++] = GetModuleHandle(TEXT("~ThisModule~"));  //or hModule from DllMain
  if(hDll = GetModuleHandle(TEXT("ApiHooks.dll"))) ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("CRTDLL.dll")))   ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("MSVCRT.dll")))   ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("MFC42.dll")))    ExcludeThem[i++] = hDll;  
  ExcludeThem[i] = NULL; // NULL terminated list
  status = HookApi(TEXT("KERNEL32.dll"), TEXT("GetLocalTime"), HOOK_ALL, ALL_MODULES, NULL, NewGetLocalTime, ExcludeThem);
  if(status != ErrorSuccess) printf("Error %x", status);

2)
  HANDLE ExcludeThem[6], hDll;
  int i = 0;
  DWORD status;
  API_HOOK DynamicApiHookChain[3] = {
    {HOOKS_DYNAMIC,                ,         ,            , ExcludeThem},
    {"KERNEL32.DLL", "GetLocalTime", HOOK_ALL, ALL_MODULES, NULL, NewWriteConsoleA},
    {HOOKS_END}
  };    
  ExcludeThem[i++] = GetModuleHandle(TEXT("~ThisModule~"));  //or hModule from DllMain
  if(hDll = GetModuleHandle(TEXT("ApiHooks.dll"))) ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("CRTDLL.dll")))   ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("MSVCRT.dll")))   ExcludeThem[i++] = hDll;  
  if(hDll = GetModuleHandle(TEXT("MFC42.dll")))    ExcludeThem[i++] = hDll;  
  ExcludeThem[i] = NULL; // NULL terminated
  status = hEstablishApiHooks((LPCTSTR)DynamicApiHookChain, GetCurrentProcess(), 0);
  if(status != ErrorSuccess) printf("Error %x", status);

Using dynamic hooks is more powerful than using HookApi. HookApi can hook 1 API
at time only.
----------------------------------------------------------------------------------
AH_LAST_STATUS:

  It is important to check this structure when the last error was ErrorTimeOut.
  Do some actions only when LastMethod == AH_LM_NEWTHREAD.
  Address of this structure is returned by GetLastStatus function.
  Address is constant, structure can be overwritten by user.

 typedef struct  _AH_LAST_STATUS   {
  DWORD        LastApi;
  DWORD        LastMethod;
  DWORD        LastTime;
  DWORD        LastError;
  HANDLE       LastThreadHandle;
  DWORD        LastThreadId;
  LPVOID       LastThreadBody;
  LPVOID       LastThreadStack;
 } AH_LAST_STATUS, *PAH_LAST_STATUS;

  LastApi          - last AH function user called, can be one of the following
                     constants: AH_LA_ESTABLISHAPIHOOKS, AH_LA_ISMODULELOADED,
                     AH_LA_LOADANDCALL, AH_LA_UNLOADMODULE, AH_LA_REMOTEEXECUTE,
                     AH_LA_HOOKAPI
  LastMethod       - last method AH used for remote execution:
                     AH_LM_OPENTHREAD, AH_LM_NEWTHREAD
  LastTime         - last dwMilliseconds
  LastError        - last ErrorCode
  LastThreadHandle - handle to thread which was used for remote execution
  LastThreadId     - ID of thread which was used for remote execution
  LastThreadBody   - memory in Target where remote code is located
  LastThreadHandle - memory in Target where is Thread's stack

  See Examples\C\TimeOut.c or Examples\Delphi\Generic\Exe.dpr