In that case i may be first one in BFME2/ROTWK who may perhaps succeed (I wish...)
I've attempted myself some stuff with game.dat since yesterday yet unfortunely without source code, .pdb file access nor debug symbols in game.dat there was not much success... Or atleast not much of it... It was more like trial and error... And progress is slow...
I've managed tho, to discover and research some stuff with help of IDA Disassembler and Cheat Engine...
Successfully i've located function responsible for shutting down game with error when custom faction was tried to be listed as usable by Create-A-Hero (Thankfully to IDA i were able to get something more readable for human rather than assembly or hex code)
For comparion here's pseudo-code of that function:
int __cdecl sub_42B914(const char *ArgList, const char **a2, int a3, char a4)
{
const char **v4; // esi@1
int v5; // edi@3
int v7; // [sp+8h] [bp-8h]@7
v4 = a2;
*(_BYTE *)a3 = 0;
if ( !a2 || !*a2 )
{
sub_42F3C1((int)&v7, 2, "INTERNAL ERROR! scanIndexList: No name list provided!");
LABEL_12:
CxxThrowException(&v7, &unk_D17000);
}
v5 = 0;
do
{
if ( !_stricmp(*v4, ArgList) )
{
*(_BYTE *)a3 = 1;
return v5;
}
++v4;
++v5;
}
while ( *v4 );
if ( a4 )
{
sub_42F3C1((int)&v7, 3, "Token '%s' is not a valid member of the index list", ArgList);
goto LABEL_12;
}
return 0;
}
And here's the same code displayed in assembly...
It looks kinda spooky but thankfully i have already some assembly knowledge so i'm not at dead end (Yet!):
; int __cdecl sub_42B914(char *ArgList, int, int, char)
sub_42B914 proc near ; CODE XREF: sub_42B999+16p
; sub_4B5E05+62p ...
var_8 = dword ptr -8
ArgList = dword ptr 8
arg_4 = dword ptr 0Ch
arg_8 = dword ptr 10h
arg_C = byte ptr 14h
push ebp
mov ebp, esp
push ecx
push ecx
mov eax, [ebp+arg_8]
push esi
mov esi, [ebp+arg_4]
test esi, esi
push edi
mov byte ptr [eax], 0
jz short loc_42B977
cmp dword ptr [esi], 0
jz short loc_42B977
xor edi, edi
loc_42B92F: ; CODE XREF: sub_42B914+33j
push [ebp+ArgList] ; Str2
push dword ptr [esi] ; Str1
call ds:__imp__stricmp
test eax, eax
pop ecx
pop ecx
jz short loc_42B967
add esi, 4
inc edi
cmp dword ptr [esi], 0
jnz short loc_42B92F
cmp [ebp+arg_C], 0
jz short loc_42B973
push [ebp+ArgList] ; ArgList
lea eax, [ebp+var_8]
push offset aTokenSIsNotAVa ; "Token '%s' is not a valid member of the"...
push 3 ; int
push eax ; int
call sub_42F3C1
add esp, 10h
jmp short loc_42B98A
; ---------------------------------------------------------------------------
loc_42B967: ; CODE XREF: sub_42B914+2Aj
mov eax, [ebp+arg_8]
mov byte ptr [eax], 1
mov eax, edi
loc_42B96F: ; CODE XREF: sub_42B914+61j
pop edi
pop esi
leave
retn
; ---------------------------------------------------------------------------
loc_42B973: ; CODE XREF: sub_42B914+39j
xor eax, eax
jmp short loc_42B96F
; ---------------------------------------------------------------------------
loc_42B977: ; CODE XREF: sub_42B914+12j
; sub_42B914+17j
push offset aInternalErrorS ; "INTERNAL ERROR! scanIndexList: No name "...
lea eax, [ebp+var_8]
push 2 ; int
push eax ; int
call sub_42F3C1
add esp, 0Ch
loc_42B98A: ; CODE XREF: sub_42B914+51j
push offset unk_D17000
lea eax, [ebp+var_8]
push eax
call _CxxThrowException
sub_42B914 endp
Function shown above seems to be responsible for crash when CaH file is analysed and Token 'Rohan' or any other newly made faction is not found on it's index list which i've yet to find... Tho this function is rather userful warning than game crasher imo. I've attempted preventing game from executing CxxThrowException aswell as sub_42F3C1 which worked as part of crash dialog to get around error but unfortunely it resulted in game.dat crashing. So one way or another if EA wouldn't add this security we get simply game.dat has stopped working from new faction in CaH. And we'd never know why? Now we've got atleast a hint... (Unless that game.dat crash was caused by some mistake of mine?)
To progress further in my goal i've started to do some stuff for altering game in C++ to experiment around more and learn more from code...
This is current version of my C++ Library which was suppose to hook 'Token is not valid' error containing function and tell me what data it passes. And eventually i started to alter myself that data. I've made also dll injector with help of internet which was suppose to put that library into actual game.dat game process. I plan to rebuild that C++ Library injector into game launcher in future perhaps for running altered game engine if things wil go nice and i'il succeed in modifying it?
Anyways here's the code:
#include "stdafx.h"
#include <Windows.h>
#include <detours.h>
#include "stdio.h"
#include <string.h>
#define ADDRESS 0x42B914 //0x42B914
//#define ADDRESS2 0x42B95D
//#define ADDRESS3 0x42B982
//#define ADDRESS4 0x42B993
int (__cdecl* originalFunction)(char *ArgList, char **a2, int a3, char a4);
#define _CRT_SECURE_NO_DEPRECATE
//declares
#define NOP 0x90
//declares
void nop_(PVOID address, int bytes)
{
DWORD d, ds;
VirtualProtect(address, bytes, PAGE_EXECUTE_READWRITE, &d);
memset(address, NOP, bytes);VirtualProtect(address,bytes,d,&ds);
}
void WriteLogFile(char *ArgList, char **a2)
{
FILE* pFile = fopen("testlogs_preview.txt", "a");
fprintf(pFile, "ArgList: %s a2: %s\n", ArgList, *a2);
fclose(pFile);
}
/*
*a2 - name of the table
ArgList - content of the table
Example:
-ArgList: Isengard a2: Men
-ArgList: Mordor a2: Men
-ArgList: Wild a2: Men
-ArgList: Angmar a2: Men
*/
int hookedFunction(char *ArgList, char **a2, int a3, char a4)
{
WriteLogFile(ArgList, a2);
return originalFunction(ArgList, a2, a3, a4);
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
originalFunction = (int(__cdecl*)(char *ArgList, char **a2, int a3, char a4))DetourFunction((PBYTE)ADDRESS, (PBYTE)hookedFunction); //Magic
//nop_((PBYTE)ADDRESS2, 5);
//nop_((PBYTE)ADDRESS3, 5);
//nop_((PBYTE)ADDRESS4, 5);
break;
}
return TRUE;
}
Small Slice Of Log File from CaH crash related function:
...
ArgList: GAME a2: SHELL
ArgList: Fortress a2: NONE
ArgList: THIS_TERRIORITY a2: THIS_TERRIORITY
ArgList: Barracks a2: NONE
ArgList: Armory a2: NONE
ArgList: Resource a2: NONE
ArgList: WORLD a2: TACTICAL
ArgList: CREEP a2: OBSTACLE
ArgList: SUMMONED a2: OBSTACLE
ArgList: CREATE_A_HERO a2: OBSTACLE
ArgList: COMMANDCENTER a2: OBSTACLE
ArgList: SHIP a2: OBSTACLE
ArgList: ATTRIBUTE a2: ATTRIBUTE
ArgList: ATTRIBUTE a2: ATTRIBUTE
ArgList: Men a2: Men
ArgList: Elves a2: Men
ArgList: Dwarves a2: Men
...
Full File Can Be Found Here If Your Curious: http://pastebin.com/raw.php?i=9GJkhz5S
From what i've observed above ArgList seems to be used for token itself and *a2 is id of index list or pointer to it perhaps...
I've experimented way too many times to describe it here, yet i guess i'il share the best results which i had:
int hookedFunction(char *ArgList, char **a2, int a3, char a4)
{
WriteLogFile(ArgList, a2);
if(!strcmp(ArgList, "Rohan"))
{
sprintf(ArgList, "Elves");
return originalFunction(ArgList, a2, a3, a4);
}
return originalFunction(ArgList, a2, a3, a4);
}
Above code managed to stop game to crash game.dat or display crash dialog if there was invalid token 'Rohan' meant to be passed.
Yet unfortunely result of that code was that game never received any info about CaH usability in Rohan faction.. So it was like it never happened... We could manage to use it somehow tho as anti-engine crasher in future if somebody screwed up CaH in mod ?
I've found also some awesome stuff in game.dat's diassembled binary
I'il link it on pastebin tho because it'd make my post way too long:
http://pastebin.com/raw.php?i=RuDxfEiV
It seems to be few strings which compiler left. They atleast show us how source code of bfme2 could looked like which is kinda nice.
It'd be way easier to edit game by source code rather than assembly/hex/C++ workarounds way
Sorry if i've forgot to mention some stuff or wrote unclearly. It's almost 23AM in my country
What i'm hoping for tho is removing some of engine's limits or providing way to overcome them in future. I'm not sure tho if i'il be able to do it. It's going to be tough tho... If it wasn't only end of my past-christmas holidays (School starts back on monday )
Currently i'm planning to name it BFME2X basing on EA's source code folder of game.
And for people who are perhaps curious how i managed to browse some of game.dat stuff or want to try luck themselves here it is:
- Visual C++ 2010
- Visual C++ Detours 1.6?
- IDA Diassembler 6.1
- Cheat Engine (This program tends to be more userful than i though it will be. It allows editing game data/code on assembly level while it's running)
Anyways that's probably it for today's post
I hope that tommorow perhaps i'il be able to locate index table in game.dat by getting address of *a2 in hooked function..
Edited by Oshizu, 31 January 2015 - 01:59 AM.