游戏作弊-内存读写原理

第一课我们浅解安卓ROOT手机如何修改游戏内存

在当前流行的FPS,MOBA游戏中,我们几乎都能看到游戏外挂的身影,在FPS游戏中,可见变态功能层出不穷,例如加速,锁血 遁地,飞天,路飞,无后座,范围伤害等…,然而在MOBA游戏中,最常见的只有透视和自瞄。

切入正题,如何操作内存?在安卓中,我们可直接操作/proc/${pid}/mem

使用C语言pread函数

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

简单解释下这个函数

fd:要读取数据的文件描述符
buf:数据缓存区指针,存放读取出来的数据
count:读取数据的字节数
offset:读取的起始地址的偏移量,读取地址=文件开始+offset。注意,执行后,文件偏移指针不变

还有另一个函数:pread64
很多人不知道pread64和pread的区别,其实pread64是用64位定位方式,用于对大文件的支持,与pread不同的是,pread64的偏移量参数为off64_t,而不是off_t

读写游戏内存最重要的是获取游戏进程的PID,什么是PID?PID就是各进程的身份标识,程序一运行系统就会自动分配给进程一个独一无二的PID。进程中止后PID被系统回收,可能会被继续分配给新运行的程序,但是在android系统中一般不会把已经kill掉的进程ID重新分配给新的进程,新产生进程的进程号,一般比产生之前所有的进程号都要大。

那么问题来了,如何获取游戏pid?

第一种方式:
遍历/proc/${pid}/cmdline
cmdline文件储存的是当前进程的启动名(包名)

直接贴代码:

pid_t GetProcessID(const char *process_name)
{
	int id;
	pid_t pid = -1;
	DIR *dir;
	FILE *fp;
	char filename[32];
	char cmdline[256];
	struct dirent *entry;
	if (process_name == NULL)
	{
		return -1;
	}
	dir = opendir("/proc");
	if (dir == NULL)
	{
		return -1;
	}
	while ((entry = readdir(dir)) != NULL)
	{
		id = atoi(entry->d_name);
		if (id != 0)
		{
			sprintf(filename, "/proc/%d/cmdline", id);
			fp = fopen(filename, "r");
			if (fp)
			{
				fgets(cmdline, sizeof(cmdline), fp);
				fclose(fp);
				if (strcmp(process_name, cmdline) == 0)
				{
					pid = id;
					break;
				}
			}
		}
	}
	closedir(dir);
	return pid;
}

第二种方式:使用shell命令的pidof

char *shell(const char *command)
{
	FILE *fp = NULL;
	char line[256] = { };
	char *result = (char *)malloc(2048);
	memset(result, 0, sizeof(result));
	fp = popen(command, "r");
	while (fgets(line, sizeof(line), fp) != NULL)
	{
		strncat(result, line, strlen(line));
	}
	pclose(fp);
	return result;
}

pid_t GetProcessID(char *process_name)
{
    char cmd[256] = {0};
    sprintf(cmd,"su -c pidof %s",process_name);
	char *id = shell(cmd);
	return strlen(id) == 0 ? -1 : atoi(id);
}

如何读内存:

char filename[256] = {0};
sprintf(filename,"/proc/%d/mem",pid);//pid为获取到的游戏pid
int fd = open(filename,O_RDWR | O_SYNC);//以可读写(O_RDWR)且同步(O_SYNC)的方式打开文件
int buf = 0;
pread(fd,&buf,sizeof(buf),内存地址);
printf("value:%d\n",buf);

学会了读取内存,那如何写入内存呢?
这时候需要用到另一个函数:pwrite
pwrite的参数和pread一样,我就不讲解了

char filename[256] = {0};
sprintf(filename,"/proc/%d/mem",pid);//pid为获取到的游戏pid
int fd = open(filename,O_RDWR | O_SYNC);//以可读写(O_RDWR)且同步(O_SYNC)的方式打开文件
int wbuf = 666;
pwrite(fd,&wbuf,sizeof(wbuf),内存地址);//向指定地址写入指定值(修改地址的值)

根据上两段代码,我们可以发现一个知识点:内存地址

这个内存地址如何获取?
在proc文件系统中,有一个内存段映射文件:/proc/${pid}/maps
打开这个文件,我们可以得到以下结构:

f1ed1000-f1ed9000 r--p 00000000 fc:02 3092        /system/lib/libsensor.so
f1ed9000-f1edf000 r-xp 00008000 fc:02 3092        /system/lib/libsensor.so
f1edf000-f1ee0000 rw-p 0000e000 fc:02 3092        /system/lib/libsensor.so
f1ee0000-f1ee2000 r--p 0000f000 fc:02 3092        /system/lib/libsensor.so
f1ee2000-f1ee3000 rw-p 00000000 00:00 0           [anon:.bss]

关于maps文件各列解释,可以参考
https://blog.csdn.net/lijzheng/article/details/23618365

可以看出,第一列既为我们需要的游戏内存地址。
现在问题来了,像gg修改器,我们如何在内存里搜索一个值呢?

这时候又涉及一个知识点:值所在的内存范围

为了方便,我们可以使用GG修改器的内存范围

struct Memory
{
	int A = 32;
	int As = 524288;
	int B = 131072;
	int Xa = 16384;
	int Xs = 32768;
	int Ca = 4;
	int Cb = 16;
	int Cd = 8;
	int Ch = 1;
	int J = 65536;
	int Jh = 2;
	int O = -2080896;
	int Ps = 262144;
	int S = 64;
	int V = 1048576;
} MemRange;


