CApiHookHelp类

牛人Jeffrey Richter写的Hook API工具类,我修正了少许BUG,在Windows XP/Visual Studio 2005环境下测试成功

 

/******************************************************************************
Module:  APIHook.h
Notices: Copyright (c) 2000 Jeffrey Richter
Revisor: ZhouQinsheng
******************************************************************************/

#pragma once

///
class CApiHookHelp
{
public:
 // Hook a function in all modules
 CApiHookHelp(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook,
  BOOL fExcludeAPIHookMod);

 // Unhook a function from all modules
 ~CApiHookHelp();

 // Returns the original address of the hooked function
 operator PROC() { return(m_pfnOrig); }

protected:
 // Calls the real GetProcAddress
 static FARPROC WINAPI GetProcAddressRaw(HMODULE hmod, PCSTR pszProcName);

 // Replaces a symbol's address in a module's import section
 static void WINAPI ReplaceIATEntryInAllMods(PCSTR pszCalleeModName
  , PROC pfnOrig, PROC pfnHook, BOOL fExcludeAPIHookMod);

 // Replaces a symbol's address in all module's import sections
 static void WINAPI ReplaceIATEntryInOneMod(PCSTR pszCalleeModName
  , PROC pfnOrig, PROC pfnHook, HMODULE hmodCaller);

private:
 // Used to trap when DLLs are newly loaded
 static HMODULE WINAPI LoadLibraryA(PCSTR  pszModulePath);
 static HMODULE WINAPI LoadLibraryW(PCWSTR pszModulePath);
 static HMODULE WINAPI LoadLibraryExA(PCSTR  pszModulePath
  , HANDLE hFile, DWORD dwFlags);
 static HMODULE WINAPI LoadLibraryExW(PCWSTR pszModulePath
  , HANDLE hFile, DWORD dwFlags);

 // Returns address of replacement function if hooked function is requested
 static FARPROC WINAPI GetProcAddress(HMODULE hmod, PCSTR pszProcName);

 // Used when a DLL is newly loaded after hooking a function
 static void WINAPI FixupNewlyLoadedModule(HMODULE hmod, DWORD dwFlags);
 
 // Returns the HMODULE that contains the specified memory address
 static HMODULE ModuleFromAddress(PVOID pv);

 VOID FirstHookAtAll(PROC pNew);
 VOID LastUnHookAtAll();

protected:
 // Instantiates hooks on these functions
 static CApiHookHelp *sm_pLoadLibraryA;
 static CApiHookHelp *sm_pLoadLibraryW;
 static CApiHookHelp *sm_pLoadLibraryExA;
 static CApiHookHelp *sm_pLoadLibraryExW;
 static CApiHookHelp *sm_pGetProcAddress;

private:
 static PVOID sm_pvMaxAppAddr;  // Maximum private memory address
 static CApiHookHelp* sm_pHead;  // Address of first object
 CApiHookHelp* m_pNext;    // Address of next  object

 PCSTR m_pszCalleeModName;   // Module containing the function (ANSI)
 PCSTR m_pszFuncName;    // Function name in callee (ANSI)
 PROC  m_pfnOrig;     // Original function address in callee
 PROC  m_pfnHook;     // Hook function address
 BOOL  m_fExcludeAPIHookMod;   // Hook module w/CApiHookHelp implementation?
};

End of File //

/******************************************************************************
Module:  APIHook.cpp
Notices: Copyright (c) 2000 Jeffrey Richter
Revisor: ZhouQinsheng
******************************************************************************/

#include "stdafx.h"
#include <ImageHlp.h>
#pragma comment(lib, "ImageHlp")

#include "ApiHookHelp.h"
#include "Toolhelp.h"

#ifdef ASSERT
#define chASSERT ASSERT
#else
#define chASSERT
#endif

///

// When an application runs on Windows 98 under a debugger, the debugger
// makes the module's import section point to a stub that calls the desired
// function. To account for this, the code in this module must do some crazy
// stuff. These variables are needed to help with the crazy stuff.

