好友
阅读权限 10
听众
最后登录 1970-1-1
本帖最后由 laozhhaiJohn 于 2022-4-16 14:09 编辑
cheat engine--CE游戏修改-共用代码-aob注入-人造指针-指针扫描--以《 枪血黑手党2》为例
20220319:
闲来无事,反正因为疫情被封在小区,鼓捣鼓捣游戏和cheat engine吧。这次用《枪血黑手党2》(Guns Gore and Cannoli 2)来一次共用代码、aob注入、人造指针、指针扫描、线程注入的游戏。
特别强调!!!!!这只是我在修改游戏时候,在win10记事本中记录的自己修改的过程和心得,由于记事本的限制,因此没有配图片,请见谅!!!!!
一、找主角生命值:
数值类型:单浮点
搜索方法:初始未知->减少、不变等等几次搜索
结果:找到三个值(查看其初始值为150),两个地址类似2D74E8**,一个地址类似455*****。
分析:不一样的那个地址,每次载入游戏会变化(指没有退出游戏情况下,比如主角别干掉。如果退出游戏到系统后再运行游戏,则3个地址都会变化,但是2个基本不变1个经常变的规律通用)。
锁定这个地址后,主角血量不减。
二、CE进行剖析:
1、在该不一样地址上右键,“找出什么改写了这个地址”
2、主角被击打掉血后,找到一条指令:
???????? - F3 0F11 AE C0010000 - movss [rsi+000001C0],xmm5
3、ce替换该指令,主角不掉血了,但是敌人也不掉血了!!!
看来不能简单粗暴的替换!
三、代码共用程序段的分析:
4、在ce找到指令的窗口中,在指令上右键点击,然后选择右键菜单中的“找出代码访问的地址”
5、然后ce打开新窗口“访问的地址为。。。”,
6、返回游戏,主角修理一下对面的几个敌人,
7、这时候发现,在“访问的地址为。。。”窗口出现了几个地址。
仔细查看可以发现,其中一个为主角血量的地址,其余几个为当前被主角击打的敌人地址。
8、在CE找到指令窗口,点击右侧按钮“显示反汇编程序”,ce新建内存浏览窗口(Memory Viewer)。
9、在窗口中点“工具”--“分析数据/结构”,出现一个“结构分析”窗口.
(步骤8、9,其实可以合为一个步骤,即在访问地址窗口选中那几个地址,然后右键,选择“打开选中地址的分析数据”,然后在新出现的窗口点击“<新建窗口>”,之后一路确定,也会打开一个下面第12步的数据分析窗口。)
10、在结构分析窗口中,将主角和敌人的地址分别加进去。
首先在群组1的第一个地址中,填写第7步窗口中主角的地址-1C0(也就是填写rsi的地址,因为访问地址中的地址,是程序的rsi+000001C0后得到的地址,现在需要从rsi开始分析结构,所以真实地址要减去1C0。)
然后,点击“文件”--“添加额外的地址”,在群组1下又出现一个地址框,将敌人的地址填入,同样减去1C0。
之后,将其余敌人地址按照上面方法一一填入。
11、地址都填写完毕,发现结构分析窗口下面空白,并没有任何数据。
点击“结构”--“定义新的结构”,可以命名该结构名称,注意:在长度位置需要填写大一些的一个值,至少要比1C0要大(1c0为十进制400多,所以可以长度填写500以上)。
这时候发现这两个地址下出现大量数据。
12、仔细对比敌我的数据,红色的为不同值,绿色的为相同值。我们主要看不同值有什么特点。
发现几组地址似乎可以用:
例如:+190处(4字节),主角为1,敌人为0
例如:+1BC处(4字节),主角为1,敌人为0
例如:+250处(4字节),主角为1,敌人为0
例如:+260处(4字节),主角为1,敌人为0
例如:+194处(4字节),主角为0,敌人为1
例如:+1A4处(4字节),主角为0,敌人为1
例如:+1DC处(浮点),主角为1,敌人为0
例如:+258处(4字节),主角为0,敌人为7
例如:+25C处(4字节),主角为2,敌人为1
例如:+184处(4字节),主角为0,敌人为巨大数值
多运行几次游戏,观察后可发现,有几处会发生变化,比如+1BC处,可能都会变为1。
不会变化的有几处:+190,+194,+1DC(浮点),+250,+260。
但是,诡异的是,这些值都是在游戏暂停时候的值!!!
一旦游戏处于非暂停的运行状态,则好几处值比如+190、+194等,无论敌我,值都会变成相同的,导致无法区分敌我。
于是再次在游戏非暂停状态下,主角或者敌人被打击的时候,观察这些值!!
发现+260处(4字节),主角为1,敌人为0不会变动。但是在第二个小关卡即楼房好多窗户中藏着好多警察的地方,这些警察的+260值竟然也为1,无法区分敌我啦。
+184(4字节),+226(2字节),+22A(2字节),这三个地址,我方为0,敌方都不为0.
选择+184这个偏移的值,作为区分敌我的判断。
四、通过分析共用代码后,进行汇编代码注入:
13、在内存浏览窗口中,点击“工具”--“自动汇编”后,出现自动汇编窗口。
14、在新窗口中,点击“模板”--“CT表框架代码”;然后继续点击“模板”--“代码注入”,ce自动填写了一些代码。
15、写代码:
主要是增加了2条指令,一个比较[rsi+1BC]处的值是否为1,为1则跳走不执行减少血量命令,为0则执行减血命令。
代码如下:
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048,01469BEF)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
cmp [rsi+00000260],1
//比较这个地址,值为1是主角,值为0是敌人
je exit
//上一条比较,为1相等(是主角)则跳走不减血。不相等,则继续执行减血指令。
originalcode:
movss [rsi+000001C0],xmm5
exit:
jmp returnhere
01469BEF:
jmp newmem
nop 3
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
01469BEF:
movss [rsi+000001C0],xmm5
//Alt: db F3 0F 11 AE C0 01 00 00
五、通过特征码扫描定位注入代码,完成锁定主角生命值任务!
16、上面的脚本勾选运行后,又发现新情况!!!
就是:完全退出游戏到win10桌面,再次打开游戏进入,发现修改无效。
再次查找血槽值,找到后,找“改写该地址的指令”,发现指令的地址变化啦(指令本身的字节数组不变,但是存放这段指令的地址发生了变化。)。
因此需要找这段指令的字节数组的特征码,然后让CE搜索此特征码,找到后再进行注入处理。
17、
第2步中的减血指令:
???????? - F3 0F11 AE C0010000 - movss [rsi+000001C0],xmm5
在CE中搜索该指令的字节码,看看是否唯一:
首先在游戏中游玩,让主角挨打以及打击敌人(否则搜索不到。)
在ce中搜索,设置如下:
数值类型:字节数组
搜索方法:注意在搜索框前面,有个十六进制的复选框,需要勾选上。
然后将“F3 0F11 AE C0010000”复制到搜索框中,点击“首次扫描”。
结果:找到1或者2个地址。
分析:有时候找到1个唯一地址,有时候找到2个地址,不知道怎么回事。但多数时候找到1个地址。
(20220322补充:后来发现,如果发现是2条的话,可能是编写的脚本没有将内存中脚本中
的该条指令清除导致的,因此,如果游戏退出到win10系统,再进入游戏,则只能找到
唯一地址。)
(因此,为了保险起见,对比找到的2个地址,发现该指令后面很长是相同的,该指令向前找几条之后发现不同。因此从这个不同开始将特征码扩大如下:
0F83 5B000000 F3 0F10 45 F0 F3 0F5A C0 F2 0F5A E8 F3 0F11 AE
然后再ce中按照上述步骤搜索,可以发现多次只能搜索到唯一一个地址。
因此确定使用这个特征码。)这段没有使用。
18、在ce的自动汇编窗口中编写指令:
在下面的CEAA中,同时增加给主角加血、对敌人一击必杀的指令。
{ Game : ggc2.exe
Version:
Date : 2022-03-20
This script does blah blah blah
}
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
aobscan(zhurudian,F3 0F 11 AE C0 01 00 00) // should be unique
alloc(newmem,$1000,zhurudian)
label(code)
label(return)
label(exit)
label(team1) //我方
label(team0) //敌方
label(team1Value) //我方血量
label(team0Value) //敌方血量
newmem:
pushfq ///保存标志位
cmp [rsi+00000184],0 ///检测是否为我方team1
//比较这个地址,值为0是主角,值不是0则敌人. 注意执行后ZF值的变化。
//等,则设置ZF=1,不等则置0
je team1 //je表示等,则跳转.等与不等看标志位ZF,zf=1表示相等。
//为1相等(是主角)则跳。不相等,则继续执行。
//cmp [rsi+00000184],0 ///检测是否为敌方team0//等,则置ZF=1,否则置0
jne team0 //不等则跳.标志位ZF=0表示不等。
exit:
popfq ///恢复标志位
code:
movss [rsi+000001C0],xmm5
jmp return
team1: //我方
movss xmm5,[team1Value]
jmp exit
team0: //敌方
movss xmm5,[team0Value]
jmp exit
team1Value: //我方
dd (float)5000 //主角血槽值5000
team0Value: //敌方
dd 0 //敌方血槽值置0,一击必杀
zhurudian:
jmp newmem
nop 3
return:
registersymbol(zhurudian)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
zhurudian:
db F3 0F 11 AE C0 01 00 00
unregistersymbol(zhurudian)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: 06E999CF
06E9999D: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
06E999A2: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
06E999A6: F3 0F 10 8E C0 01 00 00 - movss xmm1,[rsi+000001C0]
06E999AE: F3 0F 5A C9 - cvtss2sd xmm1,xmm1
06E999B2: 66 0F 2F C8 - comisd xmm1,xmm0
06E999B6: 0F 8A 61 00 00 00 - jp 06E99A1D
06E999BC: 0F 83 5B 00 00 00 - jae 06E99A1D
06E999C2: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
06E999C7: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
06E999CB: F2 0F 5A E8 - cvtsd2ss xmm5,xmm0
// ---------- INJECTING HERE ----------
06E999CF: F3 0F 11 AE C0 01 00 00 - movss [rsi+000001C0],xmm5
// ---------- DONE INJECTING ----------
06E999D7: 48 8B CE - mov rcx,rsi
06E999DA: 48 83 EC 20 - sub rsp,20
06E999DE: 49 BB 10 A3 3B 2C 00 00 00 00 - mov r11,000000002C3BA310
06E999E8: 41 FF D3 - call r11
06E999EB: 48 83 C4 20 - add rsp,20
06E999EF: 85 C0 - test eax,eax
06E999F1: 74 09 - je 06E999FC
06E999F3: 8B 46 20 - mov eax,[rsi+20]
06E999F6: 83 C8 01 - or eax,01
06E999F9: 89 46 20 - mov [rsi+20],eax
}
六、通过指针扫描获取血槽值基址。
指针扫描可以用来快速解决这个问题,首先找到所需值的地址,保存生成的指针映射,重新启动游戏,再次搜索地址,保存另一个指针映射,然后将两者进行比较。
1、搜索血量地址并加入到ce表中:(同上不再详述。)
数值类型:单浮点
扫描类型:
搜索方法:
结 果:
分 析:
锁 定:
2、找到三个地址中的关键地址,在该地址上右键--选择“对这个地址进行指针扫描”。
在指针扫描器的窗口选项中,我习惯将最大偏移设置为2000,最大偏移级别设置为6。(这样如果找不到基址,则可以考虑增大最大偏移和最大偏移级别。)其他选项可以不管。
确定后,ce提示保存到一个文件。之后,根据设置和游戏的大小以及电脑性能的不同,ce开始时间略长的一个分析。之后会报告找到n个指针路径。
3、游戏重开关卡或者退出游戏重新开启。之后再次搜索到主角血量地址,地址加入ce表。
如果指针扫描窗口已关闭,请打开保存的指针列表。这时候,列表中一些内容显示???表示错误了。
现在在扫描窗口,点“指针扫描器”-->“重新扫描内存”选项。
在新打开的选项窗口中,选“要查找的地址”,并输入新的血量地址。
为新指针列表选择一个名称保存,CE过滤掉指向错误地址的指针。指针列表中指针减少。
4、将上面1、2、3步骤重复几次,指针列表数大量减少。
观察这些指针,找指针层级较少的一些,和不同的模块下的指针,双击这些想要的指针,即可将这个指针加入到ce表中。这里建议多找一些指针存到ce表中,以备有些指针是错误的好以后剔除。
载入游戏几次后,或者重启电脑载入游戏几次后,会发现又有许多指针不能使用了。删这些错误的指针,留下正确的。
七、通过人造指针设置血槽值。
【申请地址】创建人造指针法:
(1) 右键点血量值的地址,打开“找出是谁改写了这个地址”,找到固定的程序段。
(2) 在下列操作码写入到??????窗口中,选择“显示反汇编程序”。
之后会打开该程序段的内存视图,选择“工具”-“自动汇编”-“模板”-“CT表框架”-“代码注入”或者“AOB注入”。由于本游戏这里的代码段也是随机分配的,所以选择aob注入。
(3) 使用alloc(标识名,地址长度)动态申请内存,将血量地址保存到申请的内存中。
(4) 申请的内存地址一般只能在当前脚本中使用,我们将其保存到一个全局变量中,使得可以在其它脚本中也能访问使用。
CEAA提供了一个函数命令registersymbol(标识名),表示将参数标识加入到全局表。
(5) 在[disable]中添加释放申请内存的指令dealloc(标识名,地值长度)
(6) 前面将申请的内存标识加入了全局表,那么在关闭脚本时须将标识从全局表中剔除[unregistersymbol(标识名),将参数标识从全局表中剔除]
(7) 在CE表中手动添加地址,类型为指针,地址填写该全局标识名。OK!!
以下为该CEAA脚本代码:
{ Game : ggc2.exe
Version:
Date : 2022-03-21
}
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
aobscan(INJECT,F3 0F 11 AE C0 01 00 00) // should be unique
alloc(newmem,$1000,INJECT)
alloc(my_point_HP,$4)
registersymbol(my_point_HP)
label(code)
label(return)
newmem:
push eax
lea eax,[rsi+000001C0]
mov [my_point_HP],eax
pop eax
code:
movss [rsi+000001C0],xmm5
jmp return
INJECT:
jmp newmem
nop 3
return:
registersymbol(INJECT)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT:
db F3 0F 11 AE C0 01 00 00
unregistersymbol(INJECT)
unregistersymbol(my_point_HP)
dealloc(newmem)
dealloc(my_point_HP)
{
// ORIGINAL CODE - INJECTION POINT: 0129189F
0129186D: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
01291872: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
01291876: F3 0F 10 8E C0 01 00 00 - movss xmm1,[rsi+000001C0]
0129187E: F3 0F 5A C9 - cvtss2sd xmm1,xmm1
01291882: 66 0F 2F C8 - comisd xmm1,xmm0
01291886: 0F 8A 61 00 00 00 - jp 012918ED
0129188C: 0F 83 5B 00 00 00 - jae 012918ED
01291892: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
01291897: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
0129189B: F2 0F 5A E8 - cvtsd2ss xmm5,xmm0
// ---------- INJECTING HERE ----------
0129189F: F3 0F 11 AE C0 01 00 00 - movss [rsi+000001C0],xmm5
// ---------- DONE INJECTING ----------
012918A7: 48 8B CE - mov rcx,rsi
012918AA: 48 83 EC 20 - sub rsp,20
012918AE: 49 BB 80 0A 05 2C 00 00 00 00 - mov r11,000000002C050A80
012918B8: 41 FF D3 - call r11
012918BB: 48 83 C4 20 - add rsp,20
012918BF: 85 C0 - test eax,eax
012918C1: 74 09 - je 012918CC
012918C3: 8B 46 20 - mov eax,[rsi+20]
012918C6: 83 C8 01 - or eax,01
012918C9: 89 46 20 - mov [rsi+20],eax
}
八、完善:
上面脚本中,都依赖rsi的值来确定玩家的血量地址。但是在游戏开启脚本后,会发现,rsi的值也是敌我共用的。当敌人攻击玩家的时候,rsi的值是玩家;当玩家攻击敌人时候,rsi的值是敌人。因此,自造指针在玩家攻击敌人时候显示敌人血槽值。
因此,再次研究血量减少的指令代码。在指令代码上右键后点击"指令访问的地址",之后在指令访问的地址窗口中找到玩家和敌人的地址,对这些地址按CTRL+R键(或者右键选显示寄存器状态),打开这些地址当前寄存器情况窗口,仔细对比发现:
玩家的R8=0,敌人R8都不为0
于是,在脚本中判断这个值来区分敌我试试。完全ok。
新脚本如下:
{ Game : ggc2.exe
Version:
Date : 2022-03-24
aob注入后将rsi+1C0写全局-激活才有效-fix
}
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
aobscan(INJECT,F3 0F 11 AE C0 01 00 00) // should be unique
alloc(newmem,$1000,INJECT)
alloc(my_point_HP,$4)
registersymbol(my_point_HP)
label(code) //
label(return) //
label(BuXiangDeng) //不相等
newmem:
pushfq //保存标志位
cmp R8,0 //比较R8值是否为0,为0,则现在是主角
//r8值为0则等,则设置标志ZF=1,不等则置0
jne BuXiangDeng //不等则跳:检测zf=0表示不等
//等则不跳,继续执行下面的代码
push eax //保存eax值
lea eax,[rsi+000001C0] //把玩家血量地址放到eax中转
mov [my_point_HP],eax //把玩家血量值放到”我的hp指针"
pop eax //恢复eax值
BuXiangDeng:
popfq //恢复标志位
code:
movss [rsi+000001C0],xmm5
jmp return
INJECT:
jmp newmem
nop 3
return:
registersymbol(INJECT)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT:
db F3 0F 11 AE C0 01 00 00
unregistersymbol(INJECT)
unregistersymbol(my_point_HP)
dealloc(newmem)
dealloc(my_point_HP)
{
// ORIGINAL CODE - INJECTION POINT: 0129189F
0129186D: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
01291872: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
01291876: F3 0F 10 8E C0 01 00 00 - movss xmm1,[rsi+000001C0]
0129187E: F3 0F 5A C9 - cvtss2sd xmm1,xmm1
01291882: 66 0F 2F C8 - comisd xmm1,xmm0
01291886: 0F 8A 61 00 00 00 - jp 012918ED
0129188C: 0F 83 5B 00 00 00 - jae 012918ED
01291892: F3 0F 10 45 F0 - movss xmm0,[rbp-10]
01291897: F3 0F 5A C0 - cvtss2sd xmm0,xmm0
0129189B: F2 0F 5A E8 - cvtsd2ss xmm5,xmm0
// ---------- INJECTING HERE ----------
0129189F: F3 0F 11 AE C0 01 00 00 - movss [rsi+000001C0],xmm5
// ---------- DONE INJECTING ----------
012918A7: 48 8B CE - mov rcx,rsi
012918AA: 48 83 EC 20 - sub rsp,20
012918AE: 49 BB 80 0A 05 2C 00 00 00 00 - mov r11,000000002C050A80
012918B8: 41 FF D3 - call r11
012918BB: 48 83 C4 20 - add rsp,20
012918BF: 85 C0 - test eax,eax
012918C1: 74 09 - je 012918CC
012918C3: 8B 46 20 - mov eax,[rsi+20]
012918C6: 83 C8 01 - or eax,01
012918C9: 89 46 20 - mov [rsi+20],eax
}
---------------------------------------------------------------------------
找主角武器弹药的地址:
一、链锯使用次数:
1、搜索:
数值类型:4字节
扫描类型:精确数值
搜索方法:每次扫描都输入游戏画面中的电锯值
结 果:搜索2次后找到2个地址。
分 析:分别锁定2个中的某一个,在游戏中使用电锯,可以发现1个地址是关键。
锁 定:锁定2个中的关键地址后,电锯子弹不再变化。OK!
2、(这个判断错误!)对关键地址进行指针扫描,但是扫描3次后找到0个指针!(这个判断错误!)
(----------------补充完善:上面说的不对!!!!!----------------------)
(找不到是因为设置的扫描指针层级少,当指针层级达到7或者8时候,就能搜到指针!!!)
(但是,切切注意!!!当设置扫描指针层级达到7的时候,扫描时间尚可。
当指针扫描层级设置为8的时候,扫描开始到记录结束,花费时间漫长,在我的配置较低的
电脑上,以cpu占用较高情况下,扫描花费10分钟,而这只是一个中等以下级别的游戏!!)
(所以,扫描指针的时候,一定以7级为一个量级,7级以下扫描不到,之后再设置扫描8级!)
3、用查找“改写该地址指令”的方式,找到如下指令,
062B57E3 - 89 46 1C - mov [rsi+1C],eax
但指令的地址也是动态的,每次开游戏会变动。
4、因此上AOB,进行注入解决问题:
采用搜索该代码(CE的AOB注入),然后定位该指令位置,然后汇编处理。
打开该程序段的内存视图,选择“工具”-“自动汇编”-“模板”-“CT表框架”-“AOB注入”。
CE会自动搜特征码(注意,是CE自动找,不需要人工找!),找到后定位到你指定的注入位置。
编写代码,保存到CT表,锁定,发现一切OK。
(代码段(特征码)是:48 63 46 1C FF C8 89 46 1C 48 8B 75 F8 C9)
{ Game : ggc2.exe
Version:
Date : 2022-03-22
武器链锯不掉链子的自动脚本!哈哈,新版本。
}
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
aobscan(INJECT,C8 89 46 1C 48 8B 75 F8) // should be unique
alloc(newmem,$1000,INJECT)
label(code)
label(return)
newmem:
mov eax, #8000 //给电锯加8000个子弹量,这样电锯就不会掉链子了。
//在CEAA中,#代表数值为十进制,$代表十六进制。
code:
mov [rsi+1C],eax //注意这里的eax,其值为8000了。
mov rsi,[rbp-08]
jmp return
INJECT+01:
jmp newmem
nop 2
return:
registersymbol(INJECT)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT+01:
db 89 46 1C 48 8B 75 F8
unregistersymbol(INJECT)
dealloc(newmem)
{
// ORIGINAL CODE - INJECTION POINT: 062B57E3
062B57C0: 49 BB 50 D8 75 2C 00 00 00 00 - mov r11,000000002C75D850
062B57CA: 41 FF D3 - call r11
062B57CD: 48 83 C4 20 - add rsp,20
062B57D1: 85 C0 - test eax,eax
062B57D3: 75 11 - jne 062B57E6
062B57D5: 48 63 46 1C - movsxd rax,dword ptr [rsi+1C]
062B57D9: 85 C0 - test eax,eax
062B57DB: 7E 09 - jle 062B57E6
062B57DD: 48 63 46 1C - movsxd rax,dword ptr [rsi+1C]
062B57E1: FF C8 - dec eax
// ---------- INJECTING HERE ----------
062B57E3: 89 46 1C - mov [rsi+1C],eax
// ---------- DONE INJECTING ----------
062B57E6: 48 8B 75 F8 - mov rsi,[rbp-08]
062B57EA: C9 - leave
062B57EB: C3 - ret
062B57EC: 00 00 - add [rax],al
062B57EE: 00 00 - add [rax],al
062B57F0: 00 00 - add [rax],al
062B57F2: 00 00 - add [rax],al
062B57F4: 3C 00 - cmp al,00
062B57F6: 00 00 - add [rax],al
062B57F8: 4C 00 00 - add [rax],r8l
}
bylaoz20210113 fix:20220322
二、单手枪子弹:
1、搜索:
数值类型:4字节
扫描类型:精确数值
搜索方法:每次扫描都输入游戏画面中的单手枪枪内子弹值
结 果:搜索2次后找到1个地址。
分 析:锁定1个地址。
锁 定:锁定1地址后,单手枪子弹不再变化。OK!
2、
三、双枪子弹:
1,在游戏画面中,主角头上方为血量值。再上面是手中使用武器的弹药量。
弹药量显示类似为:15/80 这样子。在斜杠左边的15,代表武器中弹夹内子弹数。
斜杠右边的80,代表携带的剩余子弹数。这两个数的和就是该武器的总弹药数。
来查找并修改枪弹夹子弹数并锁定,这样就不至于在激烈的战斗中耽误时间换弹夹啦。
2,查找枪内弹夹子弹地址:
数值类型:4字节
扫描类型:精确值
搜索方法:输入当前子弹数,几次搜索后得到唯一值。
结 果:找到唯一值,该值等于游戏画面中显示的值。
分 析:
锁 定:锁定这个地址后,弹夹内子弹数不减。
但是,但是你会发现手枪的总子弹数在减少!!!
3,查找携带的双枪子弹总数地址:
数值类型:4字节
扫描类型:精确值
搜索方法:输入弹夹子弹数+剩余子弹数,几次搜索后得到唯一值。
结 果:找到唯一值,该值不在游戏画面中显示。
分 析:
锁 定:锁定这个地址后,总弹药数不减。
同时锁定弹夹子弹数后,两个数值都不再变化!!ok!!
4,链锯、单枪、双枪弹夹、双枪总弹药这4个地址之间毫无关联关系!!!
四、找控制指令:
在分别在手枪、双枪弹夹地址上右键,点“找出什么改写了这个地址”。
发现一条指令在不停的执行,计数值不断增大。
开枪试试,发现在“下列操作码写入到??????”窗口新增了一条指令。就是下面这条指令。
2B1D0283 - mov [rdi+24],eax (字节码:89 47 24)
控制单手枪的子弹减少指令地址,同控制双枪弹夹子弹的指令和地址都完全一样!!!
再找双枪子弹总数的控制指令,发现该指令和链锯的控制指令完全一样!!!
后面的其他武器,都是这里的两条语句控制。
五、扫描查找弹夹值和总弹药值的指针:
(扫描指针层级达到7或者8时候,就能搜到这两个值的基址!!!)
(但是,切切注意!!!当设置扫描指针层级达到7的时候,扫描时间尚可。
当指针扫描层级设置为8的时候,扫描开始到记录结束,花费时间漫长,在我的配置较低的
电脑上,以cpu占用较高情况下,扫描花费10分钟,而这只是一个中等以下级别的游戏!!)
(所以,扫描指针的时候,一定以7级为一个量级,7级以下扫描不到,之后再设置扫描8级!)
弹夹值和总弹药值我分别搜索到上百个的基址。建议多选一些基址指针,层级少的一定要都加入到地址表中,之后层级多的也要选一些不同类型的加入地址表。根据我的CE使用经验,一般来说,加到地址列表的指针,经过多次重启游戏,都会有一些错误的,所以在地址表中多加一些指针以备删除错误留下正确可用的。
我加了大约20多个地址,经过几次游戏退出打开和电脑关闭打开,剔除失效不准的地址,一般我会留下10个地址存入一个地址分组中。然后将指针层级最少的之一拿出来,供其他脚本使用。
六、利用基址指针修改并锁定血槽值、弹夹值、总弹药值。20220327
但是这个脚本有个缺陷:在脚本执行中,当玩家更换武器以后,弹夹子弹不减少,但是总弹药值在减少。但是关闭脚本,再次打开脚本,这个脚本就按照我们设计的执行了,也就是说血量、、弹夹值、总弹药值又都被锁定。但是不要换武器!
{ Game : ggc2.exe
Version:
Date : 2022-03-26
指令注入到弹夹子弹减少代码位置。
}
define(hppt,[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+48]+1C0]) //血量值指针
define(djpt,[[[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+50]+028]+10]+24]) //弹夹指针
define(zzdpt,[[[[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+50]+028]+10]+18]+1C]) //总子弹指针
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
aobscan(INJECT_danjia894724,89 47 24 48 8B CF 48) // danjia894724:
alloc(newmem_danjia894724,$1000,INJECT_danjia894724) //表示:弹夹+指令操作码
label(code)
label(return)
alloc(mydjpt,$4,INJECT_danjia894724)
newmem_danjia894724: //脚本跳转到这里
mov hppt,(float)99999 //脚本运行的第二句指令,以下顺序执行.这里加血量
//mov djpt,#9999 //加子弹(但是下面的注入点的原始代码,会将eax写入弹夹地址
//而eax目前保存的是当前弹夹子弹数(未修改的)。所以这句即使
//执行了,也会因为下面mov [rdi+24],eax代码而使这里做无用功。
mov eax,#9999 //因此,这里将加子弹数先写入eax。)
mov zzdpt,#109999 //加总弹药
code: //注入点原始代码
mov [rdi+24],eax //这里eax9999写入弹夹地址。这里[rdi+24] 和djpt是同一个地址)
mov rcx,rdi
jmp return //以上顺序执行到这里,在这里跳到return
INJECT_danjia894724: //以下是原始程序中的注入点!
jmp newmem_danjia894724 //注意,这是脚本运行的第一句指令
nop
return: //跳到return这里后,脚本结束,跳回原始程序注入点下一句。
registersymbol(INJECT_danjia894724)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT_danjia894724:
db 89 47 24 48 8B CF
unregistersymbol(INJECT_danjia894724)
dealloc(newmem_danjia894724)
{
// ORIGINAL CODE - INJECTION POINT: 2A156FB3
2A156F9A: 00 00 - add [rax],al
2A156F9C: 00 00 - add [rax],al
2A156F9E: 00 00 - add [rax],al
2A156FA0: 55 - push rbp
2A156FA1: 48 8B EC - mov rbp,rsp
2A156FA4: 57 - push rdi
2A156FA5: 48 83 EC 08 - sub rsp,08
2A156FA9: 48 8B F9 - mov rdi,rcx
2A156FAC: 48 89 55 F0 - mov [rbp-10],rdx
2A156FB0: 48 8B C2 - mov rax,rdx
// ---------- INJECTING HERE ----------
2A156FB3: 89 47 24 - mov [rdi+24],eax
// ---------- DONE INJECTING ----------
2A156FB6: 48 8B CF - mov rcx,rdi
2A156FB9: 48 83 EC 20 - sub rsp,20
2A156FBD: 49 BB 00 70 15 2A 00 00 00 00 - mov r11,000000002A157000
2A156FC7: 41 FF D3 - call r11
2A156FCA: 48 83 C4 20 - add rsp,20
2A156FCE: 48 8B 7D F8 - mov rdi,[rbp-08]
2A156FD2: C9 - leave
2A156FD3: C3 - ret
2A156FD4: 00 00 - add [rax],al
2A156FD6: 00 00 - add [rax],al
}
七、利用基址指针修改并锁定血槽值、弹夹值、总弹药值--完美版!!!
经过仔细观察基址指针和脚本注入点的寄存器情况,发现只要更换武器,再内存中的这个位置
[[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+50]+028]+10]的内容会被程序改写。估计是将当前武器
的位置地址写入到这里了。
在脚本注入点位置,是武器开枪后,弹夹减少子弹的指令。仔细观察寄存器,rdi的值就是
[[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+50]+028]+10]处存放的内容。因此,可以让脚本直接读取
rdi值,然后通过指针,找到当前武器总弹药的新地址。
按照这个思路,成功完成完美版锁血量、弹夹、总弹药的脚本。20220327
{ Game : ggc2.exe
Version:
Date : 2022-03-26
用指针锁定血量、弹夹、总弹药--完美版
}
define(hppt,[[[[[["ggc2.exe"+01449AA0]+0]+10]+28]+48]+1C0]) //血量值指针
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
// 指令注入到弹夹子弹减少代码位置。
aobscan(INJECT_danjia894724,89 47 24 48 8B CF 48) // danjia894724:
alloc(newmem_danjia894724,$1000,INJECT_danjia894724) //表示:弹夹+指令操作码
label(code)
label(return)
alloc(mydjpt,$4,INJECT_danjia894724)
newmem_danjia894724: //在原程序中跳转后,到这里开始执行。
mov eax,[rdi+18] //rdi值和目前武器密切相关,换个武器,则rdi值改变。
mov [eax+1C],#109999 //将109999写入总弹药值地址。
mov hppt,(float)99999 //这里加血量
mov eax,#9999 //将弹夹子弹数9999先写入eax。
code: //注入点原始代码
mov [rdi+24],eax //这里eax(9999)写入弹夹地址。
mov rcx,rdi
jmp return //以上顺序执行到这里,在这里跳到return
INJECT_danjia894724: //以下是原始程序中的注入点!
jmp newmem_danjia894724 //注意,这是脚本运行的第一句指令
nop
return: //跳到return这里后,脚本结束,跳回原始程序注入点下一句。
registersymbol(INJECT_danjia894724)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT_danjia894724:
db 89 47 24 48 8B CF
unregistersymbol(INJECT_danjia894724)
dealloc(newmem_danjia894724)
{
// ORIGINAL CODE - INJECTION POINT: 2A156FB3
2A156F9A: 00 00 - add [rax],al
2A156F9C: 00 00 - add [rax],al
2A156F9E: 00 00 - add [rax],al
2A156FA0: 55 - push rbp
2A156FA1: 48 8B EC - mov rbp,rsp
2A156FA4: 57 - push rdi
2A156FA5: 48 83 EC 08 - sub rsp,08
2A156FA9: 48 8B F9 - mov rdi,rcx
2A156FAC: 48 89 55 F0 - mov [rbp-10],rdx
2A156FB0: 48 8B C2 - mov rax,rdx
// ---------- INJECTING HERE ----------
2A156FB3: 89 47 24 - mov [rdi+24],eax
// ---------- DONE INJECTING ----------
2A156FB6: 48 8B CF - mov rcx,rdi
2A156FB9: 48 83 EC 20 - sub rsp,20
2A156FBD: 49 BB 00 70 15 2A 00 00 00 00 - mov r11,000000002A157000
2A156FC7: 41 FF D3 - call r11
2A156FCA: 48 83 C4 20 - add rsp,20
2A156FCE: 48 8B 7D F8 - mov rdi,[rbp-08]
2A156FD2: C9 - leave
2A156FD3: C3 - ret
2A156FD4: 00 00 - add [rax],al
2A156FD6: 00 00 - add [rax],al
}
---------------------------------------------------------------------------
主角坐标寻找:
1、在画面中,横(左右)是x,纵(上下)是y。假设玩家向右走x增加,向左走x减少。据说在游戏程序中,一般来说,x、y(3D游戏中还有z轴)地址是连续存放的,且坐标值都是单浮点类型(单浮点数值在内存中占用4个字节,这个知识点要知道)。
因此,先来找主角横坐标即x坐标。
2、找横坐标:
数值类型:单浮点
扫描类型:未知的初始值
搜索方法:主角左走值变大,右走值变小,原地不动值不变。
结 果:经过大约10次扫描后,剩下770个结果,之后扫描到的地址数基本不再减少了。
分 析:将700多个结果都加到地址列表中,然后把一半锁定,回游戏看主角可否移动,不能动,就把列表中的其余一半删掉。如此这般进行1/2筛选法,直到最后剩下1个值。
锁 定:锁定后,主角无法左右移动了。
3、找纵坐标:打开这个地址的内存查看窗口,看到这个地址前面4字节是0,后面4字节有值。将这个地址加入到地址列表,锁定试试,果然,主角在纵向不停抖动。
因此,主角的纵坐标=横坐标地址 + 4
再次查看ce的地址列表,发现:主角血量地址 + hex38 = x坐标
<基本完工,少许修改修订待续>
免费评分
查看全部评分