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):
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 )
Then in the actual script, I do this:
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 )
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:
Code: Select all
mov rax,MyStoredAddress
mov rax,[rax]
Instead of:
Why? Because this 1 line above may cause the same "offset too big" error when attempted to be assembled.
BR,
Sun