int getMemRange(char *str)
{
	if (strlen(str) == 0)
		return MemRange.A;
	if (strstr(str, "/dev/ashmem/") != NULL)
		return MemRange.As;
	if (strstr(str, "/system/fonts/") != NULL)
		return MemRange.B;
	if (strstr(str, "/data/app/") != NULL)
		return MemRange.Xa;
	if (strstr(str, "/system/framework/") != NULL)
		return MemRange.Xs;
	if (strcmp(str, "[anon:libc_malloc]") == 0)
		return MemRange.Ca;
	if (strstr(str, ":bss") != NULL)
		return MemRange.Cb;
	if (strstr(str, "/data/data/") != NULL)
		return MemRange.Cd;
	if (strstr(str, "[anon:dalvik") != NULL)
		return MemRange.J;
	if (strcmp(str, "[stack]") == 0)
		return MemRange.S;
	if (strcmp(str, "/dev/kgsl-3d0") == 0)
		return MemRange.V;
	return MemRange.O;
}

如何搜索值:
通过遍历内存段映射地址,判断值是否为搜索的值
例如f1ed1000-f1ed9000,我们需要遍历f1ed1000到f1ed9000的所有地址的值来判断

直接上代码:

long start = 0xf1ed1000;
long end = 0xf1ed9000;
int value = 1;//我们要搜索的值
char filename[256] = {0};
sprintf(filename,"/proc/%d/mem",pid);
int fd = open(filename,O_RDWR | O_SYNC);
long size = end - start;
int count = 0;//计数
void *buf = calloc(1, size);
pread64(fd,buf,size,start);
int block_size = sizeof(int);
for(int i = 0;i<size;i+=block_size)
{
	int search_value = *(int*)(buf + i);
    if(search_value == value)
    {
        //搜索到数值
        printf("index:%d address:%lx value:%d\n",i,start + i,search_value);
        count++;
    }
}
printf("搜索到:%d个数值\n",count);

现在搜索数值会了,修改数值不就迎刃而解了吗?

今天的教程结束,有不懂的可以私信问我。手打代码不易,看完加个关注,持续更新游戏作弊教程

### 回答1: 易语言是一种针对Windows操作系统开发的高级编程语言,“csgo”代表“Counter-Strike: Global Offensive”,一款热门的多人在线射击游戏。在这个问题中,需要回答如何使用易语言编写一个读写“csgo”游戏内存的驱动。 要编写一个读写“csgo”游戏内存的驱动,首先需要理解内存的基本概念和原理内存是计算机用于存储数据和程序的地方,可以通过特定的地址读写数据。游戏内存中存储了各种游戏状态、变量和对象的信息,我们可以通过读取和修改这些数据来实现对游戏的控制和修改。 在易语言中,可以使用WinAPI函数来访问和操作内存。具体来说,可以使用以下函数来实现对“csgo”游戏内存读写操作: 1. 打开进程函数:使用WinAPI函数OpenProcess打开“csgo”进程,获取进程句柄。 2. 读取内存函数:使用WinAPI函数ReadProcessMemory从进程的地址中读取数据到本地变量中。 3. 写入内存函数:使用WinAPI函数WriteProcessMemory将本地变量中的数据写入到进程的地址中。 读取和写入内存时,需要确保使用正确的进程句柄和地址。可以通过一些基本的偏移量或者扫描特定的数据来找到“csgo”中需要修改的变量的地址。 需要注意的是,读写“csgo”游戏内存的驱动可能涉及到游戏的防作弊和反作弊机制,因此在编写和使用该驱动时需要小心操作,尊重游戏的规定和其它玩家的权益,遵守游戏开发者的规范。 总之,通过在易语言中使用相应的WinAPI函数,我们可以编写一个能够读写“csgo”游戏内存的驱动,实现对游戏状态和变量的控制和修改。但在使用驱动的过程中需要注意合法性和遵守游戏规定。 ### 回答2: 易语言是一种基于Windows系统编程语言,它具有简单易学、易于上手的特点。借助易语言,我们可以编写读写内存的驱动程序来实现与CSGO游戏进行交互。 首先,需要了解CSGO游戏内存结构以及我们想要读写的特定内存地址。我们可以通过一些工具(如Cheat Engine)来获取这些地址。 然后,在易语言中,我们可以使用kernal32.dll库文件来实现读写内存的功能。通过使用kernal32.dll中的ReadProcessMemory和WriteProcessMemory函数,我们可以在安装驱动程序的PC进程中读取和写入内存。 具体步骤如下: 1. 使用易语言创建一个新的项目,选择Windows驱动程序类型。 2. 在项目中导入kernal32.dll库文件。 3. 使用kernal32.dll中的OpenProcess函数来打开CSGO游戏进程,获取进程句柄。 4. 使用VirtualProtectEx函数来修改进程的内存保护属性,确保内存可以被读写。 5. 使用ReadProcessMemory函数来读取我们想要获取的内存地址的值。可以将这些值存储在易语言变量中,以供后续使用。 6. 使用WriteProcessMemory函数来写入特定的内存地址。可以将需要写入的值存储在易语言变量中,然后传递给该函数。 7. 最后,关闭进程句柄以释放资源,并退出驱动程序。 需要注意的是,编写读写内存驱动程序需要深入了解Windows操作系统的工作原理内存结构,同时也需要对C语言有一定的了解,以便理解和使用kernal32.dll中的函数。此外,为了避免违反游戏规则或者法律法规,对于游戏内存读写操作应该遵循道德准则和法律法规。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'小五'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值