windows下的內聯hook實現
HOOK技術正如其名,就像是程式碼中放下的一個“鉤子”,它在靜靜地等待捕獲系統中的某個訊息或動作。在程式設計技術中,鉤子技術在DOS時代就已經存在了。在windows下,鉤子按照實現技術的不同和掛鉤位置的不同,其種類也是越來越多,但是設定鉤子的本質卻是始終不變的。
那麼鉤子究竟有什麼用?它能幹的事非常多,例如輸入監控、API攔截、訊息捕獲、改變程式執行流程等。防毒軟體會用HOOK技術鉤住一些API函式,比如登錄檔讀寫函式,從而防止病毒對登錄檔的操作;病毒使用HOOK技術有針對性的捕獲鍵盤的輸入,從而記錄使用者的密碼;檔案系統通過HOOK技術在不改變使用者操作的情況下對使用者的檔案進行透明加密。這些都屬於HOOK的技術範疇。
內聯HOOK的原理
API函式都儲存在作業系統提供的DLL檔案中。當在程式中呼叫某個API函式並執行程式後,程式會隱式地將API函式所在的DLL檔案載入入程序中。這樣,程式就可以像呼叫自己的函式一樣呼叫API。大體過程如下圖所示:
CreateProcessW()是API 函式,API函式也是程式設計師的程式碼編譯而成,也有其對應的二進位制程式碼。既然是程式碼,就可以被修改。通過一種強制性的手段修改API函式在記憶體中的映像,從而對API 函式進行hook。使用的方法是,直接使用匯編指令的jmp指令將其的程式碼執行流程改變,進而執行自己的程式碼。執行完自己的程式碼後可以選擇性地執行其它的程式碼。
在Windows下,大部分應用程式都是由Explorer.exe程序來建立的。那麼只要把Explorer.exe中建立程序的函式CreateProcessW() hook住,就可以自主控制是否讓它建立摸個特定程序。執行流程如下:
由於這種方法是直接在程式流程中嵌入jmp指令來改變流程的,所以把它叫做Inline Hook。
在二進位制檔案中,程式碼部分都是CPU可以用來執行的機器碼,機器碼和彙編指令是一一對應的。使用 :jmp 目的地址,該彙編指令的長度為5個位元組。具體可以用OD開啟任意程式,修改某條指令為jmp格式的指令即可看到效果。其中jmp指令後跟著的是從當前地址到目的地址的偏移量。如下圖所示:
準備修改00402390地質處的反彙編程式碼為jmp指令:
修改後的反彙編程式碼:
下一個指令的末尾是95,由此可見該jmp命令的長度是5位元組。
jmp後的偏移量 = 目標地址 – 原地址 – jcc的指令長度。
下圖是,目標地址 – 原地址後的值,由於本次我們使用的jmp指令長度是5,所以在減去5,最後 偏移量 = 11F432E3,正是上面所給出的值(主機使用的是小端位元組序)。
注:
小端位元組序:低位元組存於記憶體低地址;高位元組存於記憶體高地址。
大端位元組序:高位元組存於記憶體低地址;低位元組存於記憶體高地址。
網路位元組序:就是大端位元組序。規定不同系統間通訊一律採用網路位元組序。
總結一下,InlineHook的流程大致如下:
1. 構造跳轉指令
2. 在記憶體中找到要HOOK的函式地址,並儲存要HOOK位置處的前指令長度位元組數內容。
3. 將構造的跳轉指令寫入需要HOOK 的位置處。
4. 當被HOOK位置被執行時會轉到自己的流程中執行。
5. 如果要執行原來的流程,那麼取消HOOK,也就是還原被修改的位元組。
6. 執行原來的流程。
7. 繼續HOOK原來的位置。
下面是一個簡單的例子:
首先,新建一個win32下的DLL工程。在工程中新增一個類,用於操作鉤子。
.h檔案中的主要程式碼如下:
#include<Windows.h>
class CILHOOK
{
public:
CILHOOK(); //構造
~CILHOOK(); //析構
//HOOK函式
BOOL Hook(LPSTR pszModuleName,
LPSTR pszFuncName,
PROC pfnHookFunc);
//取消HOOK函式
VOID UnHook();
//重新進行HOOK
BOOL ReHook();
private:
PROC m_pfnOrig; //函式地址
BYTE m_bOldBytes[5]; //函式入口程式碼
BYTE m_bNewBytes[5]; //Inline程式碼
};
.cpp檔案中的主要程式碼如下:
CILHOOK::CILHOOK()
{
m_pfnOrig = NULL;
ZeroMemory(m_bOldBytes, 5);
ZeroMemory(m_bNewBytes, 5);
}
CILHOOK::~CILHOOK()
{
//取消HOOK
UnHook();
m_pfnOrig = NULL;
ZeroMemory(m_bOldBytes, 5);
ZeroMemory(m_bNewBytes, 5);
}
/*
函式名:Hook
函式功能:對指定模組的函式進行掛鉤
引數說明:
pszModuleName:模組名稱
pszFuncName:函式名稱
pfnHookFunc:鉤子函式
*/
BOOL CILHOOK::Hook(LPSTR pszModuleName,
LPSTR pszFuncName,
PROC pfnHookFunc)
{
BOOL bRet = FALSE;
//獲取指定模組中函式的地址
m_pfnOrig = (PROC)GetProcAddress(GetModuleHandle(pszModuleName), pszFuncName);
if(m_pfnOrig != NULL)
{
DWORD dwNum = 0;
//將原來的資料存起來
ReadProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bOldBytes, 5, &dwNum);
//構造jmp指令
m_bNewBytes[0] = '\xe9'; //jmp Opcode
//pfnHookFunc是HOOK後的目標地址
//m_pfnOrig是原來的地址
//5是指令長度
*(DWORD *)(m_bNewBytes + 1) = (DWORD)pfnHookFunc - (DWORD)m_pfnOrig - 5;
//將構造好的地址寫入該地址處
WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bNewBytes, 5, &dwNum);
bRet = TRUE;
}
return bRet;
}
/*
函式名稱:UnHook
函式功能:取消函式的掛鉤
*/
VOID CILHOOK::UnHook()
{
if(m_pfnOrig != 0)
{
DWORD dwNum = 0;
//將原來的內容寫回hook地址
WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bOldBytes, 5, &dwNum);
}
}
/*
函式名稱:ReHook
函式功能:重新對函式進行掛鉤
*/
BOOL CILHOOK::ReHook()
{
BOOL bRet = FALSE;
if(m_pfnOrig != 0)
{
DWORD dwNum = 0;
//寫入掛鉤地址
WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bNewBytes, 5, &dwNum);
bRet = TRUE;
}
return bRet;
}
DLL中的cpp主要程式碼:
//全域性HOOK物件
CILHOOK CreateProcessHook;
BOOL WINAPI MyCreateProcessW(LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
BOOL bRet = FALSE;
//彈出被建立的程序名
if(MessageBoxW(NULL, lpApplicationName, lpCommandLine, MB_YESNO) == IDYES)
{
//自己呼叫函式前先去掉鉤子,否則會進入死迴圈
CreateProcessHook.UnHook();
bRet = CreateProcessW( lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
CreateProcessHook.ReHook();
}else{
MessageBox(NULL, "您啟動的程式被攔截", "提示", MB_OK);
}
return bRet;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
//HOOK CreateProcessW()函式
CreateProcessHook.Hook("kernel32.dll", "CreateProcessW", (PROC)MyCreateProcessW);
break;
}
case DLL_PROCESS_DETACH:
{
CreateProcessHook.UnHook();
break;
}
}
return TRUE;
}
接下來用我前面文章中用到的DLL注入器進行注入相應的DLL即可。
下面是執行時的介面:
注入explorer.exe程序,然後點選開啟IE,此時會hook到我們指定的函式。選擇是,可以開啟IE;選擇否,將不開啟IE程式。選否時如下圖所示:
相關推薦
windows下的內聯hook實現
HOOK技術正如其名,就像是程式碼中放下的一個“鉤子”,它在靜靜地等待捕獲系統中的某個訊息或動作。在程式設計技術中,鉤子技術在DOS時代就已經存在了。在windows下,鉤子按照實現技術的不同和掛鉤位置的不同,其種類也是越來越多,但是設定鉤子的本質卻是始終不變的。 那麼鉤子
合金彈頭 逆向分析與外掛制作報告【內聯HOOK】
scm 代碼塊 opc 進行 void HR creat 其它 遊戲數據 一、工具及遊戲介紹 使用工具:Ollydbg,PEID,Cheat Engine 實現功能:玩家無敵 目標:找到全局數據,或關鍵代碼塊。 遊戲版本:合金彈頭1-5代珍藏版
android 內聯 hook
bit != fff andro html -a 速度 git 其它 先回顧下 x86 下的內聯 hook.1.原理是找到你要 hook 的地址。2.保存這個地址原來的數據。(這裏要保存至少 5 個字節的數據因為一個 call指令為 5 個字節3.把這個地址修改成 call
windows 下借助7zip實現命令行解壓縮
電腦下載 調用 處理 文件 left 解壓 壓縮 dll 命令行 windows 下借助7zip實現命令行解壓縮 64位電腦下載 https://www.7-zip.org/a/7z1805-x64.exe 安裝 安裝目錄下所有文件如下: 在命令行下只需要用到 7z
VC內聯彙編實現strcpy+彙編效能分析
使用內聯彙編來實現strcpy的兩種思路: static void _strcpy1( char *dst, char *src ){ __asm { push ecx; push eax; push es
windows下vc呼叫openssl實現RSA加密
拿到了linux下c實現的RSA呼叫原始碼,想在windows下程式設計實現相同的結果,查了查資料,在vc6和vs2010除錯通過,在win7 x64和winXP 32 執行結果一致,記錄下來,以備日後查詢。 一、安裝openssl 1、進入Win32 Open
windows下的網路程式設計實現
下面是一個簡單的windows下的服務端和客戶端的實現程式碼需要注意的是 1、此程式設計實現的只是最簡單的網路通訊,不支援多程序和多執行緒的併發(網上找到很多過於多程序和多執行緒併發的伺服器端設計,不過都是在linux下的,在windows下的建立程序和執行緒的函式不熟悉,也沒怎麼看懂,
windows下使用net-snmp實現agent擴充套件(二)
剛剛實現了int型的get命令,可能更多的情況下,我們更需要的是字串型別的。在實現int型的時候,用到了netsnmp_register_int_instance這個函式,很自然想到如果是string型的,用類似的netsnmp_register_string_instanc
windows下使用net-snmp實現agent擴充套件(四)
在前三篇的內容裡,介紹了使用net-snmp實現agent的Get/Set命令,下面介紹一下發送trap訊息。傳送trap訊息時,系統預設的埠是162。使用下面的程式碼,可以實現trap訊息的傳送。 //該函式傳送實時報警資訊。與傳送一般資訊埠不同 void init_al
windows下使用net-snmp實現agent擴充套件(三)
時間隔得太長了,我都快忘了什麼是snmp了,知識啊知識,很容易在不用的時候忘卻,也可能是自己腦袋不好使了吧?翻了翻程式碼,趕緊總結下,不然真不會了…… 在上篇部落格中,實現了get/set一個字串型變數,現在來實現對多個字串變數的get/set。假設要實現獲取CPU利用率、
windows下用Go語言實現第一個hello world
1,下載go編譯器———go編譯器下載地址https://golang.org/dl/ go編譯器下載地址 2,然後點選進行安裝,由於是msi檔案,如果需要.NET元件請自行下載進行安裝
Windows下Nginx負載均衡實現
Nginx+iis站點實現負載均衡方法: 1.官網下載nginx壓縮檔案解壓。我本地解壓路徑D盤 2.配置nginx 開啟nginx.conf檔案 在http模組內新增 upstream 模組,插入 upstream www.g.cn {server
windows下編譯Fast RCNN實現物體識別
參考:http://blog.csdn.net/happynear/article/details/46822109 一、準備 1. caffe-windows:https://github.com
windows下配置mycat,實現mysql資料庫的讀寫分離!
下載Windows的安裝包 配置環境變數: 修改配置檔案 wrapper.conf Server.xml <?xmlversion=
windows下 命令列+winscp 實現與linux的遠端檔案傳輸
安裝WinSCP WinSCP 是一個 Windows 環境下使用的 SSH 的開源圖形化 SFTP 客戶端。同時支援 SCP 協議。它的主要功能是在本地與遠端計算機間安全地複製檔案,並且可以直接編輯檔案。 - 下載:https://winscp.net/e
Windows下多程序的實現案例
最近碰到一個多程序的問題牽涉到了Windows下多程序的操作。經過研究也算是找到了一種解決方案。下面具體介紹一下這個題目中自己的收穫。 背景介紹:程式涉及到Win32與Linux兩個平臺,要求同時啟動多個程序,程序下面啟動 多個執行緒。由於Win
windows下bat批處理實現數據庫備份、壓縮、刪除
rar 備份數據庫 data game -i 批處理 android backup files @echo off rem 刪除7天前的數據庫備份 cd D:\db_bak\qd_web_project\dumpforfiles /m *.sql.gz /d -7 /c
Windows下條件變數的實現
條件變數是什麼? 是一種同步物件。 條件變數有什麼用? 用於複雜的、多執行緒的、多核的程式中,實現多個執行緒
windows下控制臺程序實現窗口顯示
procedure show height ret win32 arr window classname 例程 windows下實現窗口顯示,如果限定是C/C++語言,並且是原生Windows支持,需要使用GDI或GDI+。一般是在Visual Studio裏新建Win32
mysql數據庫在Linux和windows下免安裝實現以及框架開發碰到的問題
自動啟動 過程 root mil 是否 call 啟動頁 同時 ice 2017年7月23號下午5:20分,上周我根據自己的實際情況,總結了mysql數據庫在windows系統下和linux系統下免安裝版本的實現,以及在項目開發中遇到的數據庫報錯,今天整理出來,以供日後學習