测试伊苏X(Ys.X.Proud.NORDICS.v1.03)
金币修改
有些游戏基地址不好找,可以试试AOB特征码定位。
先找搜出金币地址,查找谁写入了它,在反汇编窗口中,打开 工具 菜单选AOB注入
把mov [rax], ebx
改成mov [rax],F423F //十六进制 F423F=999999
做成脚本后,金币数量固定在999999,这样不增不减。
 |
|---|
[ENABLE]
// ==================================================
// AOB扫描段:动态定位目标代码
// ==================================================
// 在ysxl.exe模块中扫描字节序列"89 18 44 8B 44 24 28"
// INJECT: 存放找到地址的符号名
// ysxl.exe: 目标模块名称(游戏主程序)
// 89 18...: 要查找的唯一字节模式(对应mov [rax],ebx和mov r8d,[rsp+28])
aobscanmodule(INJECT,ysxl.exe,89 18 44 8B 44 24 28)
// 分配新内存区域用于存放我们的自定义代码
// newmem: 新内存区域的符号名
// $1000: 分配的内存大小(4096字节,十六进制)
// INJECT: 指定在目标地址附近分配,提高缓存效率
alloc(newmem,$1000,INJECT)
// 定义标签:用于代码跳转控制
// code: 标记原始代码执行位置
// return: 标记返回原始流程的位置
label(code)
label(return)
// ==================================================
// 新内存代码段:我们的自定义逻辑
// ==================================================
newmem:
// 这里开始是我们的自定义代码执行区域
// 将数值999,999(十六进制F423F)写入rax寄存器指向的内存地址
// 这替换了原始的mov [rax],ebx指令(原本是将ebx值写入[rax])
mov dword ptr [rax],000F423F // 注意:F423F前补零确保4字节对齐
// 跳转到code标签执行被覆盖的原始第二条指令
jmp code
// ==================================================
// 原始代码执行段:保持游戏逻辑完整性
// ==================================================
code:
// 执行被覆盖的原始第二条指令:mov r8d,[rsp+28]
// 这条指令从栈中rsp+28位置读取值到r8d寄存器
// 必须执行这条指令,否则会破坏游戏逻辑
mov r8d,[rsp+28]
// 跳转回原始代码流程的继续执行点
jmp return
// ==================================================
// 注入点修改段:重定向执行流程
// ==================================================
INJECT:
// 用5字节的jmp指令替换原始代码,跳转到我们的newmem区域
jmp newmem
// 用nop指令填充剩余的2字节空间
// 原始两条指令共7字节,jmp占5字节,所以需要2字节nop填充
nop
nop // 等同于 nop 2
return:
// 这里标记原始代码流程中注入点之后的位置
// 当从newmem跳回时,从这里继续正常执行
// 将INJECT符号注册到CE的符号表
// 这样其他脚本或地址列表可以通过名称INJECT引用这个动态地址
registersymbol(INJECT)
// ==================================================
// 禁用脚本段:清理和还原
// ==================================================
[DISABLE]
INJECT:
// 精确还原原始的7字节机器码
// db指令直接写入原始字节,避免汇编器差异问题
// 89 18: mov [rax],ebx 的机器码
// 44 8B 44 24 28: mov r8d,[rsp+28] 的机器码
db 89 18 44 8B 44 24 28
// 清理工作:注销符号并释放内存
unregistersymbol(INJECT)
dealloc(newmem)
AOB注入脚本中会用到一些命令:
| 命令/函数 | 参数说明 | 作用描述 |
|---|
aobscanmodule | (SymbolName, ModuleName, AOBString) | 在指定模块中扫描字节模式,将找到的地址存入符号。要求模式唯一。 |
alloc | (allocatedName, size, optionalNearAddress) | 分配可读、写、执行的内存。size 是16进制数(如 $1000 表示4096字节)。 |
label | (name) | 定义一个标签,用于标记代码位置。 |
registersymbol | (SymbolName) | 将符号注册到用户定义符号列表,允许其他脚本通过名称引用该地址。 |
unregistersymbol | (SymbolName) | 从用户定义符号列表中移除该符号。 |
db | 字节值列表 (如 83 AE E0 07 00 00 01) | 定义字节数据。在[DISABLE]中用于精确还原原始机器码。 |
dealloc | (allocatedName) | 释放之前由 alloc 分配的内存。 |
标准AOB注入框架结构
[ENABLE]
// 第1步:动态地址定位
aobscanmodule(标识符,模块名,字节序列)
// 第2步:内存分配
alloc(内存名,大小,附近地址)
// 第3步:标签定义
label(代码标签)
label(返回标签)
// 第4步:新内存代码(自定义逻辑)
新内存标签:
[自定义修改代码]
jmp 代码标签
// 第5步:原始代码执行
代码标签:
[被覆盖的原始指令]
jmp 返回标签
// 第6步:注入点修改
注入点标签:
jmp 新内存标签
nop [填充字节]
返回标签:
// 第7步:符号注册
registersymbol(标识符)
[DISABLE]
// 第8步:精确还原原始字节
注入点标签:
db [原始字节序列]
// 第9步:清理资源
unregistersymbol(标识符)
dealloc(内存名)
剩下的一些地址比较容易找,就不用AOB注入了。