About calculating call from different location and readmem in general

Anything Cheat Engine related, bugs, suggestions, helping others, etc..
User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

About calculating call from different location and readmem in general

Post by Horse4Horse »

First question is, why I'm getting a "Invalid address for ReadMem" error in code like this:

Code: Select all

[ENABLE]
aobscanmodule(INJECT,Exanima.exe,E8 9D B6 FB FF)
registersymbol(INJECT)
alloc(original,5)
alloc(desired,5)
registersymbol(original)
registersymbol(desired)

original:
readmem(INJECT+11,5)
desired:
readmem(INJECT,5)


INJECT+11:
readmem(desired,5)   //error here

[DISABLE]

INJECT+11:
readmem(original,5)  // is working fine

unregistersymbol(INJECT)
unregistersymbol(original)
unregistersymbol(desired)
Searched about this procedure and seen, that people are using method like this to store original values for disabling part and for them its working great. And simple reverting value to its original(when cheat is disabling - or when "readmem(desired,5) " is commented out) is working for me too, but writing desired bytes - is not. Where I'm stupid and why?

And second - Is there a way to calculate a desired call from different location?
Let's say, I have an assembler code looks like this:

Code: Select all

004B1EFE - E8 9DB6FBFF           - call 0046D5A0
004B1F03 - 8B 04 24
004B1F06 - 8B D0
004B1F08 - A1 F41E6300 
004B1F0D - 8B 00
004B1F0F - E8 14B7FBFF           - call 0046D628
I need to replace second call with the first one without allocating newmem and jumping to it and any other things, just by using readmem and some magic, so I dont need to change much code, when game is updated.
Idea is, that I save second call bytes throught readMem for later disabling procedure. Then I save first call bytes throught readMem, then I subtract two calls byte lenth difference(11 bytes) from recived bytes and then replace second call with calculated first call. And if cheat is disabled - second call is replaced with it's original.
Is it possible? Or is any other means possible? Like reading instruction opcodes, then replace second with the first? Tried to search anything about related and found nothing.
I know, that it's easier to save time and just create a newmem, but I want to learn better methods.

User avatar
TheyCallMeTim13
Administration
Administration
Posts: 1851
Joined: Fri Mar 03, 2017 12:31 am
Reputation: 1017

Re: About calculating call from different location and readmem in general

Post by TheyCallMeTim13 »

Most likely the problem is how CE deals with the scripts. It does multiple passes so it's probably that the address doesn't actually exist yet. So try it like you have it when storing that bytes, since that doesn't throw an error.

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

Re: About calculating call from different location and readmem in general

Post by SunBeam »

Horse4Horse wrote:
Mon Jan 10, 2022 9:52 pm
why I'm getting a "Invalid address for ReadMem" error in code like this:
Because "aobscanmodule(INJECT,Exanima.exe,E8 9D B6 FB FF)" failed. It returned 0, so registering a symbol with 0 won't work. Why don't you check it for yourself? Open Memory View > Ctrl+G and type in INJECT. Then click OK. If you get to the correct address, then there's another issue. Else, what I said above.

"when game is updated" -> Your snippet won't be the same when the game is updated. Once the executable is recompiled chances are high that the alignment will relocate functions/instructions. So that address of yours - 4B1EFE - won't show a "call 0046D5A0", but something else, if you inspect it in Memory View. So you will need to re-find the location to begin with (where you have your CALL that you want to switch with another).

There are quite a few things you need to do BEFORE all of your questions. And that could get solved if you study a bit more. For example: what is the formula to calculate a destination from a known EP? (If you ask me what EP means, then I dunno...)

User avatar
Rhark
Fearless Donors
Fearless Donors
Posts: 1376
Joined: Tue Apr 16, 2019 1:27 am
Reputation: 617

Re: About calculating call from different location and readmem in general

Post by Rhark »

Code: Select all

INJECT+11:
readmem(desired,5)   //error here
From what I can see it seems this is useless. Doesn't the script work without it?

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

