I recently got confronted with a situation whereby a Win 11 gamer received constant 'offset too big' errors upon using my (AC Syndicate) table. The strange thing is that the very same table runs just fine on Win 10 (and earlier Win versions). After some research/reading - guided by our contributors @CEF - I was able to solve the matter.
Since it took me some time to figure this out - and I'm expecting more of such "confrontations" myself in the foreseeable future - I wrote up this little paper (which might help out some of my colleagues here as well).
Before anything: a big thx to #VixHexven for his 'above and beyond' Q&A service. Since I never really got confronted with these errors, it was entirely up to him to test every change; and report back accordingly. And he did so 'with panache'
You can find the doc here: [ [Link] ]
If you know of similar techniques/approaches, do let me/us know.
Sidenote: the use of that particular "game_gap" was actually introduced to me by #Sunbeam some years back (as he was using that technique in one of his tables I was researching; back some years ago... already)
Some other stuff to (possibly) look into:
1. extend game exe memory during launch ? $process, getModule()
2. 32b programs and/or win x32 possible issues ?
3. trampoline ?
Convert your AOB script from ‘jump 5’ to ‘jump 14’
Re: Convert your AOB script from ‘jump 5’ to ‘jump 14’
Mentioned this several times in the past 5-10 years, quite often I'd say. I guess it takes people a while to assimilate what the fuck I was talking about
viewtopic.php?p=104318#p104318
viewtopic.php?p=63305#p63305
viewtopic.php?p=97853#p97853
viewtopic.php?p=31616#p31616
viewtopic.php?p=79247#p79247
viewtopic.php?p=40968#p40968
And so on
The solution I recommend is using trampolines. What this means is from your address you first JMP to a cave inside the game process. And since you forcefully do that, the JMP will always be 5-bytes. I personally use the PE header, whereas I make writable the memory at $process+0x500 till $process+0x1000 <- this is where the executable code starts. Here you then JMP (14-bytes) to your allocated cave.
So like this (Lua code, but you can always convert it to auto-assembler):
Then in the actual script, I do this:
So what the code above does is to place a JMP (5-bytes) at "InfiniteOxygen" address. This JMP will hop over to "Trampolines+00" address (which is at
gameModule + offset = $process + 0x500). Here it will write another JMP (14-bytes this time) that will hop over to the allocated "InfiniteOxygenHook", where our cave is. In there, another "jmp far" will hop back to original hook spot (at "InfiniteOxygen+6").
Short version: code jumps to trampoline; trampolines jumps to cave. You got a middle-man in-between, 5-bytes JMP hopping over to a 14-bytes JMP
Another thing I recommend doing is not using direct reads of variables. Get used to writing things like this:
Instead of:
Why? Because this 1 line above may cause the same "offset too big" error when attempted to be assembled.
BR,
Sun
viewtopic.php?p=104318#p104318
viewtopic.php?p=63305#p63305
viewtopic.php?p=97853#p97853
viewtopic.php?p=31616#p31616
viewtopic.php?p=79247#p79247
viewtopic.php?p=40968#p40968
And so on
The solution I recommend is using trampolines. What this means is from your address you first JMP to a cave inside the game process. And since you forcefully do that, the JMP will always be 5-bytes. I personally use the PE header, whereas I make writable the memory at $process+0x500 till $process+0x1000 <- this is where the executable code starts. Here you then JMP (14-bytes) to your allocated cave.
So like this (Lua code, but you can always convert it to auto-assembler):
Code: Select all
-- define our Trampolines spot
local gameModule = getAddress( process )
local offset = 0x500
t = gameModule + offset
fullAccess( t, 0x1000 - offset )
unregisterSymbol( "Trampolines" )
registerSymbol( "Trampolines", t, true )
Code: Select all
// Trampolines+00
[ENABLE]
alloc( InfiniteOxygenHook, 0x1000 )
registersymbol( InfiniteOxygenHook )
label( InfiniteOxygen_o )
registersymbol( InfiniteOxygen_o )
InfiniteOxygenHook:
// ..
// your code here
// ..
InfiniteOxygen_o: // original 6 bytes below read via readmem
readmem( InfiniteOxygen, 6 )
jmp far InfiniteOxygen+6
align 10 CC // this makes sure that the address of whatever is assembled below this will end in a 0; so you get "16-bytes aligned" addresses
// ^ cave ends here
// our trampoline
Trampolines+00:
jmp far InfiniteOxygenHook
align 10 CC
// our hook
InfiniteOxygen:
jmp Trampolines+00
nop 1
[DISABLE]
InfiniteOxygen:
readmem( InfiniteOxygen_o, 6 )
unregistersymbol( InfiniteOxygen_o )
dealloc( InfiniteOxygenHook )
unregistersymbol( InfiniteOxygenHook )
gameModule + offset = $process + 0x500). Here it will write another JMP (14-bytes this time) that will hop over to the allocated "InfiniteOxygenHook", where our cave is. In there, another "jmp far" will hop back to original hook spot (at "InfiniteOxygen+6").
Short version: code jumps to trampoline; trampolines jumps to cave. You got a middle-man in-between, 5-bytes JMP hopping over to a 14-bytes JMP
Another thing I recommend doing is not using direct reads of variables. Get used to writing things like this:
Code: Select all
mov rax,MyStoredAddress
mov rax,[rax]
Code: Select all
mov rax,[MyStoredAddress]
BR,
Sun
Re: Convert your AOB script from ‘jump 5’ to ‘jump 14’
I can highly recommend these methods, since you helped me with the Dark Alliance table I have been using the trampolines for all UE4 games since these are the games I've experienced the most 14-byte jmps. I use a separate LUA method for Mono games from panraven (viewtopic.php?p=204222#p204222) which I highly recommend also.
Re: Convert your AOB script from ‘jump 5’ to ‘jump 14’
Ah nice So it scans the module the hook address belongs to for 0xCCs it can overwrite (much like 0x90s) and plant there the trampoline JMPs Since you only need 5, it won't be too much hassle. Might be an issue if you have lots of injections (and not enough 0xCC groups of 5). The same can be done for normal modules (non-Unity), I believeRhark wrote: ↑Fri Apr 15, 2022 8:14 pmI can highly recommend these methods, since you helped me with the Dark Alliance table I have been using the trampolines for all UE4 games since these are the games I've experienced the most 14-byte jmps. I use a separate LUA method for Mono games from panraven (viewtopic.php?p=204222#p204222) which I highly recommend also.
Re: Convert your AOB script from ‘jump 5’ to ‘jump 14’
^ @SunBeam: I did not know that method is actually called a 'trampoline'... which i showcase in the 2nd example .
I came across the term a few times while reading through them CEF topics; but the technique wasn't all that clear to me then... And yeah, never really felt the need for it... till now.
^^ @Rhark: thx for bringing that too my/our attention: again, did some UE 3/4 games, and had/have no need for such a technique so far. But the fact that the script searches_for/collects (CC) gaps is definitely worth looking into it. I have not researched it (yet), but assume it does this dynamically ? Hence why i opted to go for the '+500~1000' mem_region for being (near) guaranteed availability... (while these/certain CC_gaps could/can change location-wise per game_session/save_load/etc)
I came across the term a few times while reading through them CEF topics; but the technique wasn't all that clear to me then... And yeah, never really felt the need for it... till now.
^^ @Rhark: thx for bringing that too my/our attention: again, did some UE 3/4 games, and had/have no need for such a technique so far. But the fact that the script searches_for/collects (CC) gaps is definitely worth looking into it. I have not researched it (yet), but assume it does this dynamically ? Hence why i opted to go for the '+500~1000' mem_region for being (near) guaranteed availability... (while these/certain CC_gaps could/can change location-wise per game_session/save_load/etc)
Re: Convert your AOB script from ‘jump 5’ to ‘jump 14’
I've only ever encountered one game that was using the area of memory at $process+500 which I think was Marvel's Avengers. Otherwise, it's a solid spot to have your trampolines.
Who is online
Users browsing this forum: No registered users