windows | 虚表hook
类中有虚函数就会存在虚表。
主要是一种间接call:
call dword ptr [xxxxxxx];
因此就可以修改间接跳转的地址实现hook。
主要步骤:
- 找到虚表
- 修改虚表的物理页属性可写
- 修改虚函数地址
代码如下:
#include <stdio.h>
#include <windows.h>
class Base{
public:
virtual void output(){
printf("i am base \n");
}
};
void hook_print(){
printf("你被hook了\n");
}
int main(int argc, char* argv[]){
Base *pb = new Base(); // 此对象的第一个DWORD指向虚表
DWORD *pVtAddr = (DWORD *)(*(DWORD*)pb); // 强转类型指向虚表
// 由于虚表的属性是只读不可写,所以要改成可写
DWORD dwOldProct = 0;
VirtualProtect(pVtAddr, 4, PAGE_READWRITE, &dwOldProct);
*pVtAddr = (DWORD)hook_print; // hook函数的地址
pb->output();
delete pb;
return 0;
}
下面是2023/11/23补充:
上面的情况过于简单,事实上,对于类函数的调用通常是thiscall的调用约定,因此参数和寄存器的处理至关重要,下面给出我最新调试好的一个示例:
// injecteddll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
extern "C" __declspec(dllexport) void __stdcall hi() // 导出一个函数,并没有实际作用
{
printf("hi from dll \n ");
}
// 保存原来的函数指针
void (__cdecl *g_pFunc)(DWORD*, int);
char s[] = "[dll] arg number: %d \n";
// 自定义的hook函数
_declspec(naked) void my_get_money(){
_asm{
push ecx ; 保存this指针
mov ecx, dword ptr [esp+8] ; 获取原先的参数值
push ecx
lea ecx, s
push ecx
call printf ;输出参数值
add esp, 8
}
_asm{
mov eax, dword ptr [esp+8] ; 获取原先的参数值
pop ecx ; 恢复this指针
add eax, 100000 ; 修改参数值
push eax ; 调用原函数
call g_pFunc
retn 4
}
}
// 用于进行hook的线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter){
Sleep(1000); // 延迟等待exe完成加载
// 进行虚表hook
DWORD* vtable = (DWORD*)0x42801C;
printf("%x %x \n", vtable[0], vtable[1]); // 读取虚表中的两个虚函数地址(用于验证)
// 由于虚表位于.rodate section,节属性为只读,因此需要对节属性进行修改
DWORD dwOldProct = 0;
VirtualProtect(vtable, 4, PAGE_READWRITE, &dwOldProct); // 节属性修改成可读可写
g_pFunc = (void (__cdecl *)(DWORD*, int))vtable[1]; // 保存原来的函数地址
vtable[1] = (DWORD)&my_get_money; // 将虚表中的地址改成我们定义的函数地址
return 0;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH){ // dll被加载时调用
hi();
CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0, NULL); //创建新线程执行代码
}
return TRUE;
}
被hook程序的源代码:
#include <stdio.h>
class Game{
public:
Game(){
this->money = 0;
}
virtual void show_menu(){
puts("\nmake a choice:");
puts(" 1. get money");
puts(" 2. buy flag");
puts(" 3. quit");
printf("your choice: ");
}
virtual void get_money(int number){
this->money += number;
printf("you get %d$ \n", number);
}
void loop(){
int choice = 0;
while(1){
show_menu();
scanf("%d", &choice);
if (choice == 3){
break;
}else if (choice == 2){
if (this->money > 1000000){
puts("you win! ");
break;
}else{
printf("you only have %d$, more to get flag. \n", this->money);
}
}else if (choice == 1){
get_money(1);
}
}
}
private:
int money;
};
int main(){
Game* game = new Game;
game->loop();
return 0;
}
本文来自博客园,作者:Mz1,转载请注明原文链接:https://www.cnblogs.com/Mz1-rc/p/15164217.html
如果有问题可以在下方评论或者email:mzi_mzi@163.com