LOADING

加载过慢请开启缓存 浏览器默认开启

一次 CE 修改游戏的经验分享

玩到一款小游戏,一如既往尝试用 CE 修改血量,发现很多不生效的地方。稍微研究一下,这个游戏的血量没有明确的数值,可以通过未知的初始值,根据数值的增加或减少找到数据的地址。

搜索未知的初始值 变动后筛选数据

找到两个,最后测试下面那个可以生效,接下来找基址。

我们右键这条地址,选择对这个地址进行指针扫描。把保存的数据随便取名,等待扫描完成(一般设置的信息默认即可)。

指针扫描配置

结果出来了:

指针扫描结果

我们先过滤一下数据:点击指针扫描器,点击“重新扫描内存” -> “移除没有指向正确地址的指针”。

重新扫描并筛选指针

切换到要查找的数值,然后切换我们要查找数据的类型,比如我们的血量数据是单精度浮点数,然后输入 93,保存结果。好的,我们可以重启游戏了。此时再次打开游戏,选中进程,我们发现数据都变了,什么数据都可能有,我们此时再筛选一下。

重启游戏后再次筛选

一般游戏到这里就可以了,但是这个游戏并不行,我们直接改写减少体力的那段指令。

右键数据,点击“找出是什么改写了这个地址”:

找出是什么改写了这个地址

点击“显示反汇编器”。

反汇编器视图

稍微看一下这些汇编指令大概意思是:

  1. 1CCA9600644 ~ 1CCA9600651:把当前血量、扣减值、上限值转成浮点数。
  2. 1CCA9600660: call r11:调用限制函数(把计算后的血量限制在 0 ~ 最大血量 之间)。
  3. 1CCA960066B: movss [rsi+000000A8],xmm5:将最终计算好的真实血量,写入角色内存地址 [rsi+A8]。
  4. 紧接着 1CCA960067B: pop rbp; ret:写完后函数直接结束返回。

我们把 1CCA960066B 使用 nop 填充,发现怪物和我们都不掉血了,说明所有的玩家和敌人受击时,调用的都是这同一行指令。因此我们需要找到玩家的 rsi 值,然后写注入脚本。

我们在详细信息中可以找到,玩家当前这局游戏的角色对象地址为 000001CCA153AD80,那么血量地址为 000001CCA153AD80 + A8。

可以写注入脚本了,打开自动汇编窗口:在当前 CE 的内存视图窗口中,确保选中的还是那一行:1CCA960066B: movss [rsi+000000A8],xmm5。按快捷键 Ctrl + A,在弹出的自动汇编窗口中,点击菜单栏的 “模板” -> “代码注入”。

粘进去写好的脚本:

[ENABLE]
alloc(newmem, 2048, 1CCA960066B)
label(returnhere)
label(exit)

newmem:
  // 1. 判断受击者是不是玩家
  push rax
  mov rax, 000001CCA153AD80   // 玩家地址
  cmp rsi, rax
  pop rax
  je exit                     // 如果是玩家,直接跳过写入

  // 2. 如果是怪物,正常执行扣血
  movss [rsi+000000A8],xmm5
  jmp exit

exit:
  jmp returnhere

1CCA960066B:
  jmp newmem
  nop 3
returnhere:

[DISABLE]
1CCA960066B:
  db F3 0F 11 AE A8 00 00 00
dealloc(newmem)

粘贴完后,再次点击窗口菜单栏的 “文件” -> “分配到当前作弊表”。

搞定,正常测试玩家不掉血,怪物掉血。