Skip to content

Instantly share code, notes, and snippets.

@Tsanfer
Created July 3, 2022 08:11
Show Gist options
  • Save Tsanfer/707f435c2e7203e33aa633b570598f06 to your computer and use it in GitHub Desktop.
Save Tsanfer/707f435c2e7203e33aa633b570598f06 to your computer and use it in GitHub Desktop.
使用 Cheat Engine 修改 Kingdom Rush 中的金钱、生命、星
<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="42">
<CheatEntries>
<CheatEntry>
<ID>3</ID>
<Description>"AOB"</Description>
<Options moHideChildren="1"/>
<LastState Activated="1"/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>{ Game : Kingdom Rush.exe
Version:
Date : 2022-06-19
Author : Tsanfer
更改金钱、生命、星
(使用 AOB 和人造指针)
}
[ENABLE]
aobscanmodule(INJECT,lua51.dll,8B 29 8B 49 04 89 2C C2) // AOB 匹配入口
alloc(newmem,1024,INJECT) // 分配 1024 字节内存,用于代码注入
alloc(man_pointer,24) // 动态分配内存,用于存放3个人造指针
// 注册全局符号
registersymbol(INJECT)
registersymbol(man_pointer) // 人造指针
// 声明标号
label(original_code)
label(return)
label(restore_reg)
label(check_is_gold)
label(check_is_gold_END)
label(check_is_live)
label(check_is_live_END)
label(check_is_star)
label(check_is_star_END)
// 数据存储结构:
// 偏移 数据 变量类型
// 0 具体值 Double
// 8 指向值所属的公共结构 指针
// └─&gt; 0
// 10 此公共结构的名称 字符串
// 程序执行顺序:(汇编代码如没有跳转,默认从上往下执行)
// INJECT -&gt; newmem -&gt; check_is_gold -&gt; check_is_live
// -&gt; check_is_star -&gt; reset_reg -&gt; original_code -&gt; return
// 注入代码段
newmem:
pushfd // 保存所有标志位
push eax // eax 压栈保存,为后续操作腾出一个寄存器
mov eax,[ecx+08] // 将当前值所属的公共类型,所在的地址,给 eax
// 判断此值的类型是否为金钱(player_gold)
check_is_gold:
cmp dword ptr [eax+10],'play' // 内存双字比较
jne check_is_gold_END // 如不匹配,则停止后续比较,跳到此比较的结尾
cmp dword ptr [eax+14],'er_g'
jne check_is_gold_END
cmp word ptr [eax+18],'ol' // 内存字比较
jne check_is_gold_END
cmp byte ptr [eax+1A],'d' // 内存字节比较
jne check_is_gold_END
mov [man_pointer],ecx // 匹配成功,将指向此值的指针保存在申请的内存中(制作人造指针)
check_is_gold_END:
// 判断此值的类型是否为生命(lives)
check_is_live:
cmp dword ptr [eax+10],'live'
jne check_is_live_END
cmp byte ptr [eax+14],'s'
jne check_is_gold_END
mov [man_pointer+8],ecx // 将指针保存在第二个内存位置
// (64位系统的指针大小为 64 bit,每个内存地址大小为 8bit,则需要平移8个内存地址,8x8=64)
check_is_live_END:
// 判断此值的类型是否为升级用的星(total_stars)
check_is_star:
cmp dword ptr [eax+10],'tota'
jne check_is_star_END
cmp dword ptr [eax+14],'l_st'
jne check_is_star_END
cmp word ptr [eax+18],'ar'
jne check_is_star_END
cmp byte ptr [eax+1A],'s'
jne check_is_star_END
mov [man_pointer+10],ecx
check_is_star_END:
// 恢复临时使用的寄存器的值
restore_reg:
pop eax
popfd // 还原所有标志位
jmp original_code
// 原始代码
original_code:
mov ebp,[ecx]
mov ecx,[ecx+04]
jmp return // 跳到返回
// 程序入口
INJECT:
jmp newmem
return: // 返回
[DISABLE]
// 还原代码
INJECT:
db 8B 29 8B 49 04
// 注销全局符号
unregistersymbol(INJECT)
unregistersymbol(man_pointer)
// 释放内存
dealloc(newmem)
dealloc(man_pointer)
{
// ORIGINAL CODE - INJECTION POINT: lua51.dll+1BDA
lua51.dll+1BBC: 23 48 08 - and ecx,[eax+08]
lua51.dll+1BBF: 6B C9 18 - imul ecx,ecx,18
lua51.dll+1BC2: 03 4D 14 - add ecx,[ebp+14]
lua51.dll+1BC5: 83 79 0C FB - cmp dword ptr [ecx+0C],-05
lua51.dll+1BC9: 75 3A - jne lua51.dll+1C05
lua51.dll+1BCB: 39 41 08 - cmp [ecx+08],eax
lua51.dll+1BCE: 75 35 - jne lua51.dll+1C05
lua51.dll+1BD0: 83 79 04 FF - cmp dword ptr [ecx+04],-01
lua51.dll+1BD4: 74 36 - je lua51.dll+1C0C
lua51.dll+1BD6: 0F B6 46 FD - movzx eax,byte ptr [esi-03]
// ---------- INJECTING HERE ----------
lua51.dll+1BDA: 8B 29 - mov ebp,[ecx]
lua51.dll+1BDC: 8B 49 04 - mov ecx,[ecx+04]
// ---------- DONE INJECTING ----------
lua51.dll+1BDF: 89 2C C2 - mov [edx+eax*8],ebp
lua51.dll+1BE2: 89 4C C2 04 - mov [edx+eax*8+04],ecx
lua51.dll+1BE6: 8B 06 - mov eax,[esi]
lua51.dll+1BE8: 0F B6 CC - movzx ecx,ah
lua51.dll+1BEB: 0F B6 E8 - movzx ebp,al
lua51.dll+1BEE: 83 C6 04 - add esi,04
lua51.dll+1BF1: C1 E8 10 - shr eax,10
lua51.dll+1BF4: FF 24 AB - jmp dword ptr [ebx+ebp*4]
lua51.dll+1BF7: 0F B6 46 FD - movzx eax,byte ptr [esi-03]
}
</AssemblerScript>
<CheatEntries>
<CheatEntry>
<ID>0</ID>
<Description>"Gold"</Description>
<LastState Value="90546" Activated="1" RealAddress="12F64B10"/>
<ShowAsSigned>0</ShowAsSigned>
<VariableType>Double</VariableType>
<Address>man_pointer</Address>
<Offsets>
<Offset>0</Offset>
</Offsets>
</CheatEntry>
<CheatEntry>
<ID>1</ID>
<Description>"Live"</Description>
<LastState Value="20" Activated="1" RealAddress="12F64AB0"/>
<ShowAsSigned>0</ShowAsSigned>
<VariableType>Double</VariableType>
<Address>man_pointer+8</Address>
<Offsets>
<Offset>0</Offset>
</Offsets>
</CheatEntry>
<CheatEntry>
<ID>2</ID>
<Description>"Total_stars"</Description>
<ShowAsSigned>0</ShowAsSigned>
<VariableType>Double</VariableType>
<Address>man_pointer+10</Address>
<Offsets>
<Offset>0</Offset>
</Offsets>
</CheatEntry>
</CheatEntries>
</CheatEntry>
</CheatEntries>
<UserdefinedSymbols/>
</CheatTable>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment