📄 roll engine.shp
字号:
itstheplayer:
pop ebx //restore the registers, keep in mind to restore the registers in reverse order
pop eax
jmp returnHealthWriter //dont execute the original code, return imeadiatly
originaldecreasehealthcode:
sub edx,eax
mov [esi+ecx*4],edx
jmp returnHealthWriter
again, I used a few labels to make it easier for me
but, that also means I'd have to declare them, else the assembler will complain it doesn't recognize them
so:
Code:
label(returnHealthWriter)
label(itstheplayer)
label(originaldecreasehealthcode)
and I prefer adding declarations at the top.
So, the complete auto assembler script would look like:
Code:
alloc(injectHealthReader,1024) //creates a identifier called injecthealthreader that points to a block of 1024 bytes
alloc(injectHealthWriter,1024) //2nd code cave to handle the code of the decrease health code, for easy management
alloc(playerhealthaddress,4) //this will hold the address of health, a 4 byte value (pointer, in 64 bit this'll have to be 8 bytes)
label(returnHealthReader) //tell the assembler than returnHealthReader is a valid identifier, so dont bug out
label(originalhealthreadercode) //same as above
label(returnHealthWriter)
label(itstheplayer)
label(originaldecreasehealthcode)
//----------------------------------------
// Healthreader
//----------------------------------------
00405000:
jmp InjectHealthAddress //jump to the codecave
nop //nops for the lost space
nop
returnHealthReader: //this is the label that is used to return to the address (so you dont have to write down 00405007 when jumping back, just to make it easy....)
injectHealthReader:
push eax //save eax, not really needed here since eax gets changed anyhow, but it's a good habbit to save and restore registers
lea eax,[esi+ecx*4] //this instruction places the result of esi+ecx*4 into eax
mov [playerhealthaddress],eax
pop eax //restore the register, again, not needed here, but good habbit to do
originalhealthreadercode: //label defining the original code, can be used to jump into or just skip, not needed here
mov eax,[esi+ecx*4] //read health
mov ecx,[esi+edx*4+4] //read something else, my gues, armor
jmp returnHealthReader //jump back to the original game code, when done successfull, it wont crash...
//----------------------------------------
// Health decreaser
//----------------------------------------
00421000:
jmp injectHealthWriter //overwrite the original code with a jump.
returnHealthWriter: //just declare it here, it'll get address 00421005, so a jmp returnHealthWriter will get converted to jmp 00421005
injectHealthWriter:
//do a check if esi+ecx*4 matches the address stored in playerhealthaddress
//if it matches, skip the original code, if it doesn't just execute it
//save the registers we use, and before I forget, do not touch esp between saving and restoring the registers unless
//it's to read something(like parameters), in which case you'll have to adjust the offset
//also, dont change the registers that you use to find the address
push eax
push ebx
mov eax,[playerhealthaddress]
lea ebx,[esi+ecx*4]
cmp eax,ebx
je itstheplayer
//not the player
pop ebx //I think I could have doen this before the je, but better safe than sorry
pop eax
jmp originaldecreasehealthcode
itstheplayer:
pop ebx //restore the registers, keep in mind to restore the registers in reverse order
pop eax
jmp returnHealthWriter //dont execute the original code, return imeadiatly
originaldecreasehealthcode:
sub edx,eax
mov [esi+ecx*4],edx
jmp returnHealthWriter
Please be aware that I havn't tested this in ce yet, I've been writing this in notepad on a pc that doesnt have ce installed, so there may be a few syntax errors, and some of the code I've written can surely be optimised, but I hope you get the general idea.
Also, there's a bug in ce 5.0 where you can't use small identiers that can apear in the name of another identifier. (e.g weirdmemlocxxx and memloc can't be used at the same time, because memloc fits in weirdmemlocxxx)
But if you use normal names for identifiers this wont couse a problem, and I recommend identifiers of more than 4 characters, else it may happen you get the name of a assembler instruction and accidentally overwrite that when used.
_____________________
The other method of using code injection is finding if there are differences between the player data and opponent data.
Lets say that if it's the player [esi+ecx*4+14] contains a 1 otherwhise a 0. you can then do a check if that is set or not, if so, skip, otherwhise, decrease health
Code:
alloc(injectHealthWriter,1024) //2nd code cave to handle the code of the decrease health code, for easy management
label(returnHealthWriter)
label(itstheplayer)
label(originaldecreasehealthcode)
//----------------------------------------
// Health decreaser
//----------------------------------------
00421000:
jmp injectHealthWriter //overwrite the original code with a jump.
returnHealthWriter: //just declare it here, it'll get address 00421005, so a jmp returnHealthWriter will get converted to jmp 00421005
injectHealthWriter:
push eax
mov eax,[esi+ecx*4+14]
cmp eax,1
je itstheplayer
//not the player
pop eax
jmp originaldecreasehealthcode
itstheplayer:
pop eax //restore the register
jmp returnHealthWriter //dont execute the original code, return imeadiatly
originaldecreasehealthcode:
sub edx,eax
mov [esi+ecx*4],edx
jmp returnHealthWriter
----- SHM ---- page 27 ----
Originally posted by Smidge204
When searching for a value in memory using the scan, here are a few pointers to find the value quickly:
1) If the value is known, but the format is not (ie: Byte, 2 Bytes, 4 Bytes...) search for the smallest type that will hold the data.
For example, if the value you want is 60, search for bytes. If the value is 1224, search for 2 Byte values, etc. The idea being that if the actual format is larger (You searched for 2 byte values but it's actually a 4 byte values) then the other bytes would be 0 anyway and the value would still be found.
But if you search for a 4 byte value when it's really less, you might never find it because you're reading nearby bytes as well that might screw up your search!
2) If the value is unknown, use the "Unknown initial value" scan along with method 1 (ie: always use bytes unless you happen to know it's size). Then do something that changes it's value.
Once the value has changed, repeat the scan using "Changed values". This will filter out all the crap.
Now go back into the game and do a bunch of stuff that DOESN'T change the value, if possible. Now repeat the scan for "Unchanged values". This will filter out stuff like position values, timers and counters.
Keep repeating until you've widdled down the searches to a managable amount, then add all the results to your list and keep an eye on them as the game runs. Remove anything that changes when it logically shouldn't. Anything that's left, try plugging in random values and see if something happens!
3) If you've found a bunch of good values, and youre looking for information that is somewhat related (Such as Lives and money, or whatever) , try restricting your search range to within a few kilobytes of the known value either way. This is especially powerful when looking for values in tables (High score list, for example) since they tend to be right next to eachother.
4) Use "Bigger than" and "Smaller than" as often as possible, especially after scans for changed or unchanged values. This can generally wittle down the results pretty fast.
5) Use arrays to peek at multiple byte values at once. Useful for detecing patterns!
6) Sometimes string values are not stored as ASCII strings, so the "Text" search doesn't work. For example, "A" might be stored as 0x01 instead of 41. If that's the case, and you have control over the value in-game (character name?) then try these steps:
-Set the character name
-Search for "Unknown initial value"
-Change name
-Search for "Changed values"
(Repeat above two steps to eliminate as much junk as possible. See also tip #2)
-Change name to all the same characters. ie: "AAAAAAA". Try to max out the space you're given.
-Search one more time for changed values. If you've increased the number of displayed results enough to get a list, scroll down and see if you have a bunch of consecutive memory locations that have the same value. (Should be the same as the length of the string!)
-Add the first address to your list as an array equal to the length of the string you entered.
-Change name to an easily identifiable pattern. ie: "ABCDEFG"
-See if the bytes in your array changed to a similar pattern. If so, start mapping the characters to their values and you're done!
Once you have the character map, you can use it to "translate" other text you couldn't find before. Simply search for an array of bytes and enter in the expected values of each letter in order.
Hope that helps!
=SMidge=
----- SHM ---- page 28 ----
Originally posted by Zhoul:
*Pre-Req!!! Windows XP Professional - (Not Home) - Upgraded to SP2. Worry not, hacked TCPIP DLL's are talked about below.*
When I first started using cheat engine, I thought it was fantastic! I hated to have to alt+tab, and am usually using 2 PC's anyhow, so I loved the fact that it came with a network client.
The problem(s)? The network client didn't do as good a job, because when I tried to do things like 'See what writes to this value', It would usually end up crashing my game, mostly the very first time I tried doing it. The network client also had more bugs and lacked the newer features.
I fiddled with the settings *a lot*, trying to see if it was something I was doing wrong, or a config option that wasn't set properly. To no avail.
I then launched a massive search for another software/debugger that had a network client, but stumbled upon something I think is a lot better.
Basically, Microsoft messed around with giving us concurrent remote desktop + console sessions. Meaning: The ability to be logged into the console, and still connect remotely, without logging the console session out. They scrapped the idea later, because of licensing. They had released termserv.dll in a beta version of SP2, and of course, it was preserved by techies everywhere.
I quickly installed the new termserv.dll, grinning from ear to ear, rebooted my PC, then tried to login remotely.
Ack! Console session was logged out! Ahh!!! I get it... the same user cannot login twice. So I created a 2nd admin account, and that solved *that* problem.
I then loaded up a game on my main PC and remote desktop'd to it, and loaded up cheat engine on the other.
ACK!! User wasn't allowed to debug?!
I quickly loaded up gpedit.msc and navigated its non-logical tree structure and finally found an option that lets you specify who has rights to debug programs (Computer Configuration > Windows Settings > Security Settings > Local Policies > User Rights Access > Debug programs). Gave my new user rights to debug then tried again.
ACK! I still wasn't allowed to 'connect' to my game, as microsoft does not allow us to 'peek' into a process that was run by an
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -