 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Thu Apr 30, 2015 9:41 pm Post subject: Custom Type and Actual Game Address |
|
|
I was attempting to build a custom type and the 64-bit code suggested RCX holds the address containing the value.
However, this address is not the game's address containing the value.
Is the actual game address accessible from within the conversion routines?
For example, if I defined ConvertRoutine as below, I would expect address 7FEFDA21000 to display the value 7FEFDA21000 using this type.
Instead, it displays some other address and is constantly changing as CE refreshes the display.
|
|
| Back to top |
|
 |
mgr.inz.Player I post too much
Reputation: 222
Joined: 07 Nov 2008 Posts: 4438 Location: W kraju nad Wisla. UTC+01:00
|
Posted: Fri May 01, 2015 3:43 am Post subject: |
|
|
Nope. Because memoryscanner unit is designed to work on copies, and copies of copies (compare to first scan results/compare to last scan results).
Also MemoryRecord unit works on copies (buf variable):
| Code: | function TMemoryRecord.GetValue: string;
var
br: PtrUInt;
bufsize: integer;
buf: pointer;
...
...
begin
bufsize:=getbytesize;
...
...
getmem(buf,bufsize);
GetRealAddress;
if ReadProcessMemory(processhandle, pointer(realAddress), buf, bufsize,br) then
begin
case vartype of
vtCustom:
begin
if customtype<>nil then
begin
if customtype.scriptUsesFloat then
result:=FloatToStr(customtype.ConvertDataToFloat(buf))
else
if showashex then result:=inttohex(customtype.ConvertDataToInteger(buf),8)
else if showassigned then result:=inttostr(integer(customtype.ConvertDataToInteger(buf)))
else result:=inttostr(customtype.ConvertDataToInteger(buf));
end
else
result:='error';
end;
...
...
...
end;
end
...
...
...
...
freemem(buf);
end; |
Yes, it is doable, but would require changing some code in CE source.
_________________
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Fri May 01, 2015 4:19 am Post subject: |
|
|
the TCheckroutine in memscan would then also need to be changed, and for every check, wheter it's a valid found result or not, the address needs to be calculated, which will slow down the scan.
so not sure if an address based custom type is worth it to slow down the normal scans, or fragment the scanner's design even more (there is already seperate handling of multiaob's and the all type)
| Code: |
if checkroutine(p,nil) then //found one
StoreResultRoutine(base+ptruint(p)-ptruint(buffer),p);
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Fri May 01, 2015 11:26 am Post subject: |
|
|
Sorry, I haven't glanced at the source code, but it wouldn't be as simple as sending the address by value as an additional argument?
All of the functions could simply ignore it and continue using their local copies of the value.
But then if the address is ever needed, we could get it from the stack.
pseudo code:
local value = readInteger(address)
compareResult(value, address)
The only reason this has come up is because of GTA5's encryption logic.
They XOR every address' value with the address itself.
So if I could add a custom type which does the same, I could more easily find the values.
|
|
| Back to top |
|
 |
