APIHOOK例項剖析 (轉)
HOOK例項剖析
關於APIHOOK的基礎知識有很多,如dll的相關知識、Hook的相關知識、程式與執行緒之間的聯絡等。具體可以看我的另兩篇文章:"/develop/article/15/15080.shtm">我的Dll(動態連結庫)學習筆記" 和 "ASP?Id=15121">我的Hook學習筆記"。:)下面進入這篇文章的重點,根據APIHook原始碼進行APIHook的剖析。
一、APIHOOK之dll部分
//////////////////////////////// APIHook_Dll.cpp ////////////////////////////////////////
// rivershan寫於2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "APIHook_Dll.h"
#include
#include
#pragma comment(lib,"ImageHlp") //定義全域性共享資料段
#pragma data_seg("Shared")
HMODULE hmodDll=NULL;
HHOOK hHook=NULL;
#pragma data_seg()
#pragma comment(linker,"/Section:Shared,rws") //設定全域性共享資料段的屬性
///////////////////////////////////// DllMain /////////////////////////////////////////
//dll的入口點
BOOL APIENTRY DllMain( HMODULE hModule,
D ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//if(sHook)
case DLL_PROCESS_DETACH:
UnInstallHook();
break;
}
hmodDll=hModule;
return TRUE;
}
///////////////////////////////////// HookOneAPI 函式 /////////////////////////////////////////
//進行IAT轉換的關鍵函式,其引數含義:
//pszCalleeModuleName:需要hook的模組名
//pfnOriginApiAddress:要替換的自己API函式的地址
//pfnDummyFuncAddress:需要hook的模組名的地址
//hModCallerModule:我們要查詢的模組名稱,如果沒有被賦值,
// 將會被賦值為列舉的所有的模組
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
ULONG size;
//獲取指向PE中的Import中IMAGE_DIRECTORY_DESCRIPTOR陣列的指標
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
if (pImportDesc == NULL)
return;
//查詢記錄,看看有沒有我們想要的DLL
for (;pImportDesc->Name;pImportDesc++)
{
LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);
if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)
break;
}
if (pImportDesc->Name == NULL)
{
return;
}
//尋找我們想要的函式
PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT
for (;pThunk->u1.Function;pThunk++)
{
//ppfn記錄了與IAT表項相應的函式的地址
PROC * ppfn= (PROC *)&pThunk->u1.Function;
if (*ppfn == pfnOriginApiAddress)
{
//如果地址相同,也就是找到了我們想要的函式,進行改寫,將其指向我們所定義的函式
WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),
sizeof(pfnDummyFuncAddress),NULL);
return;
}
}
}
//查詢所掛鉤的程式所應用的dll模組的
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
if (pszCalleeModuleName == NULL)
{
return FALSE;
}
if (pfnOriginApiAddress == NULL)
{
return FALSE;
}
//如果沒傳進來要掛鉤的模組名稱,列舉被掛鉤程式的所有引用的模組,
//並對這些模組進行傳進來的相應函式名稱的查詢
if (hModCallerModule == NULL)
{
MEMORY_BASIC_INFORMATION mInfo;
HMODULE hModHookDLL;
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
//MODULEENTRY32:描述了一個被指定程式所應用的模組的struct
VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));
hModHookDLL=(HMODULE)mInfo.AllocationBase;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
BOOL bOk = Module32First(hSnapshot,&me);
while (bOk)
{
if (me.hModule != hModHookDLL)
{
hModCallerModule = me.hModule;//賦值
//me.hModule:指向當前被掛鉤程式的每一個模組
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}
//如果傳進來了,進行查詢
else
{
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
return TRUE;
}
return FALSE;
}
//////////////////////////////////// UnhookAllAPIHooks 函式 /////////////////////////////////////
//透過使pfnDummyFuncAddress與pfnOriginApiAddress相等的方法,取消對IAT的修改
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
PROC temp;
temp = pfnOriginApiAddress;
pfnOriginApiAddress = pfnDummyFuncAddress;
pfnDummyFuncAddress = temp;
return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
////////////////////////////////// GetMsgProc 函式 ////////////////////////////////////////
//鉤子子程。與其它鉤子子程不大相同,沒做什麼有意義的事情,繼續呼叫下一個鉤子子程,形成迴圈
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
{
return CallNextHookEx(hHook,code,wParam,lParam);
}
//////////////////////////////////// InstallHook 函式 /////////////////////////////////////
//或解除安裝鉤子,BOOL IsHook引數是標誌位
//對要鉤哪個API函式進行初始化
//我們這裡裝的鉤子型別是WH_GETMESSAGE
void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)
{
if(IsHook)
{
hHook=SetHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);
//GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA"):取得要鉤的函式在所在dll中的地址
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutW"),(PROC)&H_TextOutW,NULL);
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
else
{
UnInstallHook();
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutW"),(PROC)&H_TextOutW,NULL);
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
}
///////////////////////////////////// UnInstallHook 函式 ////////////////////////////////////
//解除安裝鉤子
BOOL WINAPI UnInstallHook()
{
UnhookWindowsHookEx(hHook);
return TRUE;
}
///////////////////////////////////// H_TextOutA 函式 /////////////////////////////////////////
//我們的替換函式,可以在裡面實現我們所要做的功能
//這裡我做的是顯示一個對話方塊,指明是替換了哪個函式
BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)
{
MessageBox(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);
TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原來的函式,以顯示字元
return TRUE;
}
///////////////////////////////////// H_TextOutW 函式 /////////////////////////////////////////
//同上
BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)
{
MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);
TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原來的函式,以顯示字元
return TRUE;
}
**********************************************************************************************
**********************************************************************************************
//////////////////////////////// APIHook_Dll.h ////////////////////////////////////////
// rivershan寫於2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
//dll標頭檔案,用於宣告函式
void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD);
BOOL WINAPI UnInstallHook();
LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam);
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int);
BOOL WINAPI H_TextOutW(HDC, int, int, LPCWSTR, int);
BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *);
BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *);
**********************************************************************************************
**********************************************************************************************
;APIHook_Dll之def檔案
LIBRARY APIHook_Dll.dll
EXPORT
InstallHook
二、APIHOOK之exe部分
//////////////////////////// APIHook_EXEDlg.cpp /////////////////////////////////////////
// rivershan寫於2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "APIHook_EXE.h"
#include "APIHook_EXEDlg.h"
#include "APIHook_Dll.h"
#ifdef _DE
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAPIHook_EXEDlg dialog
CAPIHook_EXEDlg::CAPIHook_EXEDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAPIHook_EXEDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CAPIHook_EXEDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAPIHook_EXEDlg::DoData(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAPIHook_EXEDlg)
// DDX_Control(pDX, IDC_EDIT1, m_Edit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAPIHook_EXEDlg, CDialog)
//{{AFX_MSG_MAP(CAPIHook_EXEDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)
ON_BN_CLICKED(IDC_BUTTON_BEGIN, OnButtonBegin)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAPIHook_EXEDlg message handlers
BOOL CAPIHook_EXEDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CAPIHook_EXEDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAPIHook_EXEDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
///////////////////////////////////// OnButtonOut 函式 //////////////////////////////////////
//使用TextOut函式
void CAPIHook_EXEDlg::OnButtonOut()
{
// TODO: Add your control notification handler code here
HDC hdc = ::GetDC(GetSafeHwnd());
::TextOutA(hdc,0,0,"APIHOOK_EXE ---rivershan",30);
UpdateWindow();
}
///////////////////////////////////// OnButtonBegin 函式 ////////////////////////////////////
//開始掛鉤,這裡我們掛的是自身這個APIHook_EXE這個程式
void CAPIHook_EXEDlg::OnButtonBegin()
{
DWORD dwThreadId = GetWindowThreadProcessId(m_hWnd,NULL);//獲得自身程式ID
InstallHook(TRUE,dwThreadId);
}
///////////////////////////////////// OnButtonStop 函式 ////////////////////////////////////
//取消掛鉤
void CAPIHook_EXEDlg::OnButtonStop()
{
InstallHook(FALSE,0);
}
三、APIHOOK之整合
1. 用 VC++新建一個 Win32 Dynamic-Link Library 程式,命名為 APIHook_Dll。接下來選擇第二項 A Simple DLL Project;
2. 新建一標頭檔案,命名為 APIHook_Dll.h。刪除工程中 APIHook_Dll.cpp檔案中原來的內容,然後把上面的 APIHook_Dll.cpp 和 APIHook_Dll.h檔案的內容全部複製到新建的這個工程的 .cpp及 .h檔案中來;
3. 新建一 Text檔案,命名為 APIHook_Dll.def。複製上面的def檔案內容。
4. 編譯;
5. 新建一 MFC APPWizard(exe)程式,命名為 APIHook_EXE。接著選擇第三項,基於對話方塊的程式,其它預設;
6. 刪除原來對話方塊上的,然後新建三個按鈕ID分別為:IDC_BUTTON_BEGIN、IDC_BUTTON_STOP、IDC_BUTTON_OUT,Caption分別為:Bigin Hook、Stop Hook、Text Out。不要讓這三個按鈕出於對話方塊客戶區的最上面就行;
7. 複製 APIHook_Dll.h檔案到 APIHook_EXE程式目錄下,然後加到 APIHook_EXE的標頭檔案夾中。
8. 刪除工程中 APIHook_EXEDlg.cpp檔案中原來的內容,然後把上面的 APIHook_EXEDlg.cpp檔案的內容全部複製到新建的這個工程的 .cpp檔案中來;
9. 開啟 Project->Setting選單,選擇第四項link,在 /library moduls裡新增我們的dll的lib檔案的路徑:..APIHook_DllDebugAPIHook_Dll.lib;
10. 編譯;
11. 把 APIHook_Dll.dll檔案放在 APIHook_Dll.exe程式的同一個資料夾內;
12. 執行程式,點選 Bigin Hook按鈕,開始掛鉤。再點選 Text Out按鈕會跳出對話方塊並且會在程式中顯示所要顯示的字。點選 Stop Hook然後在點選 Text Out按鈕就沒有對話方塊出現了。
四、一些說明
1、我這個 HookAPI是使用了 Jeffrey Richter的改寫程式的 IAT來實現的,也可以用跳轉函式入口點的方法來實現,這個我沒做研究。:)
2、我的一些心得:
所謂 HookAPI,就是改寫程式的 IAT,再呼叫我自己寫的用於替換原API函式的函式。在我們自己寫的API函式中,我們可以進行我們想要的工作。之後呢,可以把原來的函式傳回去,也可以不傳回去,只要你設計好了就行。
而所謂呼叫自己的函式,就是把原函式引數都傳給我的替換函式。我們就可以利用這些引數去幹我們想做的事。而系統呢,我想由於設定的這個鉤子的目的(我這麼認為的),所以不會去檢查替換函式是否就是原函式,只要引數、返回值符合條件就行,要不會出錯。替換函式的返回值最好是原函式,否則有可能會出錯
HookAPI時,exe程式起到的作用就是進行Hook,把dll注入到要Hook的程式,並且傳回要掛接的程式的ID或者全域性鉤子,以便查詢所要掛接的模組的IAT。如果不注入進去,系統不會讓你去查詢IAT的。DLL做的事情是確定要掛接哪個函式和這個函式在哪個DLL中等。
rivershan 原創於 2002-9-23
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991967/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- servlet檔案下載例項剖析Servlet
- 資料庫設計三大正規化應用例項剖析(轉)資料庫
- 演示中斷處理的例項(例項六)(轉)
- 深入剖析Vue原始碼 - 例項掛載,編譯流程Vue原始碼編譯
- oracle單例項轉RACOracle單例
- (轉)MySQL優化例項MySql優化
- 網站綜合例項(轉)網站
- [轉]BDB例項程式碼
- 網站綜合例項 (轉)網站
- AsmL例項研究(二) (轉)ASM
- 如何將獨立例項轉換成叢集例項EU
- (轉)Python例項手冊Python
- 最新SS園設計模式例項剖析與深入解讀教程設計模式
- 資料庫設計三大正規化應用例項剖析資料庫
- CSS 例項之翻轉圖片CSS
- BIND 9快速安裝例項(轉)
- 基本複製應用例項(轉)
- XML程式設計例項(二) (轉)XML程式設計
- 研發專案流程例項(轉)
- PAM認證模組使用例項(轉)
- ssh埠轉發的深入例項
- ACCESS開發例項完全剖析(奮鬥的小鳥)_PDF 電子書
- [轉載] Python 機器學習經典例項Python機器學習
- js網址跳轉例項程式碼JS
- Linux的nat埠轉換例項Linux
- (轉)例項分析:MySQL優化經驗MySql優化
- Python的時間轉換 【例項】Python
- [轉]使用 db2icrt 建立例項DB2
- CBuilder中使用管道技術例項 (轉)UI
- (譯)win32asm例項-1 (轉)Win32ASM
- (譯)win32asm例項-3 (轉)Win32ASM
- 限制程式執行例項數 (轉)
- JAVA例項 陰陽曆演算法(轉)Java演算法
- VMWARE的一些操作例項(轉)
- 區域網實現VLAN例項(轉)
- Bash 例項:探討 ebuild 系統(轉)UI
- Delphi Open Tools Api例項研究(一) (轉)API
- ASP 中 Split 函式的例項 (轉)函式