开启左侧

手游作弊-内存读写源码(转小伍)

[复制链接]
发表于 2022-3-25 21:56:33 | 显示全部楼层 |阅读模式
本帖最后由 红提 于 2022-3-25 21:59 编辑

手游作弊-内存读写实例
关于手游作弊的博客我鸽的有点久了哈哈,这篇文章就和大家讲解下在内存中数据的存储格式,如何读取和修改

基础数据类型在内存中的存储空间
int - 4字节
float - 4字节
double - 8字节
long - 4字节或8字节
char - 1字节
short - 2字节

32位手游地址指针在内存占用4个字节,64位手游地址指针在内存中占用8个字节。
关于指针,我们在后面的文章会详细讲解。

在手游中,还有一个特殊的类型:XOR
XOR类型实际是int类型,这是游戏常用的防止玩家直接搜索到关键数值的一种加密方式(地址^值),其实也很简单

我们都知道,A ^ B = C,C ^ B = A,C ^ A = B
那么,加密后值^地址 = 实际值

上一期我们使用C语言的pread和pwrite函数来读取和修改内存,不过这样是很容易被游戏检测到的。
今天我们要说的方式是系统调用,使用syscall来调用SYS_process_vm_readv和SYS_process_vm_writev,这两个函数的参数和返回值可以在百度上直接找到,我就不详细说明了。

这里我直接贴上详细的代码,供大家参考:

AndroidMemDebug.h
————————————————
游客,如果您要查看本帖隐藏内容请回复

回复

使用道具 举报

 楼主| 发表于 2022-3-25 21:57:04 | 显示全部楼层
  1. int main(int argc, char **argv)
  2. {
  3. //获取ROOT
  4. getRoot(argv);
  5. //定义内存调试工具类
  6. MemoryDebug md;
  7. //设置调试应用包名(我这里调试的是QQ)
  8. md.setPackageName("com.tencent.mobileqq");
  9. //搜索内存,方式1,手动声明值类型
  10. md.search<float>(1234, FLOAT, Mem_Ca,true);
  11. //搜索内存,方式2,自动识别值类型
  12. md.search(1234, FLOAT, Mem_Ca,true);
  13. //搜索内存,不开启搜索结果打印
  14. md.search(1234, FLOAT, Mem_Ca);
  15. //搜索内存后修改第一个地址值
  16. AddressData ad = md.search(1234, FLOAT, Mem_Ca);
  17. md.edit<float>(8888.0,ad.addrs[0],FLOAT,true);
  18. return 0;
  19. }
复制代码
回复

使用道具 举报

 楼主| 发表于 2022-3-25 21:58:22 | 显示全部楼层


  1. int MemoryDebug::setPackageName(const char* name)
  2. {
  3.         int id = -1;
  4.         DIR *dir;
  5.         FILE *fp;
  6.         char filename[32];
  7.         char cmdline[256];
  8.         struct dirent *entry;
  9.         dir = opendir("/proc");
  10.         while ((entry = readdir(dir)) != NULL)
  11.         {
  12.                 id = atoi(entry->d_name);
  13.                 if (id != 0)
  14.                 {
  15.                         sprintf(filename, "/proc/%d/cmdline", id);
  16.                         fp = fopen(filename, "r");
  17.                         if (fp)
  18.                         {
  19.                                 fgets(cmdline, sizeof(cmdline), fp);
  20.                                 fclose(fp);
  21.                                 if (strcmp(name, cmdline) == 0)
  22.                                 {
  23.                                         pid = id;
  24.                                         return id;
  25.                                 }
  26.                         }
  27.                 }
  28.         }
  29.         closedir(dir);
  30.         return -1;
  31. }

  32. long MemoryDebug::getModuleBase(const char* name,int index)
  33. {
  34.         int i = 0;
  35.         long start = 0,end = 0;
  36.     char line[1024] = {0};
  37.     char fname[128];
  38.         sprintf(fname, "/proc/%d/maps", pid);
  39.     FILE *p = fopen(fname, "r");
  40.     if (p)
  41.     {
  42.         while (fgets(line, sizeof(line), p))
  43.         {
  44.             if (strstr(line, name) != NULL)
  45.             {
  46.                 i++;
  47.                 if(i==index){
  48.                     sscanf(line, "%lx-%lx", &start,&end);
  49.                     break;
  50.                 }
  51.             }
  52.         }
  53.         fclose(p);
  54.     }
  55.     return start;
  56. }

  57. long MemoryDebug::getBssModuleBase(const char *name)
  58. {
  59.         FILE *fp;
  60.         int cnt = 0;
  61.         long start;
  62.         char tmp[256];
  63.         fp = NULL;
  64.         char line[1024];
  65.         char fname[128];
  66.         sprintf(fname, "/proc/%d/maps", pid);
  67.         fp = fopen(fname, "r");
  68.         while (!feof(fp))
  69.         {
  70.                 fgets(tmp, 256, fp);
  71.                 if (cnt == 1)
  72.                 {
  73.                         if (strstr(tmp, "[anon:.bss]") != NULL)
  74.                         {
  75.                                 sscanf(tmp, "%lx-%*lx", &start);
  76.                                 break;
  77.                         }
  78.                         else
  79.                         {
  80.                                 cnt = 0;
  81.                         }
  82.                 }
  83.                 if (strstr(tmp, name) != NULL)
  84.                 {
  85.                         cnt = 1;
  86.                 }
  87.         }
  88.         return start;
  89. }

  90. size_t MemoryDebug::pwritev(long address, void *buffer, size_t size)
  91. {
  92.         struct iovec iov_WriteBuffer, iov_WriteOffset;
  93.         iov_WriteBuffer.iov_base = buffer;
  94.         iov_WriteBuffer.iov_len = size;
  95.         iov_WriteOffset.iov_base = (void *)address;
  96.         iov_WriteOffset.iov_len = size;
  97.         return syscall(SYS_process_vm_writev, pid, &iov_WriteBuffer, 1, &iov_WriteOffset, 1, 0);
  98. }


  99. size_t MemoryDebug::preadv(long address, void *buffer, size_t size)
  100. {
  101.         struct iovec iov_ReadBuffer, iov_ReadOffset;
  102.         iov_ReadBuffer.iov_base = buffer;
  103.         iov_ReadBuffer.iov_len = size;
  104.         iov_ReadOffset.iov_base = (void *)address;
  105.         iov_ReadOffset.iov_len = size;
  106.         return syscall(SYS_process_vm_readv, pid, &iov_ReadBuffer, 1, &iov_ReadOffset, 1, 0);
  107. }

  108. template < class T > AddressData MemoryDebug::search(T value, int type, int mem, bool debug)
  109. {
  110.         size_t size = judgSize(type);
  111.         MemPage *mp = NULL;
  112.         AddressData ad;
  113.         long * tmp, *ret = NULL;
  114.         int count = 0;
  115.         char filename[32];
  116.         char line[1024];
  117.         snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
  118.         FILE *fp = fopen(filename, "r");
  119.         if (fp != NULL)
  120.         {
  121.                 //临时存储搜索结果地址,空间大小可以存储1024000条地址,如果觉得不够可以自己加大
  122.                 tmp = (long*)calloc(1024000,sizeof(long));
  123.                 while (fgets(line, sizeof(line), fp))
  124.                 {
  125.                         mp = (MemPage *) calloc(1, sizeof(MemPage));
  126.                         sscanf(line, "%p-%p %s %*p %*p:%*p %*p   %[^\n]%s", &mp->start, &mp->end,
  127.                                    mp->flags, mp->name);
  128.                         // 判断内存范围和内存页是否可读(如果内存页不可读,此时如果去
  129.                         // 读取这个地址,系统便会抛出异常[信号11,分段错误]并终止调试进程)
  130.                         if ((memContrast(mp->name) == mem || mem == Mem_Auto)
  131.                                 && strstr(mp->flags, "r") != NULL)
  132.                         {
  133.                                 mp->buf = (void *)malloc(mp->end - mp->start);
  134.                                 preadv(mp->start, mp->buf, mp->end - mp->start);
  135.                                 // 遍历内存页中地址,判断地址值是否和想要的值相同
  136.                                 for (int i = 0; i < (mp->end - mp->start) / size; i++)
  137.                                 {
  138.                                         // 异或类型数值有点特殊,他是游戏防止破解者搜索到
  139.                                         // 正确数组的一种方式,其加密方式为:值 ^ 地址
  140.                                         if((type == XOR ? (*(int *) (mp->buf + i * size) ^ mp->start + i * size)
  141.                                                  : *(T *) (mp->buf + i * size)) == value)
  142.                                         {
  143.                                                 *(tmp + count) = mp->start + i * size;
  144.                                                 count++;
  145.                                                 if (debug)
  146.                                                 {
  147.                                                         std::cout
  148.                                                                 << "index:" << count
  149.                                                                 << "    value:" << (type == XOR?*(int *) (mp->buf + i * size) ^ (mp->start + i * size):*(T *) (mp->buf + i * size));
  150.                                                         printf("    address:%p\n", mp->start + i * size);
  151.                                                        
  152.                                                 }
  153.                                         }
  154.                                 }

  155.                                 free(mp->buf);
  156.                         }
  157.                 }
  158.                 fclose(fp);
  159.         }
  160.         if(debug)
  161.         printf("搜索结束,共%d条结果\n", count);
  162.         ret = (long*)calloc(count,sizeof(long));
  163.         memcpy(ret,tmp,count*(sizeof(long)));
  164.         free(tmp);
  165.         ad.addrs = ret;
  166.         ad.count = count;
  167.         free(ret);
  168.         return ad;
  169. }

  170. template < class T > int MemoryDebug::edit(T value,long address,int type,bool debug)
  171. {
  172.         if(-1 == pwritev(address,&value,judgSize(type)))
  173.         {
  174.                 if(debug)
  175.                 printf("修改失败-> addr:%p\n",address);
  176.                 return -1;
  177.         }else
  178.         {
  179.                 if(debug)
  180.                 printf("修改成功-> addr:%p\n",address);
  181.                 return 1;
  182.         }
  183.         return -1;
  184. }

  185. long MemoryDebug::ReadDword64(long address)
  186. {
  187.         long local_ptr = 0;
  188.         preadv(address, &local_ptr, 4);
  189.         return local_ptr;
  190. }

  191. int MemoryDebug::ReadDword(long address)
  192. {
  193.         int local_value = 0;
  194.         preadv(address, &local_value, 4);
  195.         return local_value;
  196. }

  197. float MemoryDebug::ReadFloat(long address)
  198. {
  199.         float local_value = 0;
  200.         preadv(address, &local_value, 4);
  201.         return local_value;
  202. }

  203. long MemoryDebug::ReadLong(long address)
  204. {
  205.         long local_value = 0;
  206.         preadv(address, &local_value, 8);
  207.         return local_value;
  208. }

  209. void getRoot(char **argv)
  210. {
  211.         char shellml[64];
  212.         sprintf(shellml, "su -c %s", *argv);
  213.         if (getuid() != 0)
  214.         {
  215.                 system(shellml);
  216.                 exit(1);
  217.         }
  218. }
复制代码
回复

使用道具 举报

发表于 2022-5-21 16:11:50 | 显示全部楼层
学习学习学习学习学习
回复

使用道具 举报

发表于 2022-6-2 11:55:01 | 显示全部楼层
66666666666666666 ,这个对于我来说还是有难度。
回复

使用道具 举报

发表于 2022-6-17 10:00:22 | 显示全部楼层
学习一下
回复

使用道具 举报

发表于 2022-8-27 14:45:08 | 显示全部楼层
这是游戏常用的防止玩家直接搜索到幸运飞艇直播澳洲幸运20走势图福彩双色球结果关键数值的一种加密方式(地址^值),其实也很简单
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表