Tower of Fantasy

Add topics here with methods, analysis, code snippets, mods etc. for a certain game that normally won't make it in the Tables or Requests sections.
Post Reply
User avatar
SunBeam
Administration
Administration
Posts: 4764
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 4403

Tower of Fantasy

Post by SunBeam »

Hello folks.

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:

Image

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:

Image

Then you want to get the data for a DEMO GAME which you can conveniently find in the Epic Games Launcher, in the Vault:

Image

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
..
}
That's why you "can't enable the console". That doesn't mean we can't create it artificially ;) We can.

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
Why go through all of this? Simple: ToF uses the same Engine build as the game that I just compiled. That means the CORE functions are going to be looking the same, more or less, and their ASM architecture will match 99.99%. That being said, you can copy a sequence of bytes from the prologue or body of a function in ShooterGame and scan for it in QRSL and you will find it. Given I was a good boy and also shipped in the .pdb file, you will now also know the NAME of the function.

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):

Image

Oh, gee, where or how can I find ProcessEvent?:

Image

Right-click it, Follow in Disassemble, select several bytes and Shift+C to copy them:

Image

Go to QRSL, press Ctrl+B, paste bytes, tick Entire Block:

Image

And voila, 1 result:

Image

Image

--

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:

Image

[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:

    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
    
    I scan for and hook the return from GetGamePlayers function. This aob works/worked on 90% of my UE4 games...

    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:

    Code: 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 )
    
    You can find the aobs laid out for you, waiting to be reused in other projects :P
  • There's an incipient hierarchy tree based on the hook I was mentioning above in the [ Debug ] section:

    Image
  • 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 :P (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:

    Image
  • Know some CVars? You can unrestrict them :P
  • 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:

Image

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:

Image

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:

Image

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:

Image

7) Now click "Structures" from the top menu and "Define new structure" and you will see these:

Image

Image

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):

Image

Image

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

IIIczumhzIII
What is cheating?
What is cheating?
Posts: 1
Joined: Wed Mar 30, 2022 5:48 am
Reputation: 0

Re: Tower of Fantasy

Post by IIIczumhzIII »

thanks for the guide im newbie want to learn hacks game

remair33
What is cheating?
What is cheating?
Posts: 3
Joined: Thu Oct 27, 2022 6:50 am
Reputation: 0

Re: Tower of Fantasy

Post by remair33 »

My initialization does not start, I use version CE 7.42, what could be the problem? Or does this method not work on 2.0 version?

User avatar
SunBeam
Administration
Administration
Posts: 4764
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 4403

Re: Tower of Fantasy

Post by SunBeam »

This is a proof of concept topic. If you're only interested in using tables for cheating, then please look for other means. Cheers.

Post Reply

Who is online

Users browsing this forum: No registered users