We're giving away Borderlands 3 gift key. Click here!

Just Cause 4 [Engine:APEX]

Upload your cheat tables here (No requests)
User avatar
SunBeam
Administration
Administration
Posts: 2819
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 1202

Just Cause 4 [Engine:APEX]

Post by SunBeam » Tue Dec 11, 2018 12:19 am

[ 19 Dec 2018 - Update #2 ]

Been studying this for a while; finally figured it out. The table's been updated with a script that lets you run all of these:

Code: Select all

ply.vehicle.burn -- sets on fire the vehicle you're in
ply.input.disable -- does nothing
ply.input.disable_except_look -- does nothing
ply.input.enable -- does nothing
ply.jesus.enable -- enables god mode
ply.jesus.disable -- disables god mode
ply.jesus.toggle -- toggles god mode
ply.ragdoll_and_stumble.enable
ply.ragdoll_and_stumble.disable
ply.jumping.enable -- does nothing
ply.jumping.disable -- does nothing
ply.grapple.enable -- does nothing
ply.grapple.disable -- does nothing
ply.weapon_pickup.enable -- does nothing
ply.weapon_pickup.disable -- does nothing
ply.pda.enable -- does nothing
ply.pda.disable -- does nothing
ply.ammo.givemax -- replenishes all ammo to max (creates an invisible beacon)
ply.explosives.remove_all -- does nothing
equipweapon -- equips given weapon
ply.pause -- player vanishes; camera locked
ply.unpause -- restores above
ply.unlimitedammo.enable -- enables unlimited magazine ammo (infinite symbol @ bottom-left)
ply.unlimitedammo.disable -- disables the above
ply.unequipweapon -- unequips current weapon
ply.health.takedamage -- damages player
ply.health.takedamage.track_event
ply.check_achievement.sanctuary -- does nothing
ply.check_achievement.i_can_show_you_the_world -- enables this achievement (reveal map?)
ply.award_achievement.i_can_see_my_house_from_here -- enables this achievement (reveal map?)
moon_gravity_on -- enables weird pull gravity (happens on jump)
moon_gravity_off -- disables the above
Image

JustCause4.CT
1.1
(25.86 KiB) Downloaded 520 times

Note not all have an effect; also, engine might disable them when you move from game world to main menu and backwards.. or if a map loads or something.

BR,
Sun

[ 12 Dec 2018 - Update #1 ]

Added the table:

Image

JustCause4.CT
1.0
(20.42 KiB) Downloaded 434 times

[ 11 Dec 2018 - First Release ]

Hello folks.

Started a bit of digging of my own in this engine; can see it's not as modular as Anvil or Dunia, but resembles something I've seen in Shadow of the Tomb Raider (or any in the series) or Dark Souls 3. Am guessing engine modules can be shared or SDK adapted from one title to another, under the same umbrella, the difference being the graphics engine; which pretty much ends-up naming the whole product. Like APEX engine here.

I'm using the CPY version for the purpose of this topic; alongside: Cheat Engine and x64dbg.

So, ran the game, dumped it to disk and found all string references. Checking through I found these:

Image

Choosing one of them and following it in disassembler led me to find even more:

Image

Heard someone was looking for gravity :)

Alright. All nice and dandy looking, but still how to execute such commands or how to even open up a console in-game? Well.. first things first. I initially checked the function with all those command references; and by "checked" I mean setting a breakpoint at its prologue and testing if x64dbg breaks on it in various moments of time. First moment in time: launching the game through the debugger. Why like that.. because I had a feeling the module gets initialized at run-time. And yes, x64dbg did break and I could trace the code. Another moment in time when the function might break is when you enter or leave the game world. But that didn't work out. So.. it only happens when you run the game from x64dbg.

I then wanted to know who CALLs this function; so I found who:

Image

The reason I already have some breaks in there is I've progressed more with the analysis that I now know which spots to break on :) The logic of the above function is this: past the "MOV ECX, 0xB28" instruction + the CALL a block of memory is allocated/initialized. This will represent our base pointer for the next part ;) In my case, the address is this:

Image

base_ptr == 0x00000000539A1400

With this as parameter, we then enter our known function:

Code: Select all

00000001409B0014 | BA 01000000  | MOV EDX,1                  |
00000001409B0019 | 48:8BC8      | MOV RCX,RAX                |
00000001409B001C | E8 2FEBFCFF  | CALL justcause4.14097EB50  | <-- call to your function
Let's continue from the prologue of 14097EB50. Trace code with F7 or F8 till you get here:

Image

Notice my RDI == base_ptr. Then we see this block:

Code: Select all

000000014097F434 | 48:8D97 B8090000  | LEA RDX,QWORD PTR DS:[RDI+9B8]    |
000000014097F43B | 48:8BCF           | MOV RCX,RDI                       |
000000014097F43E | E8 7D0E70FF       | CALL justcause4.1400802C0         |
000000014097F443 | 41:B1 01          | MOV R9B,1                         |
000000014097F446 | 41:B8 FF000000    | MOV R8D,FF                        |
000000014097F44C | 48:8D15 B54B2901  | LEA RDX,QWORD PTR DS:[141C14008]  | 0000000141C14008:"ply.input.disable"
000000014097F453 | 48:8D8F B8090000  | LEA RCX,QWORD PTR DS:[RDI+9B8]    |
000000014097F45A | E8 11A470FF       | CALL justcause4.140089870         |
So first offset in base_ptr that will be processed is 0x9B8. Let's take a look there, in memory:

Image

Once we get past the CALL at 14097F45A, we see this:

Image

Well, that to me looks like a pointer. If we adjust the display to show addresses, we see this:

Image

Execute the function till the RET and then check your block:

Image

The reason I told you to do that is the fact that I dumped the list of correspondences, string to offset:

Code: Select all

+9B8 -> 0000000141C14008:"ply.input.disable"
+9C0 -> 0000000141C14020:"ply.input.disable_except_look"
+9B0 -> 0000000141C14040:"ply.input.enable"
+9C8 -> 0000000141C14058:"ply.jesus.enable"
+9D0 -> 0000000141C14070:"ply.jesus.disable"
+9D8 -> 0000000141C14088:"ply.jesus.toggle"
+9E0 -> 0000000141C140A0:"ply.ragdoll_and_stumble.enable"
+9E8 -> 0000000141C140C0:"ply.ragdoll_and_stumble.disable"
+9F0 -> 0000000141BAD320:"ply.jumping.enable"
+9F8 -> 0000000141C140E0:"ply.jumping.disable"
+A00 -> 0000000141C140F8:"ply.grapple.enable"
+A08 -> 0000000141C14110:"ply.grapple.disable"
+A10 -> 0000000141C14128:"ply.weapon_pickup.enable"
+A18 -> 0000000141C14148:"ply.weapon_pickup.disable"
+A20 -> 0000000141C14168:"ply.pda.enable"
+A28 -> 0000000141C14178:"ply.pda.disable"
+AE0 -> 0000000141C14188:"ply.inventory.give"
+A30 -> 0000000141C141A0:"equipweapon"
+A38 -> 0000000141C141B0:"unequipweapon"
+A40 -> 0000000141C141C0:"ply.unequipweapon"
+A48 -> 0000000141C141D8:"ply.vehicle.burn"
+A50 -> 0000000141C141F0:"ply.pause"
+A58 -> 0000000141C14200:"ply.unpause"
+A60 -> 0000000141C14210:"freeze_frames"
+AC0 -> 0000000141C14220:"ply.unlimitedammo.enable"
+AC8 -> 0000000141C14240:"ply.unlimitedammo.disable"
+AE0 -> 0000000141C14260:"ply.health.takedamage"
+AD8 -> 0000000141C14278:"ply.health.takedamage.track_event"
+A78 -> 0000000141C08DE0:"ply.ammo.givemax"
+AF0 -> 0000000141C142A0:"ply.check_achievement.sanctuary"
+AF8 -> 0000000141C142C0:"ply.check_achievement.i_can_show_you_the_world"
+B00 -> 0000000141C142F0:"ply.award_achievement.i_can_see_my_house_from_here"
+A70 -> 0000000141C14328:"ply.explosives.remove_all"
+B08 -> 0000000141C14350:"moon_gravity_on"
+B10 -> 0000000141C14360:"moon_gravity_off"
So far so good; but what do we do now?.. Well, we have a table of pointers. Let's break one of them and see if it gets accessed sometime in-game :P And you'll find that it is. When:
  • you are at main menu and hit CONTINUE or NEW GAME
  • you're in-game and hit Escape, then RETURN TO MAIN MENU
Backtracing from the on-access instruction will land you here:

Image

Notice those offsets? ;) Also notice those TEST AL,AL instructions? First test of mine was to see when the function breaks, which of those CALLs returns 1 (TRUE). That will tell you which command got executed. So.. when you hit CONTINUE at main menu, this location will return TRUE:

Code: Select all

00000001409A9543 | 48:8D93 F0090000  | LEA RDX,QWORD PTR DS:[RBX+9F0]  |
00000001409A954A | 48:8BCF           | MOV RCX,RDI                     |
00000001409A954D | E8 3EAD6DFF       | CALL justcause4.140084290       |
00000001409A9552 | 84C0              | TEST AL,AL                      |
00000001409A9554 | 0F85 490B0000     | JNE justcause4.1409AA0A3        |
If you now check the table above, you'll find that 0x9F0 corresponds to "ply.jumping.enable". So when you move from main menu to game world, this is executed. Thing is past the TEST there's no other code execution, so function just exits. You can view this execution as a "do nothing".

Now, when you hit RETURN TO MAIN MENU and the LOADING animation starts, function breaks and this one returns TRUE:

Code: Select all

00000001409A947E | 48:8D93 D0090000  | LEA RDX,QWORD PTR DS:[RBX+9D0]   |
00000001409A9485 | 48:8BCF           | MOV RCX,RDI                      |
00000001409A9488 | E8 03AE6DFF       | CALL justcause4.140084290        |
00000001409A948D | 84C0              | TEST AL,AL                       |
00000001409A948F | 74 1D             | JE justcause4.1409A94AE          |
00000001409A9491 | 80BB 28030000 00  | CMP BYTE PTR DS:[RBX+328],0      |
00000001409A9498 | 0F84 050C0000     | JE justcause4.1409AA0A3          |
00000001409A949E | 33D2              | XOR EDX,EDX                      |
00000001409A94A0 | 48:8B4B 68        | MOV RCX,QWORD PTR DS:[RBX+68]    |
00000001409A94A4 | E8 6703B3FF       | CALL justcause4.1404D9810        |
00000001409A94A9 | E9 F50B0000       | JMP justcause4.1409AA0A3         |
0x9D0 == "ply.jesus.disable".

