HOOK API(四)
—— 進程防終止
這算是一個實戰吧,做的一個應用需要實現進程的防終止保護,查了相關資料後決定用HOOK API的方式實現。起初學習HOOK API的起因是因為要實現對剪切板的監控,後來面對進程保護這樣一個需求時,綜合各方資料並自己動手實現HOOK OpenProcess() 和 TerminateProcess() 來從調用層實現進程的防終止。下面將進一步介紹實現的過程,也算是對學習的一個總結與實戰。
主要參考:http://www.cnblogs.com/delphi7456/archive/2010/10/31/1865729.html
大體的HOOK API的實現思路在前面幾篇相關文章中已經講過。大致可分為以下步驟:1.確定要HOOK的API原型,並參照原型定義自己的API。2.在DLL中實現自己的API,並使用新的API入口地址替換原API地址實現HOOK,利用jmp xxxx 指令實現重定向。其中可以利用GetProcAddress()獲取系統的API地址,通過WriteProcessMemory將自己寫的API地址替換掉原API地址。3.利用鼠標鉤子將自己的DLL注入到目標進程中。
我們這裡要實現進程的防終止,設計到的API有兩個,分別是OpenProcess() 和 TerminateProcess(),這兩個API在Kernel32.dll中。如果只HOOK 其中一個API是不可行的,若只HOOK OpenProcess(),那麼任務管理器將無法獲取到受保護進程的信息,進而會出錯。若只HOOK TerminateProcess也是不可行的,因為一個進程的句柄在本進程與其他進程中是不一樣的,因此若是你不知道自己進程在其他進程中的句柄那將無法HOOK TerminateProcess。
本事例采用的方案是,同時HOOK OpenProcess()和TerminateProcess(),在OpenProcess中獲取自己的受保護進程在其他進程中的調用句柄,然後再TerminateProcess進程監控,如果發現有進程調用TerminateProcess並且所借宿的對象是自己要保護的進程,那麼就給出禁止關閉的提示窗口。
OpenProcess()是打開進程,而TerminateProcess()是結束進程,在調用TerminateProcess()結束進程時,必然會先調用OpenProcess()進程打開進程句柄。以下是這兩個API的原型:
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的訪問權限(標志)
BOOL bInheritHandle, // 是否繼承句柄
DWORD dwProcessId // 進程標示符
);
BOOL TerminateProcess(
HANDLE hProcess, //進程句柄
UINT uExitCode //進程終止碼
);
// MonitorDll.h : MonitorDll DLL 的主頭文件
//
#pragma once
#ifndef __AFXWIN_H__
#error "在包含此文件之前包含"stdafx.h"以生成 PCH 文件"
#endif
#include "resource.h" // 主符號
// CMonitorDllApp
// 有關此類實現的信息,請參閱 MonitorDll.cpp
//
class CMonitorDllApp : public CWinApp
{
public:
CMonitorDllApp();
// 重寫
public:
virtual BOOL InitInstance();
int ExitInstance();
DECLARE_MESSAGE_MAP()
};
// MonitorDll.cpp : 定義 DLL 的初始化例程。
//
#include "stdafx.h"
#include "MonitorDll.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/*
全局變量
*/
// 共享變量
#pragma data_seg("Share")
HWND g_hwnd = NULL; // 主窗口句柄,加載HOOK時傳入
HINSTANCE hInstance = NULL; // 本DLL的實例句柄
HHOOK hhook = NULL; // 鼠標鉤子句柄
DWORD g_dwProcessId; // 進程id
HANDLE g_hProcess = NULL; // 保存本進程在遠進程中的句柄
#pragma data_seg()
#pragma comment(linker,"/section:Share,rws")
// 其他變量定義
HANDLE hProcess = NULL; // 當前進程句柄
bool bIsInjected = false; // 保證只注入一次
#define CODE_LENGTH 5 // 入口指令長度
// TerminateProcess
typedef BOOL (WINAPI *TypeTerminateProcess)(_In_ HANDLE hProcess, _In_ UINT uExitCode); //Kernel32.dll
TypeTerminateProcess oldTerminateProcess = NULL;
FARPROC pfOldTerminateProcess = NULL;
BOOL WINAPI MyTerminateProcess(_In_ HANDLE hProcess, _In_ UINT uExitCode);
BYTE oldCodeTermPro[CODE_LENGTH]; // 原API入口
BYTE newCodeTermpro[CODE_LENGTH]; // 新API入口
// OpenProcess
typedef HANDLE(WINAPI *TypeOpenProcess)( _In_ DWORD dwDesiredAccess,_In_ BOOL bInheritHandle,_In_ DWORD dwProcessId);
TypeOpenProcess oldOpenProcess = NULL;
FARPROC pfOldOpenProcess = NULL;
HANDLE WINAPI MyOpenProcess(_In_ DWORD dwDesiredAccess,_In_ BOOL bInheritHandle,_In_ DWORD dwProcessId);
BYTE oldCodeOpenPro[CODE_LENGTH];
BYTE newCodeOpenPro[CODE_LENGTH];
BOOL WINAPI HookLoad(HWND hwnd,DWORD dwProcessId); // 關於dll hook 操作
VOID WINAPI HookUnload();
VOID Inject();
VOID HookOn();
VOID HookOff();
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
) ;
LRESULT CALLBACK MouseProc( // 鼠標鉤子子過程調用
int nCode, // hook code
WPARAM wParam,// message identifier
LPARAM lParam // mouse coordinates
);
BOOL WriteMemory(LPVOID lpAddress,BYTE* pcode,size_t length); //將長度為 length 的 pcode 寫入地址 lpAddress 的進程內存中
//
//TODO: 如果此 DLL 相對於 MFC DLL 是動態鏈接的,
// 則從此 DLL 導出的任何調入
// MFC 的函數必須將 AFX_MANAGE_STATE 宏添加到
// 該函數的最前面。
//
// 例如:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // 此處為普通函數體
// }
//
// 此宏先於任何 MFC 調用
// 出現在每個函數中十分重要。這意味著
// 它必須作為函數中的第一個語句
// 出現,甚至先於所有對象變量聲明,
// 這是因為它們的構造函數可能生成 MFC
// DLL 調用。
//
// 有關其他詳細信息,
// 請參閱 MFC 技術說明 33 和 58。
//
// CMonitorDllApp
BEGIN_MESSAGE_MAP(CMonitorDllApp, CWinApp)
END_MESSAGE_MAP()
// CMonitorDllApp 構造
CMonitorDllApp::CMonitorDllApp()
{
// TODO: 在此處添加構造代碼,
// 將所有重要的初始化放置在 InitInstance 中
}
// 唯一的一個 CMonitorDllApp 對象
CMonitorDllApp theApp;
// CMonitorDllApp 初始化
BOOL CMonitorDllApp::InitInstance()
{
CWinApp::InitInstance();
hInstance = AfxGetInstanceHandle(); // 獲取本dll句柄
/*
先提高權限,再獲取進程句柄。
因為只有權限足夠,才能獲取到當前進程的句柄。
*/
HANDLE hToken;
BOOL bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken);
if (bRet == FALSE)
{
AfxMessageBox(_T("權限提升失敗"));
}
SetPrivilege(hToken,SE_DEBUG_NAME,TRUE);
DWORD dwPid = ::GetCurrentProcessId();
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
if (hProcess == NULL)
{
CString str;
str.Format(_T("OpenProcess fail!!, error code = [%d]"),GetLastError());
AfxMessageBox(str);
return FALSE;
}
Inject(); // 開始注入
return TRUE;
}
//
// 實例退出函數。退出時,一定要記得恢復原函數地址!!!
//
int CMonitorDllApp::ExitInstance()
{
HookOff(); //要記得恢復原函數地址
return CWinApp::ExitInstance();
}
/*
鼠標鉤子子過程,目的是加載本dll到使用鼠標的程序.
鼠標鉤子的作用:當鼠標在某程序窗口中時,就會加載我們這個dll。
即使本DLL隨著鼠標鉤子注入到目標進程中。
*/
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
return CallNextHookEx(hhook,nCode,wParam,lParam);
}
/*
安裝鉤子。
主調程序傳入窗口句柄和進程id。
*/
BOOL WINAPI HookLoad(HWND hwnd,DWORD dwProcessId)
{
BOOL ret = FALSE;
g_hwnd = hwnd;
g_dwProcessId = dwProcessId;
hhook = ::SetWindowsHookEx(WH_MOUSE,MouseProc,hInstance,0);
if (hhook == NULL)
{
return FALSE;
}
else
{
return TRUE;
}
}
/*
卸載鉤子。
注:卸載鉤子之前,一定要記得恢復原函數地址!!!
*/
VOID WINAPI HookUnload()
{
HookOff(); // 恢復原函數地址
if (hhook != NULL)
{
UnhookWindowsHookEx(hhook);
}
if (hInstance != NULL)
{
FreeLibrary(hInstance);
}
}
/*
注入函數。
主要完成原函數地址的保存,保存到 oldCode_[]中;
新入口地址的計算,保存到newCode_[]中,即 jmp xxxx 指令。
新入口地址 = 新函數地址 - 原函數地址 - 指令長度
最後一定要記得HookOn!!
*/
VOID Inject()
{
if (bIsInjected == TRUE)
{
return;
}
bIsInjected = TRUE;// 保證只注入一次
// TerminateProcess
HMODULE hmodleKernel32;
hmodleKernel32 = ::LoadLibrary(_T("Kernel32.dll"));
if (NULL == hmodleKernel32)
{
AfxMessageBox(_T("加載Kernel32.dll失敗"));
return;
}
// 獲取原函數地址
oldTerminateProcess = (TypeTerminateProcess)GetProcAddress(hmodleKernel32,"TerminateProcess");
if (NULL == oldTerminateProcess)
{
AfxMessageBox(_T("獲取TerminateProcess函數失敗"));
return;
}
pfOldTerminateProcess = (FARPROC)oldTerminateProcess;
// 保存原函數入口
_asm
{
lea edi,oldCodeTermPro
mov esi,pfOldTerminateProcess
cld
mov ecx,CODE_LENGTH
rep movsb
}
// 替換新函數入口
newCodeTermpro[0] = 0xe9;
_asm
{
lea eax,MyTerminateProcess
mov ebx,pfOldTerminateProcess
sub eax,ebx
sub eax,CODE_LENGTH
mov dword ptr [newCodeTermpro+1],eax
}
// OpenProcess
oldOpenProcess = (TypeOpenProcess)GetProcAddress(hmodleKernel32,"OpenProcess");
if (NULL == oldOpenProcess)
{
AfxMessageBox(_T("獲取OpenProcess地址失敗"));
return;
}
pfOldOpenProcess = (FARPROC)oldOpenProcess;
_asm
{
lea edi,oldCodeOpenPro
mov esi,pfOldOpenProcess
cld
mov ecx,CODE_LENGTH
rep movsb
}
newCodeOpenPro[0] = 0xe9;
_asm
{
lea eax,MyOpenProcess
mov ebx,pfOldOpenProcess
sub eax,ebx
sub eax,CODE_LENGTH
mov dword ptr [newCodeOpenPro+1],eax
}
HookOn(); //填充完畢,開始HOOK
}
/*
將長度為 length 的 pcode 寫入地址 lpAddress 的進程內存中
*/
BOOL WriteMemory(LPVOID lpAddress,BYTE* pcode,size_t length)
{
ASSERT(hProcess != NULL);
DWORD dwtemp,dwOldProtect,dwRet,dwWrited;
dwRet = VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);
CString logInfo;
if ( 0 == dwRet)
{
logInfo.Format(_T("WriteMemory :: Call VirtualProtectEx fail, eror code = [%d]\n\n"),GetLastError());
AfxMessageBox(logInfo);
return FALSE;
}
dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);
if ( 0 == dwRet || 0 == dwWrited)
{
logInfo.Format(_T("WriteMemory :: Call WriteProcessMomory fail, error code = [%d]\n\n"),GetLastError());
AfxMessageBox(logInfo);
return FALSE;
}
dwRet = VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwtemp);
if ( 0 == dwRet )
{
logInfo.Format(_T("WriteMemory :: Recover Protect fail, error code = [%d]\n\n"),GetLastError());
AfxMessageBox(logInfo);
return FALSE;
}
return TRUE;
}
/*
開始HOOK。
即,將Inject 初始化好的入口地址進行寫入進程內存中。
這裡,將新函數入口 newCode_[],寫入內存中。
這樣一來,在原函數被調用的時候,就會跳轉到我們新函數的位置。
注: 這裡處理的函數,是當前需要替換的所有函數,所以只在Inject()函數中調用,
即進行初始化的時候用到該函數。
*/
VOID HookOn()
{
BOOL ret;
ret = WriteMemory(pfOldTerminateProcess,newCodeTermpro,CODE_LENGTH);
if (FALSE == ret)
{
AfxMessageBox(_T("HookOn :: Fail to write pfOldTerminateProcess"));
}
ret = WriteMemory(pfOldOpenProcess,newCodeOpenPro,CODE_LENGTH);
if (FALSE == ret)
{
AfxMessageBox(_T("HookOn :: Fail to write pfOldOpenProcess"));
}
}
/*
停止HOOK。
恢復原函數地址。
注:這裡處理的是所有替換的函數,所以一般情況下只有在卸載HOOK函數中調用
*/
VOID HookOff()
{
ASSERT(hProcess != NULL);
BOOL ret;
ret = WriteMemory(pfOldTerminateProcess,oldCodeTermPro,CODE_LENGTH);
if (FALSE == ret)
{
AfxMessageBox(_T("HookOff :: fail to recover pfOldTerminateProcess \n\n"));
}
ret = WriteMemory(pfOldOpenProcess,oldCodeOpenPro,CODE_LENGTH);
if (FALSE == ret)
{
AfxMessageBox(_T("HookOff :: fail to recover pfOldOpenProcess"));
}
}
/*
提升進程權限。
*/
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
CString info;
if ( !LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
info.Format(_T("LookupPrivilegeValue error: %u\n"), GetLastError() );
AfxMessageBox(info);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if ( !AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
info.Format(_T("AdjustTokenPrivileges error: %u\n"), GetLastError() );
AfxMessageBox(info);
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
info.Format(_T("The token does not have the specified privilege. \n"));
AfxMessageBox(info);
return FALSE;
}
return TRUE;
}
//
// 自己重新定義的進程終止函數。
// 檢查當前要終止的進程是否是受保護進程,若是則禁止關閉。
//
BOOL WINAPI MyTerminateProcess(_In_ HANDLE hProcess, _In_ UINT uExitCode)
{
BOOL ret;
if (g_hProcess == hProcess)
{
AfxMessageBox(_T("不能關閉受保護進程哦!!"));
ret = TRUE;
}
else
{
WriteMemory(pfOldTerminateProcess,oldCodeTermPro,CODE_LENGTH);
ret = oldTerminateProcess(hProcess,uExitCode);
WriteMemory(pfOldTerminateProcess,newCodeTermpro,CODE_LENGTH);
}
return ret;
}
//
// 自己定義的打開進程函數。
// 若當前打開進程為受保護進程,則記錄下該遠程調用句柄。
//
HANDLE WINAPI MyOpenProcess(_In_ DWORD dwDesiredAccess,_In_ BOOL bInheritHandle,_In_ DWORD dwProcessId)
{
HANDLE hProcess = NULL;
WriteMemory(pfOldOpenProcess,oldCodeOpenPro,CODE_LENGTH);
hProcess = oldOpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId);
if ( dwProcessId == g_dwProcessId)
{
g_hProcess = hProcess;
}
WriteMemory(pfOldOpenProcess,newCodeOpenPro,CODE_LENGTH);
return hProcess;
}
MonitorDll中的MonitorDll.def
; MonitorDll.def : 聲明 DLL 的模塊參數。
LIBRARY
EXPORTS
; 此處可以是顯式導出
HookLoad
HookUnload
// MyWindowDlg.h : 頭文件
//
#pragma once
// CMyWindowDlg 對話框
class CMyWindowDlg : public CDialogEx
{
// 構造
public:
CMyWindowDlg(CWnd* pParent = NULL); // 標准構造函數
// 對話框數據
enum { IDD = IDD_MYWINDOW_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
HICON m_hIcon;
HINSTANCE m_hinstHookDll; // MonitorDll的實例句柄
void HookLoad(); // 加載HOOK
void HookUnload(); // 卸載HOOK
// 生成的消息映射函數
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnClose(); // 關閉程序的時候卸載DLL !!!!!
DECLARE_MESSAGE_MAP()
};
// MyWindowDlg.cpp : 實現文件
//
#include "stdafx.h"
#include "MyWindow.h"
#include "MyWindowDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用於應用程序"關於"菜單項的 CAboutDlg 對話框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話框數據
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CMyWindowDlg 對話框
CMyWindowDlg::CMyWindowDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMyWindowDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMyWindowDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMyWindowDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()
// CMyWindowDlg 消息處理程序
BOOL CMyWindowDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將"關於..."菜單項添加到系統菜單中。
// IDM_ABOUTBOX 必須在系統命令范圍內。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設置大圖標
SetIcon(m_hIcon, FALSE); // 設置小圖標
// TODO: 在此添加額外的初始化代碼
HookLoad(); // 加載HOOK
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
void CMyWindowDlg::OnClose()
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
HookUnload(); // 退出窗口,要卸載HOOK
CDialogEx::OnClose();
}
void CMyWindowDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪制該圖標。對於使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。
void CMyWindowDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用於繪制的設備上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使圖標在工作區矩形中居中
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;
// 繪制圖標
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR CMyWindowDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CMyWindowDlg::HookLoad()
{
m_hinstHookDll = ::LoadLibrary(_T("C:\\testProject\\MonitorDll.dll"));
CString loginfo;
if ( NULL == m_hinstHookDll)
{
loginfo.Format(_T("加載 MonitorDll.dll失敗,錯誤代碼 = [%d] "),GetLastError());
AfxMessageBox(loginfo);
return;
}
typedef BOOL (WINAPI* LoadMonitor)(HWND hwnd,DWORD dwProcessId);
LoadMonitor loadMonitor = NULL;
loadMonitor = (LoadMonitor)::GetProcAddress(m_hinstHookDll,"HookLoad");
if (NULL == loadMonitor)
{
loginfo.Format(_T("獲取函數 HookLoad 失敗,錯誤代碼 = [%d]"),GetLastError());
AfxMessageBox(loginfo);
}
if (loadMonitor(m_hWnd,GetCurrentProcessId()))
{
loginfo.Format(_T("HOOK加載成功"));
AfxMessageBox(loginfo);
}
else
{
loginfo.Format(_T("HOOK加載失敗"));
AfxMessageBox(loginfo);
}
}
/*
卸載HOOKDLL
*/
void CMyWindowDlg::HookUnload()
{
CString logInfo;
if (m_hinstHookDll == NULL)
{
m_hinstHookDll = LoadLibrary(_T("MonitorDll.dll"));
if ( NULL == m_hinstHookDll)
{
logInfo.Format(_T("加載 MonitorDll.dll失敗,錯誤代碼 = [%d]"),GetLastError());
AfxMessageBox(logInfo);
return;
}
}
typedef VOID (WINAPI* UnloadHook)();
UnloadHook unloadHook = NULL;
unloadHook = (UnloadHook)::GetProcAddress(m_hinstHookDll,"HookUnload");
if (NULL == unloadHook)
{
logInfo.Format(_T("獲取函數 HookUnload 失敗,錯誤代碼 = [%d]"),GetLastError());
AfxMessageBox(logInfo);
return;
}
unloadHook();
}
本實例說明:有兩個輸出文件,一個是MonitorDll.dll,這是編譯MFC DLL工程得到的,用來實現HOOK API的功能,由主窗口調用,注入到目標進程中。主窗口程序MyWindow,在窗口初始化時加載HOOK,在窗口進程正常退出時卸載HOOK。實例測試效果如下:
窗口初始化過程,打印受保護進程id:
窗口初始化過程中自動加載HOOK,成功:
點擊確定,出現以下對話框:
打開任務管理器,找到我們的窗口進程MyWindow.exe:
試圖強制關閉我們的進程MyWindow.exe:
彈出不能關閉對話框,這樣也就防止了進程被強制關閉: