First-up, been reading left and right and it seems some people are having a hard time "reading" or "talking" in UE4 language. Not to mention the poor way in which they're transmitting this information to the public. Before this game, I learned a lot about UE4 the hard and tedious way: download the source code, compile the editor, compile a legacy game (ShooterGame) with debug symbols and f*ck around. That's how I also learned of the internal framework, how objects intertwine and a sh!t ton out of the public source-code. So those of you who think hacking UE4 games revolves around dumping Objects and SDKs.. know that it's not about that. That is merely the last part you'd get to, after a quite interesting learning path. So no, it's all about learning and getting to know Unreal Engine's internal structure. Once you master that, you're good to go. Why? Because every other game will revolve around same principles.
Saddle up, it's going to be a BIG post.
--
HOW TO BUILD THE ENGINE (for local testing, learning, etc.)
You can get the source code from Epic's github, after signing up and checking their rules below:
Download the [Link] locally. Instructions on how to build the Editor on MSVS2017 are here: [Link] ("Getting up and running" section). You can skip step 1, as you've already downloaded the source-code. And step 2, if you've already installed MSVS2017. From 3 to 6, that's your aim.
Why 4.26? Because that's what ToF is using:
Then you want to get the data for a DEMO GAME which you can conveniently find in the Epic Games Launcher, in the Vault:
I personally prefer and use the ShooterGame project.
Things to be aware of:
1) MSVS will recompile the Engine at least 1 time for each type of build you want to produce. If you want a Development build, then MSVS will build the binaries for that type. If you want a Shipping build, then MSVS will build the binaries for that type as well. Each type requires a full build at least 1 time. People who whine "I changed 1 little thing and Engine is recompiling in full again" don't know what they're doing or maybe are not aware of this aspect.
2) Always use the "Build" option in MSVS (not "Rebuild"). MSVS will do incremental builds that way and recompile only what's affected by your changes in the source code.
On my PC it took over 1-2 hours to build everything. While at it, before the build process, I've set to 1 the ALLOW_CONSOLE and ALLOW_CONSOLE_IN_SHIPPING defines in Build.h. Why? Cuz we want the console available to use in our Shipping build of the game. BY DEFAULT ALL SHIPPING BUILDS HAVE THE CONSOLE CREATION CODE COMMENTED OUT:
Code: Select all
ULocalPlayer* UGameViewportClient::SetupInitialLocalPlayer(FString& OutError)
{
..
#if ALLOW_CONSOLE
// Create the viewport's console.
ViewportConsole = NewObject<UConsole>(this, GetOuterUEngine()->ConsoleClass);
// register console to get all log messages
GLog->AddOutputDevice(ViewportConsole);
#endif // !UE_BUILD_SHIPPING
..
}
So for those who are lazy f*cks, here's the compiled project with debug symbols and all. You can also play the game:
[Link] (642MB).
The game executable you want to fiddle with is in .\WindowsNoEditor\ShooterGame\Binaries\Win64 path:
- ShooterGame-Win64-Shipping.exe
- ShooterGame-Win64-Shipping.pdb
What does the above solve: "I think the function is called..", "how or where can I find ProcessEvent?", etc. If not even with this kind of help you won't make it, then I'm at a loss for words.
--
EXAMPLE OF CROSS-FINDING FUNCTIONS
Example (top is ShooterGame, bottom is QRSL):
Oh, gee, where or how can I find ProcessEvent?:
Right-click it, Follow in Disassemble, select several bytes and Shift+C to copy them:
Go to QRSL, press Ctrl+B, paste bytes, tick Entire Block:
And voila, 1 result:
--
KNOWLEDGE IS POWER
With the logic presented above plus many other additional tricks and static analysis, I was able to understand how UE4 works, why people dump Objects and Names, what dumping of that relies on, how it is done, devise a patch to hook almost ANY UE4 version so that I can get very fast to UObjects of interest with just a simple CE table.
So below, here's my table for this game with several critical CORE stuff that you will most definitely make use of. Note that NOT EVERYTHING is updated in there, as it's a work in progress. My aim isn't to play or hack ToF, but to expose as much as possible, so any with a little bit of brain can work their way out:
[Link]
Why is the table useful at this point in time? Let's open the [ Initialize ] script:
- You have a way to run your own staticFindObject:
Code: Select all
function staticFindObjectEx( sa, sb, sc ) local StaticFindObject = getAddressSafe( "StaticFindObject" ) if StaticFindObject == 0x0 then return 0 end local s, Class, InOuter, UObject = allocateMemory( 256 ), 0, 0, 0 if sb == nil and sc == nil then writeString( s, sa, true ) writeBytes( s + #sa * 2, 0 ) UObject = executeCodeEx( 0, nil, StaticFindObject, 0, -1, s, 1 ) elseif sc == nil then writeString( s, sa, true ) writeBytes( s + #sa * 2, 0 ) Class = executeCodeEx( 0, nil, StaticFindObject, 0, -1, s, 1 ) writeString( s, sb, true ) writeBytes( s + #sb * 2, 0 ) UObject = executeCodeEx( 0, nil, StaticFindObject, Class, -1, s, 0 ) else writeString( s, sa, true ) writeBytes( s + #sa * 2, 0 ) Class = executeCodeEx( 0, nil, StaticFindObject, 0, -1, s, 1 ) writeString( s, sb, true ) writeBytes( s + #sb * 2, 0 ) InOuter = executeCodeEx( 0, nil, StaticFindObject, 0, -1, s, 1 ) writeString( s, sc, true ) writeBytes( s + #sc * 2, 0 ) UObject = executeCodeEx( 0, nil, StaticFindObject, Class, InOuter, s, 0 ) end deAlloc( s ) return UObject end local t = staticFindObjectEx( "ObjectProperty", "Engine.Engine", "GameViewport" ) if t < 1 then stopExec( "'GameViewport' ObjectProperty not found." ) end
- There's one single hook you need to get the UObject relationship starting from LocalPlayer:
I scan for and hook the return from GetGamePlayers function. This aob works/worked on 90% of my UE4 games...Code: Select all
local _script = [[ define( Trampoline__01, Trampolines+00 ) define( Trampoline__02, Trampolines+10 ) ]]..[[[ENABLE] alloc( MyHooks, 0x1000 ) registersymbol( MyHooks ) label( FViewport__Draw_hook ) registersymbol( FViewport__Draw_hook ) label( FViewport__Draw_hookspot_orig ) registersymbol( FViewport__Draw_hookspot_orig ) label( LocalPlayer ) registersymbol( LocalPlayer ) label( GameViewportClient ) registersymbol( GameViewportClient ) label( Console ) registersymbol( Console ) label( PlayerController ) registersymbol( PlayerController ) label( CheatManager ) registersymbol( CheatManager ) label( PlayerCharacter ) registersymbol( PlayerCharacter ) .. .. MyHooks: db CC align 10 CC FViewport__Draw_hook: mov [LocalPlayer],rax mov rcx,[rax+70] mov [GameViewportClient],rcx mov rcx,[rcx+40] mov [Console],rcx mov rcx,[rax+30] test rcx,rcx je short @f mov [PlayerController],rcx mov rdx,[rcx+338] mov [CheatManager],rdx mov rcx,[rcx+250] test rcx,rcx je short @f mov [PlayerCharacter],rcx @@: FViewport__Draw_hookspot_orig: readmem( FViewport__Draw_hookspot, 7 ) jmp far FViewport__Draw_hookspot+7
Code: Select all
-- hook the return from GetGamePlayers local aob_in_FViewport_Draw = "488B40??4885C074??F680????????02" sl = aobScanEx( aob_in_FViewport_Draw ) if not sl or sl.Count < 1 then stopExec( "'aob_in_FViewport_Draw' not found." ) end t = tonumber( sl[0], 16 ) unregisterSymbol( "FViewport__Draw_hookspot" ) registerSymbol( "FViewport__Draw_hookspot", t, true )
- Then there's a sh!t ton of aobs that scan for critical UE4 stuff:
You can find the aobs laid out for you, waiting to be reused in other projectsCode: Select all
unregistersymbol( StaticFindObject ) unregistersymbol( FConsoleManager__ProcessUserConsoleInput_hookspot ) unregistersymbol( Static__Exec_patchspot ) unregistersymbol( UObject__CallFunctionByNameWithArguments_hookspot ) unregistersymbol( UPlayer__Exec_epilogue ) unregistersymbol( UPlayer__Exec_hookspot ) unregistersymbol( UPlayer__Exec_prologue ) unregistersymbol( AActor__Tick ) unregistersymbol( GameEngine__ViewportClient_offset ) unregistersymbol( UConsole__StaticClass ) unregistersymbol( FOutputDeviceRedirector__AddOutputDevice ) unregistersymbol( GetGlobalLogSingleton ) unregistersymbol( StaticConstructObject_Internal ) unregistersymbol( FStaticConstructObjectParameters__FStaticConstructObjectParameters ) unregistersymbol( FObjectInitializer__AssertIfInConstructor ) unregistersymbol( pszNewObjectString ) unregistersymbol( GEngine ) unregistersymbol( pszEngineString ) unregistersymbol( FViewport__Draw_hookspot )
- There's an incipient hierarchy tree based on the hook I was mentioning above in the [ Debug ] section:
- There is a script that enables the use of the SET command in the console, with the help of which you can manually set UProperty-es (e.g.: set Engine.Actor bCanBeDamaged True)
- There is a script that helps with hooking UPlayer::Exec so that when you pass it an UObject as context and run said function in the console, it will automatically be made executable (UFUNC_Exec) and allow the running of that command in the Class context of that object:
- Know some CVars? You can unrestrict them
- Lastly, if you're tired of seeing the smear of text in the Console, you can clear it out (I'm not 100% sure the offset is correct in that script; will need to check).
Cake-san
If you want a real time method to faster determine which UObject is at which offset in some other UObject, then this guy really nailed it:
Get Cake-san's awesome Basic UE4 Win64 Base Table
Make sure you download "Automate version Update 7.3" script. Not others. Why? There's been several fixes put into update, so it makes no sense to use older versions.
So.. let's say we use both my table and his in parallel:
[My table]:
< before everything, make sure you can actually access the game's memory space; won't talk about bypassing here, now >
1) Open table and run [ Initialize ] script.
2) Considering you are in-game, expand [ Debug ] section and LocalPlayer node. Take note of what you see there:
Note that your address will be different. It's normal. Just remember YOUR value from the red rectangle.
Cake-san's table:
1) Open table in another CE instance.
2) Select QRSL.exe game process.
3) Activate "Unreal Engine" script and wait for it to finish its job. You'll know when it's done processing, as the Lua Engine window will close and sub-scripts expand. Yes, it will take about 2-3 minutes. This is what you'll see:
4) Activate "Enable UE Structure Lookup" script.
5) Click Memory View, then "Tools" from the top menu, then "Dissect data/structures", so this will open up:
6) Remember that address from the red rectangle in my table? Switch to the other CE instance, double-click and copy it (or just move the window aside so you can see it). Back to Cake-san's table, paste it in the top input field:
7) Now click "Structures" from the top menu and "Define new structure" and you will see these:
So.. where's PlayerController in LocalPlayer, I hear?? Well, it's at offset 0x30. See.. not everything revolves around CheatGear and SDK dumping
Speaking of dumping..
8) Run this script, then check your Desktop (although the file should already open for you in Notepad):
There you have it, enjoy!
--
WARNING AHEAD
PROXIMA will take measures and enhance their anti-cheat so CE can't be used at all in the future. This has been the evolution of all anti-cheats and developers across time It will happen again. So please appreciate the learning path and having been taught useful things in this topic rather than lash out with "it's your fault PROXIMA patched everything", mkay? Cheers!
BR,
Sun