  ApiWorks is very complex Scout that allows loading given module(s) and establishing
"hooks".

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
  ApiWorks functions have ANSI(A)/UNICODE(W) form. UNICODE forms can handle
only unicode characters with values in range 0-255 (codes above are mistranslated).

  Every string passed to ApiWorks functions can have (including zero terminator)
max. MAX_PATH characters. If it has more, ApiWorks returns ErrorAHException.

  For successful ApiWorks execution, the following KERNEL32.dll APIs must be original
(= import entries for those APIs in module with ApiHooks mustn't be altered = module
with ApiHooks mustn't be PE-hooked before it is initialized): GetModuleHandleA,
LoadLibraryA, GetProcAddress, VirtualQuery, GetModuleFileNameA, VirtualProtect, lstrcmpiA,
LocalAlloc, LocalFreee, FlushInstructionCache, ordinal 1. If they are PE-hooked, ApiWorks
may fail and returns ErrorAHRemote.

  Win9x: When a (large) module(s) is/are about to be loaded into more/all processes,
there must be "enough" (~100 MB) free space available on the drive with paging file
(Win386.swp).

  NT: Don't forget to set appropriate access to module to Hooks_DLL. Typically set
Read & Execute for Everyone. It is important for intersession hooking.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
  ApiWorks exports these functions for hooking:

  DWORD __stdcall  EstablishApiHooks(PRCINFO pRCI, LPCTSTR  lpszDll, DWORD ProcessId, LONG dwMilliseconds);
  DWORD __stdcall hEstablishApiHooks(PRCINFO pRCI, LPCTSTR  lpszDll, HANDLE hProcess, LONG dwMilliseconds);

  lpszDll is module that is loaded into Target and which exposes ApiHookChain.
  If lpszDll is already present in Target, EAH returns with ErrorAHSuccess immediatelly
  (hooks are taken as applied already).
  lpszDll is loaded, gets DLL_PROCESS_ATTACH followed by (except native processes)
  DLL_THREAD_DETACH notification for the same thread.
  lpszDll is called Hooks_DLL next.

  If all was successful, ErrorAHSuccess is returned.

  RemoteFunction for (h)EstablishApiHooks is implemented approx. as follows:
    HMODULE Modules[256];
    DWORD ModCnt = BuildModuleList(&Modules);
    LPHMODULE ExcludeModules= NULL;
    PAPI_HOOK AHChain;
    PAPI_HOOK (__stdcall *GetAHChain)(VOID);
    if(*(LPDWORD)lpszDll == HOOKS_DYNAMIC) {
      ExcludeModules = ((PAPI_HOOK)lpszDll).UnhookAddresses;
      AHChain = (PAPI_HOOK)lpszDll +1;
    }
    else {  
      if(GetModuleHandle(lpszDll))
        return(ErrorAHSuccess); // lpszDll already present -> hooks are thought as already applied
      else {
        if(hHooks = LoadLibrary(lpszDll)) {
          if(!(GetAHChain = GetProcAddress(hHooks, "GetApiHookChain"))) {
            if(!(AHChain = GetProcAddress(hHooks, "ApiHookChain"))) {
              if(!(AHChain = GetProcAddress(hHooks, (LPCSTR)1))) {
                return(ErrorAHRemote);  // Can't find AHChain
              }
            }
          }
          else {
            AHChain = GetAHChain();
          }
        } 
        else {
          return(ErrorAHRemote);  // Can't load lpszDll
        }
      } 
    } 
    while(AHChain->ModuleExport != HOOKS_END) {
      if(AHChain->dwFlags == HOOK_ALL_SAFE) {
        if(Is9x && (GetModuleHandle(AHChain->ModuleExport)>2GB)) {
          AHChain->dwFlags = HOOK_BY_NAME | HOOK_BY_ADDRESS;
          AHChain->ModuleImport = HALL_MODULES;
        }
      } 
      if(AHChain->ModuleImport == ALL_MODULES) { 
        for(i=0; i<ModCnt; i++) {
          ApplyHook(AHChain, Modules[i]);
        }
      }
      else {
        ApplyHook(AHChain, AHChain->ModuleImport);
      } 
      AHChain++;
    }

    VOID ApplyHooks (PAPI_HOOK ApiHook, HMODULE ModBase) {
      if((ApiHook->dwFlags & (HOOK_BY_NAME | HOOK_BY_ADDRESS))
         && IsExcluded(ModBase))
        return;
      HookPlace = EvaluateHook(ApiHooks->dwFlags, ModBase);
      ChangeBytes(ApiHook, HookPlace);
    }

    BOOL ChangeBytes(PAPI_HOOK ApiHook, PVOID HookPlace) {
      if(IsNT)
        goto StoreOld;
      if(ApiHook->dwFlags & HOOK_RAW) //can't estimate if it lies in shared section
        goto Check2GB;
      if(HookPlace is in shared section)
        if(!(ApiHook->dwFlags & HOOK_HARD))
          return(FALSE);
      Check2GB:
      if(HookPlace >= 2GB)
        if(!(ApiHook->dwFlags & HOOK_HARD))
          return(FALSE);
      StoreOld:
      if(ApiHook->UnhookAddresses)
        StoreOldBytes(ApiHook->UnhookAddresses, HookPlace);
      return(WriteBytes(HookPlace));
    }


  ApiWorks understands these structures (all must lie within writeable memory):

 a) For unhooking

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

  ReturnWhere contains address of place where ReturnWhat should be written.


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

  MaxNoAddr is maximum number of ADDR_CONTENTS structures in WhereWhat field.
  CurNoAddr (filled by AH) is current number of filled and valid ADDR_CONTENTS
  structures in WhereWhat field.
  All API_UNHOOK members must be initialized.

 b) For hooking

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

  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 (mustn't
                                  be used with HOOK_BY_NAME flag; specify main
                                  module name instead).
                                  HOOKS_END marks end of ApiHookChain.
                                  DYNAMIC_HOOKS marks dynamic hooks.
                  
                  If HOOK_RAW is set, ModuleExport can contain everything,
                  for example, pointer to symbol name.

                  Note: ApiWorks do not load ModuleExport.

  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. It can be NULL only if ModuleExport doesn't exist.

                  If HOOK_RAW is set, ApiNameOrOrd must contain 32bit virtual
                  address (valid in Target). 

  dwFlags      -  specifies how to hook, see "C-ApiWorks-dwFlags.txt".
 
  ModuleImport -  if dwFlags contains HOOK_OVERWRITE, HOOK_RAW or HOOK_ALL_SAFE
                  flag, ModuleImport is thought as pointer to pointer-to-routine
                  -to-jump-to-original-API. If this pointer is initially NULL,
                  space for routine is allocated from process' heap. Space for
                  routine must be at least 32 bytes long.
               -  otherwise is is: 
                  pointer to ANSI name of module which imports 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 (doesn't have to be exported).
                  If you are using C, your procedure can 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 Hooks_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_BY_NAME|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_BY_NAME, ALL_MODULES, NULL, NewWriteConsoleA},
	{"KERNEL32.DLL", "WriteConsoleW",  HOOK_BY_NAME, ALL_MODULES, NULL, NewWriteConsoleW},
	{"KERNEL32.DLL", "GetStdHandle",   HOOK_BY_NAME, ALL_MODULES, NULL, NewGetStdHandle},
	{"KERNEL32.DLL", "WriteFile",      HOOK_BY_NAME, ALL_MODULES, NULL, NewWriteFile},
	{"KERNEL32.DLL", "GetProcAddress", HOOK_BY_NAME, ALL_MODULES, NULL, NewGetProcAddress},
	{HOOKS_END}
      };    


  There is also possibility to build ApiHookChain on the fly (so-called dynamic hooks).
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_BY_NAME, ALL_MODULES, NULL, NewWriteConsoleA},
	{"KERNEL32.DLL", "WriteConsoleW",  HOOK_BY_NAME, ALL_MODULES, NULL, NewWriteConsoleW},
	{"KERNEL32.DLL", "GetStdHandle",   HOOK_BY_NAME, ALL_MODULES, NULL, NewGetStdHandle},
	{"KERNEL32.DLL", "WriteFile",      HOOK_BY_NAME, ALL_MODULES, NULL, NewWriteFile},
	{"KERNEL32.DLL", "GetProcAddress", HOOK_BY_NAME, ALL_MODULES, NULL, NewGetProcAddress},
	{HOOKS_END}
      };    

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
  ApiWorks also exports this high-level function:

  DWORD __stdcall HookApi(LPCTSTR  ModuleExport, LPCTSTR ApiNameOrOrd,  DWORD dwFlags, LPCTSTR ModuleImport,  PAPI_UNHOOK ApiUnhook, LPVOID HookAddress, HANDLE ExcludeModules[]);

    Prepares 1 dynamic hook and calls EstablishApiHooks
  == hooks ModuleExport.ApiNameOrOrd in the current process.

    Parameters have the same meaning as members of API_HOOK structure. ExcludeModules is
  the same as UnhookAddresses in API_HOOK {HOOKS_DYNAMIC} structure -> NULL terminated
  list of HMODULEs to exclude from hooking. UnhookAddresses and ExcludeModules parameters
  are optional: they must be NULL if they aren't used.
    If there's HOOK_OVERWRITE/RAW among/in dwFlags, ModuleImport is thought as a pointer
  to pointer-to-routine-to-jump-to-original-API. If this pointer is initially NULL, space
  for routine is allocated from current process' heap. 

    HookApi functions uses default RCINFO. If RCFlags.RC_FL_OWNFREE flag is set, memory
  isn't freed.

  If all was successful, ErrorAHSuccess is returned.

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.

  See:
    Examples\C-ApiWorks.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
  How to call original API
  ------------------------

