• 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 的引用即可(附加库目录、附加依赖项)

  • 相关阅读:
    input 框变成不可编辑的。
    git 首次往远程仓库提交项目过程。(使用idea操作)
    nacos 导入项目配置(yml文件)步骤
    instr MySQL数据库函数用法
    遍历 map 的方法
    基于分布式思想下的rpc解决方案(1)
    深入理解通信协议-(1)
    Tomcat(3)--性能优化
    并发编程(5)--并发容器
    并发编程(4)--显示锁和AQS
  • 原文地址:https://www.cnblogs.com/csnd/p/15613531.html
Copyright © 2020-2023  润新知