使用HOOK技术做进程保护

整体分析

整体思路:

  • 给系统安装鼠标消息钩子做dll注入
  • 成功注入之后,使用内联hook技术hook OpenProcess以及TerminateProcess
  • 当任务管理器需要关闭进程的时候,会先调用OpenProcess打开进程,再调用TerminateProcess结束进程。我们hook OpenProcess的时候判断任务管理器打开的进程是不是我们要保护的进程,如果是的话保留进程句柄。在任务管理器调用TerminateProcess的时候,判断一下要关闭的句柄和我们保存的句柄,如果相同则直接返回true,否则调用原来的TerminateProcess结束进程。

这里的问题是,任务管理器如何知道我们要保护的进程的pid。我的思路是在我的主进程在创建个文件映射保存pid,在dll注入到其他进程的时候打开文件映射获取PID

MFC dll代码

// MonitorDll.h: MonitorDll DLL 的主标头文件

#pragma once

#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif

#include "resource.h"		// 主符号
#include "privilege.h"

// CMonitorDllApp
// 有关此类实现的信息,请参阅 MonitorDll.cpp
//

class CMonitorDllApp : public CWinApp
{
public:
	CMonitorDllApp();

// 重写
public:
	virtual BOOL InitInstance();
	int ExitInstance();
	DECLARE_MESSAGE_MAP()
};

// MonitorDll.cpp: 定义 DLL 的初始化例程。
//

#include "pch.h"
#include "framework.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;    //    保存本进程在远进程中的句柄
CString g_dwProcessIdStr;
CString g_hProcessStr;
#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);
    CEnablePriv priv;
    priv.EnableDebugPriv();
    priv.GetAdminPriv();

    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;
    }

    //获取任务管理器的pid
    //打开文件Mapping
    HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"PID");
    if (NULL == hMapFile)
    {
        return FALSE;
    }
    //创建view
    PVOID pBuf = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 16);
    if (NULL == pBuf)
    {
        return FALSE;
    }
    g_dwProcessIdStr = (LPWSTR)pBuf;
    //MessageBox(0, g_dwProcessIdStr, _T("要保护的进程"), 0);

    //取消Mapping, 关闭句柄
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);

    CString str_pid;
    str_pid.Format(_T("%d"), dwPid);
    AfxMessageBox(str_pid);
    //g_dwProcessIdStr = str_pid;
    



    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;
    
    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"));
    }
    ////取消Mapping, 关闭句柄
    //UnmapViewOfFile(pBuf);
    //CloseHandle(hMapFile);
}

BOOL WINAPI MyTerminateProcess(_In_ HANDLE hProcess, _In_ UINT uExitCode) {
    BOOL ret;
    if (hProcess == g_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);

    CString dwProcessIdStr;
    dwProcessIdStr.Format(_T("%d"), dwProcessId);
    if (dwProcessIdStr == g_dwProcessIdStr) {
        g_hProcess = hProcess;
    }

    WriteMemory(pfOldOpenProcess, newCodeOpenPro, CODE_LENGTH);
    return hProcess;
}
; MonitorDll.def: 声明 DLL 的模块参数。

LIBRARY

EXPORTS
    ; 此处可以是显式导出

HookLoad
HookUnload

调用程序


// MyWindowDlg.h: 头文件
//

#pragma once


// CMyWindowDlg 对话框
class CMyWindowDlg : public CDialogEx
{
// 构造
public:
	CMyWindowDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MYWINDOW_DIALOG };
#endif

	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 "pch.h"
#include "framework.h"
#include "MyWindow.h"
#include "MyWindowDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMyWindowDlg 对话框



CMyWindowDlg::CMyWindowDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MYWINDOW_DIALOG, 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 != nullptr)
	{
		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: 在此添加额外的初始化代码
	//创建进程id的文件映射
	HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 16, L"PID");
	if (NULL == hMapFile || INVALID_HANDLE_VALUE == hMapFile)
	{
		return TRUE;
	}
	//创建view
	PVOID pBuf = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 16);
	if (NULL == pBuf)
	{
		return TRUE;
	}
	CString g_processId;
	g_processId.Format(_T("%d"), GetCurrentProcessId());
	//将共享数据复制到文件映射中
	wcscpy_s((PWCHAR)pBuf, 8, g_processId.GetBuffer());
	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("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();
}

坑点

  1. 32位的程序测试的时候需要使用32位的任务管理器
  2. 在任务管理器进程这个子窗口结束进程并不会调用TerminateProcess,所以hook不到的,在详细信息窗口结束进程会调用TerminateProcess
posted @ 2023-07-28 15:01  墨宸  阅读(754)  评论(0)    收藏  举报