目录

最后战役X(单机手游)连跳飞天思路

目录

最后战役X(单机手游)连跳飞天思路

赶码人

最后战役X一是款基于unity引擎的单机FPS手游,作者已经不再进行维护。打开游戏后选择“端游界面”,进入游戏即可看到“调试”按钮。这个调试按钮,是游戏作者为玩家提供的“外挂”功能,包含不掉血、无限子弹、飞天、禁止人机移动 这四种功能。其中,飞天功能无法正常使用,所以本文讲讲如何修复无法飞天的BUG。

涉及到的工具:ce+ceserver、frida、il2cppdumper、ida、ADB(其实感觉这个玩机必备工具没必要说的..)

其中有些步骤,网络上教程已经有很多,我在本文不再详细展开,直接给出参考链接;

本文仅供提高编程兴趣,请勿将本文内容用于其他游戏,本文作者不承担任何责任。

如果本教程使你有所收获,请为我的相关视频点个赞,鼓励为爱发电~

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

全文总结:在按下跳跃键时,设置y轴方向的速度。

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

最开始我想的比较简单,猜测有个变量表示是否在地面,那么,在地面搜1,在空中搜0,类型选择1字节,假如游戏的跳跃按钮按下后是判断了这个变量是1才能起跳,所有结果冻结成1,就完事了,但实际上并不能。

同理,再猜测,是否有个变量表示 是否在空中,那么,在地面搜0,在空中搜1,如果游戏逻辑是“按下跳跃后,游戏判断这个变量是0才 跳跃”,那么,所有结果冻结成0,就完事了,但,想得美。

那咋办?找自身坐标呗,找到y坐标之后,肯定不是改这个值,因为这样很不优雅,比如,如果头顶有个天花板,直接就穿透过去了。如果是下读写断点,也没有啥方便的调试工具(ce不兼容arm指令,断点也几乎只能在x86模拟器上使用,而我这里测试了几个模拟器都无法安装该游戏)。

既然这样,只能尝试dump了。

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

il2dump下载连接:https://github.com/Perfare/Il2CppDumper/releases

装好il2dump之后,参考这篇帖子:https://www.52pojie.cn/forum.php?mod=viewthread&tid=982655 跟着做,导入script.py之后,再接着本文往下看就行了

(哈哈,之前没发现已经有大佬做这么详细的教程,看来我可以少写好几段咯 )

frida安装教程:https://www.bilibili.com/read/cv13148804?spm_id_from=333.999.0.0

(不建议装12的版本,因为不支持ES6的语法写着不舒服,我这里是15.0.8 ; 否则,就把我下文的let改成var)

也建议读者再自己找找其他frida教程,多对照着看.

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

具体的探索经历就不提了,忘得差不多了,直接聊聊主线:

il2cpp.so拖到ida,可以看到很多函数名字都是sub开头的,然后按照刚才的链接,在ida执行script.py之后,就能看到各种函数名。实际上,我前面的绘制系列教程涉及的操作,放到最后战役X还是一样的。

