CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)

文章目录

    • Intro
    • Hardware
    • Return to virtual memory
    • Compiler
    • Finding assembly code
    • Example!
    • Assembly language
      • Registers
    • Assembly Example
      • Inc
      • Dec
      • Add
      • Sub
      • Mov!
      • Neg
      • Mul
      • Div
    • Assembly problem
    • 恭喜 Congratulations!

Intro

大多数人在走到这里之前就退出了,这里是 game hacking 开始变得真正有趣的地方,我们将开始学习程序集编辑,也就是汇编编辑,我们将依靠这个重写游戏代码,以使其执行我们希望它执行的操作,如果您从未编写过游戏也不要担心,课程接受你将学会使用汇编语言轻松开发自己的 game hacking command-line,同样的你也可以将这一过程看为:

  1. Find relevant assembly code
  2. Change it
  3. See if it worked

这里第一点和第二点实际上是2个不同方面的内容,他们都具有自己的学习曲线,找到汇编代码首先要知道汇编代码是什么以及如何工作

Hardware

首先我们先要了解一些硬件的知识,你的电脑有一个 CPU,复制处理代码,制造商决定哪些代码可以在 CPU 上面运行

  • x86/x64 台式机、笔记本、现在的 PS、XBOX 属于这个架构,绝大多数的关注重点
  • ARM 智能手机和手持设备倾向于使用 ARM,功效更高,功耗更好
  • PowerPC 一些旧游戏机使用它,你可能永远不会看到他除非现在回去深入他们

Return to virtual memory

我们重新审视虚拟内存中的数据排布,在 copied exe 和 DLL 中不止有静态数据还有静态代码,现在是我们学习代码的时候了

c7 40 04 32 00 00 00 90 83 6d f8 fc 48 8d 04 24 ff d5 …

现在我们可以把这些代码分组为汇编指令语言,并且不用担心理解这些东西

  • mov [rax+04],32 - C7 40 04 32 00 00 00 组成移动指令
  • nop - 90 组成无操作指令
  • sub dword ptr [rbp-08], -04 - 83 6D F8 FC 减法指令
  • lea rax, [rsp] - 48 8D 04 24
  • call rbp FF D5

在我们阅读 FF D5 时可以说他们是机器语言,但当我们把他们分组成一条指令,即汇编语言之后,就可以把相同的信息垂直堆栈起来,这就是大部分 game hacking tool 显示汇编语言的方式

Compiler

直接使用汇编工作是枯燥乏味且容易出错的,所以现在有 C、C++ 这样的高级语言,C++ 转换成汇编代码的过程就是编译器工作的过程,让我们看看编译器是如何工作的

大多数游戏都是用 C++ 编写的,游戏开发人员可以将 C++ 编译成机器语言,这对 game hacking 工作人员来说是不可读的,所以我们把机器语言 Disassembling 成汇编语言,然后我们可以编辑汇编语言以重新编程游戏

但想把机器语言逆向回 C++ 代码是不太可能的,让我们打开 godbolt.org 网站看看,他基本给你展示了 C++ 代码和汇编语言之间的联系

常见的第二个技术是 C#,当代许多游戏都是用 Unity 制作的,Java 也是一样的

这里视频作者放了一系列 PPT 来介绍 python、game maker 等等,说明了为什么 C++ 游戏比较适合汇编修改

如何确认游戏是用什么语言写的?

  1. 打开游戏文件夹
  2. 如果看到 Mono 一般是 Unity C#
  3. 看到 ue3 un4 一般是虚幻引擎制作也就是 C++

Finding assembly code

如何找到汇编代码?一个游戏可能有上百万行汇编指令,我们的目标只是找到其中的一条指令,例如伤害玩家的代码,或者购买物品时夺走我们金币的代码。

比方说,我们玩家的健康状况存储在玩家对象中,现在在 C++ 游戏中,所有代码都存储在 exe 中,所以我们知道 Player 对象处的代码负责更新此处玩家的生命值,我们的目标是找到那里的代码,我们可以在玩家的血量处设置一个叫做数据断点的东西,他会准确告诉我们 exe 中的哪一行代码尝试访问或更新玩家的生命值

Example!