So.. what if I force the code flow to run something else when I hit CONTINUE? :P Like "ply.unlimitedammo.enable". Let's see what happens.

Code: Select all

00000001409A9552 | 84C0           | TEST AL,AL                | <-- break here
00000001409A9554 | 0F85 490B0000  | JNE justcause4.1409AA0A3  |
Break at the location I indicated. Then change AL from 1 to 0. Trace till you get here:

Code: Select all

00000001409A9CEA | 48:8D93 C00A0000  | LEA RDX,QWORD PTR DS:[RBX+AC0]  |
00000001409A9CF1 | 48:8BCF           | MOV RCX,RDI                     |
00000001409A9CF4 | E8 97A56DFF       | CALL justcause4.140084290       |
00000001409A9CF9 | 84C0              | TEST AL,AL                      | <-- break here
00000001409A9CFB | 74 10             | JE justcause4.1409A9D0D         |
00000001409A9CFD | B2 01             | MOV DL,1                        |
00000001409A9CFF | 48:8B4B 68        | MOV RCX,QWORD PTR DS:[RBX+68]   |
00000001409A9D03 | E8 A843B3FF       | CALL justcause4.1404DE0B0       |
00000001409A9D08 | E9 96030000       | JMP justcause4.1409AA0A3        |
Remember that 0xAC0 offset? :P Let's try and understand what happens with the code here, past the JE: RDX is set to 1 (MOV DL,1) so we have 2nd parameter set; we then see RCX is set to [RBX+68], so that gives us the 1st parameter. If you recall, the standard x64 CALL convention uses the registers as parameters to functions in this order: RCX,RDX,R8,R9. We have 2 out of 4. So 2 parameters. In pseudo-C, we have this: sub_1404DE0B0( qword [RBX+68], bool DL ); But who is RCX? Easy to find out, by checking the member-functions vtable :) Will explain in what follows:

Image

My RCX is 0x00000000AC880000. Follow that in dump, then enter the first pointer you see there; the one at 0x0 offset. Once you do, you will see a list of addresses, then this:

Image

