The AOB for this cheat is too long, and reaches the next method, which could be different each time.
For Mono/Unity games i prefere to use the monopipe from cheatengine.
The most time its better to use full injection with class:method+offset. Especially if code is repeated often.
It has also some disadvantages like when the method changed but the code not it is required to update the offset.
Alternative aobscanmodule, aobscanregion can also search only in a method instead the complete memory.
An Example would be:
Code: Select all
usemono()
define(EconomyDirectorGetCurrValueAddress,EconomyDirector:GetCurrValue+6d)
define(EconomyDirectorGetCurrValueBytes,F3 0F 5A C0 F2 0F 5A C0)
[ENABLE]
assert(EconomyDirectorGetCurrValueAddress,EconomyDirectorGetCurrValueBytes)
alloc(newmem,$1000,EconomyDirectorGetCurrValueAddress)
label(code)
label(return)
label(economy_base)
registersymbol(economy_base)
newmem:
mov [economy_base],rax
code:
cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
jmp return
economy_base:
dq 0
EconomyDirectorGetCurrValueAddress:
jmp newmem
nop
nop
nop
return:
[DISABLE]
EconomyDirectorGetCurrValueAddress:
db EconomyDirectorGetCurrValueBytes
// cvtss2sd xmm0,xmm0
// cvtsd2ss xmm0,xmm0
unregistersymbol(economy_base)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: 07C7232D
07C72300: 0F 84 69 00 00 00 - je EconomyDirector:GetCurrValue+af
07C72306: 49 8B 47 40 - mov rax,[r15+40]
07C7230A: 48 8B C8 - mov rcx,rax
07C7230D: 48 8B D7 - mov rdx,rdi
07C72310: 48 83 EC 20 - sub rsp,20
07C72314: 83 38 00 - cmp dword ptr [rax],00
07C72317: 49 BB 80 25 C7 07 00 00 00 00 - mov r11,System.Collections.Generic:Dictionary`2:get_Item
07C72321: 41 FF D3 - call r11
07C72324: 48 83 C4 20 - add rsp,20
07C72328: F3 0F 10 40 14 - movss xmm0,[rax+14]
// ---------- INJECTING HERE ----------
07C7232D: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
07C72331: F2 0F 5A C0 - cvtsd2ss xmm0,xmm0
// ---------- DONE INJECTING ----------
07C72335: 48 83 EC 20 - sub rsp,20
07C72339: 49 BB E0 54 F0 05 00 00 00 00 - mov r11,UnityEngine:Mathf:RoundToInt
07C72343: 41 FF D3 - call r11
07C72346: 48 83 C4 20 - add rsp,20
07C7234A: 33 C9 - xor ecx,ecx
07C7234C: 48 89 4D C0 - mov [rbp-40],rcx
07C72350: C6 45 C4 01 - mov byte ptr [rbp-3C],01
07C72354: 89 45 C0 - mov [rbp-40],eax
07C72357: 48 8B 45 C0 - mov rax,[rbp-40]
07C7235B: 48 89 45 C8 - mov [rbp-38],rax
}
Edit:
It is also recommend to use getmonostruct combined with registersymbol to export the field names of the class to use it in the table.
Here is an example table entry which uses the names in the pointers instead of a value offset.
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<CheatTable>
<CheatEntries>
<CheatEntry>
<ID>85</ID>
<Description>"Find Market Base (Shoot in the Plort you wan't to edit)"</Description>
<Options moHideChildren="1"/>
<LastState/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>usemono()
define(EconomyDirectorGetCurrValueAddress,EconomyDirector:GetCurrValue+6d)
define(EconomyDirectorGetCurrValueBytes,F3 0F 5A C0 F2 0F 5A C0)
getmonostruct(CurrValueEntry)
[ENABLE]
assert(EconomyDirectorGetCurrValueAddress,EconomyDirectorGetCurrValueBytes)
alloc(newmem,$1000,EconomyDirectorGetCurrValueAddress)
label(code)
label(return)
label(economy_base)
registersymbol(economy_base)
registersymbol(CurrValueEntry.baseValue)
registersymbol(CurrValueEntry.currValue)
registersymbol(CurrValueEntry.prevValue)
registersymbol(CurrValueEntry.fullSaturation)
newmem:
mov [economy_base],rax
code:
cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
jmp return
economy_base:
dq 0
EconomyDirectorGetCurrValueAddress:
jmp newmem
nop
nop
nop
return:
[DISABLE]
EconomyDirectorGetCurrValueAddress:
db EconomyDirectorGetCurrValueBytes
// cvtss2sd xmm0,xmm0
// cvtsd2ss xmm0,xmm0
unregistersymbol(economy_base)
unregistersymbol(CurrValueEntry.baseValue)
unregistersymbol(CurrValueEntry.currValue)
unregistersymbol(CurrValueEntry.prevValue)
unregistersymbol(CurrValueEntry.fullSaturation)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: 07C7232D
07C72300: 0F 84 69 00 00 00 - je EconomyDirector:GetCurrValue+af
07C72306: 49 8B 47 40 - mov rax,[r15+40]
07C7230A: 48 8B C8 - mov rcx,rax
07C7230D: 48 8B D7 - mov rdx,rdi
07C72310: 48 83 EC 20 - sub rsp,20
07C72314: 83 38 00 - cmp dword ptr [rax],00
07C72317: 49 BB 80 25 C7 07 00 00 00 00 - mov r11,System.Collections.Generic:Dictionary`2:get_Item
07C72321: 41 FF D3 - call r11
07C72324: 48 83 C4 20 - add rsp,20
07C72328: F3 0F 10 40 14 - movss xmm0,[rax+14]
// ---------- INJECTING HERE ----------
07C7232D: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
07C72331: F2 0F 5A C0 - cvtsd2ss xmm0,xmm0
// ---------- DONE INJECTING ----------
07C72335: 48 83 EC 20 - sub rsp,20
07C72339: 49 BB E0 54 F0 05 00 00 00 00 - mov r11,UnityEngine:Mathf:RoundToInt
07C72343: 41 FF D3 - call r11
07C72346: 48 83 C4 20 - add rsp,20
07C7234A: 33 C9 - xor ecx,ecx
07C7234C: 48 89 4D C0 - mov [rbp-40],rcx
07C72350: C6 45 C4 01 - mov byte ptr [rbp-3C],01
07C72354: 89 45 C0 - mov [rbp-40],eax
07C72357: 48 8B 45 C0 - mov rax,[rbp-40]
07C7235B: 48 89 45 C8 - mov [rbp-38],rax
}
</AssemblerScript>
<CheatEntries>
<CheatEntry>
<ID>86</ID>
<Description>"Current Value"</Description>
<VariableType>Float</VariableType>
<Address>economy_base</Address>
<Offsets>
<Offset>CurrValueEntry.currValue</Offset>
</Offsets>
</CheatEntry>
<CheatEntry>
<ID>87</ID>
<Description>"Previous Value"</Description>
<VariableType>Float</VariableType>
<Address>economy_base</Address>
<Offsets>
<Offset>CurrValueEntry.prevValue</Offset>
</Offsets>
</CheatEntry>
<CheatEntry>
<ID>88</ID>
<Description>"Full Saturation"</Description>
<VariableType>Float</VariableType>
<Address>economy_base</Address>
<Offsets>
<Offset>CurrValueEntry.fullSaturation</Offset>
</Offsets>
</CheatEntry>
</CheatEntries>
</CheatEntry>
</CheatEntries>
</CheatTable>