Dota全图那些事儿

Dota全图那些事儿

      很早就着手研究全图了,也准备很多相关知识。由于自己编程基础比较差,恶补了不少知识,主要是硬生生的啃了大半本的《windows核心编程》。看这本书的过程中,有很多不懂得,但我适当跳过了(其实这是对的,因为有些知识前后联系了才懂,特别是对我这种菜鸟来说)。看了大半本,收获还是挺大的,对windows这个操作系统有了更深的认识,当然我还会继续把它读完,并且要重读,感觉写的太好了,暂时我是打算这么做的,除非出了意外。这个意外就是,听说windows 8出来后,微软有个叫win RT的东西要用来取代win api,到时若真如此而导致win api成为废物。哎,别谈这个了。到下一步吧。

      其实dota全图是这种挂是属于修改内存型的。简单分析一下需求和可行性吧,熟悉魔兽争霸的玩家都知道,在创建游戏的时候有一个高级选项,如果把“可见度”改为“总是可见的”,那么玩的时候,什么都可以看到了,就是开全图了。一般玩rpg的玩家都会开全图,顺便说一下,其实dota全图挂说法不正确,说魔兽争霸全图挂才对。玩dota,我们一般创建游戏时一般不会选择全图,因为会影响游戏的可玩性(dota中的gank很重要)。但是某些游戏玩家比较卑鄙的(想不到其他词形容),就想破坏这个规则,就想“如果其他人不是全图可见,而我是的话,那么我的优势就大了”。于是全图挂产生了。根据前面提到的,我们既然可以通过高级选项来开全图,那么说明游戏进程中一定是有个变量或多个变量来控制这种功能的。很明显,这些变量一定在游戏进程的内存空间中,如果我们通过某些手段改变了这些变量的话,那么自己的电脑就是全图的了。

      而怎么知道这些变量的内存地址呢?有个很犀利的工具,叫CE。用它就可以跟踪变量内存地址了。而怎么搜?这也是很讲技巧的,过程也是很枯燥的。不过,在我自己为魔兽争霸1.24b版本之前,已经有人做过了,他们把地址给搜出来共享了,网上可以查到(搜“魔兽1.24B内存地址一览表”)。在魔兽争霸中一个叫“Game.dll”文件,这些变量的地址其实变量在Game.dll的地址。通过CE可以直接在Game.dll修改,稍微懂电脑的人就可以 学会怎么修改,这里不提。修改后就可以作弊了。读者是否会觉得奇怪,这不是没有编程么?对,的确,这是作弊的一种手段,不可否认,CE很强大的。

      接下来介绍另一种作弊的手段,用C++编程。主要是利用windows api中的WriteProcessMemory来修改内存数据。在使用该函数修改内存之前,需要做一些事情,主要是两件:一是提高本程序的权限为debug权限,而是把Game.dll的基址找出来。解释一下,为什么要提高本程序的权限为debug权限呢?这个怎么说呢?很明显吧,一个程序的权限越大,干“坏事”的能力就越强大,如果不提高本程序的权限为debug权限,有些事是干不了的,即有些函数使用会失败。那么为什么要找出Game.dll的基址呢?上文已经提到,网上公布的变量的地址其实变量在Game.dll的地址,而不是在进程的地址。所以要把Game.dll的基址找出来。变量在Game.dll的地址+Game.dll的基址=变量在进程中的地址。大概就这门多,接下来是对我的源码分析:

 

#include <cstdlib>

#include <iostream>

#include <windows.h>

#include <Tlhelp32.h>

using namespace std;

//首先是函数声明,看一下各函数的作用吧

#define PATCH(i,w,l) WriteProcessMemory(hProc,reinterpret_cast<LPVOID>(gameBase+i),w,l,&dSize)

//定义一个宏,为何简化写

void patchW3X();//主要函数

void patchwar24b(HANDLE hProc, DWORD gameBase, DWORD dSize);

//对各内存的修改,其实就是一序列PATCH()的集合

DWORD GetPIDForProcess(char* process);

//得到某进程的进程ID

void EnableDebugPriv();

//提高权限为debug

DWORD GetDLLBase(char* DllName, DWORD tPid);

//得到指定动态链接库的基址

int main(int argc, char *argv[])

{

    SetConsoleTitle("1.24");

    patchW3X();

    system("PAUSE");

   

    return EXIT_SUCCESS;

}

//-------------------------------------------------------------------------------------------------------------

void patchW3X()

{

     DWORD PID = 0;

 

 

   puts("正在检验Warcraft 3是否已启动");

   HWND hw = FindWindowA("Warcraft III", NULL);

   while(hw == NULL)

   {

          Sleep(500);   

          hw = FindWindowA("Warcraft III", NULL);                    

   }

      puts("搜索进程id");

 

  LPDWORD lp = NULL;

  lp = &PID;

  GetWindowThreadProcessId(hw,lp);

 

//用上面那句话或者下面注释的句子都可以得到war.exe进程id

  //  GetWindowThreadProcessId

  // if(GetPIDForProcess("War3.exe") != 0)

    //   PID = GetPIDForProcess("War3.exe");

      

    //  puts("提高dubug权限");

     

   EnableDebugPriv();

  

   puts("打开进程");

 

 HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, PID);

      if(hProc)

   {

          puts("寻找Game.dll基址");

    DWORD gameBase = GetDLLBase("Game.dll", PID);

    DWORD dSize = 0;

    puts("开始修改内存");

    patchwar24b(hProc, gameBase, dSize);

      }

      else

      {

        puts("打开进程失败");

        DWORD er = GetLastError();

        printf("错误代号%d",er);  

      }

}

//-------------------------------------------------------------------------------------------------------------

void patchwar24b(HANDLE hProc, DWORD gameBase, DWORD dSize)

{

 

 

 

 //(74D103," C6 , 04 , 3E , 01 , 90 , 46");去除战争迷雾

 PATCH(0X74D103,"\xC6\x04\x3E\x01\x90\x46",6);

 

 PATCH(0x3A201D,"\xEB",1);

//(3A201D, " EB");大地图显示单位

//因为该程序不是为了真的作弊,所以没修改其他的内存数据

 

  puts("完成!");

}

//-------------------------------------------------------------------------------------------------------------

//GetWindowThreadProcessId(hw,lp);该函数的作用是lp获得创建hw窗口的进程id,返回值为创建hw窗口的线程id

//由于恰好 窗口Warcraft III是war.exe创建的,所以用GetWindowThreadProcessId代替以下函数

DWORD GetPIDForProcess(char* process)

{

    BOOL            working=0;

    PROCESSENTRY32 lppe= {0};

 DWORD            targetPid=0;

    HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS ,0);

    if (hSnapshot)

    {

        lppe.dwSize=sizeof(lppe);

        working=Process32First(hSnapshot,&lppe);

        while (working)

        {

   if(strcmp(lppe.szExeFile,process)==0)

            {

                targetPid=lppe.th32ProcessID;

                break;

            }

            working=Process32Next(hSnapshot,&lppe);

        }

    }

    CloseHandle( hSnapshot );

    return targetPid;

}

//-------------------------------------------------------------------------------------------------------------

// enable the privilege necessary to patch the process

void EnableDebugPriv()//待理解

{

     puts("提高dubug权限");

  HANDLE hToken;

  LUID sedebugnameValue;

  TOKEN_PRIVILEGES tkp;

  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

  puts("获取进程访问令牌失败!");

   DWORD er = GetLastError();

        printf("错误代号%d",er);

  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))

  {

    CloseHandle(hToken);

    puts("提高debug权限失败!");

    system("PAUSE");

  }

    er = GetLastError();

        printf("错误代号%d",er);

  tkp.PrivilegeCount = 1;

  tkp.Privileges[0].Luid = sedebugnameValue;

  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

  if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))

  {

  puts("提高debug权限失败!");

  CloseHandle( hToken );

  }

    er = GetLastError();

        printf("错误代号%d",er);

}

//-------------------------------------------------------------------------------------------------------------

//Gets the base of our dll

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;

}

//打开魔兽后,在运行本程序就可以了

 

      此外,还遇到一些风波。因为我经常用非管理员的身份登录(一般用户都是用管理员登录的,所以不会用到我接下来提到的问题),发现作弊失败。开始我是想既然非管理员不行,就用管理员身份打开程序呗,于是用了ShellExecuteEx,但还是失败。于是我用GetLastError函数来分析,发现OpenProcess调用失败,GetLastError返回值为5,即拒绝访问。继续分析,发现之前,提升权限为debug权限失败了,因为GetLastError返回值为1300,即并非所有被引用的特权都指派给呼叫方。真相是调用AdjustTokenPrivileges失败了,因为本身调用AdjustTokenPrivileges函数也是需要权限的。至于要什么权限呢?"开始"-"设置"-"控制面板"-"管理工具"-"本地安全策略"-"本地策略"-"用户权利指派"-"调试程序",用管理员身份登录后,把该权限指派给需要该权限非管理员就可以了。至于ShellExecuteEx为什么不可以呢?我猜,以管理员身份运行,但是并不意味着它某些权限提高了。暂时只能这么解释了。遗憾的事,不可以用编程的方法代替用管理员派发权限的方法。我想,这可能是不可实现的。毕竟管理员才是具有最高权限的,如果普通程序可以随便提升任意权限,那就不得了了。

当然,目前只是实现单机版的,或者局域网也行,但是平台就过不了了,要过平台,还得继续研究,包括软件逆工程,网络编程等等。如有什么指导,敬请告诉我,呵呵

下载地址: http://vdisk.weibo.com/s/14Izh

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值