一步一步教你写DOTA外挂

好久木有研究DOTA了,整理篇小菜文章。

首先,我们要提升外挂本身程序权限,使其能够有权限修改war3游戏的内存。这个c++可以使用如下代码

  1. void EnableDebugPriv()//提升程序自身权限   
  2. {  
  3.         HANDLE hToken;  
  4.         LUID sedebugnameValue;  
  5.         TOKEN_PRIVILEGES tkp;  
  6.         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return;  
  7.         if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME,&sedebugnameValue))  
  8.         {  
  9.                 CloseHandle(hToken);  
  10.                 return;  
  11.         }  
  12.         tkp.PrivilegeCount = 1;  
  13.         tkp.Privileges[0].Luid = sedebugnameValue;  
  14.         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  
  15.         if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL)) CloseHandle(hToken);  
  16. }  
void EnableDebugPriv()//提升程序自身权限
{
        HANDLE hToken;
        LUID sedebugnameValue;
        TOKEN_PRIVILEGES tkp;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return;
        if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME,&sedebugnameValue))
        {
                CloseHandle(hToken);
                return;
        }
        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);
}

其次,有了权限以后,我们要找到war3.exe进程ID。并打开进程以供编辑修改内存,到达作弊目的。
获得进程ID:下面这个函数方法就是返回进程的,直接写进程名称,如:GetPIDForProcess(“war3.exe”),还可以用FindWindow的方法,反正能找到进程ID就可以了。

  1. //HWND hwar3=::FindWindow(NULL,TEXT("Warcraft III"));   
  2. //DWORD PID, TID;   
  3. //TID = ::GetWindowThreadProcessId (hwar3, &PID);   
  4. DWORD GetPIDForProcess(char* process)//获取进程ID   
  5. {  
  6.         BOOL                    working;  
  7.         PROCESSENTRY32          lppe= {0};  
  8.         DWORD                   targetPid=0;  
  9.         HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS ,0);  
  10.         if (hSnapshot)  
  11.         {  
  12.                 lppe.dwSize=sizeof(lppe);  
  13.                 working=Process32First(hSnapshot,&lppe);  
  14.                 while (working)  
  15.                 {  
  16.                         if(strcmp((const char *)lppe.szExeFile,process)==0)  
  17.                         {  
  18.                                 targetPid=lppe.th32ProcessID;  
  19.                                 break;  
  20.                         }working=Process32Next(hSnapshot,&lppe);  
  21.                 }  
  22.         }  
  23.         CloseHandle( hSnapshot );  
  24.         return targetPid;  
  25. }  
//HWND hwar3=::FindWindow(NULL,TEXT("Warcraft III"));
//DWORD PID, TID;
//TID = ::GetWindowThreadProcessId (hwar3, &PID);
DWORD GetPIDForProcess(char* process)//获取进程ID
{
        BOOL                    working;
        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((const char *)lppe.szExeFile,process)==0)
                        {
                                targetPid=lppe.th32ProcessID;
                                break;
                        }working=Process32Next(hSnapshot,&lppe);
                }
        }
        CloseHandle( hSnapshot );
        return targetPid;
}

注意:有的名称为War3.exe或war3.exe,用toolhelp32方式需要比较进程名字,这时是会区分大小写的。FindWindow则不用,窗口标题都是固定的Warcraft III。

进程ID已经找到,现在是不是直接打开修改内存作弊呢?不,还早呢。我们修改内存也不能乱来,你得先找到Game.dll判断游戏版本,对应修改,要不会把魔兽搞火了,突然跳出来,那你就崩溃了,后悔都来不及。有木有,有木有?开图导致游戏崩溃的老实交代一下。

下面的方法获取game.dll的基址和路径。GetDLLBase(“game.dll”,PID)直接返回的就是game.dll的基址,这个后面是需要用到的。定义一个全局变量TCHAR  LastDLLPath[260],LastDLLPath返回的就是game.dll路径,。

  1. DWORD GetDLLBase(char* DllName, DWORD tPid)  
  2. {  
  3.         HANDLE snapMod;   
  4.         MODULEENTRY32 me32;  
  5.         if (tPid == 0) return 0;  
  6.         snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, tPid);   
  7.         me32.dwSize = sizeof(MODULEENTRY32);   
  8.         if (Module32First(snapMod, &me32))  
  9.         {   
  10.                 do  
  11.                 {  
  12.                         if (strcmp(DllName,(const char *)me32.szModule) == 0)  
  13.                         {   
  14.                                 strcpy(LastDLLPath ,me32.szExePath);//game.dll路径   
  15.                                 CloseHandle(snapMod);  
  16.                                 return (DWORD) me32.modBaseAddr;   
  17.                         }  
  18.                 }while(Module32Next(snapMod,&me32));  
  19.         }  
  20.         else  
  21.         {  
  22.                  Powers=true;  
  23.         }  
  24.         CloseHandle(snapMod);   
  25.         return 0;   
  26. }   
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,(const char *)me32.szModule) == 0)
                        { 
                                strcpy(LastDLLPath ,me32.szExePath);//game.dll路径
                                CloseHandle(snapMod);
                                return (DWORD) me32.modBaseAddr; 
                        }
                }while(Module32Next(snapMod,&me32));
        }
        else
        {
                 Powers=true;
        }
        CloseHandle(snapMod); 
        return 0; 
} 
还有就是使用native api ZwQueryVirtualMemory来获取gamedll的基址,这个有些麻烦不过还算是稍微底层些

  1. typedef enum _MEMORY_INFORMATION_CLASS   
  2. {  
  3.     MemoryBasicInformation,  
  4.     MemoryWorkingSetList,  
  5.     MemorySectionName,  
  6.     MemoryBasicVlmInformation  
  7. } MEMORY_INFORMATION_CLASS;  
  8.   
  9. typedef long (NTAPI * PF_ZwQueryVirtualMemory)   
  10. (         IN HANDLE ProcessHandle,  
  11.  IN PVOID BaseAddress,  
  12.  IN MEMORY_INFORMATION_CLASS MemoryInformationClass,  
  13.  OUT PVOID MemoryInformation,  
  14.  IN ULONG MemoryInformationLength,  
  15.  OUT PULONG ReturnLength OPTIONAL   
  16.  );  
  17. typedef struct _UNICODE_STRING  
  18. {  
  19.     USHORT Length;  
  20.     USHORT MaximumLength;  
  21.     PWSTR Buffer;  
  22. } UNICODE_STRING, *PUNICODE_STRING;  
  23. DWORD GetGameDLLAddr(HANDLE hWar3Handle,WCHAR * ModuleName)  
  24. {  
  25.     DWORD startAddr;  
  26.     BYTE buffer[MAX_PATH*2+4];  
  27.     MEMORY_BASIC_INFORMATION memBI;  
  28.     PUNICODE_STRING secName;     
  29.     PF_ZwQueryVirtualMemory ZwQueryVirtualMemory;  
  30.   
  31.     startAddr = 0x00000000;  
  32.     ZwQueryVirtualMemory = (PF_ZwQueryVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"),"ZwQueryVirtualMemory");  
  33.     do{  
  34.         if(ZwQueryVirtualMemory(hWar3Handle,(PVOID)startAddr,MemoryBasicInformation,&memBI,sizeof(memBI),0 ) >= 0 &&  
  35.             (memBI.Type == MEM_IMAGE))  
  36.         {  
  37.             if( ZwQueryVirtualMemory(hWar3Handle,(PVOID)startAddr,MemorySectionName,buffer,sizeof(buffer),0 ) >= 0 )  
  38.             {  
  39.                 secName = (PUNICODE_STRING)buffer;  
  40.                 if(wcsicmp(ModuleName, wcsrchr(secName->Buffer,'\\')+1) == 0)  
  41.                 {  
  42.                     return startAddr;  
  43.                 }  
  44.             }  
  45.             // 递增基址,开始下一轮查询!   
  46.         }  
  47.         startAddr += 0x10000;  
  48.     }  
  49.     while( startAddr < 0x80000000 );  
  50.     return 0;  
  51. };  
typedef enum _MEMORY_INFORMATION_CLASS 
{
	MemoryBasicInformation,
	MemoryWorkingSetList,
	MemorySectionName,
	MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;

typedef long (NTAPI * PF_ZwQueryVirtualMemory) 
(         IN HANDLE ProcessHandle,
 IN PVOID BaseAddress,
 IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
 OUT PVOID MemoryInformation,
 IN ULONG MemoryInformationLength,
 OUT PULONG ReturnLength OPTIONAL 
 );
typedef struct _UNICODE_STRING
{
	USHORT Length;
	USHORT MaximumLength;
	PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
DWORD GetGameDLLAddr(HANDLE hWar3Handle,WCHAR * ModuleName)
{
	DWORD startAddr;
	BYTE buffer[MAX_PATH*2+4];
	MEMORY_BASIC_INFORMATION memBI;
	PUNICODE_STRING secName;   
	PF_ZwQueryVirtualMemory ZwQueryVirtualMemory;

	startAddr = 0x00000000;
	ZwQueryVirtualMemory = (PF_ZwQueryVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll"),"ZwQueryVirtualMemory");
	do{
		if(ZwQueryVirtualMemory(hWar3Handle,(PVOID)startAddr,MemoryBasicInformation,&memBI,sizeof(memBI),0 ) >= 0 &&
			(memBI.Type == MEM_IMAGE))
		{
			if( ZwQueryVirtualMemory(hWar3Handle,(PVOID)startAddr,MemorySectionName,buffer,sizeof(buffer),0 ) >= 0 )
			{
				secName = (PUNICODE_STRING)buffer;
				if(wcsicmp(ModuleName, wcsrchr(secName->Buffer,'\\')+1) == 0)
				{
					return startAddr;
				}
			}
			// 递增基址,开始下一轮查询!
		}
		startAddr += 0x10000;
	}
	while( startAddr < 0x80000000 );
	return 0;
};

这里也需要注意的是game.dll的大小写或者名称,如有的平台为game124.dll。然后用下面两个方法获得版本。定义全局变量WC3VER  g_War3Ver,enum WC3VER{_UN,_120E,_124B,_124E,_125B,_126B}。

  1. void GetWar3Ver()  
  2. {  
  3.         TCHAR FileVer[64];  
  4.         ODV(TEXT("%s"),LastDLLPath);  
  5.         GetFileVer(LastDLLPath,FileVer,64);  
  6.         ODV(TEXT("%s"),FileVer);  
  7.         if(lstrcmpi(FileVer,TEXT("1, 20, 4, 6074")) ==0)  
  8.         {  
  9.                 g_War3Ver=_120E;  
  10.         }  
  11.         else if(lstrcmpi(FileVer,TEXT("1, 24, 1, 6374")) ==0)  
  12.         {  
  13.                 g_War3Ver=_124B;  
  14.         }  
  15.         else if(lstrcmpi(FileVer,TEXT("1, 24, 4, 6387")) ==0)  
  16.         {  
  17.                 g_War3Ver=_124E;  
  18.         }  
  19.         else if(lstrcmpi(FileVer,TEXT("1, 25, 1, 6397")) ==0)  
  20.         {  
  21.                 g_War3Ver=_125B;  
  22.         }  
  23.         else if(lstrcmpi(FileVer,TEXT("1, 26, 0, 6401")) ==0)  
  24.         {  
  25.                 g_War3Ver=_126B;  
  26.         }  
  27.         else  
  28.         {  
  29.                 g_War3Ver=_UN;  
  30.         }  
  31. }  
  32. DWORD  GetFileVer(__in LPTSTR FileName, __out LPTSTR lpVersion, __in DWORD nSize)   
  33. {   
  34.         TCHAR  SubBlock[64];   
  35.         DWORD  InfoSize;   
  36.         InfoSize = GetFileVersionInfoSize(FileName,NULL);        if(InfoSize==0) return 0;   
  37.         TCHAR *InfoBuf = new TCHAR[InfoSize];    
  38.         GetFileVersionInfo(FileName,0,InfoSize,InfoBuf);   
  39.         unsigned int  cbTranslate = 0;   
  40.         struct LANGANDCODEPAGE  
  41.         {   
  42.                 WORD wLanguage;   
  43.                 WORD wCodePage;   
  44.         }  
  45.         *lpTranslate;   
  46.         VerQueryValue(InfoBuf, TEXT("\\VarFileInfo\\Translation"),   
  47.                 (LPVOID*)&lpTranslate,&cbTranslate);   
  48.         // Read the file description for each language and code page.    
  49.         wsprintf( SubBlock,    
  50.                 TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"),   
  51.                 lpTranslate[0].wLanguage,   
  52.                 lpTranslate[0].wCodePage);   
  53.         void *lpBuffer=NULL;   
  54.         unsigned int dwBytes=0;   
  55.         VerQueryValue(InfoBuf, SubBlock, &lpBuffer, &dwBytes);    
  56.         lstrcpyn(lpVersion,(LPTSTR)lpBuffer,nSize);   
  57.         delete[] InfoBuf;   
  58.         return dwBytes;   
  59. }  
void GetWar3Ver()
{
        TCHAR FileVer[64];
        ODV(TEXT("%s"),LastDLLPath);
        GetFileVer(LastDLLPath,FileVer,64);
        ODV(TEXT("%s"),FileVer);
        if(lstrcmpi(FileVer,TEXT("1, 20, 4, 6074")) ==0)
        {
                g_War3Ver=_120E;
        }
        else if(lstrcmpi(FileVer,TEXT("1, 24, 1, 6374")) ==0)
        {
                g_War3Ver=_124B;
        }
        else if(lstrcmpi(FileVer,TEXT("1, 24, 4, 6387")) ==0)
        {
                g_War3Ver=_124E;
        }
        else if(lstrcmpi(FileVer,TEXT("1, 25, 1, 6397")) ==0)
        {
                g_War3Ver=_125B;
        }
        else if(lstrcmpi(FileVer,TEXT("1, 26, 0, 6401")) ==0)
        {
                g_War3Ver=_126B;
        }
        else
        {
                g_War3Ver=_UN;
        }
}
DWORD  GetFileVer(__in LPTSTR FileName, __out LPTSTR lpVersion, __in DWORD nSize) 
{ 
        TCHAR  SubBlock[64]; 
        DWORD  InfoSize; 
        InfoSize = GetFileVersionInfoSize(FileName,NULL);        if(InfoSize==0) return 0; 
        TCHAR *InfoBuf = new TCHAR[InfoSize];  
        GetFileVersionInfo(FileName,0,InfoSize,InfoBuf); 
        unsigned int  cbTranslate = 0; 
        struct LANGANDCODEPAGE
        { 
                WORD wLanguage; 
                WORD wCodePage; 
        }
        *lpTranslate; 
        VerQueryValue(InfoBuf, TEXT("\\VarFileInfo\\Translation"), 
                (LPVOID*)&lpTranslate,&cbTranslate); 
        // Read the file description for each language and code page. 
        wsprintf( SubBlock,  
                TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), 
                lpTranslate[0].wLanguage, 
                lpTranslate[0].wCodePage); 
        void *lpBuffer=NULL; 
        unsigned int dwBytes=0; 
        VerQueryValue(InfoBuf, SubBlock, &lpBuffer, &dwBytes);  
        lstrcpyn(lpVersion,(LPTSTR)lpBuffer,nSize); 
        delete[] InfoBuf; 
        return dwBytes; 
}

获得版本后就可以OpenProcess然后根据对应的版本来修改内存以实现我们想要的东东了。

  1. switch(g_War3Ver)  
  2. {  
  3.       case _120E:  
  4.       //修改内存代码自己去找吧//大地图去除迷雾   
  5.       PATCH(0x406B53,"\x90\x8B\x09");  
  6.       PATCH(0x2A0930,"\xD2");  
  7.       //野外显血           
  8.       PATCH(0x166E5E,"\x90\x90\x90\x90\x90\x90\x90\x90");  
  9.       PATCH(0x16FE0A,"\x33\xC0\x90\x90");  
  10.       //视野外点选   
  11.       PATCH(0x1BD5A7,"\x90\x90");  
  12.       PATCH(0x1BD5BB,"\xEB");  
  13.       //小地图显示单位   
  14.       PATCH(0x1491A8, "\x00");  
  15. break;  
  16.       case _124B:  
  17.       //小地图显示单位   
  18.       PATCH(0x361EAB,"\x90\x90\x39\x5E\x10\x90\x90\xB8\x00\x00\x00\x00\xEB\x07");  
  19. break;  
  20.       case _124E:  
  21. //至于作弊代码你们是直接写,还是写成一个方法调用,随你们自己。   
  22. break;  
  23.        case _UN:  
  24.        default:  
  25. break;  
  26.   }  
switch(g_War3Ver)
{
      case _120E:
      //修改内存代码自己去找吧//大地图去除迷雾
      PATCH(0x406B53,"\x90\x8B\x09");
      PATCH(0x2A0930,"\xD2");
      //野外显血        
      PATCH(0x166E5E,"\x90\x90\x90\x90\x90\x90\x90\x90");
      PATCH(0x16FE0A,"\x33\xC0\x90\x90");
      //视野外点选
      PATCH(0x1BD5A7,"\x90\x90");
      PATCH(0x1BD5BB,"\xEB");
      //小地图显示单位
      PATCH(0x1491A8, "\x00");
break;
      case _124B:
      //小地图显示单位
      PATCH(0x361EAB,"\x90\x90\x39\x5E\x10\x90\x90\xB8\x00\x00\x00\x00\xEB\x07");
break;
      case _124E:
//至于作弊代码你们是直接写,还是写成一个方法调用,随你们自己。
break;
       case _UN:
       default:
break;
  }

PATCH,这是定义的一个宏,#define  PATCH(i,w)  WriteProcessMemory(hopen,(LPVOID)(g_dwGameAddr+i),w,sizeof(w)-1,0);实现向目标进程某个地址写入数据。

这个宏在这里使用WriteProcessMemory,如果你使用DLL注入的话就要用
#define PATCH(i,w) memcpy((LPVOID)(g_dwGameAddr+i),w,sizeof(w)-1)。

最后补充一下根据上面的DWORD GetDLLBase(char* DllName, DWORD tPid)和DWORD GetPIDForProcess(char* process)可以获得War3.exe进程加载的所有模块,如果单机启动,是加载本地的game.dll。如果在平台上启动游戏,你会发现加载的是平台自带的game.dll。可以修改下GetDLLBase函数打印下加载模块的路径自己看下。

这时我通过本机跟11加载时的截图



另外还要注意下使用tlhelp32库的函数时最好程序使用ansi编码。


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值