In IDA Pro, i found a function in the game that writes text to console. Here is the function:
; void __cdecl write_to_console(char *Format, char ArgList)
write_to_console proc near ; CODE XREF: sub_4069C0+34↑p
; sub_4069C0+10A↑p ...
Format = dword ptr 4
ArgList = byte ptr 8
push esi
push 1
call sub_67D4F0
mov ecx, [eax+1000h]
lea edx, [ecx+1]
and edx, 80000003h
jns short loc_57CDEE
dec edx
or edx, 0FFFFFFFCh
inc edx
loc_57CDEE: ; CODE XREF: write_to_console+17↑j
shl ecx, 0Ah
add ecx, eax
mov [eax+1000h], edx
mov esi, ecx
mov ecx, [esp+8+Format]
lea eax, [esp+8+ArgList]
push eax ; ArgList
push ecx ; Format
push 400h ; BufferCount
push esi ; Buffer
call __vsnprintf
xor ecx, ecx
add esp, 14h
cmp eax, ecx
mov [esi+3FFh], cl
jl short loc_57CE26
cmp eax, 400h
jl short loc_57CE3C
loc_57CE26: ; CODE XREF: write_to_console+4D↑j
push esi ; ArgList
push offset byte_9EE7FC ; Format
push 1 ; int
mov [esi+3FFh], cl
call sub_651D90
add esp, 0Ch
loc_57CE3C: ; CODE XREF: write_to_console+54↑j
mov eax, esi
pop esi
retn
write_to_console endp
Here how it's called:
xor dword ptr [esi+170h], 1
test byte ptr [esi+170h], 1
mov eax, offset aGameGodmodeOn ; "GAME_GODMODE_ON"
jnz short loc_6462AA
mov eax, offset aGameGodmodeOff ; "GAME_GODMODE_OFF"
push eax
push 65h ; 'e' ; ArgList
push offset aCS ; "%c \"%s\""
call write_to_console
push eax
sub esi, offset unk_1A796F8
mov eax, 4DA637Dh
now inside my C++ i tried to call the function like this:
typedef void(__cdecl* setup)(const char*, ...);
setup write_to_console= reinterpret_cast<setup>(0x0057CDD0);
void MainThread()
{
while (true)
{
if (GetAsyncKeyState('N') & 0x8000)
{
write_to_console("The Function Call worked");
}
Sleep(50);
}
}
I expected it to write "The Function Call worked" in the game console log if i press 'N' in keyboard but instead the game freezes when i press it. How to fix that? Thanks.
EDIT1: after debugging, it turned out that the function is called with EAX beign 0, so the function was accessing invalid memory, but why is that? EAX is supposed to hold the Address of the string to be printed to console, does it have something to do with the game first moving the string address to EAX then push it instead of pushing the string address immediately?
i tried mimic the original code exactly which is:
write_to_console("%c \"%s\"",'e', "GAME_GODMODE_ON");
but didn't work, i also tried to do this before calling:
const char* msg = "GAME_GODMODE_ON";
__asm {
mov eax, msg
}
but in both EAX is still zero, i don't know what's the problem.
Image from x64dbg for the original game function been called
Image from x64dbg with my broken function as EAX=0
EDIT2:
sub_67D4F0 while debugging the original function:
0067D4F0 | mov eax,dword ptr ds:[3956508]; eax was the address of the string and here becomes 0
0067D4F5 | mov ecx,dword ptr fs:[2C]; ecx was 0 and becomes 2B95B0E8
0067D4FC | mov edx,dword ptr ds:[ecx+eax*4]; edx was 0 and becomes 09A0F3F0
0067D4FF | mov eax,dword ptr ds:[edx+28]; eax becomes 0251C9F8
0067D505 | mov ecx,dword ptr ss:[esp+4]; ecx becomes 1
0067D509 | mov eax,dword ptr ds:[eax+ecx*4] ;exact point of freeze in my broken function; eax become the address of the string "normal", at the beginning it was another address for the string "GAME_GODMODE_ON".
in my function call EAX is 0 at freeze point not 0251C9F8 like the original function.
MainThread
.std::thread consoleThread(CallWriteToConsole);
consoleThread.detach();
i tried this inside MainThread(), CallWriteToConsole() is just a void that call write_to_console, to ensure there is no deadlock, yet the game still freezes. I'm not sure if that the correct way tho. The freeze is at the execution ofwrite_to_console("The Function Call worked");
line, just when i press 'N'.eax
at function entry does not matter.call sub_67D4F0
will seteax
as that is the return value. That looks like some memory allocation function.