I would suggest saving the dump in the same folder as the original MCC-Win64-Shipping.exe file because the program references DLL dependencies relative to its current directory.
This means that we want to load our game hack DLL as early as possible since all the DLLs loaded before us will have the opportunity to run whatever code they have in their DllMain and will be in a better position to mess with us. I placed a breakpoint at the EntryPoint of the EAC library, and at first, I thought that EAC had hooked the CreateThread function because the debugger kept hitting that breakpoint, but actually, in the MSDN documentation for DllMain, it says that when the current process creates a new thread, the system calls the entry-point function of all DLLs currently attached to the process. Recall that we need to load the Easy Anti-Cheat (EAC) DLL regardless of whether we want to play in matchmaking because the EAC module calls CreateGameClient and makes the GameClientInterface.
In the previous post, however, we already figured out how to run the game without Anti-Cheat. In the next posts, I will explain how I found each of the offsets that I'll be using to make the aimbot.Īn aimbot is a cheat, and the game developers are within their rights to ban us if they detect that we are cheating. This post will be about tools and techniques for reversing the game.
In the past, I only looked at Source Engine games, so it was very exciting and fun to work with Unreal Engine 4. Since my last post, I have been reversing Halo: The Master Chief Collection game in order to find the functions and offsets needed to make an aimbot.
It is the entry in the column labeled "Base", which is left of the mcc-win64-shipping.exe entry.) See this function in IDA by subtracting the address of this function from the base address of MCC-Win64-Shipping.exe. Technically, there is another function that runs just before we return. These instructions just clean up the stack, so that means if we don't take the jump, then we immediately return 0. There is an unconditional jump after that instruction, which takes us to the line right after the line that has the comment "return 1 (success)". The instruction directly after the je is executed if we don't take the jump. Now the question is, do we want to take the jump? (In some disassemblers, the instruction will be disassembled into jz for jump zero instead of je.) This means that if SteamAPI_RestartAppIfNecessary returned 0, then we will take the jump. On the line after the test, (where I commented "jmp if returned false"), the je instruction means "jump if equal", and it will jump if the Zero flag is set. That means the program is testing whether SteamAPI_RestartAppIfNecessary returned 0. AL is the lower 16-bits of that register. Recall that _fastcall convention places the return value in the RAX register. (See here for the reason why: (x86_instruction)) The instruction test al, al sets the Zero flag if the value in AL is zero. The callstack tells us where execution will return after executing the function, so that means the instruction above the highlighted line is the instruction that actually called the function.