游戏作弊

编程入门 行业动态 更新时间:2024-10-05 19:16:39

<a href=https://www.elefans.com/category/jswz/34/1770081.html style=游戏作弊"/>

游戏作弊

第一课我们浅解安卓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文件各列解释,可以参考

可以看出,第一列既为我们需要的游戏内存地址。
现在问题来了,像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);

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

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

更多推荐

游戏作弊

本文发布于:2024-02-28 11:09:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1769172.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:游戏

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!