程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HOOK API(四)—— 進程防終止,hookapi

HOOK API(四)—— 進程防終止,hookapi

編輯:C++入門知識

HOOK API(四)—— 進程防終止,hookapi


HOOK API(四)

—— 進程防終止

0x00        前言

這算是一個實戰吧,做的一個應用需要實現進程的防終止保護,查了相關資料後決定用HOOK API的方式實現。起初學習HOOK API的起因是因為要實現對剪切板的監控,後來面對進程保護這樣一個需求時,綜合各方資料並自己動手實現HOOK OpenProcess() 和 TerminateProcess() 來從調用層實現進程的防終止。下面將進一步介紹實現的過程,也算是對學習的一個總結與實戰。

主要參考:http://www.cnblogs.com/delphi7456/archive/2010/10/31/1865729.html

0x01        實現思路

大體的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         //進程終止碼

);

0x02        HOOL DLL的實現

MonitorDll中的MonitorDll.h源碼:

// 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中的MonitorDll.cpp源碼:

// 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

 

0x03        主調MFC窗口

MyWindow的MyWindowDlg.h

 

// 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()

};

 

 

MyWindow的MyWindowDlg.cpp

 

// 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();

}

 

0x04        測試

本實例說明:有兩個輸出文件,一個是MonitorDll.dll,這是編譯MFC DLL工程得到的,用來實現HOOK API的功能,由主窗口調用,注入到目標進程中。主窗口程序MyWindow,在窗口初始化時加載HOOK,在窗口進程正常退出時卸載HOOK。實例測試效果如下:

 

窗口初始化過程,打印受保護進程id:

 

窗口初始化過程中自動加載HOOK,成功:

 

點擊確定,出現以下對話框:

 

打開任務管理器,找到我們的窗口進程MyWindow.exe:

 

試圖強制關閉我們的進程MyWindow.exe:

 

彈出不能關閉對話框,這樣也就防止了進程被強制關閉:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved