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