I am trying to make a game hack and there are a few instructions I need to get the addresses of to nop
out. However, when looking at the instructions in Cheat Engine, they do not have a static offset from any modules (DLL's or base exe). I have no idea how I would locate dynamic instructions. Any help would be very nice.
-
do you have any examples?– PhoeniXMay 26, 2017 at 13:40
3 Answers
Being an avid Cheat Engine user and game-hacker, I can walk you through a specific example that should give you solid clarity.
First, we'll use this arbitrary bit of code to work with:
7A1A7A162 - 55 - push rbp
7A1A7A163 - 00 6E 00 - add [rsi+00],ch
7A1A7A166 - 69 00 74000000 - imul eax,[rax],00000074 { 116 }
7A1A7A16C - 00 00 - add [rax],al
7A1A7A16E - 00 00 - add [rax],al
7A1A7A170 - EB C3 - jmp 7A1A7A135
7A1A7A172 - C3 - ret
Let's say the two bytes you want to nop are EB C3
, but 7A1A7A170
isn't a static address. What you now want to do is construct a unique byte signature that you can then scan for. What you're betting on here is that while the memory addresses might change, the instructions stay the same. This gives you something consistent to scan for. Ultimately, you want only one result from the scan so that you don't end up finding--and then modifying--a false positive.
In Cheat Engine, everything related to signature scanning is referred to as AOB (Array of Byte) scanning. It's essentially one in the same. Let's build what we hope is a unique AOB using the bytes from the example routine above:
55 00 6E 00 69 00 74 00 00 00 00 00 00 00 EB C3 C3
Now what you could do in Cheat Engine is select "Array of byte" from the Value Type drop-down box, then make sure the Writeable checkbox has the solid black square selection (that is, not just a check mark and not empty) which means CE will scan both read/write memory, and finally, paste those bytes into the search box and search.
If you only have one result, then you're good to go. Your scan would return the first memory address (no matter what it is), and you could then base your injection on an offset from that result, which would be 0x0E
. Cheat Engine (or whatever you use to scan for that byte pattern) finds the result starting in memory address 7A1A7A162
, then from there, your bytes are +0x0E
away at address 7A1A7A170
.
If you have multiple results, then what you need to start doing is adding bytes onto the beginning or end of your signature. Using our example, this would mean starting to incorporate bytes from instructions prior to 7A1A7A162
and/or after 7A1A7A172
.
Yes, you can sometimes end up with massive AOBs -- especially in cases where you're dealing with anti-cheat software that duplicates certain blocks of code to throw pattern scanning off. In these cases, you can try finding an array of bytes nearby that have nothing to do with the bytes you want to modify, and then base your injection on an offset from the results of that scan.
For instance, maybe there's a unique byte signature from 7A1A70000
to 7A1A7001C
, which you then reference the resulting scan (which would be 7A1A70000
) + an offset of A170
to land you at 7A1A7A170
. That sometimes doesn't work, either, such as when a game's instructions are compiled at run time (this is common with Java-based games--Minecraft being one such game; look into JIT compilation), but it's a good example to show you how to get around a common anti-pattern scan technique.
Feel free to ask if you need additional clarity on the this, but the ultimate goal is to find a unique byte signature that you can scan for, then base your injection on that. This allows you to work independently of memory addresses. =)
If this code is used in any way by your program, this location has to be stored somewhere to be used by the "static" part of your binary. So usually what you want to do is to find a chain of pointers going to your target code. You can find such a chain either by reversing the binary or blindly memory-greping addresses starting from your target.