So you're looking at a CCharacter-type structure. Some might call it a class :P

Let's see what happens in our sub_1404DE0B0:

Code: Select all

00000001404DE0B0 | E9 BB686108    | JMP justcause4.148AF4970        |
..
0000000148AF4970 | 8891 00220000  | MOV BYTE PTR DS:[RCX+2200],DL   |
0000000148AF4976 | C3             | RET                             |
So, at offset 0x2200 in CCharacter there's a BOOL. Its current value is 0. If you recall, our DL is 1. So the function turns that BOOL from 0 to 1. OK, so I ran the code and game's resumed. What did just happen? o_O Well.. go in-game :D

Image

That concludes the proof of concept. Wanna do more? Follow what I wrote above and you'll be fine. Or wait for my table.

BR,
Sun

P.S.: There are no results I could find on google regarding the Just Cause series and cheats/console commands (e.g.: search for "ply.unlimitedammo.enable" or variations; see if you find it). Aside from trainers, there's no research I could find being posted someplace. So.. I get to say "you know where you read it first". And save the date :) I'll keep an eye out for any tables/trainers using the stuff I detail here, surfacing after this article's been aired.

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

Re: Just Cause 4 [Engine:APEX]

Post by SunBeam » Tue Dec 11, 2018 1:22 am

Adding more to it as I progress:

Code: Select all

JustCause4.exe+965D125 - 48 8B 0D ECA83EF9     - mov rcx,[JustCause4.exe+2A47A18] { [0305A710] } // CWorld :P
JustCause4.exe+965D12C - 48 89 DA              - mov rdx,rbx
JustCause4.exe+965D12F - 48 8B 01              - mov rax,[rcx]
JustCause4.exe+965D132 - FF 50 30              - call qword ptr [rax+30]

Code: Select all

JustCause4.exe+9662E64 - 48 8B 0D A53B3EF9     - mov rcx,[JustCause4.exe+2A46A10] { [3E000000] } // CGameObjectManager
JustCause4.exe+9662E6B - 49 89 D0              - mov r8,rdx
JustCause4.exe+9662E6E - 31 D2                 - xor edx,edx

Code: Select all

JustCause4.exe+894B510 - 48 8B 05 39DD10FA     - mov rax,[JustCause4.exe+2A59250] { [397910C0] } // main_ptr
JustCause4.exe+894B517 - 48 85 C0              - test rax,rax
JustCause4.exe+894B51A - 74 04                 - je JustCause4.exe+894B520
JustCause4.exe+894B51C - 48 8B 40 30           - mov rax,[rax+30] // "base_ptr" from above article
JustCause4.exe+894B520 - 48 85 C0              - test rax,rax
JustCause4.exe+894B523 - 74 05                 - je JustCause4.exe+894B52A
JustCause4.exe+894B525 - 48 8B 40 68           - mov rax,[rax+68] // CCharacter :P -- the player
JustCause4.exe+894B529 - C3                    - ret 
JustCause4.exe+894B52A - C3                    - ret 
What's the name of player? o_O Inspect "base_ptr"`s memory :P

Image

Code: Select all

JustCause4.exe+2399A6 - 48 8B 05 131E7E02     - mov rax,[JustCause4.exe+2A1B7C0] { [0AC29EC0] } // CClock
JustCause4.exe+2399AD - 48 8B 90 98000000     - mov rdx,[rax+00000098]
JustCause4.exe+2399B4 - 48 C1 E2 07           - shl rdx,07 { 7 }
JustCause4.exe+2399B8 - 41 B8 80000000        - mov r8d,00000080 { 128 }
JustCause4.exe+2399BE - 66 41 23 D0           - and dx,r8w
JustCause4.exe+2399C2 - 0FB7 C1               - movzx eax,cx
JustCause4.exe+2399C5 - 66 41 23 C0           - and ax,r8w
JustCause4.exe+2399C9 - 66 3B C2              - cmp ax,dx
When was the executable built? o_O

Code: Select all

JustCause4.exe+A78C0D2 - 48 8B 0D EFF40FF8     - mov rcx,[JustCause4.exe+288B5C8] { [0AC162C0] } // follow this in dump
JustCause4.exe+A78C0D9 - E8 E2D2F4F5           - call JustCause4.exe+6D93C0
JustCause4.exe+A78C0DE - 84 C0                 - test al,al
Image

