 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Sun May 15, 2016 5:14 pm Post subject: |
|
|
Wellp, there was no ruddy documentation at all.
So I made my first ever program, in Pascal using the Lazarus IDE, to do it for me. It works like a charm, but it'll crash if you try and repeat the process without restarting the program.
I'll edit this post and attach it when I figure out what the problem is. Gotta spread the love, after all.
|
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Mon May 16, 2016 8:50 am Post subject: |
|
|
The program's still crashy, but perfectly usable. Heh.
I've finally gotten the AI structure down, and me program was a huge help. TOOTIN' ME OWN HORN, I AM!
Now, I need to figure out how to add these addresses to the list. I couldn't find a way to add an address as an AOB Search (tick the box, does the search, modifies a list entry to use the new address). The .CT I attached earlier does the same thing.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Mon May 16, 2016 11:09 am Post subject: |
|
|
If there's more than one address that matches an AoB signature, you'll have to use Lua to find all of them.
| Code: | {$lua}
if syntaxcheck then return end
[ENABLE]
local res = AOBScan("12 34 AB CD")
if res == nil then
showMessage("AoB signature not found")
return 1
end
local al = getAddressList()
local parentRec = al.createMemoryRecord()
parentRec.Description = "Memory Records"
parentRec.isGroupHeader = true
parentRec.options = "[moHideChildren]"
-- global variable names should be unique
_AOBResultParentID = parentRec.ID
for i=0, res.Count-1, 1 do
local r = al.createMemoryRecord()
r.appendToEntry(parentRec)
r.Address = res[i]
r.Type = vtByteArray
r.ShowAsHex = true
r.Aob.Size = 5
r.Description = "AOBScan result " .. i+1
end
res.destroy()
[DISABLE]
if not _AOBResultParentID then return end
local al = getAddressList()
local r = al.getMemoryRecordByID(_AOBResultParentID)
if r then r.destroy() end
_AOBResultParentID = nil |
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Mon May 16, 2016 11:23 am Post subject: |
|
|
It only returns one address, so no worries there. This is the AOB: 4E 50 43 5F 54 48 49 4E 4B 5F 50 41 52 41 4D 5F 53 54 00 20 20 20 20 20 20 20 20 20 20 20 20 20 00 02 00 00 00 00 00 00 80 16 00 00 C0 E6 00 00
After thinking for a wee bit, I think I'll be better off just making a big assembly script for each main "feature" I want to add, in regards to changing the global AI structure.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Mon May 16, 2016 11:43 am Post subject: |
|
|
Oh. In that case, you can get that with this:
| Code: | [ENABLE]
aobscan(mySpecialAOB, 4E 50 43 5F 54 48 49 4E 4B 5F 50 41 52 41 4D 5F 53 54 00 20 20 20 20 20 20 20 20 20 20 20 20 20 00 02 00 00 00 00 00 00 80 16 00 00 C0 E6 00 00)
registersymbol(mySpecialAOB)
[DISABLE]
unregistersymbol(mySpecialAOB) |
Any time you need to access that address, use the symbol mySpecialAOB. For example, add an address manually, put in mySpecialAOB for the address, and drag it on top of the above script (in the address list) to append it as a child. You can also right click on the script and go to "Group config -> Hide children when deactivated" if you want to.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Sun Jun 05, 2016 3:06 pm Post subject: |
|
|
Went through some hardcore burnout, but I've gotten over most of it. Figured I'd try something fresh to avoid going right back to burnt out city-ville.
I've designed a really simple script to compare if an enemy has the model IDs c2410 and c2400, and if they do, set the health to 0 (kill them). However, the Auto Assembler doesn't like me comparing a qword. Am I missing something, or do we have to compare individual bytes? Utter pain if we have to.
Here's what I've got so far:
| Code: | { Game : DARKSOULS.exe
Version:
Date : 2016-05-08
Author : CJWin7Main
Hooks into the assembly instruction that runs on the health of every loaded, living NPC.
Checks if the NPC is a Silver Knight via the ModelID string. If it's c2410, it's a Silver Knight.
If the NPC is a Silver Knight, change the ally value to 2 (player ally) from the original 6.
Offsets:
38 - Model ID string - Probably left over from developer's debugging?
70 - Phantom Type
74 - Team
2D4 - Health
2D8 - Max Health
ModelID | c2410 = 63 00 32 00 34 00 31 00 30 00
For cmp command: 00 30 00 31 00 34 00 32 00 63
ModelID | c2400 = 63 00 32 00 34 00 30 00 30 00
For cmp command: 00 30 00 30 00 34 00 32 00 63
}
[ENABLE]
aobscanmodule(PreHealthInstruction,DARKSOULS.exe,8B 10 89 11 59) // should be unique
alloc(newmem,2048)
label(code)
label(return)
label(CompareSilverKnight)
label(ComparePaintingGuardian)
label(GetAndCompareNPC)
newmem:
code:
//begin First Injected code section
//Bunch of procedures to check the modelID.
CompareSilverKnight:
cmp qword ptr[esi+38],0031003400320063
jne EndOfCmpSK
cmp word ptr[esi+40],0030
jne EndOfCmpSK
mov [ecx],0
EndOfCmpSK:
ret
ComparePaintingGuardian:
cmp qword ptr[esi+38],0030003400320063
jne EndOfCmpPG
cmp word ptr[esi+40],0030
jne EndOfCmpPG
mov [ecx],0
EndOfCmpPG:
ret
GetAndCompareNPC:
push esi
lea esi,[ecx-2d4] //we use lea to place the index register at the [beginning of NPC data in memory]
//begin Original code
mov edx,[eax]
mov [ecx],edx
//begin Injected procedures
//These procedures will set the health to 0 if the enemy has one of the model IDs that we're looking for
call CompareSilverKnight
//end Injected procedures
pop esi // We're done with ESI, so restore it to it's original value; from before we used it in the above code
pop ecx
jmp return
//end Original Code
PreHealthInstruction:
jmp GetAndCompareNPC
return:
registersymbol(PreHealthInstruction)
[DISABLE]
PreHealthInstruction:
db 8B 10 89 11 59
unregistersymbol(PreHealthInstruction)
dealloc(newmem)
|
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Sun Jun 05, 2016 3:12 pm Post subject: |
|
|
If you're attached to a 32-bit process, then the concept of a qword ptr doesn't exist in this context. Compare two dwords instead.
| Code: | cmp [esi+38],00320063
jne EndOfCmpSK
cmp [esi+38],00310034
jne EndOfCmpSK |
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Sun Jun 05, 2016 3:21 pm Post subject: |
|
|
| ParkourPenguin wrote: | If you're attached to a 32-bit process, then the concept of a qword ptr doesn't exist in this context. Compare two dwords instead.
| Code: | cmp [esi+38],00320063
jne EndOfCmpSK
cmp [esi+38],00310034
jne EndOfCmpSK |
|
Hah, just tried that right this moment, then checked the forum. Oh lordy.
It crashed, but I figured out one of the potential reasons; I forgot to adjust the 2nd cmp[] command. Changed it to check @ [esi+3c], as 38 + 4 (4 bytes = 1 word so we add 4) = 3C
Going to start the game up again and see if it still crashes.
Edit: Ah yeah, here's the current script:
| Code: |
{ Game : DARKSOULS.exe
Version:
Date : 2016-05-08
Author : CJWin7Main
Hooks into the assembly instruction that runs on the health of every loaded, living NPC.
Checks if the NPC is a Silver Knight via the ModelID string. If it's c2410, it's a Silver Knight.
If the NPC is a Silver Knight, change the ally value to 2 (player ally) from the original 6.
Offsets:
38 - Model ID string - Probably left over from developer's debugging?
70 - Phantom Type
74 - Team
2D4 - Health
2D8 - Max Health
ModelID | c2410 = 63 00 32 00 34 00 31 00 30 00
For cmp command: 00 30 00 31 00 34 00 32 00 63
ModelID | c2400 = 63 00 32 00 34 00 30 00 30 00
For cmp command: 00 30 00 30 00 34 00 32 00 63
}
[ENABLE]
aobscanmodule(PreHealthInstruction,DARKSOULS.exe,8B 10 89 11 59) // should be unique
alloc(newmem,2048)
label(code)
label(return)
label(CompareSilverKnight)
label(ComparePaintingGuardian)
label(GetAndCompareNPC)
newmem:
code:
//begin First Injected code section
//Bunch of procedures to check the modelID.
CompareSilverKnight:
cmp dword ptr[esi+38],00310034
jne EndOfCmpSK
cmp dword ptr[esi+3C],00320063
jne EndOfCmpSK
cmp word ptr[esi+40],0030
jne EndOfCmpSK
mov [ecx],0
EndOfCmpSK:
ret
ComparePaintingGuardian:
cmp dword ptr[esi+38],00300034
jne EndOfCmpPG
cmp dword ptr[esi+3C],00320063
jne EndOfCmpPG
cmp word ptr[esi+40],0030
jne EndOfCmpPG
mov [ecx],0
EndOfCmpPG:
ret
GetAndCompareNPC:
push esi
push ebx
lea esi,[ecx-2d4] //we use lea to place the index register at the [beginning of NPC data in memory]
//begin Original code
mov edx,[eax]
mov [ecx],edx
//begin Injected procedures
//These procedures will set the health to 0 if the enemy has one of the model IDs that we're looking for
call CompareSilverKnight
//end Injected procedures
pop esi // We're done with ESI, so restore it to it's original value; from before we used it in the above code
pop ecx
jmp return
//end Original Code
PreHealthInstruction:
jmp GetAndCompareNPC
return:
registersymbol(PreHealthInstruction)
[DISABLE]
PreHealthInstruction:
db 8B 10 89 11 59
unregistersymbol(PreHealthInstruction)
dealloc(newmem)
|
Edit2: And no dice, it crashes.
I'll start from scratch and hook the health code again, I suppose, then copy-paste me changes. I wonder if it's because I put the call procedures in the middle of the original code. Hmm.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Sun Jun 05, 2016 3:30 pm Post subject: |
|
|
Yeah, I forgot about that. Oops.
Anyways, what's with you modifying the stack so much?
| Code: | GetAndCompareNPC:
push esi
push ebx
//...
pop esi
pop ecx
jmp return |
You're effectively moving esi into ecx and moving ebx into esi. Get rid of push ebx and pop ecx, they're pointless.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Sun Jun 05, 2016 3:33 pm Post subject: |
|
|
I think they're hold overs of the original script I used as a template; the Friendly Silver Knights scripts. Good catch.
EBX was because I was struck by inspiration to use a register to work around the qword thing, but promptly figured that wouldn't work, and forgot to remove it.
edit: pop ecx is in the original assembly code from the game, by the way.
Edit #IDon'tKnow: I had an idea. And it worked!
Just replace the code in the Friendly Knights script, and voila. It clears out the areas lickety split. Working code:
| Code: |
{ Game : DARKSOULS.exe
Version:
Date : 2016-05-08
Author : MajinCry
Offsets:
38 - Model ID string - Probably left over from developer's debugging?
70 - Phantom Type
74 - Team
2D4 - Health
248 - Max Health
ModelID | c2400 = 63 00 32 00 34 00 30 00 30 00
For comparing = 00 30 00 30 00 34 00 32 00 63
ModelID | c2410 = 63 00 32 00 34 00 31 00 30 00
For Comparing = 00 30 00 31 00 34 00 32 00 63
ModelID | c2430 = 63 00 32 00 34 00 33 00 30 00
For Comparing = 00 30 00 33 00 34 00 32 00 63
ModelID | c2870 = 63 00 32 00 38 00 37 00 30 00
For Comparing = 00 30 00 37 00 38 00 32 00 63
ModelID | c3240 = 63 00 33 00 32 00 34 00 30 00
For Comparing = 00 30 00 34 00 32 00 33 00 63
}
[ENABLE]
aobscanmodule(PreHealthInstruction,DARKSOULS.exe,8B 10 89 11 59) // should be unique
alloc(newmem,2048)
label(code)
label(return)
label(MakeEnemyHealthZero)
label(GetAndCompareNPC)
newmem:
code:
//begin First Injected code section
//Procedure that will change the enemy's team to player ally. This is only processed when the function "call" is used
MakeEnemyHealthZero:
mov ptr[esi+2d4],00000000
ret
GetAndCompareNPC:
push esi
lea esi,[ecx-2d4]
cmp [esi+38],00320063
jne short EndOfSKCheck
cmp [esi+3C],00310034
jne short EndOfSKCheck
cmp word ptr[esi+40],0030
jne short EndOfSKCheck
call MakeEnemyHealthZero
EndOfSKCheck:
cmp [esi+38],00320063
jne short EndOfPGCheck
cmp [esi+3C],00300034
jne short EndOfPGCheck
cmp word ptr[esi+40],0030
jne short EndOfPGCheck
call MakeEnemyHealthZero
EndOfPGCheck:
cmp [esi+38],00330063
jne short EndOfDemStCheck
cmp [esi+3C],00330034
jne short EndOfDemStCheck
cmp word ptr[esi+40],0030
jne short EndOfDemStCheck
call MakeEnemyHealthZero
EndOfDemStCheck:
cmp [esi+38],00320063
jne short EndOfSenlCheck
cmp [esi+3C],00370038
jne short EndOfSenlCheck
cmp word ptr[esi+40],0030
jne short EndOfSenlCheck
call MakeEnemyHealthZero
EndOfSenlCheck:
cmp [esi+38],00320063
jne short EndOfChaosEatCheck
cmp [esi+3C],00340032
jne short EndOfChaosEatCheck
cmp word ptr[esi+40],0030
jne short EndOfChaosEatCheck
call MakeEnemyHealthZero
EndOfChaosEatCheck:
//end First Injection code section
pop esi
//begin Original Code
mov edx,[eax]
mov [ecx],edx
pop ecx
jmp return
//end Original Code
PreHealthInstruction:
jmp GetAndCompareNPC
return:
registersymbol(PreHealthInstruction)
[DISABLE]
PreHealthInstruction:
db 8B 10 89 11 59
unregistersymbol(PreHealthInstruction)
dealloc(newmem)
|
|
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Mon Jun 06, 2016 8:52 pm Post subject: |
|
|
Right, am I still unable to double post? Kinda need to be able to start a new train of discussion.
Is it possible to have to cheats enabled, that inject the same instruction? Or does that cause all sorts of buggery?
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Mon Jun 06, 2016 9:13 pm Post subject: |
|
|
No. When you inject code to hook an instruction, you override the game's memory with a jump to your code, do stuff in your code, and then jump back past the jump you wrote so the game can continue. So, conceptually, it follows that one jump can only jump to one other place at any given time (not two), not to mention the fact that it would break the AoB scan.
If you can't combine the two scripts into one, then you can try to find another injection point close by. If you can't do that, then you can write a master script which hooks that instruction and jumps to a section of memory that contains jumps to other scripts. Here's a hypothetical example:
| Code: | // game's code
...
jmp transitionalArea
... // transitionalArea jumps back here
//transitionalArea
jmp script1 // executes script1 which jumps back to the next instruction (script2)
jmp script2 // ^
jmp script3 // ^
jmp gameCodeReturn // jumps back to game's code |
Doing this is usually more complicated than what's necessary, as you should be able to find another injection point close by.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Cake-san Grandmaster Cheater
Reputation: 8
Joined: 18 Dec 2014 Posts: 541 Location: Semenanjung
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 155
Joined: 06 Jul 2014 Posts: 4774
|
Posted: Mon Jun 06, 2016 10:01 pm Post subject: |
|
|
It's perfectly fine to use call. I'd probably prefer it in this case, but you have to worry about where the stack is at. This commonly confuses beginners since it could change what the original code is if it accesses esp (e.g. mov eax,[esp+28] would turn into mov eax,[esp+2C] if you called your code to run).
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Majin Advanced Cheater
Reputation: 0
Joined: 04 May 2016 Posts: 87
|
Posted: Tue Jun 07, 2016 3:48 am Post subject: |
|
|
...Alrighty, that sounds above me paygrade here.
I'll stick to having just one big ol' script with comments to keep things tidy. Don't want to go straight into nitty gritty pro-level stuff right the now.
That being said, the script I've made for auto-killing enemies is getting a tad on the larger side, so I figure I should spend a bit of time optimizing the script, though I've no idea how, as it looks pretty decent as-is.
One thing I read about is the usage of SSE registers. Supposedly, an SSE instruction is around 2x faster than it's equivalent x87 instruction. Or was that SSE2 being 2x fast? I forget.
Would just chucking in the SSE equivalent of esi give a notable boost, or nah? Seems like that'd be an easy optimization, if it will.
Also, where can I find documentation about the uses of registers? Further back in the thread I was informed that ESI can't be used as a general purpose register (like EBX is), contrary to one of me sources; me source was wrong in that scenario.
So knowing what registers can be used for would be dandy. For example, is EAX used only for 'fast & temporary' code, such as a mathematical function?
| Code: |
mov eax,2
mov eax,eax*ecx
mov [ebx],ebx*eax |
Like that, and you wouldn't use EAX with a bunch of lines in-between it's usage?
Edit: It'd be of use if I posted the current, working incarnation of the script eh? Here's how it looks so far:
| Code: |
{ Game : DARKSOULS.exe
Version:
Date : 2016-05-08
Author : MajinCry
Offsets:
38 - Model ID string - Probably left over from developer's debugging?
70 - Phantom Type
74 - Team
2D4 - Health
248 - Max Health
ModelID | c2370 = 63 00 32 00 33 00 37 00 30 00
For Comparing = 00 30 00 37 00 33 00 32 00 63
ModelID | c2400 = 63 00 32 00 34 00 30 00 30 00
For comparing = 00 30 00 30 00 34 00 32 00 63
ModelID | c2410 = 63 00 32 00 34 00 31 00 30 00
For Comparing = 00 30 00 31 00 34 00 32 00 63
ModelID | c2430 = 63 00 32 00 34 00 33 00 30 00
For Comparing = 00 30 00 33 00 34 00 32 00 63
ModelID | c2800 = 63 00 32 00 38 00 30 00 30 00
For Comparing = 00 30 00 30 00 38 00 32 00 63
ModelID | c2870 = 63 00 32 00 38 00 37 00 30 00
For Comparing = 00 30 00 37 00 38 00 32 00 63
ModelID | c3240 = 63 00 33 00 32 00 34 00 30 00
For Comparing = 00 30 00 34 00 32 00 33 00 63
}
[ENABLE]
aobscanmodule(PreHealthInstruction,DARKSOULS.exe,8B 10 89 11 59) // should be unique
alloc(newmem,4096)
label(code)
label(return)
label(MakeEnemyHealthZero)
label(GetAndCompareNPC)
newmem:
code:
//begin First Injected code section
//Procedure that will change the enemy's team to player ally. This is only processed when the function "call" is used
MakeEnemyHealthZero:
mov ptr[esi+2d4],00000000
ret
GetAndCompareNPC:
push esi
lea esi,[ecx-2d4]
cmp [esi+38],00320063
jne short EndOfChannCheck
cmp [esi+3C],00370033
jne short EndOfChannCheck
cmp word ptr[esi+40],0030
jne short EndOfChannCheck
call MakeEnemyHealthZero
EndOfChannCheck:
cmp [esi+38],00320063
jne short EndOfSKCheck
cmp [esi+3C],00310034
jne short EndOfSKCheck
cmp word ptr[esi+40],0030
jne short EndOfSKCheck
call MakeEnemyHealthZero
EndOfSKCheck:
cmp [esi+38],00320063
jne short EndOfPGCheck
cmp [esi+3C],00300034
jne short EndOfPGCheck
cmp word ptr[esi+40],0030
jne short EndOfPGCheck
call MakeEnemyHealthZero
EndOfPGCheck:
cmp [esi+38],00330063
jne short EndOfDemStCheck
cmp [esi+3C],00330034
jne short EndOfDemStCheck
cmp word ptr[esi+40],0030
jne short EndOfDemStCheck
call MakeEnemyHealthZero
EndOfDemStCheck:
cmp [esi+38],00320063
jne short EndOfSenlCheck
cmp [esi+3C],00370038
jne short EndOfSenlCheck
cmp word ptr[esi+40],0030
jne short EndOfSenlCheck
call MakeEnemyHealthZero
EndOfSenlCheck:
cmp [esi+38],00320063
jne short EndOfCrystalCheck
cmp [esi+3C],00300038
jne short EndOfCrystalCheck
cmp word ptr[esi+40],0030
jne short EndOfCrystalCheck
call MakeEnemyHealthZero
EndOfCrystalCheck:
cmp [esi+38],00320063
jne short EndOfChaosEatCheck
cmp [esi+3C],00340032
jne short EndOfChaosEatCheck
cmp word ptr[esi+40],0030
jne short EndOfChaosEatCheck
call MakeEnemyHealthZero
EndOfChaosEatCheck:
//end First Injection code section
BeginOurCode:
pop esi
//begin Original Code
mov edx,[eax]
mov [ecx],edx
pop ecx
jmp return
//end Original Code
PreHealthInstruction:
jmp GetAndCompareNPC
return:
registersymbol(PreHealthInstruction)
[DISABLE]
PreHealthInstruction:
db 8B 10 89 11 59
unregistersymbol(PreHealthInstruction)
dealloc(newmem)
|
|
|
| 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
|
|