Halo Infinite

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.
User avatar
SunBeam
Administration
Administration
Posts: 4778
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 4408

Halo Infinite

Post by SunBeam »

Hello everyone,

Expanding on caliber1942's post and analysis, I decided to give this a go. I've played the game for a little bit (note that I don't want to hear or care about multi-player, so don't even bother; I'm playing the Campaign, offline), reminds me of MDK2 for some reason (the grubs, their SFX, dialogues, etc.).

Back on track, not sure how helpful this is gonna be, but hey, at least it might open up room for others to continue on it.

The first thing I usually do with any process (be it a game or not) that has any kinds of protection is to dump it. But to get there, some high level testing first. I recommend you first press Alt+Enter to send the game in windowed mode. Then exit the game so the setting is saved.

***

I've been using [Link] for a long time now as my Task Manager replacement. With that in mind, I've started the game and as soon as it started playing the intro, alt-tabbed, Ctrl+Alt+Del > Task Manager (which, in my case, starts Process Hacker 2) and this:

Image

Notice I've filtered the list for "halo" and found 2 processes derived from that string: "HaloInfinite.exe" and "DumpTool.exe". While writing this, I alt-tabbed back to Process Hacker 2 and saw this now:

Image

Notice the 2nd HaloInfinite.exe showed up. And yes, the game's frozen, just like Caliber mentioned. I also have Cheat Engine open so most likely it was detected.

If you double-click each of them you will see who the parent process is; who created that process:
  • DumpTool.exe - PID 11388 - has as parent HaloInfinite.exe
  • HaloInfinite[1].exe - PID 1172 - has as parent steam.exe (I ran the Steam shortcut on Desktop, which runs the game through Steam)
  • HaloInfinite[2].exe - PID 12896 - has as parent HaloInfinite[1].exe
I named them 1 and 2, so you know which is the original process.

The above is just informational, I wanted to see WTF is going on with just simple tools, non-invasive.

***

What I did next was to restart the game and as soon as the process starts, open Cheat Engine 7.1 (yes, I still use this version) -- or have it already open -- select HaloInfinite.exe from the Process List and PAUSE it:

Image

Why do you want to do this? Since the detection kicks in quite fast and the process hangs or crashes, you want to be able to catch it BEFORE this happens. What do I mean with "catch"? Put the process in a pause state where you can perform other operations on it. CE is the perfect tool for this, as it doesn't hog on the main thread, allowing you to ATTACH to the process with other tools ;)

***

I debug everything with [Link], so you might as well get it. This tool allows the use of plugins, which you might want to get as well. For anti-debug protections I use mostly ScyllaHide [url=[Link]]plugins[url]. With that in mind and Halo Infinite suspended in CE (paused), just fire x64dbg up and attach it to the HaloInfinite.exe process:

Image

Image

Since I have ScyllaHide active with these settings:

Image

The first thing I saw was this:

Image

Which means that API is hooked by none other than HaloInfinite.exe. Question: which OTHER APIs are hooked? ;) But we'll get to that in a minute.

Several other settings I have active, in case you want to try this:

Image

Image

So, let's dump it:

Image

Image

Image

Now we have a dump of the process, which can be opened statically in x64dbg or the process of your choice (IDA?) and inspected at will :)

***

So.. which other APIs are hooked by Halo Infinite? You'll have to close x64dbg, which will kill the game process. Back to CE, click the Pause button again so it un-pauses the already killed process (you will want to suspend it again). Start the game again, open process with CE and pause it. When done, let's use another feature almost no one talks about :) In CE, open Memory View and:

Image

Select the ones I marked and hit OK:

Image

You'll see this:

Image

The ones I highlighted are hooked by our game. Not necessarily by HaloInfinite.exe, but by *something* it spawned.

The ones that aren't highlighted are hooks from gameoverlayrenderer64.dll. How do I know? Let's pick LoadLibraryExW from the list. Double-click it:

Image

Image

Then press SPACE key on that line:

Image

Double-click another in that list and continue checking them out.

Back to the ones I've highlighted. Let's take the first one for a spin:

Image

Double-click and we're here:

Image

The reason I did that is so you see what happens next. We'll do this in the Patch list, right-clicking:

Image

What that action did was to restore the original API code. And we can see that in Memory View:

Image

Do the same with the rest.

So what we did so far was to unhook anything the game hooked, for any reason (I can tell you those hooks aren't for processing purposes, but for anti-debug). How does that help me with bypassing the anti-debug? It doesn't. You've learned how to unhook APIs :) Simple as that. Why it doesn't help you? Because the game will detect the APIs have been restored.

How does it detect this? Simple. Let's start with just one API, the first one: ntdll.RtlAddVectoredExceptionHandler. Once restored, go to its address in the dump section of Memory View (the bottom part, with bytes), right click the first byte and "Find out what accesses this address":

Image

What you need to be aware of:
  • if the game hangs while you do the above, you need to restart the process
  • you can use process suspension in CE (pause) at any given point in time
  • you can debug while the process is paused ('Find out what accesses this address' works to be activated with process paused!)
With that in mind, the moment you resume the game you'll see this in the debug window:

Image

Obviously that piece of code you see in the above isn't part of some normal process behavior. It's a scanner :) Now here's some idea that might break you skull: is this piece of code part of a THREAD you could kill?. And which thread? Well, just set a normal breakpoint on that line and resume the process. Bipity, boppity, bam:

Image

If you take a look at RAX register you can see what it does: it checks our API address for 0xCC values. What is 0xCC? Well, it's an INT3 opcode. What does that mean? Well, when you set a normal, software breakpoint on an address (so not a hardware breakpoint) what the debugger does is to WRITE an 0xCC byte there, at that address. When the address is hit, because we now there have an interrupt code, an exception is triggered. The exception is then intercepted by the debugger through what you visually perceive as "the debugger breaks at that address".

Short version: [in general] process scans APIs for software breakpoints.

Now.. if you remember this API was already hooked and before we restored it, the code there was actually a 0xCC. So what the protection actually checks for here is that you've not restored the code :) It's not checking for software breakpoints, but to see if what it hooked has been restored or not.

At the same time, my picture above shows a THREAD number: "Currently debugging thread 23E8". Let's see who created this thread and what's going on with it. I'll yet again use x64dbg for that matter, because it has some nice features to it. Even though the process is paused as we've hit a breakpoint, I can still attach x64dbg to the process. What was our thread number? Ah, yes, 23E8.

NOTES:
  • the thread number is dynamic, so don't yell "I can't find thread number on my PC" -- it will be different on your PC
  • yes, once you attach x64dbg, the process will crash (once resumed in CE, either removing the breakpoint and resuming or unpausing)
So, that thread:

Image

Image

You'll see "spaghetti" there, junk bytes. Why? Because, most likely, the protection has cleaned up the code that spawned this thread :) That doesn't mean we can't kill it. But before you do that, remember to remove the breakpoint in CE and resume the game. Why? We have CE already breaking inside the thread. If you kill the thread before letting the execution finish inside the thread, you'll get an exception - game will crash. That's at least the theory behind it. Game will crash anyway, cuz of the other protections in place I've mentioned :)

To be continued.

P.S.: Note that Process Hacker 2 is detected and game will freeze. I can only assume it's because it has the word "hack" in the name (or GetWindowTextA/W retrieving the GUI title name contains that).

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

Re: Halo Infinite

Post by SunBeam »

Apparently, the game's protection (Arbiter.dll) checks for these strings:

Code: Select all

DebugObject
ollydbg.exe
ida.exe
ida64.exe
idag.exe
idag64.exe
idaw.exe
idaw64.exe
idaq.exe
idaq64.exe
idau.exe
idau64.exe
scylla.exe
scylla_x64.exe
scylla_x86.exe
protection_id.exe
x64dbg.exe
x32dbg.exe
windbg.exe
reshacker.exe
ImportREC.exe
IMMUNITYDEBUGGER.EXE
devenv.exe
OLLYDBG
ida
disassembly
scylla
Debug
[CPU
Immunity
WinDbg
x32dbg
x64dbg
Import reconstructor
Zeta Debugger
Rock Debugger
ObsidianGUI
ID
WinDbgFrameClass
idawindow
tnavbox
idaview
tgrzoom
explorer.exe
And here's an example how it calls kernel32.Sleep API :D

Code: Select all

00007FF73E182149 | FF15 51D85901          | CALL QWORD PTR DS:[7FF73F71F9A0] |
..
..
000001A8F10E064F | 48:B8 35C42875C4E8A263 | MOV RAX,63A2E8C47528C435         |
000001A8F10E0659 | 53                     | PUSH RBX                         |
000001A8F10E065A | 48:BB 956967FF3E97A263 | MOV RBX,63A2973EFF676995         |
000001A8F10E0664 | 48:31D8                | XOR RAX,RBX                      | kernel32.Sleep
000001A8F10E0667 | 5B                     | POP RBX                          |
000001A8F10E0668 | FFE0                   | JMP RAX                          | exec API
And this is kernel32.WaitForSingleObject:

Code: Select all

000001A8F0550DCE | 48:B8 A80B2B1D75461AFA | MOV RAX,FA1A46751D2B0BA8 |
000001A8F0550DD8 | 53                     | PUSH RBX                 |
000001A8F0550DD9 | 48:BB 041E2825CE03A53B | MOV RBX,3BA503CE25281E04 |
000001A8F0550DE3 | 48:01D8                | ADD RAX,RBX              |
000001A8F0550DE6 | 48:BB BE53443F7657A37F | MOV RBX,7FA357763F4453BE |
000001A8F0550DF0 | 48:29D8                | SUB RAX,RBX              |
000001A8F0550DF3 | 48:BB 24BCE6AEB862089F | MOV RBX,9F0862B8AEE6BC24 |
000001A8F0550DFD | 48:01D8                | ADD RAX,RBX              |
000001A8F0550E00 | 48:BB BEB85AD8742ADCAA | MOV RBX,AADC2A74D85AB8BE |
000001A8F0550E0A | 48:01D8                | ADD RAX,RBX              | kernel32.WaitForSingleObject
000001A8F0550E0D | 5B                     | POP RBX                  |
000001A8F0550E0E | FFE0                   | JMP RAX                  | exec API
And ntdll.RtlEnterCriticalSection:

Code: Select all

000001A8F0AA0D72 | 48:B8 40C4840801856BC6 | MOV RAX,C66B85010884C440 |
000001A8F0AA0D7C | 53                     | PUSH RBX                 |
000001A8F0AA0D7D | 48:BB 5445F815A69809E9 | MOV RBX,E90998A615F84554 |
000001A8F0AA0D87 | 48:01D8                | ADD RAX,RBX              |
000001A8F0AA0D8A | 48:BB BBBA954917E23C64 | MOV RBX,643CE2174995BABB |
000001A8F0AA0D94 | 48:31D8                | XOR RAX,RBX              |
000001A8F0AA0D97 | 48:BB 6D46D59E4176DEF3 | MOV RBX,F3DE76419ED5466D |
000001A8F0AA0DA1 | 48:29D8                | SUB RAX,RBX              |
000001A8F0AA0DA4 | 48:BB F646C8B34A726571 | MOV RBX,7165724AB3C846F6 |
000001A8F0AA0DAE | 48:29D8                | SUB RAX,RBX              |
000001A8F0AA0DB1 | 48:BB 941C8A9EE7133648 | MOV RBX,483613E79E8A1C94 |
000001A8F0AA0DBB | 48:29D8                | SUB RAX,RBX              |
000001A8F0AA0DBE | 48:BB 68F18A25BE7C30E2 | MOV RBX,E2307CBE258AF168 |
000001A8F0AA0DC8 | 48:01D8                | ADD RAX,RBX              | ntdll.RtlEnterCriticalSection
000001A8F0AA0DCB | 5B                     | POP RBX                  |
000001A8F0AA0DCC | FFE0                   | JMP RAX                  | exec API
ntdll.LeaveCriticalSection:

Code: Select all

000001A8F0A9095C | 48:B8 FEF7B28A6394E191 | MOV RAX,91E194638AB2F7FE |
000001A8F0A90966 | 53                     | PUSH RBX                 |
000001A8F0A90967 | 48:BB BE2B18F68FC0F142 | MOV RBX,42F1C08FF6182BBE |
000001A8F0A90971 | 48:31D8                | XOR RAX,RBX              |
000001A8F0A90974 | 48:BB 8FCCF1A37CC247FB | MOV RBX,FB47C27CA3F1CC8F |
000001A8F0A9097E | 48:01D8                | ADD RAX,RBX              |
000001A8F0A90981 | 48:BB 0BCE34EDF234CB26 | MOV RBX,26CB34F2ED34CE0B |
000001A8F0A9098B | 48:01D8                | ADD RAX,RBX              |
000001A8F0A9098E | 48:BB B1C21AC4F994D7C6 | MOV RBX,C6D794F9C41AC2B1 |
000001A8F0A90998 | 48:29D8                | SUB RAX,RBX              |
000001A8F0A9099B | 48:BB 073E954298C8B4D1 | MOV RBX,D1B4C89842953E07 |
000001A8F0A909A5 | 48:01D8                | ADD RAX,RBX              | ntdll.LeaveCriticalSection
000001A8F0A909A8 | 5B                     | POP RBX                  |
000001A8F0A909A9 | FFE0                   | JMP RAX                  | exec API
Cheers,
Sun

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

Nice dissertation. It appears that every trainer that has been released, including the one from fearless app, all crash/pause/detected on my computer.

Tested with STEAM and GAMEPASS. So either whatever you are trying to show here isn't being used, or is failing. So far, the problems I outlined remain.

However, I appreciate your laying this out, as I did not know some of these features and your settings in Scilla are useful for future reference.

I assume you are implying that at some point the thread that is doing the crc checks can be killed or bypassed before it's even started or whatever?

At any rate, nice work on displaying this.

Again, there is NO TRAINER AVAILABLE BY ANYONE that doesn't crash/freeze halo infinite in my testing.

best,
Cal

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

+rep

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

Image

[Link]

Note there is many more system .dll hooks

best,
Cal

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

Re: Halo Infinite

Post by SunBeam »

caliber1942 wrote:
Sat Dec 11, 2021 1:12 am
...
The topic is informal. The main subject isn't bypassing whatever, but the kind of protection the game has. If, in the long run, I get to bypass it, so be it :) But don't assume that's what I am after here. There are a plethora of things that need to be adjusted for a full bypass: first-up, the API hooks need to be removed; secondly, Create(Remote)Thread needs to be hooked to filter out the thread(s) creation attempts (which would spawn the function(s) that check on the removal of their API hooks); lastly, once 1 and 2 are solved, one can focus on how it detects CE or any other crap (see the list of strings I posted; there surely are many more).

On another note, I just tested dxgi.dll and dinput8.dll proxies. For dxgi, while my test message box shows, as soon as you click OK, the process terminates. With dinput8 though everything works fine:

Image

Image

Image

So anything that I wanna do inside the process, I will do it from my proxy DLL.
caliber1942 wrote:
Sat Dec 11, 2021 1:22 am
Note there is many more system .dll hooks
I'd appreciate it if you check them, as well as read EVERYTHING I posted. Not all the API hooks are from the game, most are from gameoverlayrender64.dll (Steam) or whatever other overlay Microsoft Store version uses. So not useful. If you restore them, you will break Steam/MS_overlay functionality.

BR,
Sun

P.S.: I've put in the CODEX files, so I can get rid of starting from Steam client.

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

Then entire manually mapped .dll you have found part of the code for is scanned here by arbiter.dll to make sure the CRC is correct.

Arbiter.dll+25EC96 - 41 0FB6 0F - movzx ecx,byte ptr [r15] <-- starts here:

Arbiter.dll+25ECBD - E8 3E43DAFF - call Arbiter.dll+3000 <--

Arbiter.dll+25EC78 - B9 2E4E3CED - mov ecx,ED3C4E2E { -314814930 }
Arbiter.dll+25EC7D - 48 2B C8 - sub rcx,rax
Arbiter.dll+25EC80 - 48 8B 05 39620600 - mov rax,[Arbiter.dll+2C4EC0] { (1846973201) }
Arbiter.dll+25EC87 - 48 33 C1 - xor rax,rcx
Arbiter.dll+25EC8A - 48 89 05 87660600 - mov [Arbiter.dll+2C5318],rax { (1421439684) }
Arbiter.dll+25EC91 - 45 85 F6 - test r14d,r14d
Arbiter.dll+25EC94 - 74 31 - je Arbiter.dll+25ECC7
Arbiter.dll+25EC96 - 41 0FB6 0F - movzx ecx,byte ptr [r15]
Arbiter.dll+25EC9A - 48 B8 25232284E49CF2CB - mov rax,CBF29CE484222325 { -2078137563 }
Arbiter.dll+25ECA4 - 48 33 C8 - xor rcx,rax
Arbiter.dll+25ECA7 - 48 B8 B301000000010000 - mov rax,00000100000001B3 { 435 }
Arbiter.dll+25ECB1 - 48 0FAF C8 - imul rcx,rax
Arbiter.dll+25ECB5 - 4D 8D 46 FF - lea r8,[r14-01]
Arbiter.dll+25ECB9 - 49 8D 57 01 - lea rdx,[r15+01]
Arbiter.dll+25ECBD - E8 3E43DAFF - call Arbiter.dll+3000
Arbiter.dll+25ECC2 - 48 8B D8 - mov rbx,rax
Arbiter.dll+25ECC5 - EB 0A - jmp Arbiter.dll+25ECD1
Arbiter.dll+25ECC7 - 48 BB 25232284E49CF2CB - mov rbx,CBF29CE484222325 { -2078137563 }
Arbiter.dll+25ECD1 - F3 0F10 0D 976A0600 - movss xmm1,[Arbiter.dll+2C5770] { (Nan) }
Arbiter.dll+25ECD9 - F3 0F10 05 FF610600 - movss xmm0,[Arbiter.dll+2C4EE0] { (Nan) }
Arbiter.dll+25ECE1 - F3 0F58 C8 - addss xmm1,xmm0
Arbiter.dll+25ECE5 - F3 0F58 0D DB610600 - addss xmm1,[Arbiter.dll+2C4EC8] { (Nan) }
Arbiter.dll+25ECED - F3 0F11 0D E3630600 - movss [Arbiter.dll+2C50D8],xmm1 { (Nan) }
Arbiter.dll+25ECF5 - 8B 05 ED6A0600 - mov eax,[Arbiter.dll+2C57E8] { (838395965) }
Arbiter.dll+25ECFB - 35 F62B4C67 - xor eax,674C2BF6 { (130) }
Arbiter.dll+25ED00 - 3D 762EA158 - cmp eax,58A12E76 { (0) }
Arbiter.dll+25ED05 - 0F85 39040000 - jne Arbiter.dll+25F144
Arbiter.dll+25ED0B - F3 0F10 0D F5650600 - movss xmm1,[Arbiter.dll+2C5308] { (Nan) }
Arbiter.dll+25ED13 - F3 0F10 05 4D670600 - movss xmm0,[Arbiter.dll+2C5468] { (-Inf) }
Arbiter.dll+25ED1B - 0F2E C8 - ucomiss xmm1,xmm0


The thread scanning for changes to system dll hooks uses this code:

02E8D670 - 3A 01 - cmp al,[rcx]
02E8D672 - 0F85 64030000 - jne 02E8D9DC


02E8D619 - F3 0F11 0D 973B3100 - movss [031A11B8],xmm1 { (Nan) }
02E8D621 - F3 0F10 15 733A3100 - movss xmm2,[031A109C] { (Nan) }
02E8D629 - F3 0F10 0D 8B383100 - movss xmm1,[031A0EBC] { (0.64) }
02E8D631 - F3 0F58 D3 - addss xmm2,xmm3
02E8D635 - F3 0F10 05 DF423100 - movss xmm0,[031A191C] { (Nan) }
02E8D63D - F3 0F59 C8 - mulss xmm1,xmm0
02E8D641 - F3 0F5C D1 - subss xmm2,xmm1
02E8D645 - F3 0F11 15 DB353100 - movss [031A0C28],xmm2 { (Nan) }
02E8D64D - C6 44 24 30 DE - mov byte ptr [rsp+30],-22 { 222 }
02E8D652 - C6 44 24 38 12 - mov byte ptr [rsp+38],12 { 18 }
02E8D657 - 0FB6 44 24 30 - movzx eax,byte ptr [rsp+30]
02E8D65C - 0FB6 4C 24 38 - movzx ecx,byte ptr [rsp+38]
02E8D661 - 32 C8 - xor cl,al
02E8D663 - 88 4C 24 30 - mov [rsp+30],cl
02E8D667 - 48 8B 4A 20 - mov rcx,[rdx+20]
02E8D66B - 0FB6 44 24 30 - movzx eax,byte ptr [rsp+30]
02E8D670 - 3A 01 - cmp al,[rcx]
02E8D672 - 0F85 64030000 - jne 02E8D9DC
02E8D678 - 8B 05 82383100 - mov eax,[031A0F00] { (529213936) }
02E8D67E - 8B 0D BC3B3100 - mov ecx,[031A1240] { (89C63CE4) }
02E8D684 - 2B C8 - sub ecx,eax
02E8D686 - 8B 05 40423100 - mov eax,[031A18CC] { (685567672) }
02E8D68C - 2B C8 - sub ecx,eax
02E8D68E - 89 0D BC3A3100 - mov [031A1150],ecx { (-2060356679) }
02E8D694 - 48 8B 42 10 - mov rax,[rdx+10]
02E8D698 - 80 78 19 00 - cmp byte ptr [rax+19],00 { 0 }
02E8D69C - 74 22 - je 02E8D6C0
02E8D69E - 48 8B 42 08 - mov rax,[rdx+08]
02E8D6A2 - 80 78 19 00 - cmp byte ptr [rax+19],00 { 0 }


Further if you freeze the manually mapped scanner, the game will seem to operate normally and nothing crashes, BUT you cannot start missions, etc., so there is a heartbeat or 'check' of sorts or, it may be that the game won't operate if this thread isn't running. It's my belief that arbiter.dll is creating this manually mapped .dll and then checks it's integrity. The manually mapped .dll is running this thread or maybe several, as it's a LONG code function, and that it's doing all the checks of multiple things.

Sorry to post here and hijack, but you can delete or remove if this is not useful or is dirtying up your thread.

best,
Cal

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

PureReality wrote:
Sat Dec 11, 2021 1:39 am
caliber1942 wrote:
Sat Dec 11, 2021 1:12 am
Nice dissertation. It appears that every trainer that has been released, including the one from fearless app, all crash/pause/detected on my computer.

Tested with STEAM and GAMEPASS. So either whatever you are trying to show here isn't being used, or is failing. So far, the problems I outlined remain.

However, I appreciate your laying this out, as I did not know some of these features and your settings in Scilla are useful for future reference.

I assume you are implying that at some point the thread that is doing the crc checks can be killed or bypassed before it's even started or whatever?

At any rate, nice work on displaying this.

Again, there is NO TRAINER AVAILABLE BY ANYONE that doesn't crash/freeze halo infinite in my testing.

best,
Cal
Been running a trainer for several hours without a single issue here no crashes/freezes/pauses so the whole "NO TRAINER AVAILABLE BY ANYONE that doesn't crash/freeze halo infinite" is kind of not true xD

but then again, I have yet to experience any issues that anyone anywhere (steam forums / halo waypoint forums) is saying with the game crashing or having bad fps/ stutters / or any other problems even without the trainer as well so maybe I am just lucky or something.
If you are using with CODEX, then that would be a unique situation I am not able to test with. Understand that CODEX may have removed much of the 'problems' we are looking at..

best,
Cal

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

Re: Halo Infinite

Post by SunBeam »

caliber1942 wrote:
Sat Dec 11, 2021 2:07 am
Sorry to post here and hijack, but you can delete or remove if this is not useful or is dirtying up your thread.
Not hijacking at all, do post :) The more, the merrier. I don't have time 24/7 to look at it. As for CODEX, they've release just a DRM circumvention, so it bypasses Steam and lets the game run. The protection is still in. Am still amazed people who give a fuck call this a "crack". But hey, at least they didn't VMProtect their DLL this time around.

The only thing CODEX helps with is not starting the game from Steam client, but directly from the original .exe. That's all. Anything else we talked about is still there. Since it's not something the team has seen, they've not bothered restoring the binary. They did remove Denuvo + VMProtect from AC: Origins though ([Link]).

Pfft, "crack", my ass. And some moron at cs.rin.ru decided to warn me and tell me to play smart on other forums. Fine by me, their loss.

User avatar
SilentRunner
Expert Cheater
Expert Cheater
Posts: 215
Joined: Fri May 29, 2020 11:37 am
Reputation: 107

Re: Halo Infinite

Post by SilentRunner »

Thanks for sharing this SunBeam, this may come in useful for me and Dread if we make tools for Infinite.

daninthemix
Expert Cheater
Expert Cheater
Posts: 245
Joined: Tue Jul 18, 2017 6:31 pm
Reputation: 81

Re: Halo Infinite

Post by daninthemix »

Just an FYI that fearlessrevolution's trainer worked really well for me.

I literally completed the entire game using it, and didn't get a single crash. I don't see why you would - it's just pushing very large values into some variables. I don't think it's doing code injection or anything like that.

The shields cheat always worked. The no-reload sometimes didn't, but by picking up another gun and then switching back, I could usually get it to work (in other words, no-reload works probably 70-80% of the time).

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

