/// <summary>
/// 對CAPIHook進行了dotnet下的封裝。
/// 其中fnHook: 爲掛鉤的函數的新地址的委託
/// 不要傳送和掛鉤的函數不一致的委託,關於如果從程序上阻止這個行爲,暫時還沒有想到好的辦法。
//////////////////////////////////////////////////////////////////////////////////////////////////
/// 在dotnet中使用APIHook時發現了以下問題:
/// 我們在c#中一般調用API是採用以下形式:
/// [DllImport("user32", EntryPoint = "MessageBoxA")]
/// public static extern int MessageBox(IntPtr hwnd, string lpText, string lpCaption, uint wType);
/// 但是我發現
/// 1.在我們還沒有使用APIHook來Hook MessageBox時,如果調用了MessageBox,即使以後使用APIHook來Hook了,這個MessageBox函數
/// 仍然彈出正常的MessageBox,而不是我們希望的Hook MessageBox.
/// 2.如果先調用APIHook進行了Hook,然後調用MessageBox,那麼會顯示hook messagebox.這時如果對APIHook類進行Unhook,再顯示
/// messageBox還是會進入hook messagebox的函數,並沒有回到normal messagebox.
/// 針對這個情況,我推論出dotnet在invoke api時,一定採取了緩存機制,將地址保存起來了.
/// 那麼它將這一地址保存在什麼地方呢?是全局中還是隻是本類中呢?
///
/// 我又進行了一次測試:
/// 我定義了一個臨時類,該類只有一個函數就是public static extern int MessageBox,
/// 測試結果:
/// 1.如果調用Form的MessageBox,彈出normal messagebox.然後再使用APIHook進行hook,Form的messagebox仍然顯示
/// normal messagebox.但是myclass的messagebox已經顯示hooked messagebox了.
/// 2.unhook後不改變上面的行爲.
/// 結論:
/// public static extern int MessageBox(IntPtr hwnd, string lpText, string lpCaption, uint wType);
/// 是作爲類的成員保存了起來.它具有和靜態成員類似的特性.它使用時才獲得native地址,並將這個地址保存在
/// 本類中,它是作爲類的靜態成員存在的.
//////////////////////////////////////////////////////////////////////////
/// 另外對不熟悉鉤子的人來講,有一點需要說明:
/// 本類只是通過修改IAT實現了hook api,通過本類可以截獲某個進程調用了的指定api(windows api或者動態鏈接庫中的api)
/// 本類並沒有實現注入進程空間.如果需要使用hook api修改別的進程的行爲,需要先注入進程空間,然後使用hook api纔有效.
/////////////////////////////////////////////////////////////////////////
/// 使用本類可以直接用APIHook()然後調用Hook,或者使用帶參數的APIHook構造函數.
/// unhook可以不用顯式調用,系統退出時會自動釋放.
/// </summary>
/// 對CAPIHook進行了dotnet下的封裝。
/// 其中fnHook: 爲掛鉤的函數的新地址的委託
/// 不要傳送和掛鉤的函數不一致的委託,關於如果從程序上阻止這個行爲,暫時還沒有想到好的辦法。
//////////////////////////////////////////////////////////////////////////////////////////////////
/// 在dotnet中使用APIHook時發現了以下問題:
/// 我們在c#中一般調用API是採用以下形式:
/// [DllImport("user32", EntryPoint = "MessageBoxA")]
/// public static extern int MessageBox(IntPtr hwnd, string lpText, string lpCaption, uint wType);
/// 但是我發現
/// 1.在我們還沒有使用APIHook來Hook MessageBox時,如果調用了MessageBox,即使以後使用APIHook來Hook了,這個MessageBox函數
/// 仍然彈出正常的MessageBox,而不是我們希望的Hook MessageBox.
/// 2.如果先調用APIHook進行了Hook,然後調用MessageBox,那麼會顯示hook messagebox.這時如果對APIHook類進行Unhook,再顯示
/// messageBox還是會進入hook messagebox的函數,並沒有回到normal messagebox.
/// 針對這個情況,我推論出dotnet在invoke api時,一定採取了緩存機制,將地址保存起來了.
/// 那麼它將這一地址保存在什麼地方呢?是全局中還是隻是本類中呢?
///
/// 我又進行了一次測試:
/// 我定義了一個臨時類,該類只有一個函數就是public static extern int MessageBox,
/// 測試結果:
/// 1.如果調用Form的MessageBox,彈出normal messagebox.然後再使用APIHook進行hook,Form的messagebox仍然顯示
/// normal messagebox.但是myclass的messagebox已經顯示hooked messagebox了.
/// 2.unhook後不改變上面的行爲.
/// 結論:
/// public static extern int MessageBox(IntPtr hwnd, string lpText, string lpCaption, uint wType);
/// 是作爲類的成員保存了起來.它具有和靜態成員類似的特性.它使用時才獲得native地址,並將這個地址保存在
/// 本類中,它是作爲類的靜態成員存在的.
//////////////////////////////////////////////////////////////////////////
/// 另外對不熟悉鉤子的人來講,有一點需要說明:
/// 本類只是通過修改IAT實現了hook api,通過本類可以截獲某個進程調用了的指定api(windows api或者動態鏈接庫中的api)
/// 本類並沒有實現注入進程空間.如果需要使用hook api修改別的進程的行爲,需要先注入進程空間,然後使用hook api纔有效.
/////////////////////////////////////////////////////////////////////////
/// 使用本類可以直接用APIHook()然後調用Hook,或者使用帶參數的APIHook構造函數.
/// unhook可以不用顯式調用,系統退出時會自動釋放.
/// </summary>
// Hob.Toolbox.APIHook.h
#pragma once
#include "APIHook.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Diagnostics;
using namespace System::Runtime::InteropServices;
using namespace System::Diagnostics;
namespace Hob{namespace Toolbox{namespace Classes
{
public ref class APIHook
{
public:
/// <summary>
/// 構造函數
/// </summary>
APIHook()
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
}
APIHook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook,bool fExcludeAPIHookMod)
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
//hook
Hook(CalleeModName,FuncName,fnHook,fExcludeAPIHookMod);
}
APIHook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook)
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
//hook
Hook(CalleeModName,FuncName,fnHook,true);
}
{
public ref class APIHook
{
public:
/// <summary>
/// 構造函數
/// </summary>
APIHook()
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
}
APIHook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook,bool fExcludeAPIHookMod)
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
//hook
Hook(CalleeModName,FuncName,fnHook,fExcludeAPIHookMod);
}
APIHook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook)
{
//生成一個CAPIHook對象
m_apiHookPtr=new CAPIHook();
//hook
Hook(CalleeModName,FuncName,fnHook,true);
}
/// <summary>
/// 掛鉤某個API
/// CalleeModName:希望掛鉤的模塊的名字
/// FuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void Hook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook,bool fExcludeAPIHookMod)
{
//如果已經掛鉤,必須先UnHook
if(BeHook) UnHook();
/// 掛鉤某個API
/// CalleeModName:希望掛鉤的模塊的名字
/// FuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void Hook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook,bool fExcludeAPIHookMod)
{
//如果已經掛鉤,必須先UnHook
if(BeHook) UnHook();
//開始掛鉤
PSTR pszCalleeModName = (PSTR)Marshal::StringToHGlobalAnsi(CalleeModName).ToPointer();
PSTR pszFuncName = (PSTR)Marshal::StringToHGlobalAnsi(FuncName).ToPointer();
PROC pfnHook =(PROC) Marshal::GetFunctionPointerForDelegate(fnHook).ToPointer();
m_delegatefnHook = fnHook;//save delegate防止delegate被垃圾回收
m_fnHookType = fnHook->GetType();
m_apiHookPtr->Hook(pszCalleeModName,pszFuncName,pfnHook,fExcludeAPIHookMod);
}
void Hook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook)
{
Hook(CalleeModName,FuncName,fnHook,true);
}
//撤銷掛鉤
void UnHook()
{
if(!BeHook) return;//沒有hook
m_apiHookPtr->UnHook();
}
PSTR pszCalleeModName = (PSTR)Marshal::StringToHGlobalAnsi(CalleeModName).ToPointer();
PSTR pszFuncName = (PSTR)Marshal::StringToHGlobalAnsi(FuncName).ToPointer();
PROC pfnHook =(PROC) Marshal::GetFunctionPointerForDelegate(fnHook).ToPointer();
m_delegatefnHook = fnHook;//save delegate防止delegate被垃圾回收
m_fnHookType = fnHook->GetType();
m_apiHookPtr->Hook(pszCalleeModName,pszFuncName,pfnHook,fExcludeAPIHookMod);
}
void Hook(String^ CalleeModName,String^ FuncName,Delegate^ fnHook)
{
Hook(CalleeModName,FuncName,fnHook,true);
}
//撤銷掛鉤
void UnHook()
{
if(!BeHook) return;//沒有hook
m_apiHookPtr->UnHook();
}
//析構函數
~APIHook()
{
//釋放託管資源.....
//調用釋放非託管資源
this->!APIHook();
}
~APIHook()
{
//釋放託管資源.....
//調用釋放非託管資源
this->!APIHook();
}
//finallize
!APIHook()
{
//釋放非託管資源
UnHook();
delete m_apiHookPtr;
}
!APIHook()
{
//釋放非託管資源
UnHook();
delete m_apiHookPtr;
}
//得到原來函數api的委託
property Delegate^ RawAPI
{
Delegate^ get()
{
try
{
if(!BeHook) return nullptr;
property Delegate^ RawAPI
{
Delegate^ get()
{
try
{
if(!BeHook) return nullptr;
PROC pfnOrig=(PROC)(*m_apiHookPtr);
Delegate^ d=Marshal::GetDelegateForFunctionPointer(IntPtr((PVOID)pfnOrig),m_fnHookType);
return d;
}
catch (Exception^)
{
return nullptr;
}
}
}
Delegate^ d=Marshal::GetDelegateForFunctionPointer(IntPtr((PVOID)pfnOrig),m_fnHookType);
return d;
}
catch (Exception^)
{
return nullptr;
}
}
}
//是否被hook
property bool BeHook
{
bool get()
{
return m_apiHookPtr->HasHook();
}
}
private:
CAPIHook* m_apiHookPtr;//CAPIHook對象
Delegate^ m_delegatefnHook; //保存委託,避免被釋放掉,造成地址不可用
Type^ m_fnHookType;//掛鉤的新函數的委託類型
};
}}}
property bool BeHook
{
bool get()
{
return m_apiHookPtr->HasHook();
}
}
private:
CAPIHook* m_apiHookPtr;//CAPIHook對象
Delegate^ m_delegatefnHook; //保存委託,避免被釋放掉,造成地址不可用
Type^ m_fnHookType;//掛鉤的新函數的委託類型
};
}}}
//APIHook.h
#pragma once
/// <summary>
/// CAPIHook類 本類用c++寫成,可以直接在c++下用.
/// 在此對 Jeffrey Richter 表示感謝
/// 實現應該放在cpp中,並且用#pragma unmanaged標示
/// 直接寫在頭文件會被認爲是託管的代碼,從而會發生一些異常(比如託管的異常:LoadLocker和Reentrancy)
/// 注意:
/// 最好不要使用此類掛鉤 API的LoadLibraryA LoadLibraryW LoadLibraryExA LoadLibraryExW GetProcAddress
/// 因爲本dll已經掛鉤了這幾個函數了。
/// 最好不要使用多個對象掛鉤同一個API,沒有具體測試會有什麼後果。
/// </summary>
class CAPIHook
{
public:
/// <summary>
/// 構造函數
/// </summary>
CAPIHook(void);
CAPIHook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod);
//析構函數
~CAPIHook(void);
//返回被hook函數原來的地址
operator PROC();
/// <summary>
/// 掛鉤某個API
/// pszCalleeModName:希望掛鉤的模塊的名字
/// pszFuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void Hook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod);
//撤銷掛鉤
void UnHook();
//是否掛鉤了
bool HasHook();
private:
bool m_hasHook;//是否已經掛鉤
static PVOID sm_pvMaxAppAddr;// 最大私有內存空間
static CAPIHook* sm_pHead; //APIHook對象鏈表的頭部
CAPIHook* m_pNext; //本APIHook對象的下一個對象
/// CAPIHook類 本類用c++寫成,可以直接在c++下用.
/// 在此對 Jeffrey Richter 表示感謝
/// 實現應該放在cpp中,並且用#pragma unmanaged標示
/// 直接寫在頭文件會被認爲是託管的代碼,從而會發生一些異常(比如託管的異常:LoadLocker和Reentrancy)
/// 注意:
/// 最好不要使用此類掛鉤 API的LoadLibraryA LoadLibraryW LoadLibraryExA LoadLibraryExW GetProcAddress
/// 因爲本dll已經掛鉤了這幾個函數了。
/// 最好不要使用多個對象掛鉤同一個API,沒有具體測試會有什麼後果。
/// </summary>
class CAPIHook
{
public:
/// <summary>
/// 構造函數
/// </summary>
CAPIHook(void);
CAPIHook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod);
//析構函數
~CAPIHook(void);
//返回被hook函數原來的地址
operator PROC();
/// <summary>
/// 掛鉤某個API
/// pszCalleeModName:希望掛鉤的模塊的名字
/// pszFuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void Hook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod);
//撤銷掛鉤
void UnHook();
//是否掛鉤了
bool HasHook();
private:
bool m_hasHook;//是否已經掛鉤
static PVOID sm_pvMaxAppAddr;// 最大私有內存空間
static CAPIHook* sm_pHead; //APIHook對象鏈表的頭部
CAPIHook* m_pNext; //本APIHook對象的下一個對象
PCSTR m_pszCalleeModName; //希望掛鉤的模塊的名字
PCSTR m_pszFuncName; // 希望掛鉤的模塊中的函數的名字
PROC m_pfnOrig; // 被掛鉤的函數原來的地址
PROC m_pfnHook; // 掛鉤的函數的新地址
bool m_fExcludeAPIHookMod; // 建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
private:
//替換所有模塊中的函數地址爲新地址
static void ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, bool fExcludeAPIHookMod);
//替換某個模塊中的函數地址爲新地址
static void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
//調用真實的GetProcAddress獲得函數的原來的真正地址
static FARPROC WINAPI GetProcAddre***aw(HMODULE hmod,LPCSTR pszProcName);
// 得到包含指定內存地址的模塊
static HMODULE ModuleFromAddress(PVOID pv);
private:
#pragma region API被動態調用時的處理
PCSTR m_pszFuncName; // 希望掛鉤的模塊中的函數的名字
PROC m_pfnOrig; // 被掛鉤的函數原來的地址
PROC m_pfnHook; // 掛鉤的函數的新地址
bool m_fExcludeAPIHookMod; // 建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
private:
//替換所有模塊中的函數地址爲新地址
static void ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, bool fExcludeAPIHookMod);
//替換某個模塊中的函數地址爲新地址
static void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller);
//調用真實的GetProcAddress獲得函數的原來的真正地址
static FARPROC WINAPI GetProcAddre***aw(HMODULE hmod,LPCSTR pszProcName);
// 得到包含指定內存地址的模塊
static HMODULE ModuleFromAddress(PVOID pv);
private:
#pragma region API被動態調用時的處理
//下面處理LoadLibrary 和 GetProcAddress
// 當我們使用這些函數動態調用API時,本類無法正確截獲
static CAPIHook sm_LoadLibraryA;
static CAPIHook sm_LoadLibraryW;
static CAPIHook sm_LoadLibraryExA;
static CAPIHook sm_LoadLibraryExW;
static CAPIHook sm_GetProcAddress;
// 當我們使用這些函數動態調用API時,本類無法正確截獲
static CAPIHook sm_LoadLibraryA;
static CAPIHook sm_LoadLibraryW;
static CAPIHook sm_LoadLibraryExA;
static CAPIHook sm_LoadLibraryExW;
static CAPIHook sm_GetProcAddress;
//新的LoadLibrary的函數
static void FixupNewlyLoadedModule(HMODULE hmod, DWORD dwFlags);
//新的LoadLibraryA
static HMODULE WINAPI LoadLibraryA(PCSTR pszModulePath);
//新的LoadLibraryW
static HMODULE WINAPI LoadLibraryW(PCWSTR pszModulePath);
//新的LoadLibraryExA
static HMODULE WINAPI LoadLibraryExA(PCSTR pszModulePath,HANDLE hFile, DWORD dwFlags);
//新的LoadLibraryExW
static HMODULE WINAPI LoadLibraryExW(PCWSTR pszModulePath,HANDLE hFile, DWORD dwFlags);
//新的GetProcAddress
static FARPROC WINAPI GetProcAddress(HMODULE hmod, PCSTR pszProcName);
static void FixupNewlyLoadedModule(HMODULE hmod, DWORD dwFlags);
//新的LoadLibraryA
static HMODULE WINAPI LoadLibraryA(PCSTR pszModulePath);
//新的LoadLibraryW
static HMODULE WINAPI LoadLibraryW(PCWSTR pszModulePath);
//新的LoadLibraryExA
static HMODULE WINAPI LoadLibraryExA(PCSTR pszModulePath,HANDLE hFile, DWORD dwFlags);
//新的LoadLibraryExW
static HMODULE WINAPI LoadLibraryExW(PCWSTR pszModulePath,HANDLE hFile, DWORD dwFlags);
//新的GetProcAddress
static FARPROC WINAPI GetProcAddress(HMODULE hmod, PCSTR pszProcName);
#pragma endregion
};
};
//APIHook.cpp
#include "Stdafx.h"
#include "APIHook.h"
#include "MyASSERT.h"
#include "APIHook.h"
#include "MyASSERT.h"
#include <ImageHlp.h>//由於ImageHlp.h中有部分定義和system命名空間下的混淆,應該在system前include
#pragma comment(lib, "ImageHlp")
#pragma comment(lib, "ImageHlp")
#include <Tlhelp32.h>
#pragma unmanaged //以下爲非託管代碼
PVOID CAPIHook::sm_pvMaxAppAddr=NULL;// 最大私有內存空間
const BYTE cPushOpCode = 0x68; //x86平臺下的PUSH的操作碼
CAPIHook* CAPIHook::sm_pHead=NULL;
const BYTE cPushOpCode = 0x68; //x86平臺下的PUSH的操作碼
CAPIHook* CAPIHook::sm_pHead=NULL;
//構造函數
CAPIHook::CAPIHook()
{
m_hasHook=false;
m_pfnOrig=NULL;
m_pfnHook=NULL;
}
CAPIHook::CAPIHook()
{
m_hasHook=false;
m_pfnOrig=NULL;
m_pfnHook=NULL;
}
//構造函數
CAPIHook::CAPIHook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod)
{
m_hasHook=false;
m_pfnOrig=NULL;
m_pfnHook=NULL;
CAPIHook::CAPIHook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod)
{
m_hasHook=false;
m_pfnOrig=NULL;
m_pfnHook=NULL;
Hook(pszCalleeModName,pszFuncName,pfnHook,fExcludeAPIHookMod);
}
}
//析構函數
CAPIHook::~CAPIHook(void)
{
UnHook();
}
CAPIHook::~CAPIHook(void)
{
UnHook();
}
//返回被hook函數原來的地址
CAPIHook::operator PROC()
{
return(m_pfnOrig);
}
CAPIHook::operator PROC()
{
return(m_pfnOrig);
}
bool CAPIHook::HasHook()
{
return m_hasHook;
}
/// <summary>
/// 掛鉤某個API
/// pszCalleeModName:希望掛鉤的模塊的名字
/// pszFuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void CAPIHook::Hook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod)
{
//如果已經掛鉤,必須先UnHook
if(m_hasHook) UnHook();
{
return m_hasHook;
}
/// <summary>
/// 掛鉤某個API
/// pszCalleeModName:希望掛鉤的模塊的名字
/// pszFuncName:希望掛鉤的模塊中的函數的名字
/// fnHook:掛鉤的函數的新地址
/// fExcludeAPIHookMod:建立掛鉤時是否包括本類所處的模塊 true:不包括 false:包括
/// <summary>
void CAPIHook::Hook(PSTR pszCalleeModName,PSTR pszFuncName, PROC pfnHook,bool fExcludeAPIHookMod)
{
//如果已經掛鉤,必須先UnHook
if(m_hasHook) UnHook();
if (sm_pvMaxAppAddr == 0)
{
//lpMaximumApplicationAddress以上的函數地址需要進行特殊處理(僅對windows98而言)
SYSTEM_INFO si;
GetSystemInfo(&si);
sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
}
{
//lpMaximumApplicationAddress以上的函數地址需要進行特殊處理(僅對windows98而言)
SYSTEM_INFO si;
GetSystemInfo(&si);
sm_pvMaxAppAddr = si.lpMaximumApplicationAddress;
}
//修改 APIHook 對象的鏈表
m_pNext = sm_pHead;
sm_pHead = this;
m_pNext = sm_pHead;
sm_pHead = this;
//保存掛鉤的函數的信息
m_pszCalleeModName = pszCalleeModName;
m_pszFuncName = pszFuncName;
m_pfnHook = pfnHook;
m_fExcludeAPIHookMod = fExcludeAPIHookMod;
m_pfnOrig = GetProcAddre***aw(GetModuleHandleA(m_pszCalleeModName), m_pszFuncName);
m_pszCalleeModName = pszCalleeModName;
m_pszFuncName = pszFuncName;
m_pfnHook = pfnHook;
m_fExcludeAPIHookMod = fExcludeAPIHookMod;
m_pfnOrig = GetProcAddre***aw(GetModuleHandleA(m_pszCalleeModName), m_pszFuncName);
chASSERT(m_pfnOrig != NULL); //模塊中沒有找到對應函數
if (m_pfnOrig > sm_pvMaxAppAddr)
{
// 地址在共享dll中,地址需要修正(僅對windows98而言)
PBYTE pb = (PBYTE) m_pfnOrig;
if (pb[0] == cPushOpCode)
{
// 跳過PUSH操作代碼得到真正的地址
LPVOID pv = * (LPVOID*) &pb[1];
m_pfnOrig = (PROC) pv;
}
}
{
// 地址在共享dll中,地址需要修正(僅對windows98而言)
PBYTE pb = (PBYTE) m_pfnOrig;
if (pb[0] == cPushOpCode)
{
// 跳過PUSH操作代碼得到真正的地址
LPVOID pv = * (LPVOID*) &pb[1];
m_pfnOrig = (PROC) pv;
}
}
// 在當前已經加載的所有模塊中掛鉤函數
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_fExcludeAPIHookMod);
m_hasHook= (m_pfnOrig != NULL);//ok
}
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_fExcludeAPIHookMod);
m_hasHook= (m_pfnOrig != NULL);//ok
}
//撤銷掛鉤
void CAPIHook::UnHook()
{
if(!m_hasHook) return;//沒有hook
void CAPIHook::UnHook()
{
if(!m_hasHook) return;//沒有hook
//停止掛鉤函數,替換爲原來的函數
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_fExcludeAPIHookMod);
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_fExcludeAPIHookMod);
// 將對象從鏈表中移出
CAPIHook* 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;
fFound=TRUE;
break;
}
}
chASSERT(fFound==TRUE);
}
m_hasHook=false;
}
CAPIHook* 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;
fFound=TRUE;
break;
}
}
chASSERT(fFound==TRUE);
}
m_hasHook=false;
}
//替換所有模塊中的函數地址爲新地址
void CAPIHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, bool fExcludeAPIHookMod)
{
HMODULE hmodThisMod = fExcludeAPIHookMod ? ModuleFromAddress(&CAPIHook::ReplaceIATEntryInAllMods) : NULL;
void CAPIHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, bool fExcludeAPIHookMod)
{
HMODULE hmodThisMod = fExcludeAPIHookMod ? ModuleFromAddress(&CAPIHook::ReplaceIATEntryInAllMods) : NULL;
//得到當前進行的模塊列表
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());//打開
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());//打開
MODULEENTRY32 me = { sizeof(me) };
for (BOOL fOk = Module32First(hSnapshot,&me); fOk; fOk = Module32Next(hSnapshot,&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);
}
}
for (BOOL fOk = Module32First(hSnapshot,&me); fOk; fOk = Module32Next(hSnapshot,&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);
}
}
CloseHandle(hSnapshot);//關閉
}
}
//替換某個模塊中的函數地址爲新地址
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
//得到模塊(hmodCaller)引入片斷(import section)的地址
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller, TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
//得到模塊(hmodCaller)引入片斷(import section)的地址
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller, TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
// 模塊(hmodCaller)沒有引入片斷(import section)
if (pImportDesc == NULL) return;
if (pImportDesc == NULL) return;
// 查找模塊(hmodCaller)合適的引入描述符,該描述符描述的是模塊(hmodCaller)使用被調用的模塊(pszCalleeModName)的函數信息
for (; pImportDesc->Name; pImportDesc++)
{
PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
break; // Found
}
for (; pImportDesc->Name; pImportDesc++)
{
PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
break; // Found
}
// 模塊(hmodCaller)中沒有關於被調用的模塊(pszCalleeModName)的函數信息
if (pImportDesc->Name == 0) return;
if (pImportDesc->Name == 0) return;
// 得到調用者hmodCaller 使用被調用的模塊(pszCalleeModName) 的IAT(引入地址表)
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE) hmodCaller + pImportDesc->FirstThunk);
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE) hmodCaller + pImportDesc->FirstThunk);
//替換當前的函數地址爲需要的新地址
for (; pThunk->u1.Function; pThunk++)
{
//得到需要被替換的函數地址
PROC* ppfn = (PROC*) &pThunk->u1.Function;
for (; pThunk->u1.Function; pThunk++)
{
//得到需要被替換的函數地址
PROC* ppfn = (PROC*) &pThunk->u1.Function;
// 這是我們要找的函數嗎?
BOOL fFound = (*ppfn == pfnCurrent);
BOOL fFound = (*ppfn == pfnCurrent);
if (!fFound && (*ppfn > sm_pvMaxAppAddr)) //如果沒有找到,修正
{
//如果我們運行在win98下,地址在共享dll中,這個可能不是函數地址
//這種情況下,指令操作使用的地址應該是正確的地址
PBYTE pbInFunc = (PBYTE) *ppfn;
if (pbInFunc[0] == cPushOpCode)
{
// 我們找到了PUSH操作,真實地址就在後面跟着
ppfn = (PROC*) &pbInFunc[1];
{
//如果我們運行在win98下,地址在共享dll中,這個可能不是函數地址
//這種情況下,指令操作使用的地址應該是正確的地址
PBYTE pbInFunc = (PBYTE) *ppfn;
if (pbInFunc[0] == cPushOpCode)
{
// 我們找到了PUSH操作,真實地址就在後面跟着
ppfn = (PROC*) &pbInFunc[1];
// 這是我們要找的函數嗎?
fFound = (*ppfn == pfnCurrent);
}
}
fFound = (*ppfn == pfnCurrent);
}
}
if (fFound)
{
// 獲得了匹配的地址,我們改寫它(IAT)
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL);
return; // 成功,退出
}
}
{
// 獲得了匹配的地址,我們改寫它(IAT)
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL);
return; // 成功,退出
}
}
// If we get to here, the function is not in the caller's import section
}
}
//調用真實的GetProcAddress獲得函數的原來的真正地址
FARPROC WINAPI CAPIHook::GetProcAddre***aw(HMODULE hmod,LPCSTR pszProcName)
{
return ::GetProcAddress(hmod,pszProcName);
}
FARPROC WINAPI CAPIHook::GetProcAddre***aw(HMODULE hmod,LPCSTR pszProcName)
{
return ::GetProcAddress(hmod,pszProcName);
}
// 得到包含指定內存地址的模塊
HMODULE CAPIHook::ModuleFromAddress(PVOID pv)
{
MEMORY_BASIC_INFORMATION mbi;
return( (VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) ?(HMODULE) mbi.AllocationBase : NULL);
}
HMODULE CAPIHook::ModuleFromAddress(PVOID pv)
{
MEMORY_BASIC_INFORMATION mbi;
return( (VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) ?(HMODULE) mbi.AllocationBase : NULL);
}
//以下fExcludeAPIHookMod must be true,否則下面的新函數(LoadLibraryA 等等)將會死循環。也即本模塊的IAT地址不能替換.
CAPIHook CAPIHook::sm_LoadLibraryA("Kernel32.dll", "LoadLibraryA",(PROC) CAPIHook::LoadLibraryA, true);
CAPIHook CAPIHook::sm_LoadLibraryW("Kernel32.dll", "LoadLibraryW",(PROC) CAPIHook::LoadLibraryW, true);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",(PROC) CAPIHook::LoadLibraryExA, true);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",(PROC) CAPIHook::LoadLibraryExW, true);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",(PROC) CAPIHook::GetProcAddress, true);
CAPIHook CAPIHook::sm_LoadLibraryA("Kernel32.dll", "LoadLibraryA",(PROC) CAPIHook::LoadLibraryA, true);
CAPIHook CAPIHook::sm_LoadLibraryW("Kernel32.dll", "LoadLibraryW",(PROC) CAPIHook::LoadLibraryW, true);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",(PROC) CAPIHook::LoadLibraryExA, true);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",(PROC) CAPIHook::LoadLibraryExW, true);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",(PROC) CAPIHook::GetProcAddress, true);
//新的LoadLibrary的函數
void CAPIHook::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 (CAPIHook* p = sm_pHead; p != NULL; p = p->m_pNext)
{
ReplaceIATEntryInOneMod(p->m_pszCalleeModName,p->m_pfnOrig, p->m_pfnHook, hmod);
}
}
}
void CAPIHook::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 (CAPIHook* p = sm_pHead; p != NULL; p = p->m_pNext)
{
ReplaceIATEntryInOneMod(p->m_pszCalleeModName,p->m_pfnOrig, p->m_pfnHook, hmod);
}
}
}
//新的LoadLibraryA
HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath)
{
HMODULE hmod = ::LoadLibraryA(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}
HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszModulePath)
{
HMODULE hmod = ::LoadLibraryA(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}
//新的LoadLibraryW
HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath)
{
HMODULE hmod = ::LoadLibraryW(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}
HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszModulePath)
{
HMODULE hmod = ::LoadLibraryW(pszModulePath);
FixupNewlyLoadedModule(hmod, 0);
return(hmod);
}
//新的LoadLibraryExA
HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath,HANDLE hFile, DWORD dwFlags)
{
HMODULE hmod = ::LoadLibraryExA(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszModulePath,HANDLE hFile, DWORD dwFlags)
{
HMODULE hmod = ::LoadLibraryExA(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
//新的LoadLibraryExW
HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath,HANDLE hFile, DWORD dwFlags)
{
HMODULE hmod = ::LoadLibraryExW(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszModulePath,HANDLE hFile, DWORD dwFlags)
{
HMODULE hmod = ::LoadLibraryExW(pszModulePath, hFile, dwFlags);
FixupNewlyLoadedModule(hmod, dwFlags);
return(hmod);
}
//新的GetProcAddress
FARPROC WINAPI CAPIHook::GetProcAddress(HMODULE hmod, PCSTR pszProcName)
{
// Get the true address of the function
FARPROC pfn = GetProcAddre***aw(hmod, pszProcName);
FARPROC WINAPI CAPIHook::GetProcAddress(HMODULE hmod, PCSTR pszProcName)
{
// Get the true address of the function
FARPROC pfn = GetProcAddre***aw(hmod, pszProcName);
// Is it one of the functions that we want hooked?
CAPIHook* 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;
}
}
CAPIHook* 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;
}
}
#pragma managed
//MyASSERT.h
#pragma once
#pragma comment(lib, "User32.lib")
#define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0]))
inline void chMB(PCSTR s)
{
char szTMP[128];
::GetModuleFileNameA(NULL, szTMP, chDIMOF(szTMP));
MessageBoxA(GetActiveWindow(), s, szTMP, MB_OK);
}
{
char szTMP[128];
::GetModuleFileNameA(NULL, szTMP, chDIMOF(szTMP));
MessageBoxA(GetActiveWindow(), s, szTMP, MB_OK);
}
inline void chFAIL(PSTR szMsg)
{
chMB(szMsg);
DebugBreak();
}
{
chMB(szMsg);
DebugBreak();
}
// Put up an assertion failure message box.
inline void chASSERTFAIL(LPCSTR file, int line, PCSTR expr)
{
char sz[128];
wsprintfA(sz, "File %s, line %d : %s", file, line, expr);
chFAIL(sz);
}
inline void chASSERTFAIL(LPCSTR file, int line, PCSTR expr)
{
char sz[128];
wsprintfA(sz, "File %s, line %d : %s", file, line, expr);
chFAIL(sz);
}
#ifdef _DEBUG
#define chASSERT(x) if (!(x)) chASSERTFAIL(__FILE__, __LINE__, #x)
#else
#define chASSERT(x)
#endif
#define chASSERT(x) if (!(x)) chASSERTFAIL(__FILE__, __LINE__, #x)
#else
#define chASSERT(x)
#endif