標籤:
參考 http://9200cs.blog.163.com/blog/static/134577369201041111656659/
環境:VS2008
一、建立一個dll程式add,程式非常簡單,其功能就是實現簡單的a+b。
1、建立一個項目名為add
選擇dll
然後開啟dllmain.cpp,代碼:
// dllmain.cpp : 定義 DLL 應用程式的進入點。#include "stdafx.h"int WINAPI add(int a, int b){ return a + b;}BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ return TRUE;}
右鍵項目添加一個建立項名為add.def的檔案
開啟編寫代碼:
LIBRARY AddDESCRIPTION "ADD LA"EXPORTS add @1;
編譯後我們就能在Debug目錄下擷取add.dll了。
二、編寫主程式,建立一個基於對話方塊的MFC應用程式One
在嚮導中選擇基於對話方塊
雙擊確定進入,代碼為
HINSTANCE hAddDll = NULL;void COneDlg::OnBnClickedOk(){ typedef int (WINAPI*AddProc)(int a, int b);//函數原型定義 AddProc add; if (hAddDll == NULL) { hAddDll = ::LoadLibrary(_T("add.dll"));//載入dll } add = (AddProc)::GetProcAddress(hAddDll, "add");//擷取函數add地址 int a = 1; int b = 2; int c = add(a, b); CString tem; tem.Format(_T("%d+%d=%d"), a, b, c); AfxMessageBox(tem);}
編譯一下再將之前擷取到的add.dll拷貝到項目One下有exe檔案的Debug目錄下
運行結果出現
就說明我們的One已經成功調用了add.dll裡的add()方法了。
三、至此,我們的小程式已經完成了,接下來該到我們的主角HOOK登場了!
建立一個MFC DLL項目
Hook.cpp裡的代碼
// Hook.cpp : Defines the initialization routines for the DLL.#include "stdafx.h"#include "Hook.h"#ifdef _DEBUG#define new DEBUG_NEW#endif//變數定義 #pragma data_seg("SHARED") //不同Instance共用的該變數 static HHOOK hhk = NULL; //滑鼠鉤子控制代碼 static HINSTANCE hinst = NULL; //本dll的執行個體控制代碼 (hook.dll) #pragma data_seg() #pragma comment(linker, "/section:SHARED,rws") //以上的變數為共用 CString temp; //用於顯示錯誤的臨時變數 bool bHook = false; //是否Hook了函數 bool m_bInjected = false; //是否對API進行了Hook BYTE OldCode[5]; //原程式API入口代碼 BYTE NewCode[5]; //新跳轉的API代碼 (jmp xxxx) typedef int (WINAPI*AddProc)(int a, int b);//add.dll中的add函數定義 AddProc add; //add.dll中的add函數 HANDLE hProcess = NULL; //所處進程的控制代碼 FARPROC pfadd; //指向add函數的遠指標 DWORD dwPid; //所處進程ID //end of 變數定義 // CHookAppBEGIN_MESSAGE_MAP(CHookApp, CWinApp)END_MESSAGE_MAP()//滑鼠鉤子過程,什麼事情也不做,目的是注入dll到程式中 LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam){ return CallNextHookEx(hhk, nCode, wParam, lParam);}//開啟鉤子的函數 void HookOn(){ ASSERT(hProcess != NULL); DWORD dwTemp = 0; DWORD dwOldProtect; //將記憶體保護模式改為可寫,老模式儲存入dwOldProtect VirtualProtectEx(hProcess, pfadd, 5, PAGE_READWRITE, &dwOldProtect); //將所屬進程中add()的前5個位元組改為Jmp Myadd WriteProcessMemory(hProcess, pfadd, NewCode, 5, 0); //將記憶體保護模式改回為dwOldProtect VirtualProtectEx(hProcess, pfadd, 5, dwOldProtect, &dwTemp); bHook = true;}//關閉鉤子的函數 void HookOff()//將所屬進程中add()的入口代碼恢複 { ASSERT(hProcess != NULL); DWORD dwTemp = 0; DWORD dwOldProtect; VirtualProtectEx(hProcess, pfadd, 5, PAGE_READWRITE, &dwOldProtect); WriteProcessMemory(hProcess, pfadd, OldCode, 5, 0); VirtualProtectEx(hProcess, pfadd, 5, dwOldProtect, &dwTemp); bHook = false;}//然後,寫我們自己的Myadd()函數 int WINAPI Myadd(int a, int b){ //截獲了對add()的調用,我們給a,b都加上一定的數 a = a + 1; b = b + 1; HookOff();//關掉Myadd()鉤子防止死迴圈 int ret; ret = add(a, b); HookOn();//開啟Myadd()鉤子 return ret;}//好,最重要的HOOK函數: void Inject(){ if (m_bInjected == false) { //保證只調用1次 m_bInjected = true; //擷取add.dll中的add()函數 HMODULE hmod = ::LoadLibrary(_T("add.dll")); add = (AddProc)::GetProcAddress(hmod, "add"); pfadd = (FARPROC)add; if (pfadd == NULL) { AfxMessageBox(L"cannot locate add()"); } // 將add()中的入口代碼儲存入OldCode[] _asm { lea edi, OldCode mov esi, pfadd cld movsd movsb } NewCode[0] = 0xe9;//實際上0xe9就相當於jmp指令 //擷取Myadd()的相對位址 _asm { lea eax, Myadd mov ebx, pfadd sub eax, ebx sub eax, 5 mov dword ptr[NewCode + 1], eax } //填充完畢,現在NewCode[]裡的指令相當於Jmp Myadd HookOn(); //可以開啟鉤子了 }}CHookApp::CHookApp(){}CHookApp theapp;//滑鼠鉤子安裝函數: BOOL InstallHook(){ hhk = ::SetWindowsHookEx(WH_MOUSE, MouseProc, hinst, 0); return true;}//卸載滑鼠鉤子函數 void UninstallHook(){ ::UnhookWindowsHookEx(hhk);}//在dll執行個體化中獲得一些參數 BOOL CHookApp::InitInstance(){ CWinApp::InitInstance(); //獲得dll 執行個體,進程控制代碼 hinst = ::AfxGetInstanceHandle(); DWORD dwPid = ::GetCurrentProcessId(); hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid); //調用注射函數 Inject(); return TRUE;}
接著別忘了Hook.def下的配置
LIBRARY "Hook"DESCRIPTION ‘Hook Windows Dynamic Link Library‘EXPORTS ; Explicit exports can go here InstallHook MouseProc Myadd UninstallHook
編譯一下,再將之前獲得的add.dll丟一份到Hook的Debug目錄下
這樣,我們的Hook完成了
四、接下來我們就可以修改前面的One的測試程式了
添加一個按鈕,雙擊進入相應事件 代碼:
HINSTANCE hinst;void COneDlg::OnBnClickedButton1(){ hinst=LoadLibrary(_T("hook.dll")); if(hinst==NULL) { AfxMessageBox(_T("no hook.dll!")); return; } typedef BOOL (CALLBACK *inshook)(); inshook insthook; insthook=::GetProcAddress(hinst,"InstallHook"); if(insthook==NULL) { AfxMessageBox(_T("func not found!")); return; } DWORD pid=::GetCurrentProcessId(); BOOL ret=insthook();}
別忘了退出時卸掉鉤子
再加個按鈕
void COneDlg::OnBnClickedButton2(){ // TODO: 在此添加控制項通知處理常式代碼s typedef BOOL (CALLBACK *UnhookProc)(); UnhookProc UninstallHook; UninstallHook=::GetProcAddress(hinst,"UninstallHook"); if(UninstallHook==NULL) UninstallHook(); if (hinst!=NULL) { ::FreeLibrary(hinst); } if (hAddDll!=NULL) { ::FreeLibrary(hAddDll); } CDialog::OnCancel();}
再將Hook目錄下的Hook.dll也丟到One的Debug目錄下
至此,整個HOOK的例子就結束了。
最後的效果:正常為1+2=3,點擊button1後再點擊確定,就變成1+1=5了
最後需要注意的是項目裡面有2個Debug目錄,要放在這個
裡面有
不要 放錯了哦,這個Debug目錄是需要編譯過後才產生的~~!
C HOOK學習筆記