Re: Halo Infinite

Post by SunBeam »

caliber1942 wrote:
Sat Dec 11, 2021 2:07 am
Arbiter.dll+25ECA7 - 48 B8 B301000000010000 - mov rax,00000100000001B3 { 435 }
..
Arbiter.dll+25ECC7 - 48 BB 25232284E49CF2CB - mov rbx,CBF29CE484222325 { -2078137563 }
I just realized something. They are using FNV1A/1B (the 64-bit variant) for hashing parts of the code, I believe. I saw that prime value there (100000001B3) which I also found in my Cyberpunk 2077 reversing days (1.04).
FNV 1 (64-bit) is Fowler–Noll–Vo is a non-cryptographic hash function. The basis of the FNV hash algorithm was taken from an idea sent as reviewer comments to the IEEE POSIX P1003.2 committee by Glenn Fowler and Phong Vo in 1991. In a subsequent ballot round, Landon Curt Noll improved on their algorithm. In an email message to Landon, they named it the Fowler/Noll/Vo or FNV hash.

The FNV-1 means of creating non-zero FNV offset basis. This is FNV 1 64 bit flavor. For pure FNV implementations, this is determined solely by the availability of FNV primes for the desired bit length, however, the FNV webpage discusses methods of adapting one of the above versions to a smaller length that may or may not be a power of two.

One of FNV's key advantages is that it is very simple to implement. Start with an initial hash value of FNV offset basis. For each byte in the input, multiply hash by the FNV prime, then XOR it with the byte from the input.
Example from Cyberpunk 2077:

Image

I'll do some more research, but this looks interesting :)

Found like 94 references for "48B8B301000000010000" in Arbiter.dll. I've set a breakpoint in all of them and managed to get here:

Image

As you can see, they're hashing the parent process name. "DLLLoader64_3BE7.exe" is actually the DLL load stub x64dbg temporarily drops in the folder where the target DLL is. In my case, since this is Arbiter.dll, the location is the main game folder. If you go there you will see this:

Image

And the function hashing the parent process name is here:

Code: Select all

00007FFA1A2A44F3 | 0FB702        | MOVZX EAX,WORD PTR DS:[RDX] | rdx:L"DLLLoader64_3BE7.exe"
00007FFA1A2A44F6 | 66:85C0       | TEST AX,AX                  |
00007FFA1A2A44F9 | 74 1E         | JE arbiter.7FFA1A2A4519     |
00007FFA1A2A44FB | 0FB6C8        | MOVZX ECX,AL                |
00007FFA1A2A44FE | 49:FFC8       | DEC R8                      |
00007FFA1A2A4501 | 81E1 DF000000 | AND ECX,DF                  |
00007FFA1A2A4507 | 48:83C2 02    | ADD RDX,2                   | rdx:L"DLLLoader64_3BE7.exe"
00007FFA1A2A450B | 48:33CD       | XOR RCX,RBP                 |
00007FFA1A2A450E | 49:0FAFCC     | IMUL RCX,R12                |
00007FFA1A2A4512 | E8 19EBFFFF   | CALL arbiter.7FFA1A2A3030   | <- FNV_XOR_func
00007FFA1A2A4517 | EB 03         | JMP arbiter.7FFA1A2A451C    |
An example of the implementation for the above: [Link]

Note that in Arbiter.dll's case the string is wchar_t (widechar), hence why the function always increases the iterator by 2.

And to complete my example, here's how you can test it :)

We have our string: "DLLLoader64_EA37.exe". The code iterates each character in that string and applies the FNV1A64 hashing logic, whereas the character is multiplied by the offset basis (CBF29CE484222325), then xored by the prime (100000001B3). Through tracing in x64dbg I found the the value for "D" character is this:

Image

So, FNV1A64( "D" ) == 0xAF63F94C86021DD3.

How can we test we're right? Simple: [Link].

Image

The site doesn't show all characters in upper-case, but it's the same fucking result :)

In case you're wondering why they're using this hashing mechanism.. it's to obtain unique hash values for various elements the system works with. Not necessarily for integrity checking, but mostly to remove the need for referenced strings which can easily be used in reverse engineering. Also, optimization (checking a hash is faster than iterating a string every time a check needs this).

Here's a quick run-down:

Code: Select all

