Code:
#include <ida.idc>
/************************************************************************
Desc: Label and Dump each database with an appropriate name and struct
Author: kynox
Modified for Cataclysm by TOM_RUS
Modified to Dump Databases by BoredEvil
Modified for MOP by counted
Modified for Legion by counted
Credits To: Bobbysing GetWoWVersionString(), static ExtractPath( sPath ),static GetTargetPath()
Website: http://www.gamedeception.net
*************************************************************************/
static GetWoWVersionString()
{
auto sVersion, sBuild, sDate;
sVersion = FindBinary( INF_BASEADDR, SEARCH_DOWN, "\"=> WoW Version %s (%s) %s\"" );
if( sVersion == BADADDR )
{
Message( "Version format string not found" );
return 0;
}
sVersion = DfirstB( sVersion );
if( sVersion == BADADDR )
{
Message( "Version string unreferences" );
return 0;
}
sVersion = PrevHead( sVersion, 0 );
sBuild = PrevHead( sVersion, 0 );
sDate = PrevHead( sBuild, 0 );
sVersion = GetOperandValue( sVersion, 0 );
sBuild = GetOperandValue( sBuild, 0 );
sDate = GetOperandValue( sDate, 0 );
sVersion = GetString( sVersion, -1, ASCSTR_C );
sBuild = GetString( sBuild, -1, ASCSTR_C );
sDate = GetString( sDate, -1, ASCSTR_C );
return form( "Version: %s Build number: %s Build date: %s\n", sVersion, sBuild, sDate );
}
static ExtractPath( sPath )
{
auto dwIndex;
for( dwIndex = strlen( sPath ); strstr( substr( sPath, dwIndex, -1 ), "\\" ); dwIndex-- );
return substr( sPath, 0, dwIndex + 1 );
}
static GetTargetPath()
{
return ExtractPath( GetIdbPath() );
}
static WoWDb_GetName( dbBase )
{
auto dbName;
// mov eax, offset aDbfilesclientA ; "DBFilesClient\\Achievement.dbc"
dbName = GetString( Dword(dbBase), -1, ASCSTR_C );
Message("%s", dbName);
// Return the the token after \ and before .
return substr( dbName, strstr( dbName, "\\" ) + 1, -5 );
}
static BuildStruct()
{
// struct size changed, need figure out what was removed....
auto id;
id = AddStrucEx(-1,"WoWClientDB",0);
//AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=-1, tdelta=0, reftype=2)
//Add structure member
//Parameters:•sid - structure type ID
//•name - name of the new member
//•offset - offset of the new member -1 means to add at the end of the structure
//•flag - type of the new member. Should be one of FF_BYTE..FF_PACKREAL (see above) combined with FF_DATA
//•typeid - if isStruc(flag) then typeid specifies the structure id for the member if isOff0(flag) then typeid specifies the offset base. if isASCII(flag) then typeid specifies the string type (ASCSTR_...). if isStroff(flag) then typeid specifies the structure id if isEnum(flag) then typeid specifies the enum id if isCustom(flags) then typeid specifies the dtid and fid: dtid|(fid<<16) Otherwise typeid should be -1.
//•nbytes - number of bytes in the new member
//•target - target address of the offset expr. You may specify it as -1, ida will calculate it itself
//•tdelta - offset target delta. usually 0
//•reftype - see REF_... definitions
//Returns:0 - ok, otherwise error code (one of STRUC_ERROR_*)
//Note: The remaining arguments are allowed only if isOff0(flag) and you want to specify a complex offset expression
AddStrucMember(id, "VTable", 0X00, 0x20500400, 0X0, 4, 0XFFFFFFFF, 0X0, 0x000002);
AddStrucMember(id, "NumRows", 0X04, 0x20000400, -1, 4);
AddStrucMember(id, "MaxIndex", 0X08, 0x20000400, -1, 4);
AddStrucMember(id, "MinIndex", 0X0C, 0x20000400, -1, 4);
AddStrucMember(id, "Data", 0X10, 0x20000400, -1, 4);
AddStrucMember(id, "FirstRow", 0X14, 0x20000400, -1, 4);
AddStrucMember(id, "Rows", 0X18, 0x25500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
AddStrucMember(id, "Unk1", 0X1c, 0x20000400, -1, 4);
AddStrucMember(id, "unk2", 0X20, 0x20000400, -1, 4);
AddStrucMember(id, "unk3", 0X24, 0x20000400, -1, 4);
AddStrucMember(id, "RowEntrySize", 0X28, 0x20000400, -1, 4);
return id;
}
static StructBuilt()
{
return ( GetStrucIdByName( "WoWClientDB" ) != -1 );
}
static HandleLoadLoop(xref, hFile, sPrefix,sClassName,bLabel)
{
auto count;
do
{
auto dbNameOffset, dbStruct, dbName;
dbStruct = Dword(xref);
dbNameOffset = Dword(xref + 4);
if(dbStruct == 0 || dbNameOffset == 0)
break;
dbName = WoWDb_GetName(dbNameOffset);
if(bLabel)
{
Message("Labeling : %X %X %s\n", dbStruct, dbNameOffset, dbName);
SetType( dbStruct, "WoWClientDB;" );
MakeStruct( dbStruct, "WoWClientDB" );
MakeName( dbStruct, form( sPrefix + dbName ) );
}
Message("Dumping : #define " + sPrefix + "%s (" + sClassName + " DB_BaseOffset + 0x%08X)\n", dbName, dbStruct);
fprintf( hFile, "m_dbcTables.Add(eWowDBC.%s, new DbTable(0x%08X));\n", dbName, dbStruct );
xref = xref + 8;
count++;
} while(1);
return count;
}
static GetNameEffset( xref )
{
auto offset, dbName;
offset = ReadOperand( xref, "push", "offset" );
dbName = GetString( Dword(offset), -1, ASCSTR_C );
if(strstr( dbName, ".dbc" ) > -1)
return offset;
return BADADDR;
}
static ReadOperand( xref, operand, filter )
{
auto prevFunc;
prevFunc = PrevFunction( xref );
Message("%X %X\n", xref, prevFunc);
do
{
auto disasm;
disasm = GetDisasm( xref );
if ( strstr( disasm, operand ) > -1 && strstr( disasm, filter ) > -1 )
break;
xref = PrevHead( xref, prevFunc );
} while ( 1 );
return GetOperandValue( xref, operand == "mov" ? 1 : 0);
}
static main()
{
auto curAddr, y, count, hFile, sPath, sPrefix, sClassName, bLabel;
auto dataSegStart, dataSegEnd, resSegStart, resSegEnd, codeSegStart, codeSegEnd;
auto segBase, segName, segEnd, dwRet;
///////////////////////////////////////////
/////// Customisation start
///////////////////////////////////////////
sPrefix = "g_DB2_"; // Prefix of the Databases dumped and labeled
sClassName = "(CClientDB*)"; // Classname to apply to the #define macros - leave empty if you just need the offsets
bLabel = 1; // 0 = Dump only 1 = Dump + LabelDatabases in IDA
sPath = GetTargetPath() + "Database_Enum.h";
///////////////////////////////////////////
/////// Customisation end
///////////////////////////////////////////
for(y = 1; y < 5; y++)
{
segBase = SegByBase(y);
segName = SegName(segBase);
segEnd = SegEnd(segBase);
Message("Segment %d %s starts at %x and ends at %x\n", y, segName, segBase, segEnd);
if(segName == ".text")
{
codeSegStart = segBase;
codeSegEnd = segEnd;
}
else if(segName == ".rdata")
{
resSegStart = segBase;
resSegEnd = segEnd;
}
else if(segName == ".data")
{
dataSegEnd = segEnd;
dataSegStart = segBase;
}
}
if ( !StructBuilt() )
{
Message( "Building struct..\n" );
if( BuildStruct() == -1 )
{
Message( "Failed to build struct..\n" );
return;
}
}
hFile = fopen(sPath,"w");
if(hFile == -1)
{
return 0;
}
// fprintf( hFile, "#ifndef __DATABASE_ENUM_H__\n#define __DATABASE_ENUM_H__\n\n" );
fprintf(hFile,"//" + GetWoWVersionString() + "\n\n");
fprintf( hFile, "#define " + sPrefix + "BaseOffset ( 0 )\n\n" );
for(y = codeSegStart; y <= codeSegEnd;y = y + 1)
{
auto addr1, addr2, addr3, dbcName, dbcLen;
addr1 = Dword(y);
if(addr1 > resSegEnd || addr1 < resSegStart)
{
continue;
}
// Message("Address %x Points to Resource at %x\n", y, addr1);
addr2 = Dword(addr1);
if(addr2 < resSegStart || addr2 > resSegEnd)
{
continue;
}
// Message("Resource %x Points to Resource at %x\n", addr1, addr2);
// addr3 = Dword(addr2);
auto fulldbcName = GetString( addr2, -1, ASCSTR_C );
// Message("Found %s\n", fulldbcName);
if ( strstr( fulldbcName , ".db2" ) != -1 )
{
auto subName;
if(strstr(fulldbcName, "-sparse") != -1) // This is to remove the dash in Item-sparse
{
auto s1 = substr(fulldbcName, 14, strstr( fulldbcName, "-" ));
auto s2 = substr( fulldbcName, strstr( fulldbcName, "-" ) + 1, -1);
subName = form("%s_%s",s1, s2);
Message("*************************** Found %s ***********************\n", subName);
}
else
{
subName= substr(fulldbcName, 14, strlen(fulldbcName) -4);
}
// Message("Found %s %d | %d\n", subName);
if(bLabel)
{
auto labeladdr = y - 14;
auto nameAddr = Dword(labeladdr);
if(nameAddr > dataSegEnd || nameAddr < dataSegStart)
{
continue;
}
// SetType( nameAddr,"WoWClientDB;" );
// MakeStruct(nameAddr, "WoWClientDB" ); // I have not reversed the struct to see what changed
auto labelname = form( sPrefix + subName, subName);
dwRet = MakeName( nameAddr, labelname );
if(dwRet != 0 )
{
Message("Labeling : 0x%08X %s\n", nameAddr, labelname);
fprintf( hFile, "#define %s 0x%08X\n", labelname, nameAddr);
count++;
}
}
}
}
// fprintf( hFile, "\n#endif //__DATABASE_ENUM_H__" );
fclose(hFile);
Message("DBC count %u\n", count);
}