我正在进行一些逆向工程,我有一个程序,并且在其上有一个全局定义的类指针。
#include <includesandsuch.h>
myclass* g_Class = NULL;
int WinMain( ... )
{
g_Class = new myclass(0);
}
在我的课上有一个我想从dll调用的方法,我尝试使用__thiscall
的函数原型,但是类this
将为0,因为该方法写入会导致程序崩溃类成员数据。现在,我提出了一个可行的解决方案,认为这是一个SSCE,或者在这种情况下是SLCE。
DWORD* g_Input = 0;
void* operator new(size_t sz)
{
cout << "mynew" << endl; //yes i'm using (using namespace std;) but please focus on the issue
g_Input = (DWORD*)::new char [sz];
return g_Input;
}
void *operator new [](size_t size)
{
// if (size > MAX_SIZE) ...
cout << "mynew" << endl;
return malloc(size);
}
class ZInput
{
public:
ZInput( int n );
~ZInput(){};
void CallMe( int n, DWORD b );
private:
int m_nData;
};
ZInput::ZInput( int n ){
m_nData = n;
}
void ZInput::CallMe( int n, DWORD b ) {
cout << n <<" "<< b << endl;
}
void Fake_RealSpace2_Input( int n, DWORD b )
{
__asm
{
mov ecx, g_Input
mov eax, 0x012C7310 //example address of ZInput::CallMe
push n
push b
call eax
}
}
int _tmain(int argc, _TCHAR* argv[])
{
ZInput* pInput = new ZInput(2);
cout << pInput << endl;
cout << g_Input << endl;
Fake_RealSpace2_Input(4,5 );
delete pInput;
return 0;
}
这样我就可以在有效的ZInput::CallMe
类对象上成功调用ZInput
。
现在我的问题是我想将此代码移植到DLL,并从那里调用ZInput::CallMe
(类ZInput在主应用程序上,我想从dll调用它),因为我有CallMe
的地址我只需要g_Class
的地址(g_Class
在主应用程序上,在主应用程序WinMain
上g_Class指针将指向一个new
堆分配的对象),问题是我不能出于显而易见的原因从dll重载operator new。假设在主应用程序g_Class
上使用new
的唯一数据类型如何找到g_Class
从我的dll指向的地址?
答案 0 :(得分:1)
在目标应用程序中找不到指针没有明确的方法。需要一些练习和经验。
您的案例的一个良好开端是使用调试器在原始CallMe函数的开头打破并读取ECX以获取原始类指针。现在你可以在它上面设置一个内存断点(或者使用作弊引擎“找出访问这个地址的内容”)并从那里开始工作,最终得到一个静态地址,你可以从中获得类实例的动态地址。 / p>
如果类因多态性而使用虚拟表,则可以在其中找到函数指针(ZInput :: CallMe)。这是您可以在目标应用程序中找到的虚拟函数调用的示例:
CPU Disasm
Address Hex dump Command
006A4F94 8B4E 38 MOV ECX,(class ptr)
006A4F97 8B01 MOV EAX,DWORD PTR DS:[ECX]
006A4F99 8B50 04 MOV EDX,DWORD PTR DS:[EAX+4]
006A4F9C FFD2 CALL EDX
将类ptr加载到ECX以进行此调用。读出虚拟表ptr(VT位于第一个成员)。成员函数ptr从表中读取并被调用(这里是表中的第二个条目)。
对于此示例,ZInput的定义如下所示:
class ZInput
{
public:
virtual void unknown();
virtual void CallMe(int, DWORD);
};
现在要调用成员函数,你可以直接在有效的类上调用它(不是你自己分配的!):
ZInput *inp = *(ZInput**)(0x01112233 + 0x8); // example to get pointer
inp->CallMe(4, 5);
如果它不使用虚函数表,则为函数指针使用静态值,并使用一些程序集黑客进行调用。但是ECX仍然必须是目标的类实例而不是你自己的。