对于游戏外挂来说游戏钩子 源码,首先要做的就是将我们的代码放到游戏进程中,从而达到“不可告人的目的”。 这里我介绍一个比较常用的技术。 将DLL放入游戏进程中就是进程hook的方法。 其实这也是一些木马窃取账号和密码的一种方法。 这里我们只是解释如何通过进程钩子将代码注入到游戏进程中。 从第二节我们知道如何编写C++MFC DLL。 这里我们首先创建一个新的DLL。 首先告诉大家,这里我会用到4个Window AP函数。
HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName );
该API用于查找给定类名或窗口名的窗口句柄。 参数无需引入。 顾名思义,第一个参数是窗口类名,第二个参数是窗口名。 我们在这里只使用第二个参数。 将 NULL 放入第一个参数中。 我们可以通过Spy++获取窗口名称。 这是VS的一个工具:
打开这个工具。
将该圆圈拖到游戏标题栏并将其抬起以查看游戏窗口的标题。 我们按照这个标题找到窗口句柄。
DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );
此 API 返回创建指定窗口的线程的 ID。 MSDN 说“该函数检索创建指定窗口的线程的标识符,以及创建该窗口的进程的标识符(可选)”
参数hWnd是窗口句柄。 它是 FindWindow 函数返回的值。 lpdwProcessId 是创建窗口的进程ID。 它是一个输出参数,是一个指针。 就像C#中的out参数一样。 该参数可以为 NULL。 如果不为NULL游戏钩子 源码,则返回创建指定窗口的进程标志。
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod, DWORD dwThreadId);
这个API就是设置hook的。 第一个参数是钩子类型。 具体的hook类型请参考MSDN。 这里我们使用WH_KEYBOARD。 第二个参数是回调函数。 回调函数的格式如下:
LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam );
第三个参数是DLL的模块句柄,我们可以通过API函数获取。
HMODULE GetModuleHandle( LPCTSTR lpModuleName);
这个时候,大家都会心疼的。 SetWindowsHookEx的第三个参数是HINSTANCE类型,但GetModuleHandle返回HMODULE。 这能配吗? 其实是可以搭配的。 你可以查看定义它的头文件,我们可以看到typedef HINSTANCE HMODULE,这样你就可以很容易地看出它们是相同的东西。 这在Windows核心编程中经常见到。 当我们编写Windows游戏插件时,最好研究一下Windows核心编程。 推荐一本比较优雅的书《Windows核心编程》。 我的是最新版本。 这本书的作者对Windows系统绝对有很高的研究水平。 值得反复阅读和研究。 不离题了,我们继续…… GetModuleHandle的第一个参数是要注入的DLL的路径,可以是等效的,也可以是绝对的。 当然,我推荐相对路径。 SetWindowsHookEx的最后一个参数是GetWindowThreadProcessId返回的值。 通过这个解释你应该明白了。
以下是游戏账号买卖平台的实际代码。 让我们创建一个新的 MFC DLL(我的名字是 GameHookDLL)。
///钩子回调函数 LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ){ AFX_MANAGE_STATE(AfxGetStaticModuleState()); if(wParam==VK_F1&&((lParam&(1<<31))==0)){ AfxMessageBox(L"F1键在游戏窗口被按下了!"); } return CallNextHookEx(0,code,wParam,lParam); } //(LPWSTR)"YB_OnlineClient" void SetHook(LPWSTR prc_name){ AFX_MANAGE_STATE(AfxGetStaticModuleState()); HWND hd=FindWindow(NULL,prc_name); if(hd==NULL) { AfxMessageBox(L"请打开输入的程序进程"); return; } DWORD dwid=GetWindowThreadProcessId(hd,NULL); // HINSTANCE hdll=::GetModuleHandleW(L"GameHookDLL.dll"); SetWindowsHookEx(WH_KEYBOARD,&KeyboardProc,hdll,dwid); }
这是我在 DLL 中添加的两个函数。 以上就是SetWindowsHookEx的反弹处理函数。对了,别忘了这个回调函数的最后一行
returnCallNextHookEx(0,代码,wParam,lParam); 如果反弹KeyboardProc中的code值大于0,则会跳过并调用下一条消息。 MSDN中的原文是:如果code小于零,钩子过程必须将消息传递给CallNextHookEx函数而不进行进一步处理,并且应该返回CallNextHookEx返回的值。 所以我建议自己去学习一下MSDN。 与我有限的个人能力相比,也许我的理解是错误的。 当然,如果这里有什么不对或者理解有误的地方,希望大家谅解。 这里我们的DLL只需要暴露第二个函数voidSetHook(LPWSTR prc_name)。 至于如何曝光,大家自己看第二季吧。
if(wParam==VK_F1&&((lParam&(1<<31))==0)){ AfxMessageBox(L"F1键在游戏窗口被按下了!"); }
wParam==VK_F1表示我们按下的F1键。(lParam&(1<<31))==0对lParam参数不熟悉的就不好理解了。lParam的第31位如果是0表示按下,如果是1表示按键弹起。我们这里是判断F1按键被按下。 如果没有(lParam&(1<<31))==0我们按下F1键将会弹出两次,一次是按下时弹出,一次是F1弹起式弹出。所以要保证lParam的第31位是0我们才弹出对话框。1<<31是10000000000000000000 0000000000后面有31个0而lParam的0~30位我们不确定但是我们&一下肯定都是0,然后第31位是0最后结果肯定是0这样就实现了判断。
MSDN COSCO英文是:
lParam[in]指定重复计数、扫描代码、扩展键标志、上下文代码、先前键状态标志和转换状态标志。 有关 lParamparameter 的详细信息,请参阅击键消息标志。 该参数可以是以下一个或多个值。
0-15.指定重复次数。 该值是由于用户按住按键而重复击键的次数。
16-23.指定扫描码。 该值取决于 OEM。
24.指定该键是否为扩展键,例如功能键或数字键盘上的键。 如果密钥是扩展密钥,则该值为 1; 否则为0。
25-28。 预订的。
29.指定上下文代码。 如果 ALT 键按下,则该值为 1; 否则为0。
30.指定之前的按键状态。 如果在消息发送之前按键按下,则该值为 1; 如果钥匙抬起则为 0。
31.指定过渡状态。 如果按键被按下,则值为 0;如果按键被释放,则值为 1。
接下来我们去新建一个MFC exe程序。 在此程序中,调用 voidSetHook(LPWSTR prc_name) 函数。 将窗口名称作为参数传递。 我这里添加的是MFC简单对话框。 对话框的布局如下:
然后将CString类型变量txt_prc_name关联到直播号文本框。 在击键风暴中添加注册钩子代码:
void CGameWGClientDlg::OnBnClickedOk() { UpdateData(true); LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name; SetHook(s1); // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); }
这些只需要你对MFC有一点了解。 LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name; 这里已经转换了两次,主要是CString类型不能直接转换成LPWSTR类型。 于是就这么处理了。 好的代码就完成了,我们来看看效果:
在MFC客户端程序中,输入我们使用Spy++找到的游戏窗口名称,然后点击确定,这样钩子就注册到了游戏进程中。 这时我们就可以在登录框中输入任何我们想要的内容,直到输入F1时弹出一个对话框。 这样,通过鼠标钩子注入的进程原型就完成了。 这就是本节的内容。 下一节我们将使用这个hook来实现手动喝药的过程(比较慢,更新可能会慢,希望大家理解)。