C++ 使用 PolyHook 框架

PolyHook 源码下载地址(GitHub)
PolyHook 使用介绍(Code Project)

首先下载 GitHub 上的源码到本地,编译一遍,我这里用的是 vs2019。编译完成后我们找到以下几个文件/文件夹:
在这里插入图片描述在这里插入图片描述
之后我们新建一个工程(我的工程名叫 Test_Console),把 Capstone 文件夹放在项目根目录下:
在这里插入图片描述
在源目录下创建两个文件夹 Include、Import,分别存放我们需要的头文件和库:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
然后来到 Test_Console 的项目属性,改一下 VC++目录中的 包含目录库目录
在这里插入图片描述注意这里的 库目录在编译成 x86 和 x64 时要选择的文件夹是不一样的。

最后添加如下代码到 .cpp 内:

// Test_Console.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "CatchUnitTest.h"
#include "PolyHook.hpp"

#pragma region 1

typedef int(__stdcall* tMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
tMessageBoxA oMessageBoxA;

int __stdcall hkMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
    return oMessageBoxA(hWnd, "Hooked", lpCaption, uType);
}

#pragma endregion

#pragma region 2

class VirtualTest
{
public:
    virtual int NoParamVirt()
    {
        return 4;
    }
    virtual int NoParamVirt2()
    {
        return 1;
    }
};

typedef int(__thiscall* tVirtNoParams)(DWORD_PTR pThis);
tVirtNoParams oVirtNoParams;

int __fastcall hkVirtNoParams(DWORD_PTR pThis)
{
    return 0;
}

#pragma endregion

#pragma region 3



#pragma endregion 

#pragma region 4



#pragma endregion 

#pragma region 5

typedef DWORD(__stdcall* tGetCurrentThreadId)();
tGetCurrentThreadId oGetCurrentThreadID;

DWORD __stdcall hkGetCurrentThreadId()
{
    return 123456;
}

#pragma endregion

#pragma region 6

typedef int(__stdcall* tVEH)(int intparam);
tVEH oVEHTest;
int __stdcall VEHTest()
{
    return 3;
}

std::shared_ptr<PLH::VEHHook> VEHHook_Ex;
int __stdcall hkVEHTest()
{
    //auto ProtectionObject = VEHHook_Ex->GetProtectionObject();
    return /*oVEHTest(param) + 1*/1;
}

#pragma endregion

int main()
{
    // 1.正常 Hook
    std::shared_ptr<PLH::Detour> Detour_Ex(new PLH::Detour);
    Detour_Ex->SetupHook((BYTE*)&MessageBoxA, (BYTE*)&hkMessageBoxA);
    MessageBoxA(NULL, "", "", NULL);
    Detour_Ex->Hook();
    oMessageBoxA = Detour_Ex->GetOriginal<tMessageBoxA>();
    MessageBoxA(NULL, "", "", NULL);
    Detour_Ex->UnHook();
    MessageBoxA(NULL, "", "", NULL);

    /* ****************************** 非正常 Hook ******************************* */
    std::shared_ptr<VirtualTest> ClassToHook(new VirtualTest);

    // 2.虚函数 Hook
    std::shared_ptr<PLH::VFuncDetour> VFuncDetour_Ex(new PLH::VFuncDetour);
    VFuncDetour_Ex->SetupHook(*(BYTE***)ClassToHook.get(), 0/*函数下标*/, (BYTE*)&hkVirtNoParams);
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VFuncDetour_Ex->Hook();
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VFuncDetour_Ex->UnHook();
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;

    // 3.替换虚函数表
    std::shared_ptr<PLH::VTableSwap> VTableSwap_Ex(new PLH::VTableSwap);
    VTableSwap_Ex->SetupHook((BYTE*)ClassToHook.get(), 0/*函数下标*/, (BYTE*)&hkVirtNoParams);
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VTableSwap_Ex->Hook(); 
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VTableSwap_Ex->UnHook();
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;

    // 4.更改原虚函数表中的值,以指向我们的代码
    std::shared_ptr<PLH::VFuncSwap> VFuncSwap_Ex(new PLH::VFuncSwap);
    VFuncSwap_Ex->SetupHook(*(BYTE***)ClassToHook.get(), 0/*函数下标*/, (BYTE*)&hkVirtNoParams);
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VFuncSwap_Ex->Hook();
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;
    VFuncSwap_Ex->UnHook();
    std::cout << ClassToHook->NoParamVirt() << "," << ClassToHook->NoParamVirt2() << std::endl;

    // 5.导入表 Hook
    std::shared_ptr<PLH::IATHook> IATHook_Ex(new PLH::IATHook);
    IATHook_Ex->SetupHook("kernel32.dll", "GetCurrentThreadId", (BYTE*)&hkGetCurrentThreadId);
    std::cout << "GetCurrentThreadId = " << GetCurrentThreadId() << std::endl;
    IATHook_Ex->Hook();
    std::cout << "GetCurrentThreadId = " << GetCurrentThreadId() << std::endl;
    IATHook_Ex->UnHook();
    std::cout << "GetCurrentThreadId = " << GetCurrentThreadId() << std::endl;

    // 6.异常处理 Hook
    // 没整明白,有知道的老哥请留言告知,不甚感激

    getchar();
    return 0;
}

其中包含了一些测试代码,用的时候酌情删除便是。


PolyHook v2 编译

既然出了第二版,那么再用第一版总感觉有点 Low ,所以花点时间看下第二版相对第一版的改动。

编译方面 v2 改用了 cmake 方式编译,首先打开 git ,输入命令:git clone --recursive https://github.com.cnpmjs.org/stevemk14ebr/PolyHook_2_0.git ,注意这里的网址为什么不是 github.com 而是 github.com.cnpmjs.org 这是因为第二种方式 clone 代码的速度会 快很多 ,具体原因感兴趣的朋友可以自己查阅资料,在这里不再深究。

执行完成之后,我出现了如下错误:
在这里插入图片描述
polyhook 框架用到了反汇编引擎 capstone ,而不知道什么原因我们下载 capstone 的时候出错了。这时候我们完全可以再某个地方新建一个目录,再打开一个 git 控制台,输入:git clone https://github.com.cnpmjs.org/aquynh/capstone.git
下载完成后,把内容拷贝到 polyhook 的 capstone 文件夹里:
在这里插入图片描述
然后来到我们最开始打开的那个控制台,执行:cd PolyHook_2_0

在这里插入图片描述

再输入:git submodule update --init --recursive 检查一下更新,这个项目目前作者仍在持续维护,所以保险起见检查更新的操作是很有必要的:
在这里插入图片描述再输入 cmake -B"./_build" -DCMAKE_INSTALL_PREFIX="./_install/" -DPOLYHOOK_BUILD_SHARED_LIB=ON -G "Visual Studio 16 2019" -A x64 ,使用 cmake 生成 .sln 文件。
如果要编译为 32位项目,只需要把末尾的 -A x64 改为 -A Win32 即可

在这里插入图片描述
之后我们可以选择打开 _build 文件夹下的 .sln 来自己编译(用 vs):
在这里插入图片描述
在这里插入图片描述
或者使用命令编译:cmake --build "./_build" --config Release --target INSTALL
在这里插入图片描述
编译完成之后,想要的东西都在 _install 文件夹内:
在这里插入图片描述

PolyHook 使用 Demo

// Test_Console_1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cstdarg>
#include <memory>
#include <Catch.hpp>

#pragma region Detour
#include "polyhook2/CapstoneDisassembler.hpp"    
#include "polyhook2/Detour/x64Detour.hpp"
uint64_t u64_hMessageBoxA = NULL;
NOINLINE int __cdecl hook_MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {

    return PLH::FnCast(u64_hMessageBoxA, &MessageBoxA)(NULL, "hook MessageBoxA", "LYSM", NULL);
}
#pragma endregion

#pragma region BreakPointHook
#include "polyhook2/Exceptions/BreakPointHook.hpp"
NOINLINE int hookMe() {
    volatile int i = 0;
    i += 1;
    i += 2;

    return i;
}
std::shared_ptr<PLH::BreakPointHook> bpHook;
NOINLINE int hookMeCallback() {
    std::cout << "调用 hookMe 前先进入回调函数" << std::endl;

    return hookMe();
}
#pragma endregion 