User avatar
BooBoo
Fearless Donors
Fearless Donors
Posts: 527
Joined: Sat May 06, 2017 2:28 pm
Reputation: 115

Re: Just Cause 4 [Engine:APEX]

Post by BooBoo » Tue Dec 11, 2018 1:36 am

Jesus :D, good one. Keep up the good work SB.

User avatar
teinousi
Expert Cheater
Expert Cheater
Posts: 238
Joined: Wed Mar 29, 2017 10:19 am
Reputation: 23

Re: Just Cause 4 [Engine:APEX]

Post by teinousi » Tue Dec 11, 2018 4:39 am

SunBeam wrote:
Tue Dec 11, 2018 1:22 am
I think , just think , u need to make a video to tell what r u doing of those stuff and how it works , because everything u make is not everyone knowadge :cry:

KS212
Expert Cheater
Expert Cheater
Posts: 653
Joined: Fri Mar 03, 2017 5:29 pm
Reputation: 37

Re: Just Cause 4 [Engine:APEX]

Post by KS212 » Tue Dec 11, 2018 4:23 pm

I'd probably say wait for Squeenix to actually fix the game before digging into it further, hehe. Also one reason you can't find anything about JC4 console commands or what not is everyone is too busy crying about water textures :P

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

Re: Just Cause 4 [Engine:APEX]

Post by SunBeam » Tue Dec 11, 2018 5:31 pm

I played a bit.. game is just pure crap.

User avatar
jonaaa
Expert Cheater
Expert Cheater
Posts: 144
Joined: Thu Apr 06, 2017 6:08 am
Reputation: 31

Re: Just Cause 4 [Engine:APEX]

Post by jonaaa » Tue Dec 11, 2018 5:38 pm

SunBeam wrote:
Tue Dec 11, 2018 5:31 pm
I played a bit.. game is just pure crap.
Yeah, JC2 is much better.

jonasbeckman
Expert Cheater
Expert Cheater
Posts: 239
Joined: Sat May 06, 2017 1:26 pm
Reputation: 11

Re: Just Cause 4 [Engine:APEX]

Post by jonasbeckman » Tue Dec 11, 2018 7:17 pm

Well if Apex is going to be fairly similar under the hood then the research here might help with other upcoming games from Avalanche, which I guess is mainly Rage 2 though since Avalanche New York worked on Just Cause 3 and Just Cause 4 here published under Square Enix and then Avalanche Sweden was the studio behind Just Cause, Just Cause 2, Mad Max (Published under WB Games.) and the upcoming Rage 2 (Published under Bethesda and also with aid from idSoftware.) then the shared code might be a bit varied although key functions might still be similar enough to help do the same for their upcoming titles. :)

Beyond these there's also The Hunter, The Hunter Call of the Wild and Generation Zero.


Anyways, game is going to need quite a bit of patching due to the state it launched in (Repeat of Just Cause 3 kinda.) with the first 1.1 update coming out in a few weeks although fixing the game bugs, graphical glitches and stability problems isn't going to help the actual gameplay and the changes from the earlier Just Cause games moving away from chaos and the mechanic to these defend and wait missions and removing things like explosive throwing items like grenades and C4 and even the side arm is gone in Just Cause 4 for some reason.

Nice bit of work though, it's always fun to read up on these things and how they were accomplished. :)

skywolf23
Expert Cheater
Expert Cheater
Posts: 81
Joined: Mon Nov 13, 2017 3:00 pm
Reputation: 1

Re: Just Cause 4 [Engine:APEX]

Post by skywolf23 » Tue Dec 11, 2018 8:43 pm

eh i dont mind the gameplay, the rockets and balloons are hella fun still, story sofar is low key, the water though...god i cant stand being in or near water them ps2 gfx yo. ;p

hopefully they fix this game up.

Asuma
Cheater
Cheater
Posts: 35
Joined: Thu Mar 08, 2018 9:39 am
Reputation: 4

Re: Just Cause 4 [Engine:APEX]

Post by Asuma » Tue Dec 11, 2018 9:21 pm

I'll just wait for the Table. Nice information though.

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

Re: Just Cause 4 [Engine:APEX]

Post by SunBeam » Wed Dec 12, 2018 1:31 am

^ Will do. After Prague :P

If you remember this piece of code:

Code: Select all

000000014894B510 | 48:8B05 39DD10FA   | MOV RAX,QWORD PTR DS:[142A59250]  |
000000014894B517 | 48:85C0            | TEST RAX,RAX                      |
000000014894B51A | 74 04              | JE justcause4.14894B520           |
000000014894B51C | 48:8B40 30         | MOV RAX,QWORD PTR DS:[RAX+30]     |
000000014894B520 | 48:85C0            | TEST RAX,RAX                      |
000000014894B523 | 74 05              | JE justcause4.14894B52A           |
000000014894B525 | 48:8B40 68         | MOV RAX,QWORD PTR DS:[RAX+68]     | // read our player pointer
000000014894B529 | C3                 | RET                               |
000000014894B52A | C3                 | RET                               |
I got curios where it's actually initialized. And found the spot here (this break occurs right after clicking OK at main menu):

Code: Select all

00000001409ACC90 | 48:8BC4              | MOV RAX,RSP                                 |
00000001409ACC93 | 55                   | PUSH RBP                                    |
00000001409ACC94 | 56                   | PUSH RSI                                    |
00000001409ACC95 | 57                   | PUSH RDI                                    |
00000001409ACC96 | 41:54                | PUSH R12                                    |
00000001409ACC98 | 41:55                | PUSH R13                                    |
00000001409ACC9A | 41:56                | PUSH R14                                    |
00000001409ACC9C | 41:57                | PUSH R15                                    |
00000001409ACC9E | 48:8DA8 38FBFFFF     | LEA RBP,QWORD PTR DS:[RAX-4C8]              |
00000001409ACCA5 | 48:81EC 90050000     | SUB RSP,590                                 |
00000001409ACCAC | 48:C745 20 FEFFFFFF  | MOV QWORD PTR SS:[RBP+20],FFFFFFFFFFFFFFFE  |
00000001409ACCB4 | 48:8958 20           | MOV QWORD PTR DS:[RAX+20],RBX               |
00000001409ACCB8 | 0F2970 B8            | MOVAPS XMMWORD PTR DS:[RAX-48],XMM6         |
00000001409ACCBC | 48:8B05 BD78F801     | MOV RAX,QWORD PTR DS:[142934580]            |
00000001409ACCC3 | 48:33C4              | XOR RAX,RSP                                 |
00000001409ACCC6 | 48:8985 78040000     | MOV QWORD PTR SS:[RBP+478],RAX              |
00000001409ACCCD | 4D:8BF9              | MOV R15,R9                                  |
00000001409ACCD0 | 4D:8BE8              | MOV R13,R8                                  |
00000001409ACCD3 | 48:8BF2              | MOV RSI,RDX                                 | rdx:"Rico"
00000001409ACCD6 | 48:8BF9              | MOV RDI,RCX                                 |
00000001409ACCD9 | 48:81C1 40010000     | ADD RCX,140                                 |
00000001409ACCE0 | 41:B8 04000000       | MOV R8D,4                                   |
00000001409ACCE6 | 48:8D15 87762601     | LEA RDX,QWORD PTR DS:[141C14374]            | rdx:"Rico", 0000000141C14374:"Rico"
00000001409ACCED | E8 4EC76BFF          | CALL justcause4.140069440                   |
00000001409ACCF2 | 0FB685 F0040000      | MOVZX EAX,BYTE PTR SS:[RBP+4F0]             |
00000001409ACCF9 | 8887 28030000        | MOV BYTE PTR DS:[RDI+328],AL                |
00000001409ACCFF | 4C:897F 68           | MOV QWORD PTR DS:[RDI+68],R15               | <-- write
However, at that location R15 is already initialized and used in the processing. So I back-traced. After a bit of dilly-dallying I found that this loop happens after some initialization occurred:

Code: Select all

000000014099A674 | 49:8B45 08         | MOV RAX,QWORD PTR DS:[R13+8]      |
000000014099A678 | 49:8B5D 10         | MOV RBX,QWORD PTR DS:[R13+10]     |
000000014099A67C | 48:3BC3            | CMP RAX,RBX                       |
000000014099A67F | 74 69              | JE justcause4.14099A6EA           |
000000014099A681 | 4C:8BF0            | MOV R14,RAX                       |
000000014099A684 | 0F1F40 00          | NOP DWORD PTR DS:[RAX],EAX        |
000000014099A688 | 0F1F8400 00000000  | NOP DWORD PTR DS:[RAX+RAX],EAX    |
000000014099A690 | 48:8B38            | MOV RDI,QWORD PTR DS:[RAX]        |
000000014099A693 | 48:8D96 F0000000   | LEA RDX,QWORD PTR DS:[RSI+F0]     |
000000014099A69A | 48:8BCF            | MOV RCX,RDI                       |
000000014099A69D | E8 9E1A8AFF        | CALL justcause4.14023C140         |
000000014099A6A2 | 48:8B07            | MOV RAX,QWORD PTR DS:[RDI]        |
000000014099A6A5 | 48:8D96 F0000000   | LEA RDX,QWORD PTR DS:[RSI+F0]     |
000000014099A6AC | 48:8BCF            | MOV RCX,RDI                       |
000000014099A6AF | FF50 30            | CALL QWORD PTR DS:[RAX+30]        |
000000014099A6B2 | 48:8BCF            | MOV RCX,RDI                       |
000000014099A6B5 | E8 A63990FF        | CALL justcause4.14029E060         |
000000014099A6BA | 48:8B07            | MOV RAX,QWORD PTR DS:[RDI]        |
000000014099A6BD | 48:8D15 6CA71901   | LEA RDX,QWORD PTR DS:[141B34E30]  |
000000014099A6C4 | 48:8BCF            | MOV RCX,RDI                       |
000000014099A6C7 | FF50 10            | CALL QWORD PTR DS:[RAX+10]        |
000000014099A6CA | 84C0               | TEST AL,AL                        |
000000014099A6CC | 74 10              | JE justcause4.14099A6DE           |
000000014099A6CE | 48:8D4F F0         | LEA RCX,QWORD PTR DS:[RDI-10]     |
000000014099A6D2 | 48:85C9            | TEST RCX,RCX                      |
000000014099A6D5 | 74 07              | JE justcause4.14099A6DE           |
000000014099A6D7 | B2 01              | MOV DL,1                          |
000000014099A6D9 | E8 E2FBB3FF        | CALL justcause4.1404DA2C0         |
000000014099A6DE | 49:8D46 10         | LEA RAX,QWORD PTR DS:[R14+10]     |
000000014099A6E2 | 4C:8BF0            | MOV R14,RAX                       |
000000014099A6E5 | 48:3BC3            | CMP RAX,RBX                       |
000000014099A6E8 | 75 A6              | JNE justcause4.14099A690          |
In this loop, there's this check:

Code: Select all

000000014099A6C7 | FF50 10            | CALL QWORD PTR DS:[RAX+10]        |
000000014099A6CA | 84C0               | TEST AL,AL                        |
000000014099A6CC | 74 10              | JE justcause4.14099A6DE           |
000000014099A6CE | 48:8D4F F0         | LEA RCX,QWORD PTR DS:[RDI-10]     |
000000014099A6D2 | 48:85C9            | TEST RCX,RCX                      |
Leading to this:

Code: Select all

0000000148AB4FB0 | 8B02         | MOV EAX,DWORD PTR DS:[RDX]   |
0000000148AB4FB2 | 3D A6CAB7D5  | CMP EAX,D5B7CAA6             |
0000000148AB4FB7 | 74 07        | JE justcause4.148AB4FC0      |
0000000148AB4FB9 | 3D CC95B015  | CMP EAX,15B095CC             |
0000000148AB4FBE | 75 03        | JNE justcause4.148AB4FC3     |
0000000148AB4FC0 | B0 01        | MOV AL,1                     |
0000000148AB4FC2 | C3           | RET                          |
When [RDX] == 0xD5B7CAA6, we're looking at our player structure (Rico) :P What's even more interesting is the next bit:

Code: Select all

000000014099A6D7 | B2 01              | MOV DL,1                          |
000000014099A6D9 | E8 E2FBB3FF        | CALL justcause4.1404DA2C0         |
Which leads to this piece:

Code: Select all

00000001404DA2C0 | E9 FB6D6108     | JMP justcause4.148AF10C0        |
..
0000000148AF10C0 | 8891 A8290000   | MOV BYTE PTR DS:[RCX+29A8],DL   |
0000000148AF10C6 | C3              | RET                             |
In translation: if [ptr+0x10] == 0xD5B7CAA6, then write 0x1 at [ptr+0x29A8]. Much like.. if player, then you know where to get that 0x1 flag :P (player - 1; enemy - 0). Something tells me enemy structures have a 0 at 0x29A8 :)

