目录
前言:
本篇文章需要借助一个软件的帮助,这个软件就是CE(cheat engine),Cheat Engine是一款强大的内存修改工具,支持多种变量的搜索和修改,被广泛用来进行外挂开发,支持内存反汇编和修改功能,能够查看指定区域汇编代码并进行修改和插入自己的代码。
下载地址:https://www.jb51.net/game/18931.html#downintro2
因为如果去官网下载,win11会禁止安装。
注意:C语言程序是从上往下依次执行的,所以你在最底下定义一个全局变量,上边无法使用是很正常的。
一、什么是变量?
1、声明变量
变量类型 变量名;
变量类型 用来说明宽度是多大
int 4个字节
short 2个字节
char 1个字节 等等...
变量的命名规则:
1、只能以字母、数字、下划线组成,且第一个字母必须是字母或下划线
2、区别大小写
3、不能使用C语言的关键字
举个例子:
int就是变量类型,x就是变量名
int x就是说x这个变量占用的字节数是4个字节。
上面这个操作就叫做声明变量。
2、变量的本质
变量的本质是什么,我们可能看不出来,这里我们可以给变量赋一个值,那么就可以看到变量的本质是什么东西了。
赋值--设置断点--转到反汇编
结果:
我们可以看到x=1122就是往一个地址里存入数字1122,所以x就是这个地址的别名而已,所以说变量就是一块内存地址的别名 ,另外从dword我们可以知道这是一个占用4字节大小的内存。
二、全局变量
1、什么是全局变量?
定义在所有函数的外边,不在函数里边定义的变量就是全局变量。
2、全局变量的特点?
1) 编译的时候就已经确定了内存地址和宽度,变量名就是内存地址的别名
2)如果不重新编译,全局变量的内存地址不变。游戏外挂中的找"基址",其实就是找全局变量。
3)全局变量中的值从定义全局变量的地方开始往下任何的函数都可以对他进行更改。
第一条不用验证了,上面就是。
验证第二点,我们先定义一个全局变量并赋值,注意:
我们先定义一个全局变量然后F7进行编译:
设置断点,然后第一次F5执行,转到反汇编查看全局变量的地址:
终止程序,等待几秒,F5进行第二次执行(不要动其他东西):
第二次执行结果如下:
重新生成exe
运行结果如下:
验证成功。
验证第三点:
源码如下,看不懂的地方不用管
#include <stdio.h> // printf输出语句的头文件
int x; // 全局变量
int test01() // 函数1
{
x=123; // 为x赋值为123
printf("test01:x=%d\n",x); // 输出x的值
return 0; // 返回
}
int test02()
{
x=x+1;
printf("test02:x=%d\n",x); // 输出x的值
return 0;
}
int main()
{
test01(); // 调用函数1
test02(); // 调用函数2
x=1122; // 赋值
printf("main:x=%d\n",x); // 输出x
getchar(); // 卡死当前进程,以免一运行直接关闭了
return 0;
}
运行结果如下:
可以看到,每一个函数对他进行的修改都会成功,这就是全局变量。
三、修改数值外挂原理解析
先将这个,因为涉及到CE软件的使用。
代码如下,看不懂没关系:
#include <stdio.h> // printf函数的头文件
#include <windows.h> // Sleep函数的头文件
int x; // 全局变量
int main() // 主函数,函数的入口
{
x=1000; // 为变量赋值
while(1) // 死循环执行代码,每隔三秒在控制台输出一下x的值
{
Sleep(3000); // 延时3秒
printf("生命值:%d\n",x); // 打印x的值
}
return 0; // 函数结束
}
F7编译F5运行看看效果。
找到自己项目目录下debug文件夹中的.exe文件
编译的时候会显示路径
双击exe文件,使其保持运行的状态。
然后打开CE软件添加当前的exe:
查询值为1000的int类型(4字节内容)
点击首次扫描,如下:
我们关掉exe文件,再重新打开,看看全局变量的值是否改变了,按照上面的步骤来:
修改生命值:
查看一下程序中的值
这就做到了修改生命值
游戏中的某些数值,他就是全局变量,你如果找到了他的地址那么你就可以为所欲为,因为全局变量她如果不重新编译是不会改变的,地址就是唯一的,哪怕你下一次启动它,他还是那个地址,但是并不是所有的数值都是全局变量。
我们就是全局变量地址不变的这一点,就可以通过CE进行修改数值,这就是所谓的外挂。
四、局部变量
1、什么是局部变量?
局部变量就是在函数里面定义的变量,或者是在某些块作用域里定义的变量,它本身是属于定义它的那个函数的东西,所以其他函数修改它不会成功也是情有可原。
2、局部变量的特性
1) 局部变量时函数内部申请的,如果函数没有执行,那么局部变量就没有内存空间。
2)局部变量的内存是在堆栈中分配的,程序执行时才分配,我们无法预知程序何时执行,这也就意味着,我们无法确定局部变量的内存地址。
3)因为局部变量地址内存是不确定的,所以,局部变量只能在函数内部使用,其他函数不能使用。
验证第一点:
代码如下:
#include <stdio.h> // printf函数的头文件
#include <windows.h> // Sleep函数的头文件
int test01()
{
int x; // 函数里定义的变量叫局部变量
x=33445566; // 赋值
return 0;
}
int main() // 主函数,函数的入口
{
while(1); // 卡住程序,防止程序退出CE无法正常进行
return 0; // 函数结束
}
我们在test1中定义的局部变量,但是我们主函数中并没有使用到它
使用ce查找值为33445566的变量,结果如下:
扫描不到,观点1正确(x的值不能那么简单,因为程序编译的时候也会有一些值的定义)
验证第二点:
代码如下:
#include <stdio.h> // printf函数的头文件
#include <windows.h> // Sleep函数的头文件
int test01()
{
int x; // 局部变量
x=33445566; // 赋值
while(1); // 卡住进程
return 0;
}
int main() // 主函数,函数的入口
{
test01(); // 使用"x"局部变量
return 0;
}
第一次运行,查看值为33445566的变量的地址:
第二次执行,查看值为33445566的变量的地址:
两次的地址不一样,这就是他与全局变量的区别,我们之前看到的绿色的全局变量,程序编译之后,运行两次变量的地址都没有变,但是局部变量运行两次地址是不一样的。
验证第三点:
如下:
第三点验证完毕。
总结
外挂中提到的所谓基址,其实就是全局变量,变量是什么?变量就是一块地址的别名。全局变量全局可见,从被定义往下所有的地方都可以对它进行操作,局部变量只能在定义它的函数内使用,其他地方不可见。
最后,感谢大家观看!望以后一起进步!