在讨论这个问题前,我们先把外挂分类。
按是否需要游戏客户端分为 内挂 和 脱机(这是我的称呼,你可以用别的名词称呼)
内挂又可以按照修改游戏的方法分成 模拟操作型 、 修改内存型 、 封包型 。
===================================================
脱机的不需要特别说明,利用 Mircosoft Winsock Control 6.0 可以实现功能相当强大的脱机客户端,
在这方面VB相对于其他编程语言没有明显的劣势,甚至是优势。
对于内挂型的~
一、 模拟按键型
因为在VB中嵌入API已经不是什么难事,所以VB6应用程序也可以方便的调用
keybd_event
mouse_event
来实现键盘和鼠标的模拟。在WindowsNT上,这两个函数是不被推荐使用的可以使用SendInput代替~但
是SendInput在VB的API浏览器没有包含~
二、 修改内存
修改目标游戏内存,类似于FPE,GM之类的软件,但是修改的目标确是不同,一般上说FPE等单机游戏内
存修改器主要是修改数据区内容,而网络游戏修改内存外挂主要是修改程序指令~
具体要使用到的API是
WriteProcessMemory
ReadProcessMemoryF
OpenProcess
CloseHandle
第一个被调用的API是OpenProcess,第一个参数dwDesiredAccess 使用的常量在VB中是没有声明能够的。
在winnt.h(4318)的定义如下
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED SYNCHRONIZE 0xFFF)
用这个值做参数调用OpenProcess得到的操作权将是最大的,同时破坏性也最大,使用不当容易使游戏进
程DOWN掉。所以我个人推荐使用:
#define PROCESS_VM_READ (0x0010)
#define PROCESS_VM_WRITE (0x0020)
分别对应ReadProcessMemoryWriteProcessMemory
第二个参数一般做0 意义是 是否让自进程继承这个句柄
第三个参数就是目标进程ID,进程ID可以通过FindWindow得到句柄后调GetWindowThreadProcessId得到
打开进程,获得进程句柄后,就可以利用ReadProcessMemoryWriteProcessMemory来读写游戏进程数据了~
记住使用完成后,及时调用CloseHandle来释放句柄,不然你的程序运行一段时间后就会出错~
三、 封包型
封包型也可以分为两种:
1)代理型
2)hook winsock api型
第一种主要就是在本机虚拟一个游戏服务器,让游戏的数据包先发给你的程序,有你处理后再发往真实的游
戏服务器,这种方法简单灵活,但是,目前绝大多数的网络游戏都对这型外挂有ANTI机制。(一下不知道该
用什么词 :) )
HOOKAPI型,一直是VB外挂程序的禁区,因为目前所使用的大多数方法,都需要建立一个DLL EJECT到目标
进程中,而VB建立的DLL是不能满足要求的~
下面来说重点吧~(至少我这么认为)
WIN32API中有这么一套API,叫做调试API.
先是DebugActiveProcess,
BOOL DebugActiveProcess(
DWORD dwProcessId process to be debugged
);
参数就一个就是目标进程的ID,可以用我前面说的方法来得到。
当开始调试一个进程后,就可以使用WaitForDebugEvent,
BOOL WaitForDebugEvent(
LPDEBUG_EVENT lpDebugEvent, pointer to debug event structure
DWORD dwMilliseconds milliseconds to wait for event
);
来等待DEBUG事件了~
DEBUG_EVENT的结构定义是这样的:
typedef struct _DEBUG_EVENT { de
DWORD dwDebugEventCode;
DWORD dwProcessId;
DWORD dwThreadId;
union {
EXCEPTION_DEBUG_INFO Exception;
Create_THREAD_DEBUG_INFO CreateThread;
Create_PROCESS_DEBUG_INFO CreateProcessInfo;
EXIT_THREAD_DEBUG_INFO ExitThread;
EXIT_PROCESS_DEBUG_INFO ExitProcess;
LOAD_DLL_DEBUG_INFO LoadDll;
UNLOAD_DLL_DEBUG_INFO UnloadDll;
OUTPUT_DEBUG_STRING_INFO DebugString;
RIP_INFO RipInfo;
} u;
} DEBUG_EVENT;
typedef struct _EXCEPTION_RECORD { exr
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
typedef struct _EXCEPTION_DEBUG_INFO { exdi
EXCEPTION_RECORD ExceptionRecord;
DWORD dwFirstChance;
} EXCEPTION_DEBUG_INFO;
在众多事件中,我们关心的只有EXCEPTION_DEBUG_EVENT,当dwDebugEventCode==EXCEPTION_DEBUG_EVENT时,
U的结构展开是这样的!
ExceptionCode表明了DEBUG事件产生的原因;可能的值中,需要我们关心的只有EXCEPTION_BREAKPOINT。
当目标执行到指令INT3时就会触发上面的EXCEPTION_BREAKPOINT时间,所以,我们大可以在SENDRECV等API入
口处放一个INT3指令,
当游戏调用该API时就触发了一个调试事件,进程被挂起,然后通知调试进程,这个时候,我们就可以从游戏
程序的堆栈中读取参数,
甚至修改~~
最后,做了一些必要的出来后记得调用ContinueDebugEvent来继续游戏程序的执行~