Negative Time - 170 (Game)
Writeup by r3ndom_
Created: 2015-12-8
Problem
In the game engine's FPS limitation algorithm, the current time is logged.
What if the current time were to become negative?
Hint
Game is Windows only. :)
Answer
Overview
Make the time variable go negative.
Methods: 1) Patch the check. 2) Patch the point when variable thats checked it set. 3) Decrypt the string.
Details
This can be found in two ways, going to the next encrypted string or finding uses of the clock()
function. The variable for fps limitation is set using two clock()
calls then subtracting the two to determine the frame time. That variable is then referenced to decide whether to print the string.
I went with finding the usage of the encrypted string and found this code.
loc_4092CB: ; CODE XREF: sub_409190+A0j
; sub_409190+ADj
cmp word_568834, 0FF9Ch
jge loc_4093E4
cmp byte_568833, 0
jnz loc_4093E4
mov eax, dword_55C4FC
sub esp, 18h
mov esi, esp
mov dword_55C564, eax
sub esp, 18h
mov dword_55C568, ebx
mov ecx, esp ; int
mov dword_55C56C, 2
mov byte_568833, 1
push 24h ; size_t
mov dword ptr [ecx+14h], 0Fh
mov dword ptr [ecx+10h], 0
push offset a322505102c1a28 ; "322505102c1a282e0d21242110023e192834"
mov byte ptr [ecx], 0
call sub_40A2D0
mov ecx, esi
call sub_408C20
add esp, 18h
lea ecx, [esp+48h+var_1C]
call sub_408D30
mov esi, eax
add esp, 18h
cmp esi, offset dword_55C628
jz short loc_4093CB
cmp dword_55C63C, 10h
jb short loc_409365
push dword_55C628 ; void *
call j__free
add esp, 4
Note the check at the top against 0xff9c, aka -100. If its less than that the code lets this string print.
// Where to return to.
dword g_dwRet = 0;
// My code to do a little comparison myself and set the flags I want.
__declspec(naked) void mfHook()
{
__asm
{
mov dword ptr ds : [0x568834], -101
cmp dword ptr ds :[0x568834], 0xff9c
jmp dword ptr ds : [ g_dwRet ]
}
}
dword HookThread(LPVOID lpParam)
{
g_dwRet = Detour((byte*)0x4092CB, (byte*)mfHook, 8);
return 0;
}
#define COERCE_THREAD(a) reinterpret_cast<LPTHREAD_START_ROUTINE>(a)
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
HookThread(0);
//CreateThread(0, 0, COERCE_THREAD(HookThread), 0, 0, 0);
}
return TRUE;
}
This is kind of a long way to do it, but its the first that came to mind. Again patching the compare with nops would have taken less time but I think it also has less finesse. Some games do hash checks on themselves and as such modifying the binary itself can be dangerous.
Flag
sctf{negamegatime}
Alternative Methods (in brief)
Decrypting the string is possible as always.
There are also many possible modifications that all achieve the same goal of skipping the check, I chose that in particular because it was fairly quick.
The other code for setting the word that gets checked is at 0x408E33 in the binary. Its something like:
word begin = clock();
// Do something that I guess is drawing, it doesn't do any calls in here so I don't know what exactly to make of it
// without reversing more... Its just like a loop where it sets variables in a struct array.
word_568834 = begin - clock();
Which of course is trivial to modify. Also it should probably be clock() - begin to avoid people with trash frames from getting the flag... But to each his own code, I guess.