做教学视频又耗时又累,白嫖率(收藏和点赞的比例)偏高(如下图所示),并且本人录制和剪辑效率低,蚌埠住了,
如果直接摆烂宣布放弃,会愧对于 点过赞、投过币、充过电的朋友,所以停更是不可能的,本系列教程剩下的部分做成图文版,这样也能提高你的浏览效率;大约每2000字~3000字发布一次。
前面的教程1~9在视频的开头都有一个目录,那个目录就是个大致方向,从这期开始不展示目录了,本系列教程写完之后会有一篇文章专门用于导航。
有问题直接在文章底部评论,我懂的问题会回复,同时也欢迎在本文评论区纠错。
本系列教程【新手向】(本人在此方面也算初学者),大佬勿喷。
这里以坦克英雄激光战争为例(因为它是纯粹的单机游戏,并且多年未更新;后文简称"T游戏"),纯路人不必担心本文破坏游戏体验(相反,逆向工程会维护游戏环境、提升你的游戏体验),本文与各种联网游戏完全无关,本文内容仅供学习IDA基本操作,提高编程开发以及逆向工程的学习兴趣,以及为将来的维护游戏安全、反外挂工作提供思路、“埋下种子”。
准备好IDA,本系列教程不需要懂汇编,跟着我无脑F5看伪代码,会看LR寄存器就够了。
首先要知道,通常游戏逆向领域所谓的找数组,数组是最常见的用于存储敌人信息的结构,这个数组当中的每个元素都对应着一个敌人的结构体,数组里的元素可能是这个结构体的地址(大部分游戏是这样的),也可能直接就是某个结构体(某个结构体类型的数组,T游戏是这种)。
这里随便举个例子吧(虽然意义不大):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
#include <stdio.h>
struct Role{
int hp; //血量
float x;
float y;
float z;
//...实际上,属性会多的很,并且可能有指向另一个结构体(比如武器)的指针,这里省略...
};
#define ROLE_MAX_COUNT 20
struct GameData1{
int roleCount; //敌人实际数量
struct Role* roles[ROLE_MAX_COUNT]; //敌人数组
//...省略
} gd1;
struct GameData2{
int roleCount; //敌人实际数量
struct Role roles[ROLE_MAX_COUNT]; //敌人数组
//...省略
} gd2;
int main(void){
gd1.roleCount = 3;
struct Role r1, r2, r3;
r1.hp = 100;
r1.x = 1;
r1.y = 2;
r1.z = 3;
r2.hp = 90;
r2.x = 10;
r2.y = 2;
r2.z = 30;
r3.hp = 95;
r3.x = 30;
r3.y = 2;
r3.z = 20;
gd1.roles[0] = &r1;
gd1.roles[1] = &r2;
gd1.roles[2] = &r3;
gd2.roleCount = 3;
gd2.roles[0].hp = 100;
gd2.roles[0].x = 1;
gd2.roles[0].y = 2;
gd2.roles[0].z = 3;
gd2.roles[1].hp = 90;
gd2.roles[1].x = 10;
gd2.roles[1].y = 2;
gd2.roles[1].z = 30;
gd2.roles[2].hp = 95;
gd2.roles[2].x = 30;
gd2.roles[2].y = 2;
gd2.roles[2].z = 20;
getchar();
return 0;
}
|
代码中gd1和gd2就是两种不同的敌人数组的形式,
用NDK编译,推到手机运行,ce+ceserver附加(我前面视频教程演示过,本文省略),添加地址两次,分别直接写gd1和gd2:
情况一
情况二
GG视角:
情况一(GG视角)
情况二(GG视角)
拿捏了敌人数组,就可以获取全部敌人的各种属性了,比如坐标和血量。
蚌埠住了,时间太晚了,天亮继续更新