How does the above relate to our player pointer, you ask? Simple.. remember there's a pointer at 0x0 in this structure, leading to a member-functions vtable? Well, let's inspect it a bit. In my case, the pointer leads to 0xE15C8000:

Image

So the pointer to member-functions, found at 0x0 in this structure, is 0x141B515C0. If you follow it in memory, you'll find this list:

Image

What I did next was to check the member-functions one by one, starting from 0x0. What I know is the first function is a destructor, so skip it. Then inspect the others. I got as far as 0x20 offset when I saw this:

Image

Went there and..

Image

Remember that hardcoded DWORD -> 0xD5B7CAA6? :P Yeah, you get the idea now.

So there you have it; several more ways to determine our player ;)

BR,
Sun

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

Re: Just Cause 4 [Engine:APEX]

Post by SunBeam » Wed Dec 12, 2018 3:21 am

This would be where the player coordinates are written to:

Code: Select all

JustCause4.exe+4EF301 - 48 8D 8B B8AF0200     - lea rcx,[rbx+0002AFB8] // RBX here is CCharacter_Rico
JustCause4.exe+4EF308 - F3 0F10 56 20         - movss xmm2,[rsi+20]
JustCause4.exe+4EF30D - 48 8B D3              - mov rdx,rbx
JustCause4.exe+4EF310 - E8 2BDA0300           - call JustCause4.exe+52CD40 // write
Then:

Code: Select all

JustCause4.exe+8DC2DDD - 48 8D 55 C0           - lea rdx,[rbp-40]
JustCause4.exe+8DC2DE1 - 48 89 D9              - mov rcx,rbx
JustCause4.exe+8DC2DE4 - E8 A7D074F7           - call JustCause4.exe+50FE90
JustCause4.exe+8DC2DE9 - 0F10 00               - movups xmm0,[rax]
JustCause4.exe+8DC2DEC - 0F11 87 08010000      - movups [rdi+00000108],xmm0
JustCause4.exe+8DC2DF3 - 0F10 48 10            - movups xmm1,[rax+10]
JustCause4.exe+8DC2DF7 - 0F11 8F 18010000      - movups [rdi+00000118],xmm1
JustCause4.exe+8DC2DFE - 0F10 40 20            - movups xmm0,[rax+20]
JustCause4.exe+8DC2E02 - 0F11 87 28010000      - movups [rdi+00000128],xmm0
JustCause4.exe+8DC2E09 - 0F10 48 30            - movups xmm1,[rax+30]
JustCause4.exe+8DC2E0D - 0F11 8F 38010000      - movups [rdi+00000138],xmm1     // <-- here
JustCause4.exe+8DC2E14 - 44 0F28 A4 24 40010000  - movaps xmm12,[rsp+00000140]

User avatar
GreenHouse
Table Makers
Table Makers
Posts: 246
Joined: Fri Oct 12, 2018 10:25 pm
Reputation: 197

Re: Just Cause 4 [Engine:APEX]

Post by GreenHouse » Wed Dec 12, 2018 10:23 pm

The game has a debug camera:
- scripts/camera/debug_cam.xpy
- scripts/camera/freefly.xpy (Inputs: camera_freefly/freefly_slower/toggle_freefly/toggle_freefly_camera)
- DebugCam1/DebugCam2/FreeFly/MovieCam/SoakFly

There may be a way to enable it.

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

Re: Just Cause 4 [Engine:APEX]

Post by SunBeam » Wed Dec 12, 2018 11:18 pm

Cielos will surely move faster than me figuring that ^ out. So I'll leave the noclip part to him; whenever he can, if he has the time to.

User avatar
Meltic
Expert Cheater
Expert Cheater
Posts: 51
Joined: Mon May 01, 2017 1:02 pm
Reputation: 1

Re: Just Cause 4 [Engine:APEX]

Post by Meltic » Fri Dec 14, 2018 8:45 pm

Woah! A debug camera for the game ? Has anybody tested it yet to see if it works ?

Post Reply

Who is online

Users browsing this forum: benny89, Bing [Bot], IkilledKennyx99, James Shane, killerkrok555, samsonng922, Vodos