TheyCallMeTim13 wrote:
Mon Jan 10, 2022 10:21 pm
Most likely the problem is how CE deals with the scripts. It does multiple passes so it's probably that the address doesn't actually exist yet. So try it like you have it when storing that bytes, since that doesn't throw an error.
I think that may be the exactly reason - because it tries to readmem before actual oabscan is completed and "INJECT" is registered, but it ignores these errors because script doesn't write anything to the game memory right before:

Code: Select all

INJECT+11:
readmem(desired,5)
And if I comment out that part(or change it to db %something%) - injecting are working properly, and after disabling - it reverts bytes that was actually stored in "original". May be it's because after [DISABLE] CE have that bytes stored in "original"(and "changed", I tried that too, any other readmem is working fine after disabling part).
I tried to separate scripts - one is

Code: Select all

[ENABLE]
aobscanmodule(INJECT,Exanima.exe,E8 9D B6 FB FF)
registersymbol(INJECT)
alloc(original,5)
alloc(desired,5)
registersymbol(original)
registersymbol(desired)

original:
readmem(INJECT+11,5)
desired:
readmem(INJECT,5)

[DISABLE]
unregistersymbol(INJECT)
unregistersymbol(original)
unregistersymbol(desired)
and second is:

Code: Select all

[ENABLE]
INJECT+11:
readmem(desired,5)

[DISABLE]
INJECT+11:
readmem(original,5)
Then I enable first one, and after - second. And it's working as intended, writing all "desired" bytes and reverting "original" like it should. So you're exactly right - thats the problem with an CE's AA script handler. But is there any way to bypass that error? Like pausing writing to memory before readmem values are get?
Dont want to make a longpost, so I'll separate answers.

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

SunBeam wrote:
Mon Jan 10, 2022 11:50 pm
Horse4Horse wrote:
Mon Jan 10, 2022 9:52 pm
why I'm getting a "Invalid address for ReadMem" error in code like this:
"when game is updated" -> Your snippet won't be the same when the game is updated. Once the executable is recompiled chances are high that the alignment will relocate functions/instructions. So that address of yours - 4B1EFE - won't show a "call 0046D5A0", but something else, if you inspect it in Memory View. So you will need to re-find the location to begin with (where you have your CALL that you want to switch with another).

There are quite a few things you need to do BEFORE all of your questions. And that could get solved if you study a bit more. For example: what is the formula to calculate a destination from a known EP? (If you ask me what EP means, then I dunno...)
I think answer to the first part are already said, it's script handler error, and not my brain damage(phew), so I dont include that as quote.

It's hard to explain my idea, but I'll try.
Injecting are done every time in the exact location, and all code in between "desired" and "original" can be changed in numbers, but not in lenght. So "desired" is always be "INJECT+0" and "original" will be always a "INJECT+11". All what I plan - is to read that "desired" bytes, then subtract 11 bytes from second byte of it, and write that to "INJECT+11". Because at "INJECT+11" it will be correct call to the "desired" location.
Even easer - I can just "readmem(INJECT+1,1)", and calculate that one byte, because all other bytes wont change at all(two calls arent separated enough, but if "desired" will something on the borderline - better to increase readmem to 2 bytes).
I know, that I'm searching with aobscan - that call instruction, and after any update it will be changed, and aobscan fail. I just trying find a easy example to explain my idea. Real injection will be in the place without all that variables(calls, jumps, movs etc), just with unique bytes.
Maybe I dont understand something, but I checked out that part in other game versions - and these two calls separated exaclty by 11 bytes every time. So in theory it is possible.
I need to separate scripts(mainly because of the first problem) and in the first script calculate "desired_calculated" from "desired-(desired-original)=desired_calculated". Or simply "desired-0x11 = desired_calculated" - because spacing between calls likely will not change. And if will - so "original" value wil be wrong already, because "readmem" will read wrong bytes from wrong location(maybe like a "xor eax,eax" and etc).
So how about it?
And yea, I dont know about an entry point, only a year passed after I started to learn CE seriosly, from an easy and unstable solutions to more complex and failproof(mainly because I tired to fix everything after game updates).
Last edited by Horse4Horse on Tue Jan 11, 2022 2:39 pm, edited 1 time in total.

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

Rhark wrote:
Tue Jan 11, 2022 2:19 am

Code: Select all

