The update changed some stuff, I've taken some time to update the interface as well, it should be easier to understand now.
PHP Code:
#pragma once
#include <windows.h>
#include <map>
//#include "Database_Enum.h"
class CClientDB // size = 0x24
{
public:
class CRow
{
DWORD * pdwFields;
public:
bool IsValid()
{
return pdwFields != 0;
}
unsigned long GetField( unsigned long dwIndex );
};
DWORD GetMinIndex();
DWORD GetMaxIndex();
CRow * GetRow( unsigned long dwIndex );
private:
DWORD * pdwCustomVMT;
DWORD dwUnknown[2];
DWORD dwMaxIndex;
DWORD dwMinIndex;
DWORD dwUnknown2[3];
CRow * pRows;
};
class CWoWClientDB
{
std::map<const unsigned long, CClientDB *> m_mDatabases;
public:
CWoWClientDB();
CClientDB * GetDatabase( unsigned long dwIndex );
};
PHP Code:
#include "CClientDB.h"
DWORD CClientDB::CRow::GetField( DWORD dwIndex )
{
return pdwFields[dwIndex];
}
DWORD CClientDB::GetMaxIndex()
{
return dwMaxIndex;
}
DWORD CClientDB::GetMinIndex()
{
return dwMinIndex;
}
CClientDB::CRow * CClientDB::GetRow( DWORD dwIndex )
{
if( dwIndex < GetMinIndex() || dwIndex >= dwMaxIndex )
return 0;
CRow * pRet = &pRows[ dwIndex - GetMinIndex() ];
if( !pRet->IsValid() )
return 0;
return pRet;
}
CWoWClientDB::CWoWClientDB()
{
#pragma pack( push, 1 )
struct SConstructorCall
{
BYTE bPushOpcode1;
DWORD dwPushValue1;
BYTE bPushOpcode2;
DWORD dwPushValue2;
BYTE bMovOpcode3;
DWORD dwMovValue3;
BYTE bCallOpcode;
DWORD dwCallAddress;
};
#pragma pack( pop )
for( SConstructorCall * pCall = reinterpret_cast<SConstructorCall*>( gpWoWX->GetFindPattern()->GetAddress( "RegisterBase_ClientDB" ) ); pCall->bPushOpcode1 != 0xC3; pCall = reinterpret_cast<SConstructorCall*>( reinterpret_cast<DWORD>( pCall ) + sizeof( SConstructorCall ) ) )
{
// DBGLOG( "DB( " << pCall->dwPushValue1 << " ) -> " << pCall->dwMovValue3 );
m_mDatabases[ pCall->dwPushValue1 ] = reinterpret_cast<CClientDB*>( pCall->dwMovValue3 );
}
}
CClientDB * CWoWClientDB::GetDatabase( DWORD dwIndex )
{
return m_mDatabases[ dwIndex ];
}
"RegisterBase_ClientDB" is currently located at 0x005A48C0 and I used
PHP Code:
DWORD dwValue = dwFindPattern( "\x8B\x40\x28\x83\xF8\xFF\x74\x09\x85\xC0\x74\x33\x83\xF8\x01\x75", "xx?xx?x?xxx?xx?x" ) + 0x19;
dwValue = *(DWORD*)dwValue + dwValue + 4; // we get it from a function call
If you want to loop through all entries of a database for example, the code would look like this
PHP Code:
CClientDB * pLangDB = GetClientDB()->GetDatabase( DB_Languages );
if( pLangDB )
{
for( DWORD dwIndex = pLangDB->GetMinIndex(); dwIndex < pLangDB->GetMaxIndex(); dwIndex++ )
{
CClientDB::CRow * pRow = pLangDB->GetRow( dwIndex );
if( pRow ) // don't assume they're always valid
{
const char * pszLanguage = reinterpret_cast<const char*>( pRow->GetField( 1 ) );
MessageBoxA( 0, pszLanguage, "Language entry!", 0 );
}
}
}
You can use DumpDatabases.idc from my "IDC scripts" post to dump the database ids like "DB_Languages".
Have fun!