1

我正在做一些逆向工程,我有一个程序,上面有一个全局定义的类指针。

#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在主应用程序上,并且在主应用程序上WinMaing_Class 指针将指向new堆分配的对象),问题是我不能从 dll 重载 operator new ,原因很明显。假设在主应用程序g_Class上是唯一使用的数据类型,new我怎样才能找到g_Class指向我的 dll 的地址?

4

1 回答 1

1

没有确定的方法可以在目标应用程序中找到指针。这需要一些练习和经验。

对于您的案例,一个好的开始是使用调试器在原始 CallMe 函数的开头中断并读取 ECX 以获​​取原始类指针。现在您可以在其上设置内存断点(或使用作弊引擎的“找出访问此地址的内容”)并从那里开始工作,最终以静态地址结束,您始终可以从中获取类实例的动态地址。


如果该类由于多态性而使用虚拟表,您可以在其中找到函数指针(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 为 thiscall 加载到 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 仍然必须是目标的类实例,而不是您自己的。

于 2013-06-29T16:00:45.853 回答