一步一步教你写DOTA外挂
来源:互联网 发布:铣床加工环形槽编程 编辑:程序博客网 时间:2024/05/22 10:55
好久木有研究DOTA了,整理篇小菜文章。
首先,我们要提升外挂本身程序权限,使其能够有权限修改war3游戏的内存。这个c++可以使用如下代码
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就可以了。
//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路径,。
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的基址,这个有些麻烦不过还算是稍微底层些
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}。
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然后根据对应的版本来修改内存以实现我们想要的东东了。
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编码。
- 一步一步教你写DOTA外挂
- 一步一步教你写DOTA外挂
- 教你编写DOTA外挂
- 一步一步教你写pdf文件
- 教你一步一步写快速排序
- 一步一步教你写SAP RFC
- 教你用VC6写热血江湖小外挂
- 一步一步教你写一个jQuery的插件(Plugin)
- 一步一步教你写SAP RFC (实战项目)
- 一步一步教你写SAP RFC (实战项目)
- Dagger2 简单教程,一步一步教你怎么写!
- 教你一步一步用OpenGL写游戏——前言
- 拆轮子系列之一步一步教你写FlowLayout
- 一步一步教你写BT种子嗅探器-原理篇
- 一步一步教你写股票走势图——分时图一(概述)
- 一步一步教你写股票走势图——分时图二(自定义xy轴)
- 一步一步教你写股票走势图——分时图四(高亮联动)
- 一步一步教你写股票走势图——分时图五(自定义标记)
- jQuery官方基础教程笔记
- XCode 4 Distribution App to AppStore
- mysql 的innodb和myisam数据库引擎的认识
- Oracle 优化器详解
- 我的找工作之路
- 一步一步教你写DOTA外挂
- Radius工作原理
- Struts2学习笔记(12)-----Struts2之动态方法调用
- CSDN太。。。
- mysql修改默认字符和默认存储引擎
- (转载)编译你自己的Linux内核(Kernel)
- ORG.APACHE.CATALINA.CORE.STANDARDCONTEXT LISTENERSTART
- android开发日记 ——avata项目
- 浅谈2D游戏开发,面向C++初学者