mgr.inz.Player I post too much
Reputation: 222
Joined: 07 Nov 2008 Posts: 4438 Location: W kraju nad Wisla. UTC+01:00
|
Posted: Fri May 01, 2015 6:39 pm Post subject: |
|
|
I changed CustomTypeHandler and MemoryRecordUnit units.
(and it is still backward compatible for older custom AA scripts)
Results:
I'm still editing memscan unit.... can take a while.
EDIT:
Patch:
https://github.com/mgrinzPlayer/cheat-engine/commit/ee33e74cfb93e96b615fcf51592d57663fab55a0
CustomTypeHandler, MemoryRecordUnit, byteinterpreter, memscan
Info:
Real address value passed to convert routines.
in ConvertRoutine routine, I appended realAddress just after "structure/chunk/RAWDataCopy"
depends on currently used ByteSize.
in ConvertBackRoutine routine, realAddress is inside [EBP+10] or R8
| Code: | ByteSize:
dd 4
ConvertRoutine:
[64-bit]
// eax = output (store result in EAX)
//[rcx] = address of input
//[rcx+ByteSize] = "realAddress" (the value is the real address from the game)
// bytesize is 4 (hexadecimal)
// struct starts at [RCX+0] and ends at [RCX+03]
// appended "realAddress" is at [RCX+04]
mov eax,[rcx] // get value
xor eax,[rcx+4] // xor with "realAddress"
ret
[/64-bit]
|
Example:
| Code: | alloc(ConvertRoutine,1024)
alloc(ConvertBackRoutine,1024)
alloc(TypeName,256)
alloc(ByteSize,4)
alloc(UsesFloat,1)
alloc(UsesRealAddress,1)
TypeName:
db 'encrypted float (xor with address)',0
ByteSize:
dd 4
UsesFloat:
db 1
UsesRealAddress:
db 1
ConvertRoutine:
[64-bit]
// eax = output (store result in EAX)
//[rcx] = address of input
//[rcx+ByteSize] = "realAddress" (the value is the real address from the game)
mov eax,[rcx] // get value
xor eax,[rcx+4] // xor with "realAddress"
ret
[/64-bit]
[32-bit]
// eax = output (store result in EAX)
//[ebp+8] = address of input
//[[ebp+8]+ByteSize] = "realAddress" (the value is the real address from the game)
push ebp
mov ebp,esp
push ebx
mov ebx,[ebp+8] // get addres
mov eax,[ebx] // get origbytes
xor eax,[ebx+4] // xor with "realAddress"
pop ebx
pop ebp
ret 4
[/32-bit]
ConvertBackRoutine:
[64-bit]
//ecx = input (value you want to write)
//rdx = address of output
//r8 = "realAddress"
xor ecx,r8 // xor rcx,r8
mov [rdx],ecx
ret
[/64-bit]
[32-bit]
//[ebp+8] = input (value you want to write)
//[ebp+c] = address of output
//[ebp+10] = "realAddress"
push ebp
mov ebp,esp
push eax
push ebx
mov eax,[ebp+8] //load the value into eax
mov ebx,[ebp+c] //load the address into ebx
xor eax,[ebp+10] //xor with "realAddress"
mov [ebx],eax //write the value into the address
pop ebx
pop eax
pop ebp
ret 8
[/32-bit] |
Download:
https://github.com/mgrinzPlayer/cheat-engine/releases/tag/CE6.4-15.05.01
https://github.com/mgrinzPlayer/cheat-engine/releases/download/CE6.4-15.05.01/customTypeMod.15.05.01.7z
How to:
1. make a copy of current CE6.4 folder, rename the copy to something meaningful, e.g. "CE64_mod"
2. download customTypeMod.15.05.01.7z, extract everything into "CE64_mod"
3. overwrite everything
4. CT files created with this new CE, better test them on original CE6.4 before posting them.
What I've tested so far:
- first scan
- next scan, value increased/decreased
- next scan, smaller/bigger than, between
- editing values via "memoryrecords"
_________________
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Fri May 01, 2015 7:14 pm Post subject: |
|
|
why not use r8=realaddress for convertroutine ?
(you forgot the all type loop)
And try not to put any extra IF statements inside "while (ptruint(p)<=lastmem) do" loops. See the first scan example for vtByteArrays and vtAll scan, instead of putting the if statement inside it, put it outside of it
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping
Last edited by Dark Byte on Fri May 01, 2015 7:26 pm; edited 1 time in total |
|
| Back to top |
|
 |
mgr.inz.Player I post too much
Reputation: 222
Joined: 07 Nov 2008 Posts: 4438 Location: W kraju nad Wisla. UTC+01:00
|
Posted: Fri May 01, 2015 7:26 pm Post subject: |
|
|
I wanted to save original "real address" for some checkroutines (compare to previous or saved).
I forgot to add a note:
| Code: | | Not available in "Value Type: All" scans. |
_________________
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Fri May 01, 2015 7:30 pm Post subject: |
|
|
| mgr.inz.Player wrote: | | I wanted to save original "real address" for some checkroutines (compare to previous or saved). |
I know, but people are going to complain about that (trust me)
Besides, if you're going to have a separate scanloop for custom types anyhow, you can just as well add a TCustomCheckRoutine where the address is passed as well (or use a private var in TScanner and use that to pass to the custom type)
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
mgr.inz.Player I post too much
Reputation: 222
Joined: 07 Nov 2008 Posts: 4438 Location: W kraju nad Wisla. UTC+01:00
|
Posted: Fri May 01, 2015 8:01 pm Post subject: |
|
|
I agree.
For now, the changes I made are just for "proof of concept".
I know that scans for customtype with UsesRealAddress will take about 105% more of time (another copyMemory).
And scans for non-customtype will be slightly slower because of those extra IFs...
| Quote: | | you can just as well add a TCustomCheckRoutine |
| Quote: | | instead of putting the if statement inside it, put it outside of it |
If current customTypeMod.15.05.01 build works for somebody, I will add/commit those changes.
Another note:
setting a value with "foundlist - change value of selected addresses" doesn't work for now.
edit:
afk
_________________
|
|
| Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Fri May 01, 2015 9:06 pm Post subject: |
|
|
Throwing out some random ideas. No experience with Pascal or CE's source, so forgive me.
1. Would it be a monumental change or cause a performance hit to pass the input by reference instead?
procedure TCustomType.ConvertToData(input: pointer; output: pointer); or
procedure TCustomType.ConvertToData(input: ptruint; output: pointer);
Or if useRealAddress is enabled, then to use this third, new conversion routine instead?
So as to not affect standard custom searches.
This way you are interacting directly with game memory.
2. In your current approach, to not affect other custom searches, you could:
| Code: | if (variableType=vtCustom) and customType.scriptNeedsRealAddress then
begin
while (ptruint(p)<=lastmem) do
begin
...
end
else
while (ptruint(p)<=lastmem) do
begin
...
end
end |
3. Again, not certain how each module fits together, but doesn't the 'p' variable already hold the address you are currently examining in the code [if checkroutine(p,nil)]? Not sure of the use of all that modifiedMEM code. (You don't need to explain it, I just wanted to make sure all of that logic was needed)
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Fri May 01, 2015 9:26 pm Post subject: |
|
|
1: cheat engine has no direct access to the game's memory. Only copies it inspects locally. So when ConvertToData(input, output) input and output are CE's addresses, not the game's
And sure, I could let the custom type do the ReadProcessMemory call,for every single address, but that would just be too slow
2: I did, but it just looks so cluttery
3: p holds the address of the current copy
CE allocates a block of up to 512KB (depending on the settings) copies a chunk of the game's memory into there
sets P to the start of the copy, and lastmem to the end of the copy
and then goes through the loop which will check every bytes or 4 bytes (fastscan) if the value matches what was being looked for
To calculate the actual address ce needs to get the base address of the copy, the original address and p, then add the difference of p and the copy to the actual address
Doing that for every address, including the ones that don't have a matching value, is a small amount of wasted cpu cycles, but for a 2GB game that would be :(2147483648-found results) * number of wasted cpu cycles
anyhow, I just implemented something of my own.
I added a new calling convention you can activate with
this will give you the following functions to implement:
| Code: |
cdecl int ConvertRoutine(unsigned char *input, PTR_UINT address);
cdecl void ConvertBackRoutine(int i, PTR_UINT address, unsigned char *output);
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Fri May 01, 2015 11:51 pm Post subject: |
|
|
1. checkroutine doesn't need to be sent currentAddress?
2. Should you be adding base again to AddressFound?
| Code: | vtCustom:
begin
+ while (ptruint(p)<=lastmem) do
begin
+ currentAddress:=base+ptruint(p)-ptruint(buffer);
+ if checkroutine(p,nil) then //found one *** 1 ***
begin
+ StoreResultRoutine(currentAddress,p);
+ if OnlyOne then
+ begin
+ AddressFound:=base+currentAddress; *** 2 ***
+ exit;
+ end;
end;
+
+ inc(p,stepsize);
end; |
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Sat May 02, 2015 3:59 am Post subject: |
|
|
1: no, the TCheckRoitine methodcall does not need an address, else it would have to be applied to other types as well.
In this case the tscanner. currentaddress var is a type specific addition for vtCustom which the CheckRoutine implementation for custom scan uses to figure out the address
2: that is a bug yes (not a big one as it only takes effect in lua scripts that use the vtCustom type specifically in a custom memory scan, and use the only one result option, which is most of the time useless for integer types)
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
mgr.inz.Player I post too much
Reputation: 222
Joined: 07 Nov 2008 Posts: 4438 Location: W kraju nad Wisla. UTC+01:00
|
Posted: Sat May 02, 2015 5:35 pm Post subject: |
|
|
OK. I deleted my realAddressForCustomType branch... There's no point in keeping it.
"ret" instead of "ret 4" in 32bit ConvertRoutine
ConvertBackRoutine also different: RDX==>R8, [ebp+c]==>[ebp+10], "ret 8"==>"ret"
Recent changes, CE is no longer backward compatible with my collection of CustomType scripts.
Also typo here:
| Code: |
Add('//example:');
Add('mov [r8],ecx //place the integer at the 4 bytes pointed to by rdx') |
should be: "pointed to by r8"
_________________
|
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25836 Location: The netherlands
|
Posted: Sat May 02, 2015 6:17 pm Post subject: |
|
|
if you set CALLMETHOD to 0 (or don't define it at all) it should be fully compatible with the old custom types (and old custom types don't have that defined)
but yes, new scripts developed for 6.5 won't work for 6.4(unless made for 6.4 specifically), which isn't anything that new (same goes for lua, new lua functions won't work on 6.4)
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|