#pragma region HWBreakPointHook
#include "polyhook2/Exceptions/HWBreakPointHook.hpp"
NOINLINE int hookMeHWBP() {
    volatile int i = 0;
    i += 1;
    i += 2;
    return i;
}
std::shared_ptr<PLH::HWBreakPointHook> hwBpHook;
NOINLINE int hookMeCallbackHWBP() {
    std::cout << "调用 hookMeHWBP 前先进入回调函数" << std::endl;
    return hookMeHWBP();
}
#pragma endregion

#pragma region IatHook
#include "polyhook2/PE/IatHook.hpp"
uint64_t oGetCurrentThreadID;
NOINLINE DWORD __stdcall hkGetCurrentThreadId() {
    return 0;
}
#pragma endregion

#pragma region EatHook
#include "polyhook2/PE/EatHook.hpp"
typedef void(*tEatTestExport)();
uint64_t oEatTestExport;
extern "C" __declspec(dllexport) NOINLINE void EatTestExport() {
    std::cout << "EatTestExport" << std::endl;
}
NOINLINE void hkEatTestExport() {
    std::cout << "hkEatTestExport" << std::endl;
}
#pragma endregion

#pragma region MemProtector
#include "polyhook2/MemProtector.hpp"
#pragma endregion 

#pragma region VTableSwapHook
#include "polyhook2/Virtuals/VTableSwapHook.hpp"
class VirtualTest {
public:
    virtual ~VirtualTest() {}
    virtual int NoParamVirt() {
        return 4;
    }
    virtual int NoParamVirt2() {
        return 7;
    }
};
typedef int(__thiscall* tVirtNoParams)(uintptr_t pThis);
PLH::VFuncMap origVFuncs;
NOINLINE int __fastcall hkVirtNoParams(uintptr_t pThis) {
    std::cout << "执行虚函数之前先执行 hkVirtNoParams" << std::endl;
    return ((tVirtNoParams)origVFuncs.at(1))(pThis);
}
#pragma endregion

#pragma region VFuncSwapHook
#include "polyhook2/Virtuals/VFuncSwapHook.hpp"
class VirtualTest2 {
public:
    virtual ~VirtualTest2() {}
    virtual int NoParamVirt() {
        return 4;
    }
    virtual int NoParamVirt2() {
        return 7;
    }
};
typedef int(__thiscall* tVirtNoParams)(uintptr_t pThis);
PLH::VFuncMap origVFuncs2;
NOINLINE int __fastcall hkVirtNoParams2(uintptr_t pThis) {
    std::cout << "执行虚函数之前先执行 hkVirtNoParams2" << std::endl;
    return ((tVirtNoParams)origVFuncs2.at(1))(pThis);
}
#pragma endregion