// The highest private memory address (used for Windows 98 only)
PVOID CApiHookHelp::sm_pvMaxAppAddr = NULL;
const BYTE cPushOpCode = 0x68;   // The PUSH opcode on x86 platforms

///

// The head of the linked-list of CApiHookHelp objects
CApiHookHelp *CApiHookHelp::sm_pHead = NULL;

CApiHookHelp *CApiHookHelp::sm_pLoadLibraryA = NULL;
CApiHookHelp *CApiHookHelp::sm_pLoadLibraryW = NULL;
CApiHookHelp *CApiHookHelp::sm_pLoadLibraryExA = NULL;
CApiHookHelp *CApiHookHelp::sm_pLoadLibraryExW = NULL;
CApiHookHelp *CApiHookHelp::sm_pGetProcAddress = NULL;

///
CApiHookHelp::CApiHookHelp(PSTR pszCalleeModName,
         PSTR pszFuncName,
         PROC pfnHook,
         BOOL fExcludeAPIHookMod)
{
 FirstHookAtAll(pfnHook);

 if (sm_pvMaxAppAddr == NULL)
 {
  // Functions with address above lpMaximumApplicationAddress require
  // special processing (Windows 98 only)
  SYSTEM_INFO si;
  GetSystemInfo(&si);
  sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
 }

 m_pNext  = sm_pHead;    // The next node was at the head
 sm_pHead = this;        // This node is now at the head

 // Save information about this hooked function
 m_pszCalleeModName   = pszCalleeModName;
 m_pszFuncName        = pszFuncName;
 m_pfnHook            = pfnHook;
 m_fExcludeAPIHookMod = fExcludeAPIHookMod;
 m_pfnOrig    = GetProcAddressRaw(GetModuleHandleA(pszCalleeModName)
  , m_pszFuncName);

 chASSERT(m_pfnOrig != NULL);  // Function doesn't exist

 if (m_pfnOrig > sm_pvMaxAppAddr)
 {
  // The address is in a shared DLL; the address needs fixing up
  PBYTE pb = (PBYTE) m_pfnOrig;
  if (pb[0] == cPushOpCode)
  {
   // Skip over the PUSH op code and grab the real address
   PVOID pv = * (PVOID*) &pb[1];
   m_pfnOrig = (PROC) pv;
  }
 }

 // Hook this function in all currently loaded modules
 ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook
  , m_fExcludeAPIHookMod);
}

///

CApiHookHelp::~CApiHookHelp()
{
 // Unhook this function from all modules
 ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig,
  m_fExcludeAPIHookMod);

 // Remove this object from the linked list
 CApiHookHelp* p = sm_pHead;
 if (p == this)  // Removing the head node
 {
  sm_pHead = p->m_pNext;
 }
 else
 {
  BOOL fFound = FALSE;

  // Walk list from head and fix pointers
  for (; !fFound && (p->m_pNext != NULL); p = p->m_pNext)
  {
   if (p->m_pNext == this)
   {
    // Make the node that points to us point to the our next node
    p->m_pNext = p->m_pNext->m_pNext;
    break;
   }
  }

  chASSERT(fFound);
 }

 LastUnHookAtAll();
}

///

// NOTE: This function must NOT be inlined
FARPROC WINAPI CApiHookHelp::GetProcAddressRaw(HMODULE hmod,
              PCSTR pszProcName)
{
 if(sm_pGetProcAddress && sm_pGetProcAddress->m_pfnOrig)
 {
  return ((FARPROC (WINAPI *)(HMODULE, PCSTR))sm_pGetProcAddress->m_pfnOrig)(hmod, pszProcName);
 }

 return ::GetProcAddress(hmod, pszProcName);
}

///

void CApiHookHelp::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
           PROC pfnCurrent,
           PROC pfnNew,
           BOOL fExcludeAPIHookMod)
{
 HMODULE hmodThisMod = fExcludeAPIHookMod
  ? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;

 // Get the list of modules in this process
 CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId());

 MODULEENTRY32 me = { sizeof(me) };

 for (BOOL fOk = th.ModuleFirst(&me); fOk; fOk = th.ModuleNext(&me))
 {
  // NOTE: We don't hook functions in our own module
  if (me.hModule != hmodThisMod)
  {
   // Hook this function in this module
   ReplaceIATEntryInOneMod(pszCalleeModName, pfnCurrent, pfnNew
    , me.hModule);
  }
 }
}

///

void CApiHookHelp::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
             PROC pfnCurrent,
             PROC pfnNew,
             HMODULE hmodCaller)
{
 // Get the address of the module's import section
 ULONG ulSize;
 PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
  ImageDirectoryEntryToData(hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT
  , &ulSize);

 if (pImportDesc == NULL)
 {
  return;  // This module has no import section
 }

 // Find the import descriptor containing references to callee's functions
 for (; pImportDesc->Name; pImportDesc++)
 {
  PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
  if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
  {
   break;   // Found
  }
 }

 if (pImportDesc->Name == 0)
 {
  return;  // This module doesn't import any functions from this callee
 }

 // Get caller's import address table (IAT) for the callee's functions
 PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
  ((PBYTE) hmodCaller + pImportDesc->FirstThunk);

 // Replace current function address with new function address
 for (; pThunk->u1.Function; pThunk++)
 {
  // Get the address of the function address
  PROC* ppfn = (PROC*) &pThunk->u1.Function;

  // Is this the function we're looking for?
  BOOL fFound = (*ppfn == pfnCurrent);

  if (!fFound && (*ppfn > sm_pvMaxAppAddr))
  {
   // If this is not the function and the address is in a shared DLL,
   // then maybe we're running under a debugger on Windows 98. In this
   // case, this address points to an instruction that may have the
   // correct address.
   PBYTE pbInFunc = (PBYTE) *ppfn;
   if (pbInFunc[0] == cPushOpCode)
   {
    // We see the PUSH instruction, the real function address follows
    ppfn = (PROC*) &pbInFunc[1];

    // Is this the function we're looking for?
    fFound = (*ppfn == pfnCurrent);
   }
  }

  if (fFound)
  {
   // The addresses match, change the import section address
   if(!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew
    , sizeof(pfnNew), NULL))
   {
    DWORD dwOldFlag = 0;
    VirtualProtectEx(GetCurrentProcess(), ppfn, sizeof(pfnNew)
     , PAGE_WRITECOPY, &dwOldFlag);
    WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew
     , sizeof(pfnNew), NULL);
    VirtualProtectEx(GetCurrentProcess(), ppfn, sizeof(pfnNew)
     , dwOldFlag, &dwOldFlag);
   }

   return;  // We did it, get out
  }
 }             // If we get to here, the function is not in the caller's import section
}


///

HMODULE WINAPI CApiHookHelp::LoadLibraryA(PCSTR pszModulePath)
{
 HMODULE hmod = ((HMODULE (WINAPI *)(PCSTR))sm_pLoadLibraryA->m_pfnOrig)(pszModulePath);
 FixupNewlyLoadedModule(hmod, 0);
 return(hmod);
}

///

HMODULE WINAPI CApiHookHelp::LoadLibraryW(PCWSTR pszModulePath)
{
 HMODULE hmod = ((HMODULE (WINAPI *)(PCWSTR))sm_pLoadLibraryW->m_pfnOrig)(pszModulePath);
 FixupNewlyLoadedModule(hmod, 0);
 return(hmod);
}

///

HMODULE WINAPI CApiHookHelp::LoadLibraryExA(PCSTR pszModulePath,
           HANDLE hFile,
           DWORD dwFlags)
{
 HMODULE hmod = ((HMODULE (WINAPI *)(PCSTR, HANDLE, DWORD))sm_pLoadLibraryExA->m_pfnOrig)(pszModulePath, hFile, dwFlags);
 FixupNewlyLoadedModule(hmod, dwFlags);
 return(hmod);
}

///

HMODULE WINAPI CApiHookHelp::LoadLibraryExW(PCWSTR pszModulePath,
           HANDLE hFile,
           DWORD dwFlags)
{
 HMODULE hmod = ((HMODULE (WINAPI *)(PCWSTR, HANDLE, DWORD))sm_pLoadLibraryExA->m_pfnOrig)(pszModulePath, hFile, dwFlags);
 FixupNewlyLoadedModule(hmod, dwFlags);
 return(hmod);
}

///

FARPROC WINAPI CApiHookHelp::GetProcAddress(HMODULE hmod,
           PCSTR pszProcName)
{
 // Get the true address of the function
 FARPROC pfn = GetProcAddressRaw(hmod, pszProcName);

 // Is it one of the functions that we want hooked?
 CApiHookHelp* p = sm_pHead;

 for (; (pfn != NULL) && (p != NULL); p = p->m_pNext)
 {
  if (pfn == p->m_pfnOrig)
  {
   // The address to return matches an address we want to hook
   // Return the hook function address instead
   pfn = p->m_pfnHook;
   break;
  }
 }

 return(pfn);
}

///

void CApiHookHelp::FixupNewlyLoadedModule(HMODULE hmod,
            DWORD dwFlags)
{
 // If a new module is loaded, hook the hooked functions
 if ((hmod != NULL) && ((dwFlags & LOAD_LIBRARY_AS_DATAFILE) == 0))
 {
  for (CApiHookHelp* p = sm_pHead; p != NULL; p = p->m_pNext)
  {
   ReplaceIATEntryInOneMod(p->m_pszCalleeModName
    , p->m_pfnOrig, p->m_pfnHook, hmod);
  }
 }
}

///

// Returns the HMODULE that contains the specified memory address
HMODULE CApiHookHelp::ModuleFromAddress(PVOID pv)
{
 MEMORY_BASIC_INFORMATION mbi;
 return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
  ? (HMODULE) mbi.AllocationBase : NULL);
}

///

// Hook LoadLibrary functions and GetProcAddress so that hooked functions
// are handled correctly if these functions are called.

VOID CApiHookHelp::FirstHookAtAll(PROC pNew)
{
 if(sm_pLoadLibraryA)
 {
  return;
 }

 if(pNew == reinterpret_cast<PROC>(LoadLibraryA)
  || pNew == reinterpret_cast<PROC>(LoadLibraryW)
  || pNew == reinterpret_cast<PROC>(LoadLibraryExA)
  || pNew == reinterpret_cast<PROC>(LoadLibraryExW)
  || pNew == reinterpret_cast<PROC>(GetProcAddress))
 {
  return;
 }

 sm_pLoadLibraryA = new CApiHookHelp("Kernel32.dll", "LoadLibraryA", 
  reinterpret_cast<PROC>(LoadLibraryA), TRUE);

 sm_pLoadLibraryW = new CApiHookHelp("Kernel32.dll", "LoadLibraryW",
  reinterpret_cast<PROC>(LoadLibraryW), TRUE);

 sm_pLoadLibraryExA = new CApiHookHelp("Kernel32.dll", "LoadLibraryExA",
  reinterpret_cast<PROC>(LoadLibraryExA), TRUE);

 sm_pLoadLibraryExW = new CApiHookHelp("Kernel32.dll", "LoadLibraryExW",
  reinterpret_cast<PROC>(LoadLibraryExW), TRUE);

 sm_pGetProcAddress = new CApiHookHelp("Kernel32.dll", "GetProcAddress",
  reinterpret_cast<PROC>(GetProcAddress), TRUE);
}

VOID CApiHookHelp::LastUnHookAtAll()
{
 if(!sm_pGetProcAddress)
 {
  return;
 }

 if(sm_pHead != sm_pGetProcAddress)
 {
  return;
 }

 delete sm_pGetProcAddress;
 sm_pGetProcAddress = NULL;
 delete sm_pLoadLibraryExW;
 sm_pLoadLibraryExW = NULL;
 delete sm_pLoadLibraryExA;
 sm_pLoadLibraryExA = NULL;
 delete sm_pLoadLibraryW;
 sm_pLoadLibraryW = NULL;
 delete sm_pLoadLibraryA;
 sm_pLoadLibraryA = NULL;
}

End of File //

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值