INJECT+11:
readmem(desired,5)   //error here
From what I can see it seems this is useless. Doesn't the script work without it?
It just reads memory on "desired", which was "inject+0", i.e. "0x21" , as I think.
But why is it useless on your opinion, and disabling part -

Code: Select all

INJECT+11:
readmem(original,5)
- is not?

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

Nwm, naild it. By very raw and stupid code, but it works.
The main problem is - that lua function call isnt working inside first script. Even if separated like that:

Code: Select all

{$lua}
function calculatedesired()
  intdesired = tonumber(readBytes("desired"))-17
  return WriteByte("desired_calculated",intdesired)
end
{$asm}
{$lua}
calculatedesired()
{$asm}
But when it called outside, from different script - it's working properly. I think it correlates with the first problem with an readmem error.
So, I found many posts about different parts of this code on many forums, spent around 6 hours or so(Yea, I'm that kind of stupid) and hope, that this help someone too:
First script:

Code: Select all

[ENABLE]
aobscanmodule(INJECT,Exanima.exe,E8 21 C3 FB FF)
registersymbol(INJECT)
alloc(original,1)
alloc(desired,1)
alloc(desired_calculated,1)
registersymbol(original)
registersymbol(desired)
registersymbol(desired_calculated)

original:
readmem(INJECT+12,1)
desired:
readmem(INJECT+1,1)

[DISABLE]

unregistersymbol(INJECT)
unregistersymbol(original)
unregistersymbol(desired)
unregistersymbol(desired_calculated)
Second:

Code: Select all

[ENABLE]

{$lua}
function calculatedesired()
  intdesired = tonumber(readBytes("desired"))-17
  return WriteByte("desired_calculated",intdesired)
end
calculatedesired()
{$asm}

INJECT+12:
readmem(desired_calculated,1)

[DISABLE]
INJECT+12:
readmem(original,1)
And actually you can write that function "calculatedesired" into "Cheat Table Lua Script" and in the second script you just call it.
But main problem remains - you cant write anything by readmem in the first script, and if function code is located in it - you cant call it too, only if function is written in the main "cheat table lua script".
Is there any way of pausing the "write" part of the script before injection and allocation is completed?
Or only suitable solution is to just attach second script as a child to the first, and share activating and deactivating with the children with addition

Code: Select all

INJECT+12:
readmem(original,1)
After [DISABLE] part of the first script?

User avatar
TheyCallMeTim13
Administration
Administration
Posts: 1851
Joined: Fri Mar 03, 2017 12:31 am
Reputation: 1017

Re: About calculating call from different location and readmem in general

Post by TheyCallMeTim13 »

Horse4Horse wrote:
Tue Jan 11, 2022 2:33 pm
...
The problem is not in the script handler, it's in you misunderstanding how it works. What you store at "desired" is the same as what's at "INJECT", and "desired"s address won't exist til the script is completed but "INJECT"s address does. So "try it like you have it when storing the bytes" means, use the address that exists. Meaning use "INJECT" as the address not "desired". You really don't even need to store those bytes to "desired".

User avatar
GreenHouse
GreenHouse!
GreenHouse!
Posts: 804
Joined: Fri Oct 12, 2018 10:25 pm
Reputation: 724

Re: About calculating call from different location and readmem in general

Post by GreenHouse »

Pretty much what Tim said. You ended up using two scripts to do something really simple. Try this:

Code: Select all

[ENABLE]
aobscanmodule(INJECT,Exanima.exe,E8 9D B6 FB FF)
registersymbol(INJECT)
alloc(original,5)
registersymbol(original)

original:
readmem(INJECT+11,5)

INJECT+11:
readmem(INJECT,5)

[DISABLE]
INJECT+11:
readmem(original,5)

unregistersymbol(INJECT)
unregistersymbol(original)

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

TheyCallMeTim13 wrote:
Tue Jan 11, 2022 4:54 pm
Horse4Horse wrote:
Tue Jan 11, 2022 2:33 pm
...
The problem is not in the script handler, it's in you misunderstanding how it works. What you store at "desired" is the same as what's at "INJECT", and "desired"s address won't exist til the script is completed but "INJECT"s address does. So "try it like you have it when storing the bytes" means, use the address that exists. Meaning use "INJECT" as the address not "desired". You really don't even need to store those bytes to "desired".
I understand what you're talking about(and as I said - it was an example, real values like +26 from "INJECT", its just for simplicity), but if I try to use any other address to be "desired"(inject+5 as example) - I'm getting the same error. And I dont see any other way to read memory, subtract it and write to location in one script without heavy lifting lua commands.
Last edited by Horse4Horse on Tue Jan 11, 2022 5:22 pm, edited 1 time in total.

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

GreenHouse wrote:
Tue Jan 11, 2022 5:07 pm
Pretty much what Tim said. You ended up using two scripts to do something really simple. Try this:

Code: Select all

[ENABLE]
aobscanmodule(INJECT,Exanima.exe,E8 9D B6 FB FF)
registersymbol(INJECT)
alloc(original,5)
registersymbol(original)

original:
readmem(INJECT+11,5)

INJECT+11:
readmem(INJECT,5)

[DISABLE]
INJECT+11:
readmem(original,5)

unregistersymbol(INJECT)
unregistersymbol(original)
Yes, something like that is working fine, but only before the part where I need to subtract bytes. Because if you insert those same bytes to different location - that call instruction will turn into gibberish.
This is what I asked for - is there any way to subtract bytes "on the fly", or you need to store them and then do math on stored bytes, so later you can insert them into differnt location?

User avatar
GreenHouse
GreenHouse!
GreenHouse!
Posts: 804
Joined: Fri Oct 12, 2018 10:25 pm
Reputation: 724

Re: About calculating call from different location and readmem in general

Post by GreenHouse »

That could be done with LUA for example. It might be the cheesiest way, but it should work.
And it also could be simplified by someone that knows LUA more than I do.

Code: Select all

[ENABLE]
{$lua}
if syntaxcheck then return end
xAddress = AOBScanModuleUnique('Exanima.exe','E8 9D B6 FB FF 8B 04 24')
x1, x2, x3, x4 = splitDisassembledString(disassemble(xAddress[0]))
xSavedCall = readBytes(tonumber(x4,16) + 0x11,5,true)
writeBytes(tonumber(x4,16) + 0x11,assemble(x2,tonumber(x4,16) + 0x11))

[DISABLE]
{$lua}
if syntaxcheck then return end
writeBytes(tonumber(x4,16) + 0x11,xSavedCall,5)

User avatar
Horse4Horse
Expert Cheater
Expert Cheater
Posts: 50
Joined: Thu Aug 02, 2018 7:54 pm
Reputation: 8

Re: About calculating call from different location and readmem in general

Post by Horse4Horse »

GreenHouse wrote:
Tue Jan 11, 2022 7:32 pm
That could be done with LUA for example. It might be the cheesiest way, but it should work.
And it also could be simplified by someone that knows LUA more than I do.

Code: Select all

[ENABLE]
{$lua}
if syntaxcheck then return end
xAddress = AOBScanModuleUnique('Exanima.exe','E8 9D B6 FB FF 8B 04 24')
x1, x2, x3, x4 = splitDisassembledString(disassemble(xAddress[0]))
xSavedCall = readBytes(tonumber(x4,16) + 0x11,5,true)
writeBytes(tonumber(x4,16) + 0x11,assemble(x2,tonumber(x4,16) + 0x11))

[DISABLE]
{$lua}
if syntaxcheck then return end
writeBytes(tonumber(x4,16) + 0x11,xSavedCall,5)
Thanks for the code! I'll try to figure out it later, you're already pointig me to the stuff, described only at celua.txt and not at the wiki. The main problem for me was - to figure out, how properly do the math, because some func are returning strings, some integers, some hex and it was very confusing. But functions that you used("disassemble" and "splitDisassembledString") are looks very helpfull in general!

User avatar
TheyCallMeTim13
Administration
Administration
Posts: 1851
Joined: Fri Mar 03, 2017 12:31 am
Reputation: 1017

Re: About calculating call from different location and readmem in general

Post by TheyCallMeTim13 »

Horse4Horse wrote:
Tue Jan 11, 2022 5:14 pm
...
I understand what you're talking about(and as I said - it was an example, real values like +26 from "INJECT", its just for simplicity), but if I try to use any other address to be "desired"(inject+5 as example) - I'm getting the same error. And I dont see any other way to read memory, subtract it and write to location in one script without heavy lifting lua commands.
Sorry I was thinking wrong about a call address, I use some lua function I wrote (posted below) so I haven't needed to think about it in a long time. I should have also told you to use [Link].

Code: Select all

[ENABLE]
aobscanmodule(INJECT, Exanima.exe, E8xxxxxxxx8B04248BD0A1)
registersymbol(INJECT)
alloc(original, 5)
registersymbol(original)

original:
readmem(INJECT+11, 5)


INJECT+11:
reassemble(INJECT)

[DISABLE]

INJECT+11:
readmem(original, 5)

unregistersymbol(INJECT)
unregistersymbol(original)
As for doing it with lua, these are two functions I wrote and use regularly:

Code: Select all

---- 
---- Calculates the address stored in opcode if 64 bit, or reads the address if 32 bit.
---- 
---- getOpcodeAddress(address)
---- 
---- Parameters:
---- 	address : number - string :
---- 		The address of the opcode the stored address is.
---- Return:
---- 	number :
---- 		The address stored at the given opcode address.
function getOpcodeAddress(address)
	address = getAddress(address)
	if targetIs64Bit() then
		local os = readInteger(address, true) or 0
		return address + 4 + os
	else
		return readInteger(address)
	end
end
registerLuaFunctionHighlight('getOpcodeAddress')

---- 
---- Calculates the address stored in opcode.
---- 
---- getCallAddress(address)
---- 
---- Parameters:
---- 	address : number - string :
---- 		The address of the opcode the stored address is.
---- Return:
---- 	number :
---- 		The address stored at the given opcode address.
function getCallAddress(address)
	address = getAddress(address)
	local os = readInteger(address, true) or 0
	return address + 4 + os
end
registerLuaFunctionHighlight('getCallAddress')
EDIT:
And I actually use custom auto assembler commands in the end, but these have some dependencies (3 modules for these to work) and you need to modify them to make them work. Just thought that mutch code would be more confusing, but that these might help illustrate how the above functions work.

Code: Select all


local function getOpcodeAddressAA(parameters, syntaxcheck)
	----
	---- getOpcodeAddress(symbol, address)
	----
	local symbol, address = commands.getParameters(parameters)
	local status, msg = commands.checkParameter(symbol, 'symbol', 'getOpcodeAddress')
	if not status then return nil, msg end
	symbol = commands.checkForLuaGlobal(symbol)
	status, msg = commands.checkParameter(address, 'address', 'getOpcodeAddress')
	if not status then return nil, msg end
	address, msg = commands.parseNumberOrAddress(address, 'address', 'getOpcodeAddress')
	if not address then return nil, msg end
	if syntaxcheck then
		return string.format('define(%s, %016X)', symbol, 0)
	end
	local addr = getOpcodeAddress(address)
	return string.format('define(%s, %016X)', symbol, addr or 0)
end
registerAutoAssemblerCommand('getOpcodeAddress', getOpcodeAddressAA)

local function getCallAddressAA(parameters, syntaxcheck)
	----
	---- getCallAddress(symbol, address)
	----
	local symbol, address = commands.getParameters(parameters)
	local status, msg = commands.checkParameter(symbol, 'symbol', 'getCallAddress')
	if not status then return nil, msg end
	symbol = commands.checkForLuaGlobal(symbol)
	status, msg = commands.checkParameter(address, 'address', 'getCallAddress')
	if not status then return nil, msg end
	address, msg = commands.parseNumberOrAddress(address, 'address', 'getCallAddress')
	if not address then return nil, msg end
	if syntaxcheck then
		return string.format('define(%s, %016X)', symbol, 0)
	end
	local addr = getCallAddress(address)
	return string.format('define(%s, %016X)', symbol, addr or 0)
end
registerAutoAssemblerCommand('getCallAddress', getCallAddressAA)

Post Reply

Who is online

Users browsing this forum: No registered users