Hook技术第二讲,之虚表HOOK

一、认识虚表指针以及虚表

讲解之前我们要认识一下类在内存中的表现形式,以及认识虚表指针

1.首先我们知道,当类中有虚函数的时候,则会生成虚表指针,虚表指针指向了虚表,虚表中保存的则是当前类中所有虚函数的函数地址。

内存结构图:

  

第一个是类的内存结构,第二个是虚表。

那么我们就有想法了,当我们调用虚函数的时候,会通过虚表指针,找到虚表,而后找到虚函数地址

那么现在我们是否可以将虚函数的地址改为我们的函数地址?

聪明:其实就是很简单,理解了内存结构,理解了虚表指针,虚表那么就可以进行操作了。

我们只需要将虚表中的虚函数地址更改成我们的即可。

上面都是原理,下面说一下步骤:

总共分为三个步骤:

1.获得虚表指针
2.修改虚表的内存保护属性
3.修改虚表中的虚函数地址为我们的函数地址

很简单三步

高级代码:

#include "stdafx.h"
#include <windows.h>
class MyTest
{
public:
    MyTest();
    ~MyTest();
    void print();
    virtual void ShowHelloWorld();
    int m_Number;
};

MyTest::MyTest()
{
    printf("MyTest::MyTest()\r\n");
    
}

MyTest::~MyTest()
{
    printf("MyTest::~MyTest()\r\n");
}

void MyTest::ShowHelloWorld()
{
   printf("Hello World!\n");
}

void ShowData()                                //我们将虚表中的函数地址换为我们的函数地址
{
    printf("有木有被坑的感觉\r\n");
}

void MyTest::print()
{
     printf("void MyTest::print()\r\n");
}


int main(int argc, char* argv[])
{
    MyTest test;
    MyTest &obj = test;     //可以虚调用
   
    int DwAddress = *(int *)&test;        //第一步,获取自己的虚表指针
    
    obj.ShowHelloWorld();                //虚函数调用,测试作用

    DWORD dwOld = 0;                    //第二步修改虚表指针的内存保护属性,下方更改虚表
    VirtualProtect((void *)DwAddress,0x1000,PAGE_EXECUTE_READWRITE,&dwOld);//修改内存保护属性,其地址是虚表指针地址

    (*(int *)DwAddress) = (int)ShowData;//第三步,HOOK,也就是将我们的函数地址,写入到虚表中.
    
    obj.ShowHelloWorld();                    //重新调用,看看是否被HOOK
    return 0;
}

上面代码可以直接拷贝粘贴,VS2013测试成功。

贴上测试图:

这里只是简单的HOOK了一下自己类的虚表,你可以通过自己的分析,找到别的进程中的虚表,然后更改。

当然这个HOOK很简单,也有自己的适用场合。各种HOOK,注入等等一系列的操作,都在最适合自己的场合能发挥出最大的作用。

在 C++ 中,虚函数通过虚函数表(vtable)来实现。虚函数表是一个存储了虚函数指针的数组,每个类的对象都有一个指向其对应虚函数表的指针。 要 hook C++ 虚函数表并替换其中的虚函数指针,你可以按照以下步骤进行: 1. 获取要 hook 的类的对象指针。 2. 访问对象的虚函数表指针。 3. 根据虚函数的索引找到要 hook 的虚函数指针。 4. 替换虚函数指针为你想要调用的函数指针。 以下是一个示例代码,展示了如何 hook C++ 虚函数表并替换其中的虚函数指针: ```cpp #include <iostream> // 假设有一个基类 BaseClass class BaseClass { public: virtual void virtualFunction() { std::cout << "BaseClass::virtualFunction()" << std::endl; } }; // 定义一个替代原始虚函数的函数 void replacementFunction() { std::cout << "Replacement function called" << std::endl; } int main() { // 创建 BaseClass 对象 BaseClass obj; // 获取对象的虚函数表指针 uintptr_t* vtable = *(uintptr_t**)&obj; // 获取要 hook 的虚函数的索引(假设是第一个虚函数) int virtualFunctionIndex = 0; // 替换虚函数指针为 replacementFunction uintptr_t replacementFunctionPtr = (uintptr_t)&replacementFunction; vtable[virtualFunctionIndex] = replacementFunctionPtr; // 调用虚函数,将会调用替代函数 obj.virtualFunction(); return 0; } ``` 请注意,这个方法可能涉及到一些平台相关的细节,因此在不同的编译器和操作系统上可能会有所不同。在实际应用中,确保了解你所使用的编译器和平台的特定要求和限制是非常重要的。此外,修改虚函数表可能会破坏程序的稳定性和预期行为,谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值