逆向工程
逆向工程原本是指通过拆解机器装置并观察其运行情况来推导其制造方法、工作原理和原始设计的行为,但在软件领域,逆向工程主要指的是阅读反汇编(将机器语言代码转换成汇编语言代码)后的代码,以及使用调试器分析软件行为等工作
汇编能够更好地理解 CPU 的工作原理,从而能够处理系统内核、驱动程序这一类近乎于黑箱的底层问题
CE
Cheat Engine(CE)是一个开源的内存扫描和修改工具,广泛用于游戏作弊和软件逆向工程。它允许用户搜索、修改和调试内存中的数据
代码替换
代码替换是指将程序中的某些指令替换为其他指令,以改变程序的行为。常见的代码替换包括空指令替换和代码替换
空指令替换是指将某些指令替换为不执行任何操作的指令,以达到修改程序行为的目的。通常用于锁定游戏中的某些状态,如锁血、锁定分数等
首先通过数值搜索查到血量数值地址,然后对地址进行(访问了这个地址或者改写了这个地址)指令记录,程序中血量数值发生减少时将会记录,选中记录进入反汇编器
程序段
如果程序段的地址是 0x00400000 开头的,那么它就是主程序段,这个地址相对可靠不会发生变动。在这里进行代码替换或注入是一个很好的选择,因为它通常包含了程序的主要逻辑和功能。反之如果不是 0x00400000 开头的地址,那么它可能是动态分配的内存地址,可能会随着程序的运行而变化,这样的地址不适合进行代码替换/注入,需要另外处理
如果这条指令是 mov [address], value
这种形式的指令,那么它就是一个写内存的指令,在程序中的逻辑是减少血量,即使不懂汇编,也可以使用空指令替换来达到锁血效果
如果懂一点汇编,可以直接修改这条指令为 mov [address], [address]
,这样就相当于把血量数值赋值给自己,达到了锁血的效果,这就是代码替换
代码注入
代码注入是指将自身代码插入到其他程序或脚本中,以改变其行为或执行特定操作,在此之前必须先了解汇编语言的基础知识
mov eax, [address] ; 将后面操作数加载到寄存器 eax 中
add eax, 100 ; 将寄存器 eax 中的值加上 100
sub eax, 50 ; 将寄存器 eax 中的值减去 50
cmp eax, 0 ; 比较寄存器 eax 中的值与 0
je label ; 如果相等则跳转到标签 label
jne label ; 如果不等则跳转到标签 label
call function ; 调用函数
jmp label ; 跳转到标签 label
inc eax ; 自增
dec eax ; 自减
回到 CE 的反汇编器中,找到血量减少这一条指令,在工具栏中点击自动汇编,然后选择模板(CT表框架代码),ENABLE 和 DISABLE 是 CE 的指令,表示启用和禁用代码注入
由于已经知道当前的指令是减少血量的指令,所以可以直接在模板中修改这条指令为增加血量的指令
[ENABLE]
00427694:
add [eax], 100 ; 增加血量 100
[DISABLE]
00427694:
sub [eax], 100 ; 减少血量 100
也可以直接对当前内存地址进行数据写入,假如add [eax], 100
在内存中的数据是 0x8B 0x04 0x25 0x00 0x00 0x00 0x00
(可以定位到这条指令的地址查看内存区域),那么可以直接在 CE 的内存编辑器中将这段数据替换为 0x83 0xC0 0x64
,这样就实现了代码注入
[ENABLE]
00427694:
db 83 C0 64 ; 增加血量 100
[DISABLE]
00427694:
db 83 C8 64 ; 减少血量 100
两者都是等效的
[ENABLE]
alloc(newmem,2048) // 分配 2048 字节的内存空间
label(returnhere)
label(originalcode)
label(exit)
newmem:
mov ebx, 0 // 假设 ebx 是血量减少的值
originalcode:
sub [eax], ebx // 减少血量
mov [edi], eax // 将 eax 的值存储到 edi 指向的地址
exit:
jmp returnhere
[DISABLE]
是按顺序执行的,执行完 newmem,然后执行 originalcode
这样就达到了既没有修改原来的语句又达到了修改的效果
公用代码段
在一些程序中,血量的减少可能是通过调用一个公用的函数来实现的,这个函数可能在多个地方被调用。这导致如果在这个地方直接修改代码,可能会影响到其他地方的功能,比如自己不掉血的同时,敌人也不掉血
但是在程序中一定有一个值用来区分敌人和玩家的血量,这个值可能是一个标志位或者一个特定的内存地址。通过查找这个值,可以在代码中添加条件判断,只对玩家的血量进行修改,而不影响敌人的血量
在反汇编中,可以通过 CE 的分析数据功能来查找这个用于区分敌我的值,然后在代码中添加条件判断
特征码注入
特征码值得是在内存区域中有一系列特定的字节序列,它在程序中具有唯一性,可以通过字节数组定位到这个地址
线程注入
CE 中的线程注入是指将代码注入到其他线程中执行,这通常用于修改其他线程的行为或状态。通过 CE 的线程注入功能,可以将自己的代码插入到目标程序的线程中,从而实现对程序行为的控制,通常结合程序的 call 指令来实现
调用 Windows API
调用 Windows API 是指在程序中使用 Windows 提供的系统函数来实现特定的功能,比如文件操作、网络通信等。在 CE 中,可以通过调用 Windows API 来实现一些高级功能,比如修改窗口标题、发送键盘输入等
只要程序载入了 Windows 的相关 DLL,就可以使用 Windows API
调试器
步入和步过是调试器中常用的两种操作,步入(Step Into)是指进入当前行的函数调用,步过(Step Over)是指跳过当前行的函数调用,直接执行下一行代码