00007FFA1A2C11F2 | 49:BF 43858F1466468EFD | MOV R15,FD8E4666148F8543      | hash_in
00007FFA1A2C11FC | 49:8BCF                | MOV RCX,R15                   |
00007FFA1A2C11FF | E8 CC30FEFF            | CALL arbiter.7FFA1A2A42D0     |
..
..
00007FFA1A2A44EF | 48:8B53 50             | MOV RDX,QWORD PTR DS:[RBX+50] | [rbx+50]:L"DLLLoader64_F5D1.exe"
00007FFA1A2A44F3 | 0FB702                 | MOVZX EAX,WORD PTR DS:[RDX]   |
00007FFA1A2A44F6 | 66:85C0                | TEST AX,AX                    |
00007FFA1A2A44F9 | 74 1E                  | JE arbiter.7FFA1A2A4519       |
00007FFA1A2A44FB | 0FB6C8                 | MOVZX ECX,AL                  |
00007FFA1A2A44FE | 49:FFC8                | DEC R8                        |
00007FFA1A2A4501 | 81E1 DF000000          | AND ECX,DF                    |
00007FFA1A2A4507 | 48:83C2 02             | ADD RDX,2                     |
00007FFA1A2A450B | 48:33CD                | XOR RCX,RBP                   |
00007FFA1A2A450E | 49:0FAFCC              | IMUL RCX,R12                  |
00007FFA1A2A4512 | E8 19EBFFFF            | CALL arbiter.7FFA1A2A3030     | FNV1A64XOR_func
00007FFA1A2A4517 | EB 03                  | JMP arbiter.7FFA1A2A451C      | hash_out ( FNV1A64XOR( "DLLLoader64_F5D1.exe" ) == D3B4DC569887E147
00007FFA1A2A4519 | 48:8BC5                | MOV RAX,RBP                   |
00007FFA1A2A451C | 48:3BC6                | CMP RAX,RSI                   | hash_in vs. hash_out -> FD8E4666148F8543 vs. D3B4DC569887E147 ==> not_equal
That "hash_in" is the FNV1A64XOR for "KERNEL32.DLL" :D So they're hashing module names, API names, etc.

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

Re: Halo Infinite

Post by SunBeam »

Alright.

Ammo (clip) is stored as WORD (2 bytes) and debugging it - on write - led to this spot:

Image

More as I study this.

caliber1942
Expert Cheater
Expert Cheater
Posts: 93
Joined: Thu Oct 17, 2019 5:15 pm
Reputation: 213

Re: Halo Infinite

Post by caliber1942 »

daninthemix wrote:
Sat Dec 11, 2021 7:33 pm
Just an FYI that fearlessrevolution's trainer worked really well for me.

I literally completed the entire game using it, and didn't get a single crash. I don't see why you would - it's just pushing very large values into some variables. I don't think it's doing code injection or anything like that.

The shields cheat always worked. The no-reload sometimes didn't, but by picking up another gun and then switching back, I could usually get it to work (in other words, no-reload works probably 70-80% of the time).
Every trainer that is in the wild, including ours, is having to capture addresses by doing JMP to codecave, albeit doing so in micro seconds and then reverting back to normal trying to avoid being detected. If you keep mashing the option buttons over and over on any one of the trainers you will see that they all are detected because the CRC check. If you could 'pause' the scanning thread for a second (since it is running separately) while the JMP is being done then being undone, it would theoretically help prevent being detected. However, in my experience and reversing, I wasn't able to isolate the scanning thread, since it is going from manually mapped .dll in random memory. Note also, that the scanning .dll is also scanned by the Arbiter.dll for changes, which likely also looks for heartbeat or if that .dll is paused. If there was a way to reliably pick out the scanning .dll and pause it for a second, while you do the captures or writes, then undo the JMP back to normal, then resume that thread it would theoretically make the trainers undetected.

I was able to re route the virtual tables to point to my own code to semi force the game to go to my section of code, but the problem here is determining the offsets and method used to get to the (ammo for instance) from a captured register.

For instance, this code:

HaloInfinite.exe+120F7D0: 48 8D 05 D1 CB 61 03 - lea rax,[HaloInfinite.exe+482C3A8]

Holds the base to all of the COPIES of the virtual tables that point to some functions in the game. The game (as I stated before) makes a COPY of the game .exe .text, and if you write to the original OR the copy, the results are mirrored to each. The COPY is SCANNED by the game for changes, and I don't recall by maybe the original is scanned as well. But the point here is that:

HaloInfinite.exe+120F7D0: 48 8D 05 D1 CB 61 03 - lea rax,[HaloInfinite.exe+482C3A8]

if you take the address held here [HaloInfinite.exe+482C3A8] (not LEA, but READ it)

You get the base of the virtual tables. Calle it vTableBase.

[vTableBase+278] holds pointer address to the READ AMMO function used in the game, which is here:

(snipppet)
HaloInfinite.exe+5F886C - 33 D2 - xor edx,edx
HaloInfinite.exe+5F886E - E9 01000000 - jmp HaloInfinite.exe+5F8874
HaloInfinite.exe+5F8873 - CC - int 3
HaloInfinite.exe+5F8874 - 48 89 5C 24 08 - mov [rsp+08],rbx
HaloInfinite.exe+5F8879 - 48 89 6C 24 18 - mov [rsp+18],rbp
HaloInfinite.exe+5F887E - 48 89 74 24 20 - mov [rsp+20],rsi
HaloInfinite.exe+5F8883 - 57 - push rdi
HaloInfinite.exe+5F8884 - 41 54 - push r12
HaloInfinite.exe+5F8886 - 41 55 - push r13
HaloInfinite.exe+5F8888 - 41 56 - push r14
HaloInfinite.exe+5F888A - 41 57 - push r15
HaloInfinite.exe+5F888C - 48 83 EC 20 - sub rsp,20 { 32 }
HaloInfinite.exe+5F8890 - 48 63 DA - movsxd rbx,edx
HaloInfinite.exe+5F8893 - 48 8B E9 - mov rbp,rcx
HaloInfinite.exe+5F8896 - 48 83 C1 10 - add rcx,10 { 16 }
HaloInfinite.exe+5F889A - BA 656A626F - mov edx,6F626A65 { "ejbo" }
HaloInfinite.exe+5F889F - 4D 8B E8 - mov r13,r8
HaloInfinite.exe+5F88A2 - E8 F914DDFF - call HaloInfinite.exe+3C9DA0

further down you see code here:

reload
=========

HaloInfinite.exe+5F88F9 - 49 8D 4E 10 - lea rcx,[r14+10]
HaloInfinite.exe+5F88FD - 48 03 C8 - add rcx,rax

THEN RCX word clip in gun
rcx+0 word is clip
rcx+2 word is clip copy value

So you can write to

[vTableBase+278]

Which holds the address:
HaloInfinite.exe+5F886C

To make it hold the address of your CodeCave, which ideally would capture register RCX, and would look something like:

mov [WeaponBase],rcx
JMP HaloInfinite.exe+5F886C

Now.. if you knew what else to capture or a surefire chain of offsets that pointed to the ammo and the clip, this would be golden.

This is NOT correct, but let's say it was:

RCX+[EDI*EAX+48]

was how we determine location of CLIP

then write [RCX+[EDI*EAX+48]]+0 and [RCX+[EDI*EAX+48]]+2 some WORD sized amount. You could do it in the CODECAVE.

You would so similar in some function that has base of PLAYERSTRUCT where the health is located, then redirect the virtualtable to point to your cave then the cave JMP back to the normal code flow.

I tested this and it works, but I was not able to work out the proper formula to arrive for every weapon at ammo and clip. So I did not even try for playerhealth, especially since the playerhealth is read in multiple functions which are all shared by multiple entities, and the enemies at times, and trying to isolate this, you run into the eventual suspend/crash by the game for using breakpoints, so it's a time consuming blah that most of us just made the JMP-Write-JMP back, then undo method so we could move on from this game.

The rest of this is an exercise in reversing and seeing how the anticheats in this game work, and what to do about them. I am not so interested in defeating the VEH detection, although that would immensely help or could even be used as a method to JMP to codecaves via VEH detours. What would be good to see is how to pause the threads or defeat the scanners, some of which are not in memory in normal module listing fashion, but are manually mapped. The Arbiter.dll, I suspect, holds a lot of answers (but also problems).

best,
Cal

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

Re: Halo Infinite

Post by SunBeam »

caliber1942 wrote:
Mon Dec 13, 2021 6:13 pm
...
You got most of the things wrong, because you love to dwindle in the limited terminology you use in a lot of your posts. I've seen the CH posts, I've seen the UC posts, I've seen the posts on this forum. 50% of what you're saying is mis-informative.

Yes, there is a mechanism at play here. It's called Arbiter. Do a little digging and you'll see what ARBITER stands for in the Halo universe: [Link]. Now if you take what you've read about this word and apply it to the protection itself, what would you discover from this simple correlation?

Can we please stop using the word "CRC" so loosely? CRC stands for cyclic redundancy check. The game does not use any "CRC". It's hashing blocks of executable code, blocks of SHELL code (you call it "manually mapped" -- what's manual about it? it's a process doing it, not a human being; you don't control the mapping, so nothing manual about it), strings, APIs, etc. The reason FNV1A 64-bit is used is because it returns unique hashes with very little collisions. Here's more on the subject: [Link]. These non-cryptographic mechanisms are very reliable and optimize the speed at which you'd hash an entire map. You've probably seen the game is lagging a little bit every once in a while, though it's still playable. That's how reliable these hashing mechanisms are.