int main()
{
    // 测试 —— Detour

    /*PLH::CapstoneDisassembler dis(PLH::Mode::x64);
    PLH::x64Detour detour((char*)&MessageBoxA, (char*)&hook_MessageBoxA, &u64_hMessageBoxA, dis);
    detour.hook();
    std::cout << std::hex << "为 jmp 申请的内存地址,用来恢复被 jmp 覆盖的指令:" << u64_hMessageBoxA << std::endl;
    MessageBoxA(NULL,"Failed.","LYSM",NULL);
    detour.unHook();*/

    // 测试 —— BreakPoint

    /*bpHook = std::make_shared<PLH::BreakPointHook>((char*)&hookMe, (char*)&hookMeCallback);
    if (bpHook->hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    std::cout << "hookMe():" << hookMe() << std::endl;
    if (bpHook->unHook() == true) {
        std::cout << "unHook success." << std::endl;
    }
    std::cout << "hookMe():" << hookMe() << std::endl;*/

    // 测试 —— HWBreakPoint

    /*hwBpHook = std::make_shared<PLH::HWBreakPointHook>((char*)&hookMeHWBP, (char*)&hookMeCallbackHWBP,GetCurrentThread());
    if (hwBpHook->hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    std::cout << "hookMeHWBP():" << hookMeHWBP() << std::endl;
    if (hwBpHook->unHook() == true) {
        std::cout << "unHook success." << std::endl;
    }
    std::cout << "hookMeHWBP():" << hookMeHWBP() << std::endl;*/

    // 测试 —— IatHook

    /*PLH::IatHook hook("kernel32.dll", "GetCurrentThreadId", (char*)&hkGetCurrentThreadId, (uint64_t*)&oGetCurrentThreadID, L"");
    if (hook.hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    std::cout << "原 IAT 表中 GetCurrentThreadId 地址:0x" << std::hex << oGetCurrentThreadID << std::endl;
    std::cout << "TID:" << GetCurrentThreadId() << std::endl;
    if (hook.unHook() == true) {
        std::cout << "unhHook success." << std::endl;
    }
    std::cout << "TID:" << GetCurrentThreadId() << std::endl;*/

    // 测试 —— EatHook

    /*PLH::EatHook hook("EatTestExport", L"", (char*)&hkEatTestExport, (uint64_t*)&oEatTestExport);
    if (hook.hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    std::cout << "原 EAT 表中 EatTestExport 地址:0x" << std::hex << oEatTestExport << std::endl;
    tEatTestExport pExport_1 = (tEatTestExport)GetProcAddress(GetModuleHandle(nullptr), "EatTestExport");
    pExport_1();
    if (hook.unHook() == true) {
        std::cout << "unHook success." << std::endl;
    }
    tEatTestExport pExport_2 = (tEatTestExport)GetProcAddress(GetModuleHandle(nullptr), "EatTestExport");
    pExport_2();*/

    // 测试 —— MemProtector

    /*char* page = (char*)VirtualAlloc(0, 4 * 1024, MEM_COMMIT, PAGE_NOACCESS);
    PLH::MemoryProtector prot((uint64_t)page, 4 * 1024, PLH::ProtFlag::R | PLH::ProtFlag::W | PLH::ProtFlag::X);
    if (prot.isGood()) {
        std::cout << "修改内存保护属性成功." << std::endl;
    }
    page = "test";
    std::cout << "page:" << page << std::endl;
    VirtualFree(page, 0, MEM_RELEASE);*/

    // 测试 —— VTableSwapHook

    /*std::shared_ptr<VirtualTest> ClassToHook(new VirtualTest);
    PLH::VFuncMap redirect = { {(uint16_t)1, (uint64_t)&hkVirtNoParams} };
    PLH::VTableSwapHook hook((char*)ClassToHook.get(), redirect);
    if (hook.hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    origVFuncs = hook.getOriginals();
    std::cout << "NoParamVirt:" << ClassToHook->NoParamVirt() << std::endl;
    if (hook.unHook() == true) {
        std::cout << "unHook success." << std::endl;
    }
    std::cout << "NoParamVirt:" << ClassToHook->NoParamVirt() << std::endl;*/

    // 测试 —— VFuncSwapHook

    /*std::shared_ptr<VirtualTest2> ClassToHook(new VirtualTest2);
    PLH::VFuncMap redirect = { {(uint16_t)1, (uint64_t)&hkVirtNoParams2} };
    PLH::VFuncSwapHook hook((char*)ClassToHook.get(), redirect, &origVFuncs2);
    if (hook.hook() == true) {
        std::cout << "hook success." << std::endl;
    }
    std::cout << "NoParamVirt:" << ClassToHook->NoParamVirt() << std::endl;
    if (hook.unHook() == true) {
        std::cout << "unHook success." << std::endl;
    }
    std::cout << "NoParamVirt:" << ClassToHook->NoParamVirt() << std::endl;*/


    getchar();
    return 0;
}

PolyHook_2 将 dll 项目改为 lib 项目

修改 PolyHook_2 的项目属性,如下:
在这里插入图片描述

在这里插入图片描述

重新编译,会生成 lib 而不是 dll。 但此时如果直接使用这个 lib 会在 lib 里报错:无法解析的外部符号 _cs_open … _cs_free 等等,全局搜索了一下,这个引用是在 PolyHook_2 的 cpp 里,其中找不到的这些外部符号来自 Capstoon ,所以只需要在 PolyHook_2 的项目里添加对 Capstoon 的 lib 的引用即可(附加库目录、附加依赖项)

原文地址:https://www.cnblogs.com/csnd/p/15613531.html