In case of HOOK_OVERWRITE is only one way of calling original API.
Similar case is HOOK_RAW, but developer must have intimate knowledge of code he hooks
(for example: all general registers and flags must be preserved, often it is not possible
to call original code - NewAPI must jump there).


In case of HOOK_BY_NAME or HOOK_BY_ADDRESS there are two possibilities of calling original
API:
  a) just call the API
    DWORD WINAPI NewGetVersion {
      DWORD Result = GetVersion() +1;
      return(Result);
    }
    In this case API is statically imported - ModuleExport was loaded by OS and Hooks_DLL
    import entry for GetVersion points to ModuleExport.GetVersion.

  b) call API using UnhookAddresses
    DWORD WINAPI NewGetVersion {
      DWORD Result =
      (TGetVersion)(ApiHookChain[GETVERSION_ENTRY].UnhookAddresses.WhereWhat[0].ReturnWhat)() +1;
      return(Result);
    }
    In this case ModuleExport should not be loaded due to Hooks_DLL loading (if Hooks_DLL
    doesn't import from ModuleExport at all).

Method b) is required for hook chaining. Consider two Hooks_DLL hooking the same
ModuleExport.ApiNameOrOrd in the same ModuleImport.
1) Hooks are established according to ApiHookChain of the first Hooks_DLL1. ApiNameOrOrd
   in ModuleImport points to NewApiOrOrd1.
2) AH is about to establish hooks according to ApiHookChain of the second Hooks_DLL2:
   HOOK_BY_ADDRESS fails - ModuleImport's IAT entry for ApiNameOrOrd was changed (points
   to Hooks_DLL1.NewApiNameOrOrd, not to ModuleExport.ApiNameOrOrd.
   Hooks_DLL2 must use HOOK_BY_NAME method. O.K., hooks were established and ApiNameOrdOrd
   in ModuleImport points to NewApiOrdOrd2.
   See: Examples\C-ApiWorks\HookSharing.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
  Being hook-friendly
  -------------------

  Some programs expect specific bytes to be located on address of API+-X.
What happens, if these special conditions aren't fulfilled, depends on particular application.

Example: In TMext01 I've put 0xb8,0,0,0 at OpenProcess+0x24 -> ATM can control threads.
