超强回归—菜鸟进阶,c++魔兽争霸全图外挂制作全教程
半年前浅尝制作外挂,初试成功,很是兴奋。发表一贴《菜鸟教程-全图外挂制作全程教学》。地址:https://www.360docs.net/doc/7711061600.html,/thread-2485-1-1.html。
貌似点击量很高。但看贴后的留言,有很多人说难?也有人骂我,说我自己都不会的,是抄袭别人的文章,我还轮不到你个瘪三来指三道四。下面不说这个瘪三了,进入正题。
难在何处?我想:
第一,你不会编程。对于这类人,你们应该去学习,至少掌握一门编程语言。如C++,VB,Delphi等。
第二,你没有弄懂外挂制作原理和思路。首先说原理,思路下面再详细说。其实这个在《菜鸟教程-全图外挂制作全程教学》中有提到。外挂原理一般包括:模拟式,内存式,封包式和指今修改式。比如:大部分改建就是模拟键盘(模拟式)。全图外挂为内存式或指令修改式。
第三,你没有仔细看《菜鸟教程-全图外挂制作全程教学》,对于这类人,我要严重的批判和表示强烈的鄙视。
好了,我们继续正题。如果你已经掌握一门编程语言了,想做外挂,你必须清楚实现整个功能的思路,这个在《菜鸟教程-全图外挂制作全程教学》中也是有的。我们做的全图外挂为内存式,又分DLL注入和程序两种形式,我这里讲的是软件形式,DLL注入的看BR以前的源码。
首先,我们要提升外挂本身程序权限,使其能够有权限修改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.}
其次,有了权限以后,我们要找到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(hSna
pshot,&lppe);
21. }
22. }
23. CloseHandle( hSnapshot );
24. return targetPid;
25.}
注意:有的名称为War3.exe或war3.exe,需要区分大小写。c++有不区分大小写比较的方法,自己去找……我操,这点专研精神都没有,怎么不去死,还学编程做外挂?自己先挂吧。其实我后面有个教你们查看自己的进程和game.dll到底是大写还是小些的方法。
进程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(LastDLLP
ath ,me32.szExePath);//game.dll路径
15. CloseHandle(sna
pMod);
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.}
这里也需要注意的是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;
https://www.360docs.net/doc/7711061600.html,Size =
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\\FileV
ersion"),
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.}
获得版本后我们就可以打开进程了。
1.HANDLE hopen=OpenProcess( PROCESS_ALL_ACCESS|PROCESS_TERMINA
TE|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,FALSE,P ID);
2.//打开war进程以供编辑
再用switch语句判断。如
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.}
这里还有个特别重要的:PATCH,这是定义的一个宏,不懂的百度。
#define PATCH(i,w) WriteProcessMemory(hopen,(LPVOID)(g_dwGameAd dr+i),w,sizeof(w)-1,0);
hopen就是先打开war进程以供编辑时返回的句柄的,g_dwGameAddr就是GetDLLBase(char* DllName, DWORD tPid)返回的基址。
回想:在《菜鸟教程-全图外挂制作全程教学》里面,有人在那“教训”我,我只想说:“你装B装的可以了,爷我法眼一开就知道你是个瘪三”。
记得有人问过为什么这个宏在这里使用WriteProcessMemory,和BR的不同,什么意思?是因为这个是在自己的程序里面,如果DLL注入的话就要用
#define PATCH(i,w) memcpy((LPVOID)(g_dwGameAddr+i),w,sizeof(w)-1)。
这个教程难免还有疏漏的地方,如有留言,看到必回。谢谢大家支持!
补充一下,在前面,两处说道大小写不一致的问题,这里教你们一个方法,怎么知道具体的名称.
首先,我们打开魔兽,找到War3.exe进程,直接就可以看出他的大小写是什么。然后可以根据上面的DWORD GetDLLBase(char* DllName, DWORD tPid)和DWORD GetPIDForProcess(char* process)获得War3.exe进程加载的所有模块,如果单机启动,是加载本地的game.dll。如果在平台上启动游戏,你会发现加载的是平台自带的game.dll。
如建一个控制台程序,源码如下:
1.#include "StdAfx.h"
2.#include
3.#include
4.#include
5.TCHAR LastDLLPath[260];
6.DWORD GetDLLBase(char* DllName, DWORD tPid)
7.{
8. HANDLE snapMod;
9. MODULEENTRY32 me32;
10. if (tPid == 0) return 0;
11. snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
tPid);
12. me32.dwSize = sizeof(MODULEENTRY32);
13. if (Module32First(snapMod, &me32))
14. {
15.
16. do
17. {
18. /*if (strcmp(DllName,(const
char *)me32.szModule) == 0)
19. { */
20. printf( "%s\n
",me32.szExePath);
21.
22. /*}*/
23. }
24. while(Module32Next(snapMod,&me32));
25. }
26. CloseHandle(snapMod);
27. return 0;
28.}
29.DWORD GetPIDForProcess(char* process)
30.{
31. BOOL working;
32. PROCESSENTRY32 lppe= {0};
33. DWORD targetPid=0;
34.HANDLE
hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS ,0);
35. if (hSnapshot){
36. lppe.dwSize=sizeof(lppe);
37. working=Process32First(hSnapshot,&lppe)
;
38. while (working){
39.if(strcmp((const char
*)lppe.szExeFile,process)==0)
40. {
41. targetPid=lppe.
th32ProcessID;
42. break;
43. }working=Process32Next(hSna
pshot,&lppe);
44. }
45. }
46. CloseHandle( hSnapshot );
47. return targetPid;
48.}
49.
50.
51.int main(int argc, char* argv[])
52.{
53. HANDLE hToken;
54. LUID sedebugnameValue;
55. TOKEN_PRIVILEGES tkp;
56.OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
57.LookupPrivilegeValue(NULL,
SE_DEBUG_NAME,&sedebugnameValue);
58. tkp.PrivilegeCount = 1;
59. tkp.Privileges[0].Luid = sedebugnameValue;
60. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
61. AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp,
NULL, NULL);
62. CloseHandle(hToken);
63.
64.//HWND hwar3=::FindWindow(NULL,TEXT("Warcraft
III"));
65. //DWORD PID,TD;
66. //TD = GetWindowThreadProcessId (hwar3, &PID);
67. //和下面一样的效果。
68. DWORD PID=GetPIDForProcess("war3.exe");
69. GetDLLBase("war3.exe",PID);
70. getchar();
71. return 0;
72.}