dump之后还能得到一个dump.cs文件,然后根据感觉搜就行了,或者直接看,比如men表示人物,再比如下图这个94798这一行,后面注释有个0x18,这个就表示men对象地址+0x18就是这个对象的血量。再多扯几句,0x38那个zj表示“是否为自己”,什么zj,myca,syd,不得不说,游戏作者的编码风格属于是自带混淆(吐槽归吐槽,我还是很respect这位游戏作者

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/14305d5aaba45ae69e4c6e33eb3fbf187973eafa.png@942w_861h_progressive.png

现在符号有了,咱要搞连跳飞天,直接搜吧,但你会发现搜不出来有价值的函数,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/3c4e21c70a682534909e9d7cc0f662191c3e083d.png@830w_222h_progressive.png

我在这里卡了很久,我甚至搜了tiao,ty,也是没收获,实际上是游戏作者打错单词了,把jump打成了jumap,

搜jumap,好,这下子有了:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/8a059755822209fa411330c13bc982f8ea51d4bf.png@942w_545h_progressive.png

这里不提他里面具体都做了啥,光标放函数名这一行,观察这个窗口下方有个状态栏,表示这个函数的地址,0x71FF68,记住它,接下来我们看这个函数被调用的情况,开始搞frida代码,先新建个1.js,内容如下:

1
2
3
4
5
6
7
8
9
let so_addr = Module.findBaseAddress("libil2cpp.so")


let jump_call = so_addr - 0 + 0x71ff68;
Interceptor.attach(new NativePointer(jump_call), {
	onEnter: function(args){
		console.log('uidm__jumap 被调用')
	},
})

这段代码,可以让jumap函数被调用后(jumap内部代码被执行之前),在终端/cmd执行我们1.js的onEnter指定的方法(这里是输出个提示),

先看看它的调用情况如何,比如是否会被调用,如果这个函数确实会被调用,分两种情况,

一个是点击一下跳跃按钮,这个函数就调用一次;另一情况是,输出次数(调用次数)和跳起次数一致,只有能跳起了才有输出。说白了就是,这个函数内部是否进行了"是否跳起"的判断。

ADB连接手机,开个终端进入adb打开frida-server,然后再来个终端切换到1.js所在目录,执行下图所示操作,首先是获取游戏pid,然后注入1.js,然后跳就完事了,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/0ccdf833ec01704c5c7a34e069a2d8033a58e6eb.png@942w_593h_progressive-20220206101630634.png

会发现只要按下了跳跃键,就会有输出,也就是说,大概率是在这个函数内部,或者是这个函数的内部调用的某个函数中,进行了能否跳起的判断,

但是我nop半天,也没找到,顶多是让连续按下两次跳跃后,人物则会在第一次跳起落地后开始第二次跳跃,这就比较麻烦了,

于是我准备换思路,开始查资料,看游戏开发者会如何实现跳跃,查了查,通常是通过addForce函数执行跳跃,确实也搜到了,但是经过测试,这些函数似乎并没有执行??

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/a14ea20199868d00a816963f2b57246079c419f2.png@512w_200h_progressive-20220206101636975.png

addForce是施加力,力是啥啊,初中物理早忘了,为了严谨我百度搜到了这一段:

牛顿第二定律揭示了力和运动的因果性,力是产生加速度的原因,加速度是力的作用效果,故力是改变物体运动状态的原因。

玩家能在地上走,还持续受到了重力的作用,不多扯了,只要知道,跳起的时候,速度越来越小,方向向上(是一个正数),到最高点,速度为0,然后速度方向向下(负号),速度的值越来越大,直到落地,

所以,jumap这个函数也不算白找,我们可以让这个函数被调用的时候,把自己的速度改了。

可以模糊搜索速度的地址,但是,我观察jumap的代码,

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/d060bb7ebbbf1a81575212818f6823e95e252ffb.png@942w_533h_progressive.png

然后就无意得到了人物y方向速度基址偏移,正数是方向向上,负数是方向向下,

CE这样表示:[[[libil2cpp.so + A8BDC8]+b8]]+58+14

那么,咱们这样写就行了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
let so_addr = Module.findBaseAddress("libil2cpp.so")

function vy(){
	let baseaddr = ptr(so_addr - 0 + 0xA8BDC8).readLong()
	let v2 = ptr( ptr(baseaddr + 0xb8).readLong() ).readLong()
	let vy = ptr(v2 + 0x58 + 0x14)

	vy.writeFloat(10);
}


let jump_call = so_addr - 0 + 0x71ff68;
Interceptor.attach(new NativePointer(jump_call), {
	onEnter: function(args){
		vy();
	},
})

就是说,只要按一下跳跃键,就把速度写入+10,那么接下来的一小段时间内,咱们会越飞越高,同时速度也在趋近于0,紧接着速度为0,达到最高点,然后速度逐渐向下增大,总之,和普通的跳跃的视觉效果是一样的。

至此为止,本文已经结束了。

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

这篇文章标题是思路,思路 已经搞完了,

但是还存在两个问题,首先是目前没有开关,也就是说,开启后,关不掉这个功能。获取“飞天”选择框的选中状态,我打算过两天再写,这篇文章截止到这里已经2700字了。

其次,如果关掉frida,或者没有电脑,咱这不就不能连跳了?这就涉及到frida持久化问题,看情况,应该也能放到下一篇文章。

感谢支持~,接下来我会发一个效果视频,包括[[[libil2cpp.so + A8BDC8]+b8]]+58的值在ce看起来的样子。如果本文使你有所收获,请帮忙给效果视频点个赞~~

https://i0.hdslb.com/bfs/article/02db465212d3c374a43c60fa2625cc1caeaab796.png

效果视频:

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/69b3d9b342cb7899419aa067f4bbbd0581a93f43.png

https://www.bilibili.com/video/BV1Xa41117He