首先我们还是启动游戏,然后仍然是去找到生命值或者金钱之类的你感兴趣的数值,想要找到编辑此数值的代码能做的就是右键然后点击 Find out what writes to this address,或者 Find out what accesses this address 正在读取这个数值的地址比如说死亡检测之类的东西。

比如我们查找是什么让我们受伤,肯定是有什么写入了数据,所以这里选择 Find out what writes to this address
在这里插入图片描述
当我们在游戏中改变这个数值时,会发现多了一条指令出现在这个列表
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第1张图片
我们选中它并选择 Add to the codelist,最好给出一个名字比如 update gold / update health
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第2张图片
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第3张图片
很酷的是,我们可以右键 codelist 中的这条指令然后将其替换为不执行任何操作的代码,当然你也可以随后选择恢复成原来的代码样子。

我这里是植物大战僵尸的金币增加代码,如果这样做了,将会导致后续不再能够获取金币。

CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第4张图片
让我们重新打开植物大战僵尸,选择阳光作为我们的关注对象,当我们使用一个卡牌时可以捕获到这样一条指令

CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第5张图片
如果我们把它替换成 nop 无操作指令,在游戏中使用阳光你会发现什么都没有发生,没有阳光被消耗了(这里的逻辑是消耗,增加阳光或者其他更改阳光数值的逻辑途径不受影响!

不幸的是,有些游戏的受伤或者治疗代码适用于所有对象,也就是说,你不会受到伤害了,但怪物也不会了,这不是我们想要的

CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第6张图片
一个重要的点是:动态地址再重启游戏后不再会有效,但你找到的这些 code 他们是不会有变化的,因为这些代码都存放在 exe 中

Assembly language

所以我们找到了我们感兴趣的代码,也许可以用一些 nop 无操作指令来填充他,这对 90% 情况都够用了,我们可以把伤害玩家、夺走玩家金币的代码删除。但在某些情况下编写自定义汇编能够更有价值,但我们要先学会汇编语言

Registers

第一个概念是寄存器,寄存器是 CPU 中的临时存储,在我们深入了解我们需要的寄存器之前,了解代码如何在硬件上运行。我们知道当用户双击一个 exe 时,他会从硬盘复制到 RAM 中,但是我们需要该代码在 cpu 上运行,而 cpu 存储空间非常之小,我们不能只是复制所有游戏代码到 cpu 里面,因此,所有的代码都是逐行传输到 cpu 中,就像视频网站传输视频一样。

但是存在一个小问题,Code ‘streamed’ to CPU,但有时代码需要访问数据,CPU 可能会运行一些代码来读取玩家的生命值,然后更新一下数据再放回 RAM 中,不幸的是从 CPU 访问 RAM 实际上是相当昂贵的,所以人们在 CPU 上面放置了非常少量的存储空间,这就是寄存器

  • 硬盘离 CPU 非常远,访问速度相当慢,但存储相当多的东西
  • 内存离 CPU 较近,速度较快,中等存储量
  • CPU Memory 离 CPU 最近,速度最快,但容量极小

内存通过 L3 Cache -> L2 Cache -> L1 Cache(Code/Data) -> Registers 进入寄存器,其中1级缓存具有2个部分,分别存储代码和数据。幸运的是,对我们来说不需要关注中间的 Cache 缓存,只需要了解 Registers 中发生了什么即可

在我们想要进行操作之前我们要先把数据放到寄存器中,这样我们可以把玩家的生命值放到寄存器里,然后加载一些我们可能造成的伤害,然后把两者进行减法,然后写回 RAM 中

这是 32-bit game 中寄存器的示例,在 32-bit 计算机中寄存器有 4bytes :

  • EAX 0000 0064
  • EBX 0000 0005
  • ECX 0000 002C
  • EDX 0000 0019
  • EDI 018B 1000
  • ESI 018B 1000
  • EBP 6FF9 30CC
  • ESP 6FF9 3070
  • EIP 02C1 A07B

如果我们把游戏在此时冻结,可能会注意到 EAX = 64 可能是玩家的生命值,EBX = 5 可能是玩家即将受到的伤害

而 64-bit game 其实是类似的,只是寄存器长度翻倍为 8bytes,而且寄存器以 R 开头而不是 E:

  • x86 Assembly 32-bit games, push eax
  • x64 Assembly 64-bit games, push rax

x86 实际上是 intel 早期一些 cpu 命名,而 64-bit 出现时他们必须给一个新名字,所以就又变成了 x64,这看起来似乎有些愚蠢

区分 32位 和 64位 游戏很简单,当你使用你的 Tools 打开游戏看看里面的寄存器是 R 开头还是 E 开头就可以了,其他几乎一样

在寄存器中不要随便弄乱 EBP ESP EIP 这三个,他们一般用来指向下一条指令,而其他的指令一般都作为 General use,可以作为重点关注对象

Assembly Example

Inc

inc ecx 执行时给 ecx 的值 + 1
int [eax] 执行时给 eax 地址所在的值 + 1,比如 eax = 50393088,那么在地址 50393088 值为 12 变成了 13
int [edi + 8] 沿着 edi 地址,向下经过2个整数(4bytes),自增那个位置的数值

Dec

和 inc 的操作完全一样,只是变成了减 1

Add

add 拥有了2个寄存器作为参数
add eax, 2 给 eax 加 2
add ecx, edx 给 ecx 加 edx
add [ebp + 8], esi 结合上面的 Inc,也是类似的

Sub

和 add 的操作完全一样,只是加法变成了减法 subtracts

Mov!

比较重要的一个是 mov 移动指令,移动的工作原理是将一个值复制到该寄存器中
mov ebx, 200 200 覆盖到 ebx 上面
mov ecx, edx edx 的值覆盖到 ecx 上面
mov [eax], 10 10 覆盖到 eax 所在的地址位置
下面的省略,仍然和上面的指针版本一样,但需要注意的是,你不能在这里写 2个带 [ ] 的东西,比如 mov [eax], [edx] 这是不可能的,从 CPU 访问 RAM 的代价是昂贵的

Neg

neg 是一个简单的指令,只是对数字取反

Mul

mul 也是一个简单的指令,和 add 一样只不过现在是乘法 mul ebx, 2

Div

div 是所有指令中最令人恼火的一条,它的工作方式和乘法不同,只有一个寄存器可以作为参数传递给他
div ecx 比如此时 eax = 120,ecx = 12,当你执行这个指令时就会 使得 eax 除以您传递的任何值
当你执行之后 eax = 10, ecx = 12,如果你再执行一次,eax = 0,整数部分显然是 0,随后余数将会到 ecx 里面也就是 ecx = 2,这是非常奇怪的,他的工作方式和其他指令都不一样,可以尝试避免使用他!

Assembly problem

我们可以尝试着手修改,做一些简单事情作为例子,视频中使用了扫雷,将自增改变为 +2,随后你会发现一个问题,我们填写的代码长度和原有的代码长度不符,exe 的长度是固定的,我们不可能改变这里的代码长度
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第7张图片
正确的思路是:生成一个新的代码块并分配新的内存,在那里编写代码并运行
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第8张图片
现在我们选中这条指令,点击 Tools 里面的 Auto Assembly 或者按下 Ctrl + A
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第9张图片
填入上面的内容以后点击 Template 里面的 Code inject,注意这里一定要选中你要修改的那条指令
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第10张图片
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第11张图片
这样就会生成一段 Code injection 代码,你可以删除一些自动生成的注释,同时记得把上面的 label 也删除:
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第12张图片
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第13张图片
总之,上面的 [Enable] 代码块包含了当我们启动时运行的代码,[Disable] 包含了当我们禁用时的代码。你会发现代码先通过alloc申请了内存,然后在 “popcapgame1.exe”+1F634 跳(jump)到了newmem内存块,所以我们现在可以在 newmem 上面进行修改了,比如把 sub 改成 add 这样的操作
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第14张图片
然后我们选择 File - Assign to current cheat table 加入当前的 CE 表
在这里插入图片描述
接下来选中他最左一列的 Active 或者选中按空格就可以启动这个 Script 了,种下太阳花发现果然阳光不再减少而是加了 2!
CS420 课程笔记 P8 - 如何编辑汇编代码 (最终篇)_第15张图片

恭喜 Congratulations!

到这里你已经掌握了 game hacking 的基础了,随着后续精进汇编语言,了解更多 game hacking 方法,你将学会游戏逆向的大多数内容。

作为一名游戏开发者,后续将更新如何应对这些 game hacking,也就是 anti-cheat 的基本思路和方法,敬请期待!

你可能感兴趣的:(逆向工程,笔记,汇编,c++)