Urgently need help!

Anything Cheat Engine related, bugs, suggestions, helping others, etc..
Post Reply
JK89526
What is cheating?
What is cheating?
Posts: 3
Joined: Tue May 23, 2023 6:23 pm
Reputation: 0

Urgently need help!

Post by JK89526 »

I'm making a cheat trainer and I've run into this kind of problem. Does anyone know how to solve it? Problem: I'm trying to get the address of a specific function; I have offsets and I'm trying to get the right address, but it gives out a completely wrong address in the program (that is, my cheat trainer). And the thing is that the Cheat Engine somehow calculates the address offset using its own method. I have a certain base address: "*DLL name*.dll" + 00120C78 , the address I got is: 632B0C78. After I check the Pointer box and my address is converted to a 64 bit address, the address I got is: 1000A3284. So far there is nothing special. Then I write in the text input window the first offset: 25C , and the address I got is: 1000A34E0. Then I add a second offset and the previous address from the first offset changes from 1000A34E0 to 1003E6C10. And no matter how many offsets I add, each previous offset changes its address. How is this possible? And how can I implement this in my cheat trainer? Indeed, according to the essence, the offsets that I received alternately add up with the base address. (base2 = base + 1 offset; base3 = base2 + 2 offset;.....and so on)

User avatar
LeFiXER
LeFixer
LeFixer
Posts: 476
Joined: Wed Mar 24, 2021 9:35 am
Reputation: 242

Re: Urgently need help!

Post by LeFiXER »

1000A3284 + 25C = 1000A34E0. Why are you adding the previous address to it? Pointers are a relative simple construct. You have an address that when an offset is added to it, the address points to value which is an address of another place in memory. It's the intended behaviour to change the value the address points to when you add offsets to the intitial pointer address moreover, is your cheat trainer made within Cheat Engine or a programming language?

JK89526
What is cheating?
What is cheating?
Posts: 3
Joined: Tue May 23, 2023 6:23 pm
Reputation: 0

Re: Urgently need help!

Post by JK89526 »

I am writing a cheat trainer in the C++ programming language. You apparently do not quite understand me. This will indeed be correct: 1000A3284 + 25C = 1000A34E0. In theory, I should sum the offsets with the base address, as I wrote above (base2 = base + 1 offset; base3 = base2 + 2 offset;.....and so on). In my program, I sum the offsets with the base address and get a non-existent address: 0xccccccccccccc.... I began to figure out what the problem was. First I checked the sum of the base address and the first offset: 1000A3284 + 25C = 1000A34E0. (the address is correct) To check in Cheat Engine, I added a new address via the "Add Address Manually" button and wrote the address "*DLL name*.dll" + 00120C78. The address I received is 632B0C78. Then I clicked on the "Pointer" checkbox. Next to the address input window (where it was written: "*DLL name*.dll"+00120C78) there is a label with the text: "-> 1000A3284". (address 632B0C78 was converted to a 64bit address) So far, there is nothing special about this, everything is correct. Then in the box for entering the text of the first offset, I entered: 25C. Next to it is an underlined label with the text: "1000A3284 + 25C = 1000A34E0". (Everything is correct, everything is the same in the program). Then I click the "Add Offset" button. After that, a box for entering text for the second offset appears. And immediately the text of the label, which is next to the box for entering the text of the first offset, changes to: "[1000A3284 + 25C] -> 1003E6C10" (How is 1003E6C10 obtained if 1000A3284 + 25C = 1000A34E0?). That is, the second offset will already be: 1003E6C10 + *second offset*. (It was all in the Cheat Engine). If in my program I add the first and second offset to the sum of the base address, then I will get a non-existent address: 0xccccccccccccc.... How does Cheat Engine convert the address 1000A34E0 to 1003E6C10?? And how can I implement it in my program? (At the moment, while I am writing a replay, the address that is being converted is already not 1003E6C10, but 1003E7010. Although in the previous session of the game it was 1003E6C10)

User avatar
SunBeam
RCE Fanatics
RCE Fanatics
Posts: 4638
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 4141

Re: Urgently need help!

Post by SunBeam »

CE does not "convert" anything; a pointer, by definition, is an address that points to the memory space of another address. If your address is 1000A3284 and you add 25C, then 1003E6C10 is the read value of that sum. Which value is an address itself. [...] brackets mean read in ASM mnemonics. Whenever you see [addr] that means the read value of addr. ReadProcessMemory, in your cpp world, if you will.

User avatar
Chucky
Expert Cheater
Expert Cheater
Posts: 75
Joined: Thu Mar 08, 2018 4:01 pm
Reputation: 28

