我是一个非计算机相关专业的工科生.半年前,我构思了一种简单,安全的Dota全图新思路,经过一周的努力,把它写成了程序.应各位网友要求,在此开源,供学术交流.

游戏是一种封装体,开发者希望玩家看到的是游戏画面,音乐等等,希望得到的是玩家对游戏角色的操作命令.这就是这个封装体与玩家交互的Ouput和 Intput.然而程序的运行必然会借助硬件,游戏程序的运行,包括了各种数据接收,处理,运算,发送.游戏数据并不是全部传送的服务器运算然后传回,而是在本地完成大多数运算,运算过程肯定要在内存上完成.玩家看到的游戏画面,其实是各种游戏数据在空间上的有序展示.无论是1602液晶LCD显示器,还是计算机显示屏,都存在一个映射关系: f(memroy)=Display.当然,我没有什么游戏开发经历,这只是我的一些比较感性的想法.

所谓全图,就是知晓地图作战信息.以往常见的思路,是去除战争迷雾.我认为去除战争迷雾可能涉及到修改内存地址,容易被对战平台发现,所以没有采用这种思路.我的思路是读取内存地址.读出对方英雄的(x,y)坐标,经过坐标变换后,显示到小地图上.

问题一:如何通过读取内存获得游戏数据?因为程序运行必然借助硬件,它们之间存在数据交互,所以封装不可能是绝对完美的,只需用程序远程读取游戏程序所在的内存地址便可达到目的.

问题二:如何把读到的游戏数据显示在小地图上?这个很简单,测量算出数据(x,y)和屏显(X,Y)的变换关系,读到(x,y)坐标后,变换,用一个循环函数将屏显函数挂起,便可在屏幕上不断显示最新的坐标点.

问题三:如何获得英雄坐标对应内存地址?我把这个放在最后说是因为这个问题是最难的,最核心的.我花了7天写这个小程序,其中有4-5天是在解决这个问题.我有挺多思路,做了很多实验:

1.首先我采集了4组数据(用CE和War3trainer配合测地址数据),想看看在一把Dota中,10个英雄的X坐标之间有没有线性的关系.我把这 10个十六进制数排序,相减,发现间隔值有很多是一样的,但不规律.所以,它们之间没关系.我们无法通过测出一个X坐标地址,推算出其他.

2.基址+偏移量法.好像和我们C语言课老师讲的多级指针有关系,这种方法真是广为流传.其实我现在也不太会用CE测基址偏移量,不是不会用,是不太会用.所以我基本上也没算出坐标X地址的基址和偏移量,当然也不能怪我.

3.复查法.连搞了三天还没有一点进展,难免会用这种极端的手段,算是走了个弯路吧.所谓复查法,就是不断筛选,把War3游戏内存地址遍历一遍,存下符合条件的X#,完事再筛...故称复查法. 从10W筛到2W,就筛不下去了,放弃.

痛苦的实验了无数遍,我决定还得从基址+偏移量入手,因为我认为我的测量手法不对,所以测不出基、偏.所以我不停的实验,各种选英雄什么的.真是无数次实验...终于有一次,我偶尔-repick了一次,结果还真测出基址来了.于是我赶忙把实验步骤记录下来,照做了几遍,果然测出了基址(在CE中体现为绿色数字).但是,第二天睡醒了起来做,就再也做不出来了,即使按照步骤来.完全想不出为什么,只是继续不停的实验,不停的实验,做的多了,观察的多了,突然就发现了问题:那个基址,记录的是移动的单位的X#.关键词:移动.

得到内存分配关系如下:

AddY=AddX+0x4;         AddY是储存Y坐标值的变量所对应的内存地址;AddX同理. 这个关系是一个前辈测算出来的.

AddX=X#+0x78;       X#就是上一段话最后说的X#,一定要牢记.就是X#这个地址,正偏0x78个单位,便是AddX;我测的.

ReadProcessMemory(hProc,LPVOID(gameBase+reinterpret_cast<char*>(0xACE5B0)),&fx1,4,NULL);

上面这行代码,是整个程序的灵魂,也就是我实验了无数遍发现的游戏内存地址分配规则:

如果Game.dll的内存首注入点为gameBase,那么这个关键基址是gameBase+0xACE5B0.一般情况下,gameBase=0x6F000000,对战平台为了反作弊,改变了Game.dll的内存首注入点,使内存ZB器失效,除此之外,再无高明之策略,而这个关键基址0x6FACE5B0,它储存的值,是即时在移动的单位的X#值.据我粗略的观察,理论上,在 [t0,T]时间段内,ReadValue(6FACE5B0,t0)=X#,设这个单位坐标值(x,y),如果有dx/dt!=0或dy/dt!=0, 那么ReadValue(6FACE5B0,t)=X#.粗略感觉是这样的.实际上,ReadValue(6FACE5B0,t)的值瞬息万变,只要t-->无穷,那它涵盖了整个游戏中所有正在移动的单位的X值,所以我们只需定义一个数组,将符合条件的X#存起来,存够了数,便把他们转换,显示,就达到目的了.

我之前一直在说,符合条件的X#.实际上是说符合条件的(x,y)组合.那何为符合条件?我提几条:

1.浮点型数据类型

2.x,y∈(0,500)

3.(AddX,AddY)?{(AddX,AddY)|Had saved ever before}

第一条为啥就不说了.第二条,如果你好好做过实验,你会发现dota 地图是个面积500x500的图,这个500是个长度当量,不同的电脑,这个当量是一样的,就是500.而显示函数的 分辨率就随电脑分辨率而变,所以写显示函数的时候要刻意读系统注册表获得分辨率信息,这是后话了.第三条,意思就是已经有了的坐标地址,就不要再存了,避免重复而漏掉其他.

X#值瞬息万变,就要求有一个强力的判断函数,来过滤出合格的X#,存好.这个函数直接影响程序效率,这也是我开源的一个原因:想请大家来完善它.

虽然我说了,ReadValue(6FACE5B0,t)=X#, 但也不尽如此.6FACE5B0的确是一个很优秀的基址,但也是含有杂质的.有些杂质地址不可思议的通过了判断函数,被存了起来,很困扰.还有个问题是这个程序在别的电脑上可能运行不成功,有可能是权限问题..所以编译好的exe请用管理员身份运行.这个程序虽小,还不是一两句话能说清的,自己看代码吧. 打字累了.

我的联系方式是:dotaallmap@qq.com 欢迎来信讨论.

本来想按照这个思路开发LOL挂,没成功.缺乏工具,而且网游试验起来很卡,不灵活.

特别鸣谢: TC天驰,linger2012liu

TC天驰 很多人都认识他....大神,War3Trainer是他的作品..而且一直在更新,真是很好的实验工具.感谢!

linger2012liu 我的程序的思路起源于他,基本上是以他的程序为基础改的,...其实改动很多的..感谢!

程序C源代码:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <cstdlib>
#include <iostream>
#include <Tlhelp32.h>

void EnableDebugPriv();
void Getpid();
void Printcurrent();
int system(const char *string);
void Getaddress();
void Getgameinfo();
int Judgesize(float,float);
void Welcome();
double getscreenRX();
DWORD GetPIDForProcess(char* process);
DWORD GetDLLBase(char* DllName, DWORD tPid);

HANDLE hProc;
DWORD gameBase;
float x1;
float y1;
char* fx1;
char* addupx[6];
char* addupy[6];
HDC hdc;
HWND hwnd;
int info[2]={0,0};
double ScreenRate;
//-------------------------------------------------------------------------//

void main()
{
SetConsoleTitle("Dota For 1.24b");
Welcome();
EnableDebugPriv();
Getpid();
Getgameinfo();
Getaddress();
Printcurrent();
}

void Welcome()
{
printf("-----------------------------------------------------------------------------\n");
printf("\n  Dota all map program is running!\n");
printf("\n  Version 2.5 For Win7 & XP,War3-1.24b\n");
printf("\n\t\tProgrammed By LC\n");
Sleep(1500);
system("cls");
printf("-----------------------------------------------------------------------------\n");
}

void Getgameinfo()
{
  printf("What your Enemy is?\n");
  printf("Please Enter 9(TZ) or 1(JW).\n");
  scanf("%d",&info[0]);
  printf("\nHow Much Enemies you want to know?\n");
  printf("Please Enter 1-6.\n");
  scanf("%d",&info[1]);
  ScreenRate=getscreenRX();
}

void Getaddress()
{
int k=0,i=0;
char* nowaddx;
int iexist=0;int tt;
    printf("\nNow we get the gameinfo and start to collect addresses.\n");
info[1]--;
for(k=0;k<=0+info[1];)
{  
  int iexist=0;
  ReadProcessMemory(hProc,LPVOID(gameBase+reinterpret_cast<char*>(0xACE5B0)),&fx1,4,NULL);
  ReadProcessMemory(hProc,LPVOID(fx1+0x78),&x1,4,NULL);
        ReadProcessMemory(hProc,LPVOID(fx1+0x78+0x4),&y1,4,NULL);
  nowaddx=fx1+0x78;

if((int)fx1)
   {
  for(tt=0;tt<=i;tt++) if(addupx[tt]==nowaddx) iexist++;
  if(!(Judgesize(x1,y1)+iexist)) {addupx[i]=nowaddx;addupy[i]=nowaddx+0x4;i++;}
   }
  if(i>k) {k=i;printf("\nOne more:%x",fx1);}
}
printf("\nNow we get %d unit addresses!\n",k);
}

void Printcurrent()
{
  printf("\nWell Done!");
  printf("\nNow you can see your enemies on the map!");
  char ch[] = "@";
  float X1,Y1;
  while(1)
  {
   hdc = GetWindowDC(hwnd);
      SetTextColor(hdc,RGB(255,0,0));
      SetBkMode(hdc,NULL);
    if(addupx[0]!=0)
{  
  ReadProcessMemory(hProc,LPVOID(addupx[0]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[0]),&y1,8,NULL);
  X1=0.36*x1*ScreenRate+5;
        Y1=-0.36*y1+753;
        TextOut(hdc,X1,Y1,"1",strlen(ch));
}
if(addupx[1]!=0)

  ReadProcessMemory(hProc,LPVOID(addupx[1]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[1]),&y1,8,NULL);
     X1=0.36*x1*ScreenRate+5;
        Y1=-0.36*y1+753;
        TextOut(hdc,X1,Y1,"2",strlen(ch));
}
if(addupx[2]!=0)

  ReadProcessMemory(hProc,LPVOID(addupx[2]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[2]),&y1,8,NULL);
     X1=0.36*x1*ScreenRate+5;
        Y1=-0.36*y1+753;
        TextOut(hdc,X1,Y1,"3",strlen(ch));
}
if(addupx[3]!=0)

  ReadProcessMemory(hProc,LPVOID(addupx[3]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[3]),&y1,8,NULL);
     X1=0.36*x1*ScreenRate+5;
        Y1=-0.36*y1+753;
  TextOut(hdc,X1,Y1,"4",strlen(ch));
}
if(addupx[4]!=0)

  ReadProcessMemory(hProc,LPVOID(addupx[4]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[4]),&y1,8,NULL);  
     X1=0.36*x1*ScreenRate+5;
        Y1=-0.36*y1+753;
        TextOut(hdc,X1,Y1,"5",strlen(ch));
}
if((addupx[5]!=0)&&(info[1]!=0))

  ReadProcessMemory(hProc,LPVOID(addupx[5]),&x1,8,NULL);
        ReadProcessMemory(hProc,LPVOID(addupy[5]),&y1,8,NULL);
     X1=0.36*x1+5;
        Y1=-0.36*y1+753;
  TextOut(hdc,X1,Y1,"6",strlen(ch));
}
   UpdateWindow(hwnd);
   ReleaseDC(hwnd,hdc);
  }
}

int Judgesize(float nowx,float nowy)
{  
int Isfloat=((int)nowx!=nowx)&&((int)nowy!=nowy);
    int ifJW=((info[0]==1)&&((nowx+nowy)<=140)&&((nowx>20)&&(nowy>20)));
    int ifTZ=((info[0]==9)&&((nowx+nowy)>=830)&&((nowx<480)&&(nowy<480)));
if((ifJW||ifTZ)&&Isfloat) return 0;
else return 1;
}

double getscreenRX()
{
DWORD Value;
DWORD ValueHeight=0;
HKEY hkResult;
int ret=RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Blizzard Entertainment\\Warcraft III\\Video",0,KEY_ALL_ACCESS,&hkResult);
DWORD VDlong=sizeof(ValueWidth);
RegQueryValueEx(hkResult,"reswidth",0,NULL,(PBYTE)&ValueWidth,&VDlong);
RegQueryValueEx(hkResult,"resheight",0,NULL,(PBYTE)&ValueHeight,&VDlong);
if( (ValueWidth>=500)&&(ValueWidth<=3500)&&(ValueHeight>=500)&&(ValueHeight<=3500) ) return ( (1.0*ValueWidth/ValueHeight)/(1.0*1024/768) );
else return 1;
}
//-----------------------------------------------------------------------//
void Getpid()
{
   hwnd = FindWindowA(NULL,"Warcraft III");
   DWORD PID = 0;
   HWND hw = FindWindowA("Warcraft III", NULL);
   while(hw == NULL)
   {
          Sleep(500);  
          hw = FindWindowA("Warcraft III", NULL);
   }
      GetWindowThreadProcessId(hw,&PID);
      hProc = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
      gameBase = GetDLLBase("Game.dll", PID);
   if(!gameBase)
   {
    printf("\nWarning:Not Get Debug Privilege.");
    gameBase = 0x6F000000;
   }
   if(!hProc)
   {
    printf("\nNot Get hProc.");
   }
}

void EnableDebugPriv()
{
  HANDLE hToken;
  LUID sedebugnameValue;
  TOKEN_PRIVILEGES tkp;

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    CloseHandle(hToken);
  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
  {
    CloseHandle(hToken);
    system("PAUSE");
  }
  tkp.PrivilegeCount = 1;
  tkp.Privileges[0].Luid = sedebugnameValue;
  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
  CloseHandle( hToken );
}
DWORD GetDLLBase(char* DllName, DWORD tPid)
{
    HANDLE snapMod;
    MODULEENTRY32 me32;
    if (tPid == 0) return 0;
    snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, tPid);
    me32.dwSize = sizeof(MODULEENTRY32);
    if (Module32First(snapMod, &me32)){
        do{
            if (strcmp(DllName,me32.szModule) == 0){
                CloseHandle(snapMod);
    return (DWORD) me32.modBaseAddr;
            }
        }while(Module32Next(snapMod,&me32));
    }
    CloseHandle(snapMod);
    return 0;
}

转载于:https://blog.51cto.com/rozbo/1241356

[转载]只需要读内存实现的Dota全图相关推荐

  1. 使输入框(input   textarea)变为只可读状态readonly=readonly,禁用输入框disabled=disabled...

    使输入框变为只可读状态 readonly="readonly" <input class="select-city" placeholder=" ...

  2. 转载:Windows CE内存管理

    内存管理 如果你在写Windows CE 程序中遇到的最重要的问题,那一定是内存问题.一个WinCE 系统可能只有4MB 的RAM,这相对于个人电脑来说是十分少的,因为个人电脑的标准配置已经到了128 ...

  3. mysql 32位4g存储_基础 - 32位操作系统最多只支持4G内存。

    32位操作系统最多只支持4G内存. CPU能不能直接访问硬盘的数据呢, 不能. 只能通过把硬盘的数据先放到内存里, 然后再从内存里访问硬盘的数据.我们平时玩游戏碰上读图loading 进度条的这个过程 ...

  4. (转载)VC的内存泄漏检查

    原文链接:https://blog.csdn.net/psbeond/article/details/99546363 日期: 2016-12-20 参考:MSDN:ms-help://MS.MSDN ...

  5. 【Linux 内核 内存管理】优化内存屏障 ④ ( 处理器内存屏障 | 八种处理器内存屏障 | 通用内存屏障 | 写内存屏障 | 读内存屏障 | 数据依赖屏障 | 强制性内存屏障 |SMP内存屏障 )

    文章目录 一.处理器内存屏障 二.Linux 内核处理器内存屏障 一.处理器内存屏障 " 处理器内存屏障 " 针对 " CPU " 之间的内存访问乱序 和 CP ...

  6. Linux 设置windows可见的文件夹共享,创建只拥有读权限的共享用户,samba工具安装,“smbpasswd: command not found“问题解决

    linux 设置 windows 可见的共享文件夹 第一章:文件夹共享设置方法 ① 设置文件共享,只拥有读权限 ② windows 用户访问测试 ③ samba 服务安装,"smbpassw ...

  7. 双路服务器只显示一半内存,双路服务器只显示一半内存

    双路服务器只显示一半内存 内容精选 换一换 北京时间1月3日,Intel处理器芯片被曝出存在严重的Meltdown和Spectre安全漏洞,漏洞详情如下:漏洞名称:Intel处理器存在严重芯片级漏洞漏 ...

  8. win10服务器只显示4g内存,系统win10 64位 两个内存条一个4g一共8g显示8g但是可用只有3.9g...

    点击查看系统win10 64位 两个内存条一个4g一共8g显示8g但是可用只有3.9g具体信息 系统win10 64位 两个内存条一个4g一共8g显示8g但是... 答:在开始图标上右键,选择运行,输 ...

  9. 过TP C读内存 测试可过dxf 切换CR3

    过TP C读内存 测试可过dxf 切换CR3 在win10下可以读写dxf void KReadProcessMemory(IN PEPROCESS Process, IN PVOID Address ...

最新文章

  1. C# 编码规范和编程好习惯
  2. Git Permission to fazhiyun86/Test.git denied to MarRoar
  3. 【Python】Matplotlib切割图片
  4. Python进阶(十四) logging标准库
  5. 《计算机网络微课堂》一、计算机网络概述(你确定不点进来看看?)
  6. 可靠性试验(环境试验、机械试验、HALT试验等)
  7. 微信公众号消息推送教程
  8. 【kali技巧】kali更新系统
  9. 数电快速入门(三)(卡诺图化简法的介绍)
  10. Udacity 传感器融合笔记 (一)lidar
  11. Python处理二进制流(一)
  12. iText7添加页眉、页脚
  13. 2019全国大学生信息安全竞赛—Web
  14. DC/DC直流隔离升压电源模块5V12V24V转60V/100V/110V/150V/200V/250VDC
  15. Windows强行关闭任务管理器无法结束的程序
  16. 计算机视觉:图像映射与全景拼接
  17. RNN入门(三)利用LSTM生成旅游点评
  18. APIcloud的基本使用
  19. 【图像分类】2022-MPViT CVPR
  20. 计算机代码rsi是什么意思,自编RSI指标

热门文章

  1. 曙光“城市大数据平台”冲破数据孤岛、创造数据价值
  2. 7-21 统计大写辅音字母 (15 分)
  3. 【招聘】极限网络全国招聘,海量岗位职等你来
  4. Latex——属于符号
  5. cocos2dx创造精灵的五种方法
  6. 抖音评论怎么引流?商家如何利用抖音评论区
  7. [资源分享][Unity][人物模型][动作]一些人物模型以及动作的分享
  8. java excel导入校验_excel导入前校验
  9. Python 读取文件夹下的Excel文件导入到数据库
  10. 秋天,小溪潺潺,古老的树上黄叶灿灿,阳光像一个魔法师,在树叶间流动,远山,云天,充满秋阳的光线。以此景观做一首诗...