目录
一、什么是AOB注入?
二、什么时候使用AOB注入?
三、代码注入
四、全部注入
五、“全部注入”和“AOB注入”的分别
六、代码注入与AOB注入的区别
CE自动汇编的模板中,有三种注入代码的方式:
第一种是代码注入,就是训练教程中的步骤7所示。
一、什么是AOB注入?
AOB(Array of Bytes)是一系列唯一的字节数组,除了我们的指令能在内存中生成这些字节数组外,内存中的其它任何地方都不会再有这样的字节。这将有助于作弊者在游戏重新启动后,通过查找这些字节码,再次准确的提取那些动态地址。
二、什么时候使用AOB注入?
比如写了一个作弊器,但是游戏版本更新了,很有可能出现,涉及到作弊的那段游戏代码本身没有变化,但代码在内存中的位置却可能会变动的情况。这个时候,是不是又要重新去寻找一遍代码地址?
如果采用AOB注入的方式,则不需要再重新寻找地址了,因为它是通过代码在内存中的字节码来寻找地址。
自动汇编的界面如下,可以在“模板”中选择“AOB注入”:
我们还是拿训练教程的步骤7作为例子:
找到修改代码后,选择“自动汇编”中的“AOB”注入:
完整的代码如下:
[ENABLE]
aobscanmodule(INJECT,Tutorial-x86_64.exe,83 AE E0 07 00 00 01) // should be unique
alloc(newmem,$1000,INJECT)
label(code)
label(return)
newmem:
code:
//sub dword ptr [rsi+000007E0],01
add dword ptr [rsi+000007E0],02 // 增加2
jmp return
INJECT:
jmp newmem
nop 2
return:
registersymbol(INJECT)
[DISABLE]
INJECT:
db 83 AE E0 07 00 00 01
unregistersymbol(INJECT)
dealloc(newmem)
这个代码稍微复杂了一点,先看第一行代码:
aobscanmodule(INJECT,Tutorial-x86_64.exe,83 AE E0 07 00 00 01) // should be unique
这里面的"83 AE E0 07 00 00 01"就是sub指令行在内存中的字节码,虽然是模板里面可以自动生成,但是我们也可以手动确认下,可以在“Memory Viewer”界面内找到这个字节码:
然后,在CE主界面,搜索16进制数据,先选择“数值类型”为字节数组,才能选择扫描类型。
另外,一定不要勾选“可写”类型,要取消选择(表示不可写)或像设为“方框”,表示可不可写无所谓。
aobscanmodule函数表示在模块中搜索,第一个参数是搜索结果(如果有的话)的别名,当标签使用,第二个参数是要搜索的模块,第三个参数就是要搜索的字节码。
脚本命令registersymbol和unregistersymbol,前者是说将目标注册成一个全局符号,一旦注册,无论是其他脚本还是CE地址列表,都可以直接用这个注册的符号来表示这个地址,后者则表示取消注册符号。
需要注意的是在DISABLE部分,这里直接用了“db 83 AE E0 07 00 00 01”来还原,而非汇编指令。本质上来说,“db 83 AE E0 07 00 00 01”字节码代表的意思和下面的代码意思一样:
"Tutorial-x86_64.exe"+2DB57:
sub dword ptr [rsi+000007E0],01
那为什么不用上面的汇编指令来替换呢?其实是可以这么做的,但是一般来说,用字节码更好。
要知道,同样的汇编代码,可能会因为不同的汇编器而生成不同的字节代码。平时无所谓,像这种通过AOB来定位的方式,如果我们激活脚本,然后关闭脚本,一旦在代码还原时生成了不同的字节码,则脚本就无法再次激活了。所以直接写回原来的机器码是更好的选择。实际上,任何时候这都是个更好的选择。
最后,将sub改成add后,点击“文件”中的“分配到当前的CT表”,我们可以观察激活这段汇编脚本前后的变化情况。
激活前:
激活后:
可以看出,“INJECT”标签已经代替了“Tutorial-x86_64.exe”模块。
三、代码注入
代码注入,前面文章已经讲了,这里直接贴代码:
[ENABLE]
alloc(newmem,2048,"Tutorial-x86_64.exe"+2DB57)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
jmp returnhere
originalcode:
//sub dword ptr [rsi+000007E0],01
add dword ptr [rsi+000007E0],02 // 增加2
exit:
jmp returnhere
"Tutorial-x86_64.exe"+2DB57:
jmp newmem
nop 2
returnhere:
[DISABLE]
dealloc(newmem)
"Tutorial-x86_64.exe"+2DB57:
sub dword ptr [rsi+000007E0],01
四、全部注入
“全部注入”的方式其实和AOB是差不多的,见下列代码:
define(address,"Tutorial-x86_64.exe"+2DB57)
define(bytes,83 AE E0 07 00 00 01)
[ENABLE]
assert(address,bytes)
alloc(newmem,$1000,"Tutorial-x86_64.exe"+2DB57)
label(code)
label(return)
newmem:
add dword ptr [rsi+000007E0],2
code:
//sub dword ptr [rsi+000007E0],01
jmp return
address:
jmp newmem
nop 2
return:
[DISABLE]
address:
db bytes
// sub dword ptr [rsi+000007E0],01
dealloc(newmem)
五、“全部注入”和“AOB注入”的分别
//全部注入
define(address,"Tutorial-x86_64.exe"+2DB57)
define(bytes,83 AE E0 07 00 00 01)assert(address,bytes)
//AOB注入
aobscanmodule(INJECT,Tutorial-x86_64.exe,83 AE E0 07 00 00 01) // should be unique
。。。
registersymbol(INJECT)
可以看出,“全部注入”加了一句assert,它的意思是先要判断下,address与bytes要相同,才执行后面的代码。另外,AOB注入会增加一个全局符号INJECT。
六、代码注入与AOB注入的区别
1.代码注入与AOB注入的主要区别是,寻址方式不同:
//代码注入
alloc(newmem,2048,"Tutorial-x86_64.exe"+2DB57)
//aob注入
aobscanmodule(INJECT,Tutorial-x86_64.exe,83 AE E0 07 00 00 01) // should be unique
alloc(newmem,$1000,INJECT)
可以看出,“代码注入”直接使用"Tutorial-i386.exe"+2DB57,而AOB是通过搜索其对应的字节码来定位。
2.还原方式不一样:
//代码注入,还原代码
[DISABLE]
dealloc(newmem)
"Tutorial-x86_64.exe"+2DB57:
sub dword ptr [rsi+000007E0],01//AOB注入,还原代码
[DISABLE]
INJECT:
db 83 AE E0 07 00 00 01unregistersymbol(INJECT)
dealloc(newmem)
AOB注入通过程序代码的字节码还原。