Re: Urgently need help!

Post by Chucky »

JK89526 wrote:
Wed May 24, 2023 5:40 pm
I am writing a cheat trainer in the C++ programming language........
Post your cpp function and how you use it or PM me.

User avatar
Rixef
Cheater
Cheater
Posts: 27
Joined: Wed May 10, 2023 7:43 am
Reputation: 20

Re: Urgently need help!

Post by Rixef »

JK89526 wrote:
Wed May 24, 2023 5:40 pm
I am writing a cheat trainer in the C++ programming language. You apparently do not quite understand me. This will indeed be correct: 1000A3284 + 25C = 1000A34E0. In theory, I should sum the offsets with the base address, as I wrote above (base2 = base + 1 offset; base3 = base2 + 2 offset;.....and so on). In my program, I sum the offsets with the base address and get a non-existent address: 0xccccccccccccc.... I began to figure out what the problem was. First I checked the sum of the base address and the first offset: 1000A3284 + 25C = 1000A34E0. (the address is correct) To check in Cheat Engine, I added a new address via the "Add Address Manually" button and wrote the address "*DLL name*.dll" + 00120C78. The address I received is 632B0C78. Then I clicked on the "Pointer" checkbox. Next to the address input window (where it was written: "*DLL name*.dll"+00120C78) there is a label with the text: "-> 1000A3284". (address 632B0C78 was converted to a 64bit address) So far, there is nothing special about this, everything is correct. Then in the box for entering the text of the first offset, I entered: 25C. Next to it is an underlined label with the text: "1000A3284 + 25C = 1000A34E0". (Everything is correct, everything is the same in the program). Then I click the "Add Offset" button. After that, a box for entering text for the second offset appears. And immediately the text of the label, which is next to the box for entering the text of the first offset, changes to: "[1000A3284 + 25C] -> 1003E6C10" (How is 1003E6C10 obtained if 1000A3284 + 25C = 1000A34E0?). That is, the second offset will already be: 1003E6C10 + *second offset*. (It was all in the Cheat Engine). If in my program I add the first and second offset to the sum of the base address, then I will get a non-existent address: 0xccccccccccccc.... How does Cheat Engine convert the address 1000A34E0 to 1003E6C10?? And how can I implement it in my program? (At the moment, while I am writing a replay, the address that is being converted is already not 1003E6C10, but 1003E7010. Although in the previous session of the game it was 1003E6C10)
SunBeam and LeFiXER are correct. You've almost got it but you need to read up just a little more on pointers and how memory addresses work and is how it's read. You got the right motions down but seem to be lacking a bit of the full grasp of what exactly it's all doing.

So let's say you're reading your player health in a game.
The address; 0xDEADBEEF has your health value. so the value of 0xDEADBEEF is your health. Let's say the game you're hacking stores health as a simple 4byte int(int32), no obfuscation of any sort, and we're not reading Multi Level Pointers rn, just the simple address that contains your health. So let's read your health from the game into your cpp program:

Code: Select all

int myPlayerHealth; //This is a 32bit(4 bytes) signed integer so 4bytes = 00 00 00 00 in hex(spacing there to obviate what 4 bytes looks like)

ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF, &myPlayerHealth, sizeof(myPlayerHealth), 0);

//RPM = ReadProcessMemory

//Let's break down ReadProcessMemory a bit, excluding the handle
//RPM's second argument is [in]  LPCVOID lpBaseAddress
//What this means is you input an address to read the value of, typecasting it as a Long Pointer to Constant Void(LPCVOID) so that
//RPM knows how to read the address that you're inputting.
//So with that knowledge we have:
//ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF

//But now we want to store the value it's reading at that address so what's next?
//The third argument of RPM is [out] LPVOID  lpBuffer
//Which means you're going to put a variable here that is going to be the output of the RPM function.
//Read "&" as "address of"; so if we have &myPlayerHealth then that means we're outputting a value to the "address of" myPlayerHealth
//So in other words, in memory; myPlayerHealth has it's own address with it's own value. We're setting the value at myPlayerHealth to the value of the address 0xDEADBEEF

//Okay, so we've got a storage place to read the value of 0xDEADBEEF into. Now what?
//Fourth argument of RPM; [in]  SIZE_T  nSize
//This is telling RPM how much memory to read at the address 0xDEADBEEF. We know your health in the game is a simple 4byte int so here we pass that on to RPM to read 4 bytes at the address of 0xDEADBEEF
//Note that these all mean the same thing:
//ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF, sizeof(myPlayerHealth)
//ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF, sizeof(int)
//ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF, 4
//All that means is that we're reading 4 bytes at 0xDEADBEEF. You can literally just put 4 there if you want. I like using sizeof(varName) most a the time.

//Okay, sweet! that's pretty much it, there's only 1 more argument to RPM function and it's optional;
//[out] SIZE_T  *lpNumberOfBytesRead
//which means this is another output variable that just stores how many bytes were read from at 0xDEADBEEF
//it's useful if you're reading a more variable amount of bytes and need to calculate that later but we're not doing that here so we can just fill it in with 0
//ReadProcessMemory(handle, (LPCVOID)0xDEADBEEF, &myPlayerHealth, sizeof(myPlayerHealth), 0);

//So in conclusion:
//ReadProcessMemory(fromThisProcessHandle, readTheMemoryAtThisAddress, intoTheMemoryAtThisAddress, readThisMuchMemoryFromDEADBEEF, logHowMuchMemoryWeReadFromDEADBEEF);
So, now that we hopefully have a better grasp of ReadProcessMemory and what exactly is happening when we read memory, let's take a look at the issue:

In CE, you have; [1000A3284 + 25C] -> 1003E6C10
What the hell, right? 1000A3284 + 25C = 1000A34E0 so how tf is it getting 1003E6C10??
Here's what's happening and where you almost have it.
Cheat Engine is doing the math for you (1000A3284 + 25C) and getting the same address as you are; 1000A34E0
Sweet! You're on the right track! But CE is also doing one extra step. As SunBeam pointed out; Read "[...]" as "value of"
So in other words whenever you see [address + offset] in CE it means; add this offset to this address and then get me the value of that new address(1000A34E0 in this case) so it's adding those together and then performing another ReadProcessMemory on that new sum(1000A34E0). That's called a Multi Level Pointer/Pointer Chain. It's where the value of an address is yet another address. So you then have to read the other address that you get from that one.

tl;dr; Here's one way to read MultiLevelPointers in C++:

Code: Select all

//you don't need this many variables to achieve this but for the sake of clarity of what's happening, I'm putting them into separate variables
uintptr_t baseAddress = *DLL name*.dll;
uintptr_t addressPointedTo;
uintptr_t secondAddressPointedTo;
int offset1 = 0x00120C78, offset2 = 0x25C; //can use DWORD (4byte int alias) instead of int here; kinda helps with keeping track of your offset variables
int myPlayerHealth; //where we will store your health being read into your C++ program

ReadProcessMemory(handle, (LPCVOID)(baseAddress + offset1), &addressPointedTo, sizeof(addressPointedTo), 0);
cout << addressPointedTo << endl; //output: 1000A3284 (cout might print this as decimal, I can't remember, but that would be 4295635588)

ReadProcessMemory(handle, (LPCVOID)(addressPointedTo + offset2), &secondAddressPointedTo, sizeof(secondAddressPointedTo), 0);
cout << secondAddressPointedTo << endl; //output: 1000A34E0 (decimal; 4295636192)

//Now we're at our health/whatever address(secondAddressPointedTo) so this one we're going to read as a 4byte int instead of uintptr_t which is 8 byte unsigned int
ReadProcessMemory(handle, (LPCVOID)secondAddressPointedTo, &myPlayerHealth, sizeof(myPlayerHealth), 0);
cout << myPlayerHealth << endl; //idk if you're actually looking for health but this should print the value that you're looking for which is whatever is at the end of your pointer chain/MultiLevelPointer


User avatar
tdg6661
Table Makers
Table Makers
Posts: 677
Joined: Sat Dec 15, 2018 12:10 pm
Reputation: 245

Re: Urgently need help!

Post by tdg6661 »

It would be easier to understand if you used Cheat Engine's Dissect Data, entered the base address, you'll see:

Code: Select all

Offset       Address                        Value
0                1000A3284                  xxxxxxx
4                1000A3288                  xxxxxxx
8                1000A328C                  xxxxxxx
C                1000A3290                  xxxxxxx
.........
.........
25C           1000A34E0                 1003E6C10
264            1000A34E8                  xxxxxxx
Address '1000A34E0' is pointing to address '1003E6C10'

When you click the add pointer button, CE will read the value of the current address plus the offset, which is 1000A3284+25C = 1003E6C10, and use it as a new address for the next input box.

JK89526
What is cheating?
What is cheating?
Posts: 3
Joined: Tue May 23, 2023 6:23 pm
Reputation: 0

Re: Urgently need help!

Post by JK89526 »

Thanks everyone, I solved my problem! :)

Post Reply

Who is online

Users browsing this forum: No registered users