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        // 进程标示符

扫描二维码关注公众号,回复: 11352009 查看本文章

);

 

 

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:

 

弹出不能关闭对话框,这样也就防止了进程被强制关闭:


来源:python脚本自动迁移

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:

 

弹出不能关闭对话框,这样也就防止了进程被强制关闭:


猜你喜欢

转载自www.cnblogs.com/hookjc/p/13183380.html