RTTI(Runtime Type Identification,运行时类型识别)由c++编译器将对象的类型信息嵌入程序的只读数据段,以 支持C++的各种操作符在运行时确定(typeid)和检查(dynamic_cast)一个对象的数据类型。
对微软的编译器而言,RTTI和虚表位置在-4的地址构建。
#include <stdio.h>
#include <Windows.h>
#define VTSIZE 6
#pragma pack(1)
class Parent
{
public:
virtual void Fun1() = 0;
virtual void Fun2() = 0;
virtual void Fun3() = 0;
virtual void Fun4() = 0;
virtual void Fun5() = 0;
};
class Child: public Parent
{
public:
void Fun1()
{
printf("11111\n");
}
void Fun2()
{
printf("22222\n");
}
void Fun3()
{
printf("33333\n");
}
void Fun4()
{
printf("44444\n");
}
void Fun5()
{
printf("55555\n");
}
};
typedef struct _JMP_TABLE_ITEM{
//UCHAR uPushesi; //backup esi for checkesp push esi, pop esi
UCHAR uMoveEaxForFactAddr;
DWORD dwFactAddr;
UCHAR uPashEaxForFactAddr;
//UCHAR uPushad; //0x60
//UCHAR uPushfd; //0x9c
//UCHAR uJmp;
//DWORD dwCheckAddr;
//jmp to check function
//simulate messagebox exist issue
#ifdef DEBUG
UCHAR push0;
UCHAR zero0;
UCHAR push1;
UCHAR zero1;
UCHAR push2;
UCHAR zero2;
UCHAR push3;
UCHAR zero3;
UCHAR tempmoveax;
DWORD dwmsgAddr;
UCHAR uJmpmsg; //FF
DWORD uJmpeaxaddr;
UCHAR add;
UCHAR esp;
UCHAR four;
#endif
//UCHAR uPopad; //61
//UCHAR uPopfd; //9d
UCHAR uPopeax; //58
UCHAR uJmp22; //FF
UCHAR uJmpEax; //EO
}JMP_TABLE_ITEM;
void CheckFunc(DWORD checkNum)
{
}
void InitFakeVirtualTable(DWORD *pfakevt,JMP_TABLE_ITEM *pJMPTable, DWORD pFactvt, DWORD msgaddr)
{
DWORD *pvt = (DWORD*)*(DWORD*)pFactvt;
for(int i = 0; i < VTSIZE; ++i)
{
*pfakevt = (DWORD)pJMPTable;
pJMPTable->uMoveEaxForFactAddr = 0xB8;
pJMPTable->dwFactAddr = *(DWORD*)(pvt+i);
pJMPTable->uPashEaxForFactAddr = 0x50; //push fact virtual function address
//pJMPTable->uPushad = 0x60;
//pJMPTable->uPushfd = 0x9C;
//pJMPTable->uJmp = 0xE9;
//pJMPTable->dwCheckAddr = (DWORD)CheckFunc;
#ifdef DEBUG
pJMPTable->push0 = 0x6A;
pJMPTable->zero0 = 0x0;
pJMPTable->push1 = 0x6A;
pJMPTable->zero1 = 0x0;
pJMPTable->push2 = 0x6A;
pJMPTable->zero2 = 0x0;
pJMPTable->push3 = 0x6A;
pJMPTable->zero3 = 0x0;
pJMPTable->tempmoveax = 0xB8;
pJMPTable->dwmsgAddr = msgaddr;
pJMPTable->uJmpmsg = 0xFF; //FF
pJMPTable->uJmpeaxaddr = 0xE0;
pJMPTable->add = 0x83;
pJMPTable->esp = 0xC4;
pJMPTable->four = 0x10;
#endif
//pJMPTable->uPopad = 0x61;
//pJMPTable->uPopfd = 0x9d;
pJMPTable->uPopeax = 0x58;
pJMPTable->uJmp22 = 0xFF;
pJMPTable->uJmpEax = 0xE0;
pfakevt++;pJMPTable++;
}
}
void main()
{
//Fake virtual table
DWORD *pfakeVirtualTable = new DWORD[VTSIZE]();
JMP_TABLE_ITEM *pJMPTable = new JMP_TABLE_ITEM[VTSIZE]();
DWORD oldprotect = 0;
VirtualProtect(pfakeVirtualTable,1024,PAGE_EXECUTE_READWRITE,&oldprotect);
//VirtualProtect(pJMPTable,1024,PAGE_EXECUTE_READWRITE,&oldprotect);
Parent *pChild = new Child();
DWORD ptemp = (DWORD)pChild;
//simulate checkfunc
HMODULE hNtdll = GetModuleHandleA("user32.dll");
DWORD addr = (DWORD)GetProcAddress(hNtdll,"MessageBoxA");
InitFakeVirtualTable(pfakeVirtualTable,pJMPTable,ptemp,addr);
*(DWORD*)pChild = (DWORD)pfakeVirtualTable;
pChild->Fun1();
pChild->Fun2();
pChild->Fun3();
pChild->Fun4();
pChild->Fun5();
VirtualProtect(pfakeVirtualTable,1024,oldprotect,&oldprotect);
//VirtualProtect(pJMPTable,1024,oldprotect,&oldprotect);
}