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

简介:

我是一个非计算机相关专业的工科生.半年前,我构思了一种简单,安全的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; 
}










本文转自 OH51888 51CTO博客,原文链接:http://blog.51cto.com/rozbo/1241356,如需转载请自行联系原作者
目录
相关文章
|
存储 缓存 固态存储
你还不懂硬盘,内存和CPU的关系 ?(程序员入门)
你好我是辰兮,很高兴你能来阅读,本篇文章小结了硬盘,内存和CPU的关系,献给初学者,分享获取新知,大家共同进步。
822 0
你还不懂硬盘,内存和CPU的关系 ?(程序员入门)
|
3月前
|
缓存 算法
内存系列学习(七):ARM处理器的快速上下文切换技术
内存系列学习(七):ARM处理器的快速上下文切换技术
45 0
|
3月前
|
存储 缓存 Linux
内存系列学习(三):ARM处理器地址变换过程
内存系列学习(三):ARM处理器地址变换过程
61 0
|
7月前
|
存储
数据在内存中的存储(超级无敌究极详细!)
数据在内存中的存储(超级无敌究极详细!)
|
7月前
|
算法 Linux Shell
我能在不同空间下操作寄存器,快学起来!
我能在不同空间下操作寄存器,快学起来!
|
芯片
主存储器与CPU的连接计算题详解
本篇文章主要讨论计算机组成原理中主存储器与CPU的连接中出现的计算题,希望能对正在学习计算机组成原理或即将学习本科目的同学有所帮助。
205 2
主存储器与CPU的连接计算题详解
|
SQL 缓存 监控
坏代码导致的性能问题大赏:CPU占用飙到了900%!
坏代码导致的性能问题大赏:CPU占用飙到了900%!
坏代码导致的性能问题大赏:CPU占用飙到了900%!
|
存储 编译器 程序员
CPU 执行程序的秘密,藏在了这 15 张图里
图灵机的工作方式;冯诺依曼模型;线路位宽与CPU位宽;程序执行的基本过程;a = 1 + 2执行具体过程
CPU 执行程序的秘密,藏在了这 15 张图里
|
并行计算 图形学 异构计算
CPU是什么?GPU是什么?有图有真相(2)
CPU是什么?GPU是什么?有图有真相(2)
118 0
CPU是什么?GPU是什么?有图有真相(2)
|
机器学习/深度学习 缓存 人工智能
CPU是什么?GPU是什么?有图有真相(3)
CPU是什么?GPU是什么?有图有真相(3)
162 0