看来一些资料,觉得这篇写的比较好,做此笔记。
栗子如下:
#pragma once
#include <iostream>
using namespace std;
class A
{
public:
int iVal1;
int iVal2;
virtual void print1()
{
cout<<"iVal1(A) = "<<iVal1<<endl;
}
virtual void print2()
{
cout<<"iVal2(A) = "<<iVal2<<endl;
}
virtual void print_all()
{
cout<<"iVal1(A) = "<<iVal1<<"\t"<<"iVal2(A) = "<<iVal2<<endl;
}
virtual void print_extern(int ext)
{
cout<<"ext(A) = "<<(ext+0)<<endl;
}
};
class B
{
public:
int iVal1;
int iVal2;
virtual void print1()
{
cout<<"iVal1(B) = "<<iVal1<<endl;
}
virtual void print2()
{
cout<<"iVal2(B) = "<<iVal2<<endl;
}
virtual void print_all()
{
cout<<"iVal1(B) = "<<iVal1<<"\t"<<"iVal2(B) = "<<iVal2<<endl;
}
virtual void print_extern(int ext)
{
cout<<"ext(B) = "<<(ext+100)<<endl;
}
};
大家应该比较熟悉这两个类的内存结构,如图:
Mission 1:对象a去调用类B的函数
方法:寄存器ecx中放入对象a的地址,然后找到类B相应的函数指针,调用之。
// 1.对象a去调用类B的函数
void CallAMethodWithBObject(A* pA, B* pB)
{
_asm
{
push eax // 暂存eax寄存器到堆栈中
push ecx // 暂存ecx寄存器到堆栈中
mov eax,dword ptr [pB] // pB对象地址所指的内容放入eax中(指向pb虚表)
mov ecx,dword ptr [pA] // pA虚表的地址放入ecx中
mov eax,dword ptr [eax] // pB虚表的地址放入eax中(pB对象的第一个元素)
add eax,12 // 虚表地址+12,即b对象的第4个函数B::print_extern()的地址
push 4
call dword ptr [eax] // 调用类B的函数B::print_all(),但是实际上传入a对象的变量(this指针放在ecx中)
pop ecx // 从堆栈中弹回ecx
pop eax // 从堆栈中弹回eax
}
}
Mission 2:交换对象a和对象b的所有虚函数
方法:很简单,就是交换两个对象的虚表指针,如图。
代码如下:
// 2.交互两个对象的虚表地址
void exchangVB(A* pA, B* pB)
{
_asm
{
push eax
push ecx
push esi
push edi
mov esi, dword ptr[pB]
mov edi, dword ptr[pA]
mov eax, dword ptr[esi]
mov ecx, dword ptr[edi]
mov dword ptr[esi], ecx
mov dword ptr[edi], eax
pop edi
pop esi
pop ecx
pop eax
}
}
Mission 3:交换类A和类B的第二个和第四个函数
方法:需要修改虚表,交换类A和类B的第二、四个函数,如图:
代码如下:
// 3.交换类A和类B的第二个和第四个函数
void ExchangeMethod(A* pA, B* pB)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
long** pplVrtableA = (long**)(pA);
long** pplVrtableB = (long**)(pB);
MEMORY_BASIC_INFORMATION mbiA = {0};
if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
return;
MEMORY_BASIC_INFORMATION mbiB = {0};
if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableB), &mbiB, sizeof(mbiB)) != sizeof(mbiB))
return;
DWORD dwOldProtectA = 0;
DWORD dwOldProtectB = 0;
if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA))
return;
if(!::VirtualProtectEx(hProcess, mbiB.BaseAddress, mbiB.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectB))
return;
_asm
{
push eax //压入需要使用的寄存器到堆栈中
push ecx
push esi
push edi
mov esi,dword ptr [pA] //a对象指针
mov edi,dword ptr [pB] //b对象指针
mov esi,dword ptr [esi] //a对象虚表地址
mov edi,dword ptr [edi] //b对象虚表地址
add esi,4
add edi,4
mov eax,dword ptr [esi] //交换第二个函数地址:print2
mov ecx,dword ptr [edi]
mov dword ptr [edi],eax
mov dword ptr [esi],ecx
add esi,8
add edi,8
mov eax,dword ptr [esi] //交换第四个函数地址:print_extern
mov ecx,dword ptr [edi]
mov dword ptr [edi],eax
mov dword ptr [esi],ecx
pop edi
pop esi
pop ecx
pop eax
}
DWORD dwTemp = 0;
::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, dwOldProtectA, &dwTemp);
::VirtualProtectEx(hProcess, mbiB.BaseAddress, mbiB.RegionSize, dwOldProtectB, &dwTemp);
CloseHandle(hProcess);
}
Mission 4:hook类A的第三个函数
方法:比较麻烦,但是也是不难弄的。将类A的第三个虚函数指针替换成我们自己定义的地址,如同:
代码如下:
void* g_pSaveAddr = 0;
void load_hook(A* pA, DWORD hook_proc)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
long** pplVrtableA = (long**)(pA);
MEMORY_BASIC_INFORMATION mbiA = {0};
if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
return;
DWORD dwOldProtectA = 0;
if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA))
return;
_asm
{
push eax
push ecx
mov eax,dword ptr [pA] //获取对象指针
mov eax,dword ptr [eax] //获取虚表地址
add eax,8 //获取虚表中类A第三个函数指针的地址
mov ecx,dword ptr [eax] //取出类A第三个函数指针
mov dword ptr [g_pSaveAddr],ecx //保存到g_pAddr变量中
mov ecx, dword ptr hook_proc //替换为hook_proc指针
mov dword ptr [eax],ecx
pop ecx
pop eax
}
cout<<"A::print_all() hooked!"<<endl;
DWORD dwTemp = 0;
::VirtualProtectEx(hProcess, mbiA.BaseAddress, 4, dwOldProtectA, &dwTemp);
CloseHandle(hProcess);
}
void unload_hook(A* pA)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
long** pplVrtableA = (long**)(pA);
MEMORY_BASIC_INFORMATION mbiA = {0};
if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
return;
DWORD dwOldProtectA = 0;
if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA))
return;
_asm
{
push eax
push ecx
mov eax,dword ptr [pA] //获取对象指针
mov eax,dword ptr [eax] //获取虚表地址
add eax,8 //获取虚表中类A第三个函数指针的地址
mov ecx,dword ptr [g_pSaveAddr] //取出事先保存的A::print_all()地址
mov dword ptr [eax],ecx
pop ecx
pop eax
}
cout<<"A::print_all() unhooked!"<<endl;
DWORD dwTemp = 0;
::VirtualProtectEx(hProcess, mbiA.BaseAddress, 4, dwOldProtectA, &dwTemp);
CloseHandle(hProcess);
}
主函数如下:
int _tmain(int argc, _TCHAR* argv[])
{
A a;
a.iVal1 = 0;
a.iVal2 = 1;
B b;
b.iVal1 = 1000;
b.iVal2 = 1001;
A* pA = &a;
B* pB = &b;
//CallAMethodWithBObject(pA, pB);
//ExchangeMethod(pA, pB);
//pA->print1();
//pA->print2();
//pA->print_all();
//pA->print_extern(-200);
//cout<<endl;
//pB->print1();
//pB->print2();
//pB->print_all();
//pB->print_extern(-200);
load_hook(pA, DWORD(&hook_proc));
pA->print_all();
unload_hook(pA);
pA->print_all();
getchar();
return 0;
}
本文引用:http://bbs.pediy.com/showthread.php?t=71775