Another reason you see lagging is due to how the anti-hardware breakpoints protection works. I've posted about it here: https://www.u(nknown)cheats.me/forum/3317670-post28.html. The shell code checks the breakpoints' registers for their return values, as well as running interrupts (INT2C) to catch debuggers. All of these are constantly ran and checked in debug events.

** If you could 'pause' the scanning thread for a second **

There's no thread. There's multiple threads, there's debug events, there's the same integrity checks as part of game events (functions) that are executed when called on/needed. Picture this: I'd create the game code and in every call to switching the weapon, reloading the weapon, loading/unloading a map or picking up a power-up, health pack or w.e. - I'd plant 1 CALL to the integrity check function. Those cannot be defeated by randomly looking for threads..

** However, in my experience and reversing, I wasn't able to isolate the scanning thread, since it is going from manually mapped .dll in random memory. Note also, that the scanning .dll is also scanned by the Arbiter.dll for changes, which likely also looks for heartbeat or if that .dll is paused. If there was a way to reliably pick out the scanning .dll and pause it for a second, while you do the captures or writes, then undo the JMP back to normal, then resume that thread it would theoretically make the trainers undetected. **

You are missing a very BIG point. Due to what I've explained in the previous paragraph, even pausing main thread would still catch you while attempting code changes. I tend to believe there are a lot of the game's structures that contain the integrity check call to mapped shell code in their virtual tables. Then there's the regular member-functions (e.g.: ReloadWeapon, FireWeapon, etc.) that do the same.

Lastly, you seem keen on convincing the world there's no trainer out there working for this game just cuz it doesn't meet your standards of a trainer. Then again all I see is frustration in your posts, mostly cuz you hate being defeated by such protections. Then you go on justifying yourself to the CH community and explaining in great lengths WHY you can't do it. As if those users/players would understand what you're talking about.. Why, I ask?.. As someone put it bluntly, it's interesting you know very well what other trainers for this game do :)

Back on track, I went down that path with back-tracing from what I posted earlier:

Code: Select all

HaloInfinite.exe+7A44A8 - 48 89 5C 24 08 - mov [rsp+08],rbx
HaloInfinite.exe+7A44AD - 48 89 6C 24 10 - mov [rsp+10],rbp
HaloInfinite.exe+7A44B2 - 48 89 74 24 18 - mov [rsp+18],rsi
HaloInfinite.exe+7A44B7 - 57             - push rdi
HaloInfinite.exe+7A44B8 - 48 83 EC 20    - sub rsp,20 { 32 }
HaloInfinite.exe+7A44BC - 33 ED          - xor ebp,ebp
HaloInfinite.exe+7A44BE - 41 8B D8       - mov ebx,r8d
HaloInfinite.exe+7A44C1 - 48 8B F2       - mov rsi,rdx
HaloInfinite.exe+7A44C4 - 48 8B F9       - mov rdi,rcx
HaloInfinite.exe+7A44C7 - 45 85 C0       - test r8d,r8d
HaloInfinite.exe+7A44CA - 7E 0E          - jle HaloInfinite.exe+7A44DA
HaloInfinite.exe+7A44CC - 33 D2          - xor edx,edx
HaloInfinite.exe+7A44CE - 48 8B CE       - mov rcx,rsi
HaloInfinite.exe+7A44D1 - E8 D2BFF4FF    - call HaloInfinite.exe+6F04A8
HaloInfinite.exe+7A44D6 - 84 C0          - test al,al
HaloInfinite.exe+7A44D8 - 75 48          - jne HaloInfinite.exe+7A4522
HaloInfinite.exe+7A44DA - 48 8B CE       - mov rcx,rsi
HaloInfinite.exe+7A44DD - E8 C6000000    - call HaloInfinite.exe+7A45A8
HaloInfinite.exe+7A44E2 - 84 C0          - test al,al
HaloInfinite.exe+7A44E4 - 75 20          - jne HaloInfinite.exe+7A4506
HaloInfinite.exe+7A44E6 - 66 89 5F 10    - mov [rdi+10],bx <<
HaloInfinite.exe+7A44EA - 66 89 5F 12    - mov [rdi+12],bx <<
I got back to this chain:

Code: Select all

HaloInfinite.exe+754BEB - 41 8B E8              - mov ebp,r8d
HaloInfinite.exe+754BEE - BA 04000000           - mov edx,00000004 { 4 }
HaloInfinite.exe+754BF3 - 8B D9                 - mov ebx,ecx
HaloInfinite.exe+754BF5 - E8 7659D3FF           - call HaloInfinite.ManagedNetworkedPropertyDefinition_GetName+6C0
HaloInfinite.exe+754BFA - BA 656A626F           - mov edx,6F626A65 { "ejbo" }
HaloInfinite.exe+754BFF - 48 8B F0              - mov rsi,rax
HaloInfinite.exe+754C02 - 48 8D 48 10           - lea rcx,[rax+10]
HaloInfinite.exe+754C06 - E8 9551C7FF           - call HaloInfinite.exe+3C9DA0
HaloInfinite.exe+754C0B - 48 69 D7 50030000     - imul rdx,rdi,00000350 { 848 }
HaloInfinite.exe+754C12 - 4C 8B C8              - mov r9,rax
HaloInfinite.exe+754C15 - 48 89 44 24 30        - mov [rsp+30],rax
HaloInfinite.exe+754C1A - 48 8B 88 900C0000     - mov rcx,[rax+00000C90]
..
..
HaloInfinite.exe+754C4D - 48 8D 8E D8040000     - lea rcx,[rsi+000004D8]
HaloInfinite.exe+754C54 - 33 D2                 - xor edx,edx
HaloInfinite.exe+754C56 - 66 39 11              - cmp [rcx],dx
HaloInfinite.exe+754C59 - 76 07                 - jna HaloInfinite.exe+754C62
HaloInfinite.exe+754C5B - 0FB7 51 02            - movzx edx,word ptr [rcx+02]
HaloInfinite.exe+754C5F - 48 03 D1              - add rdx,rcx
HaloInfinite.exe+754C62 - 48 6B C8 34           - imul rcx,rax,34
HaloInfinite.exe+754C66 - 4C 8D 04 80           - lea r8,[rax+rax*4]
HaloInfinite.exe+754C6A - 89 6C 24 20           - mov [rsp+20],ebp
HaloInfinite.exe+754C6E - 49 C1 E0 05           - shl r8,05 { 5 }
HaloInfinite.exe+754C72 - 48 03 CA              - add rcx,rdx
HaloInfinite.exe+754C75 - 4D 03 81 4C0C0000     - add r8,[r9+00000C4C]
HaloInfinite.exe+754C7C - 48 8D 54 24 30        - lea rdx,[rsp+30]
HaloInfinite.exe+754C81 - E8 5696FFFF           - call HaloInfinite.exe+74E2DC
HaloInfinite.exe+754C86 - EB B0                 - jmp HaloInfinite.exe+754C38
..
..
HaloInfinite.exe+74E39C - 4C 8B 4F 08           - mov r9,[rdi+08]
HaloInfinite.exe+74E3A0 - 33 DB                 - xor ebx,ebx
HaloInfinite.exe+74E3A2 - 44 8B A4 24 B0000000  - mov r12d,[rsp+000000B0]
HaloInfinite.exe+74E3AA - 8B C6                 - mov eax,esi
HaloInfinite.exe+74E3AC - 8B EB                 - mov ebp,ebx
HaloInfinite.exe+74E3AE - 41 2B C4              - sub eax,r12d
HaloInfinite.exe+74E3B1 - 45 8B C6              - mov r8d,r14d
HaloInfinite.exe+74E3B4 - 49 8B D1              - mov rdx,r9
HaloInfinite.exe+74E3B7 - 49 8B CF              - mov rcx,r15
HaloInfinite.exe+74E3BA - 0F49 E8               - cmovns ebp,eax
HaloInfinite.exe+74E3BD - E8 E6600500           - call HaloInfinite.exe+7A44A8
HaloInfinite.exe+74E3C2 - 48 8B 07              - mov rax,[rdi]
Ignore the fake named symbols in the code, they're not reliable. What you would want to know is the value by which the PLAYER structure is obtained here:

Code: Select all

HaloInfinite.exe+754BEE - BA 04000000           - mov edx,00000004 { 4 }
HaloInfinite.exe+754BF3 - 8B D9                 - mov ebx,ecx // 00000000811D023A
HaloInfinite.exe+754BF5 - E8 7659D3FF           - call HaloInfinite.exe+48A570
I've seen that 0x811D023A value in all Halo games since they've started the MCC. So I know it's a marker for the Player or PlayerEntity. I've not studied much this Engine, mostly cuz there wasn't any challenge in doing so and the remakes of the old titles left me cold.

This would return the address you want as the starting point. Example of returned pointer from the TLS (thread local storage): 00000269F6E88E40.

Then there's the following, as you pointed out:

Code: Select all

HaloInfinite.exe+754BFA - BA 656A626F           - mov edx,6F626A65 { "ejbo" }
HaloInfinite.exe+754BFF - 48 8B F0              - mov rsi,rax
HaloInfinite.exe+754C02 - 48 8D 48 10           - lea rcx,[rax+10]
HaloInfinite.exe+754C06 - E8 9551C7FF           - call HaloInfinite.exe+3C9DA0
And so on till you get to the base for ammo, following the "white rabbit".

The only problem with the above code is I wasn't able to find TLS_base, as executing the function in a thread (HaloInfinite.exe+48A570) would not return a valid RAX. Tried it manually via Lua:

Code: Select all

local getPlayer = getAddressSafe( "HaloInfinite.exe" ) + 0x48A570
local Player = executeCodeEx( 0, nil, getPlayer, 0x811D023A, 0x4 ) << crash in here
I know the parameters are fine. Something inside it fails:

Code: Select all

HaloInfinite.exe+48A570 - 40 53                 - push rbx
HaloInfinite.exe+48A572 - 48 83 EC 20           - sub rsp,20 { 32 }
HaloInfinite.exe+48A576 - 8B C1                 - mov eax,ecx
HaloInfinite.exe+48A578 - 4C 8D 05 815AB7FF     - lea r8,[HaloInfinite.exe] { (9460301) }
HaloInfinite.exe+48A57F - 83 E0 01              - and eax,01 { 1 }
HaloInfinite.exe+48A582 - 8B D9                 - mov ebx,ecx
HaloInfinite.exe+48A584 - 49 83 BC C0 205D4304 00 - cmp qword ptr [r8+rax*8+04435D20],00 { 0 }
HaloInfinite.exe+48A58D - 74 39                 - je HaloInfinite.exe+48A5C8
HaloInfinite.exe+48A58F - 41 8B 8C 80 305D4304  - mov ecx,[r8+rax*4+04435D30]
HaloInfinite.exe+48A597 - FF 15 1B549B02        - call qword ptr [HaloInfinite.exe+2E3F9B8] { ->25CA56B09AA }
HaloInfinite.exe+48A59D - 4C 8B C0              - mov r8,rax // fails here
HaloInfinite.exe+48A5A0 - 83 FB FF              - cmp ebx,-01 { 255 }
HaloInfinite.exe+48A5A3 - 74 1E                 - je HaloInfinite.exe+48A5C3
HaloInfinite.exe+48A5A5 - D1 EB                 - shr ebx,1
HaloInfinite.exe+48A5A7 - 81 E3 FF7F0000        - and ebx,00007FFF { 32767 }
HaloInfinite.exe+48A5AD - 49 8B 40 78           - mov rax,[r8+78]
HaloInfinite.exe+48A5B1 - 0FB7 CB               - movzx ecx,bx
HaloInfinite.exe+48A5B4 - 48 8D 14 49           - lea rdx,[rcx+rcx*2]
HaloInfinite.exe+48A5B8 - 48 8B 44 D0 10        - mov rax,[rax+rdx*8+10]
HaloInfinite.exe+48A5BD - 48 83 C4 20           - add rsp,20 { 32 }
HaloInfinite.exe+48A5C1 - 5B                    - pop rbx
HaloInfinite.exe+48A5C2 - C3                    - ret 
HaloInfinite.exe+48A5C3 - 83 CB FF              - or ebx,-01 { 255 }
HaloInfinite.exe+48A5C6 - EB E5                 - jmp HaloInfinite.exe+48A5AD
HaloInfinite.exe+48A5C8 - 4D 8B 84 C0 A87B4104  - mov r8,[r8+rax*8+04417BA8]
HaloInfinite.exe+48A5D0 - EB CE                 - jmp HaloInfinite.exe+48A5A0
"call qword ptr [HaloInfinite.exe+2E3F9B8] { ->25CA56B09AA }" is TlsGetValue API, which accounts for what I've mentioned: TLS :)
Retrieves the value in the calling thread's thread local storage (TLS) slot for the specified TLS index. Each thread of a process has its own slot for each TLS index.
Image

In most games, there's a global pointer holding the TLS base. Example from Valhalla:

Image

I have a feeling something similar is going on in Halo Infinte. Instead of executing TlsGetValue with given index, you can run this piece of ASM which gets your base:

Code: Select all

mov rax,gs:[00000058]
Then we know the offset, it's 0xE5.

P.S.: "ejbo" is a truncation for "Object". Read it backwards.

Post Reply

Who is online

Users browsing this forum: No registered users