菜鸟的VC6神迹外挂的DIY之路

发布时间:2014-10-25 2:21:12
来源:分享查询网

本文转自:http://www.cppblog.com/niewenlong/archive/2007/07/20/28446.aspx     (一)外挂一般都能在游戏的界面中按一个热键(比如F12,HOME等),就可以呼出外挂的窗口,然后在里面进行外挂的功能设置,这个外挂的窗口是怎么弄出来的呢?要想在游戏里显示出窗口,那么我们要显示的这个窗口就要和游戏本身“混”在一起,也就是说我们的外挂窗口要“混入”游戏的内部,让游戏不排斥外挂窗口,把外挂窗口当做“自己人”,这样我们的外挂才能去“影响”游戏本身的运行。行话把这个叫“注入”。那怎么“注入”呢?Windows操作系统有个API函数SetWindowsHookEx,该函数的可以在系统上安装一个“钩子(HOOK)”。也就是把我们自己编写的一个回调函数设置为系统“钩子”。“钩子(HOOK)”有什么用呢?系统发送给各种程序窗口的消息,都要先经过“钩子”先处理之后再送到它本来要去的窗口。而在“钩子”处理来的消息的时候,Windows操作系统就已经自动把“钩子”“钩”在了消息即将到达的目的程序窗口上了,此时“钩子”就已经“混入”了目的窗口的内部了==========================================以下shaker注明:这个教程存在一个漏洞,以使一些对DLL编程不是很了解的人不能顺利的完成编译。BUG如下:原文中的S3DHOOK.DEF文件中的内容如下; S3DHook.def : Declares the module parameters for the DLL.LIBRARY      "S3DHook"DESCRIPTION  "S3DHook Windows Dynamic Link Library"EXPORTS    ; Explicit exports can go here使得生成的DLL没有任何输出函数,在编译EXE工程出现错误,要解决这个问题只要改变原来的S3DHook.def文件的内容如下:; S3DHook.def : Declares the module parameters for the DLL.LIBRARY      "S3DHook"DESCRIPTION  "S3DHook Windows Dynamic Link Library"EXPORTS    ; Explicit exports can go hereInstallHookUninstallHook如此,问题便得到解决!//////////////////////////////////////////////////////////////////////////关于版主shaker的注明:这个并不能说是个BUG由于:在S3DHook.h头文件中加入#ifndef S3DHOOKAPI#define S3DHOOKAPI extern "C" __declspec(dllimport)#endif在S3DHook.cpp中#include "S3DHook.h"这一句之前加入#define S3DHOOKAPI extern "C" __declspec(dllexport)也就是这个样子成了这个#define S3DHOOKAPI extern "C" __declspec(dllexport)#include "S3DHook.h"这样一来就不需要用.def文件来导出函数了关于这种导出方法,DLL编程的初学者,最好先去去看看windows核心编程,这本书,这种方法就是作者所推崇的把有关外挂功能的代码和“钩子”函数一起放到同一个DLL中,那么我们的外挂也就一同被注入到游戏里面去了在“我的文档”中建立一个文件夹名字叫“神迹外挂”然后打带VC6,建立新工程点OK,选择Regular DLL using shared mfc DLL在S3DHook.h头文件中加入#ifndef S3DHOOKAPI#define S3DHOOKAPI extern "C" __declspec(dllimport)#endif在S3DHook.cpp中#include "S3DHook.h"这一句之前加入#define S3DHOOKAPI extern "C" __declspec(dllexport)也就是这个样子成了这个#define S3DHOOKAPI extern "C" __declspec(dllexport)#include "S3DHook.h"在S3DHook.cpp中加入全局共享数据#pragma comment(linker,"section:Shared,rws")#pragma data_seg("Shared")HHOOK g_hhook;#pragma data_seg()在S3DHook.cpp加入钩子回调函数LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam){BOOL bKeyUp = lParam & (1 << 31);if (bKeyUp && wParam == VK_F12 && nCode == HC_ACTION) {AfxMessageBox("ok");}return ::CallNextHookEx(g_hhook, nCode, wParam ,lParam);}在文件前面加入函数的原形以便后面引用LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);在S3DHook.H里加入“导出(export)”的钩子安装卸载函数原形S3DHOOKAPI BOOL WINAPI InstallHook();S3DHOOKAPI BOOL WINAPI UninstallHook();在S3DHook.CPP里加入钩子安装卸载函数的实现S3DHOOKAPI BOOL WINAPI InstallHook(){if (g_hhook == NULL) {g_hhook = ::SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, theApp.m_hInstance, 0);if (g_hhook != NULL)return TRUE;}return FALSE;}S3DHOOKAPI BOOL WINAPI UninstallHook(){return ::UnhookWindowsHookEx(g_hhook);}好了,现在我们建立的这个DLL具有基本的键盘钩子的功能,编译生成S3DHook.dll下面建立一个EXE来调用这个DLL这个是对话框型的工程在MainDlg.cpp中加入对DLL的调用插入头文件包含#include "../s3dhook/s3dhook.h"更改工程设置Project->settings->link->Object/library modules:输入../s3dhook/debug/s3dhook.lib在对话框的OnInitDialog中加入InstallHook();安装键盘钩子在OnClose中加入UninstallHook();关闭程序时卸载键盘钩子编译这个对话框EXE把这两个工程生成的S3DHook.dll和Main.exe放到同一个文件夹中,运行在游戏窗口中按F12,会出现一个消息框,游戏会暂时定住注意消息框的标题是游戏程序的名字这说明这个消息框是在游戏内部显示出来的我们已经从游戏程序的内部显示了一个消息框出来了但还不够,我们要在游戏能够呼出外挂的界面,至少要显示一个对话框出来下面我们在S3DHook这个DLL工程中添加一个从CDialog派生的CS3DHookDlg类把DIALOG ID改为IDD_S3DHOOK_DIALOG添加的对话框类的操作如下主菜单->Insert->New Form为了方便,把CS3DHookDlg的源程序文件名字分别改为s3dhook.hs3dhook.cpp把刚才自动生成的对话框的Caption改为"外挂呼出窗口"下面定义一个全局窗口指针来保存我们要生成的这个窗口的指针,以便后面对"外挂呼出窗口"进行控制,把它和全局变量CS3DHookApp theApp;写在一起,也就是这个样子CS3DHookApp theApp;CS3DHookDlg *pCWndWGMain;下面对钩子回调函数进行改造,以便使我们的"外挂呼出窗口"能够在按F12时呼出如下:LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam){//按F12弹起时呼出外挂BOOL bKeyUp = lParam & (1 << 31);if (bKeyUp && wParam == VK_F12 && nCode == HC_ACTION) {if (pCWndWGMain == NULL) {//更改当前有效模块状态到DLL中//以便正确的读取对话框的资源AFX_MANAGE_STATE(AfxGetStaticModuleState());//找到当前的有效激活窗口CWnd *pCWnd = CWnd::GetForegroundWindow();//生成CS3DHookDlg类的对象实例//此处应该生成一个非模态对话框pCWndWGMain = new CS3DHookDlg();pCWndWGMain->Create(IDD_S3DHOOK_DIALOG, pCWnd);}else {//根据当前呼出窗口的状态来显示或隐藏呼出窗口pCWndWGMain->ShowWindow(pCWndWGMain->IsWindowVisible() ? SW_HIDE : SW_SHOW);}}return ::CallNextHookEx(g_hhook, nCode, wParam ,lParam);}有关上面的这一句在Regular MFC DLL中使用资源时非常重要AFX_MANAGE_STATE(AfxGetStaticModuleState());更多说明请参看http://www.csdn.net/develop/article/25/25358.shtm当关掉外挂的主程序时,还要做点善后工作重载CS3DHookApp类的ExitInstance函数,在其中删除对话框int CS3DHookApp::ExitInstance() {// TODO: Add your specialized code here and/or call the base classdelete pCWndWGMain;return CWinApp::ExitInstance();}重新编译生成S3DHOOK.dll并和Main.exe放到一起,运行它试试看运行后,随便打开一个其他的什么窗口,按F12,看到什么了?哈哈,我们的"外挂呼出窗口"呼出来了,真是千呼万唤始出来啊我在记事本中试了试:上次的程序已经可以在其他窗口中呼出我们的"外挂呼出窗口"了是不是已经有那么点"外挂"的样子了当我做到这一步的时候,当时非常兴奋!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!广大菜鸟们是不是有同感?让高手们见笑了:)但是,多试几次,发现还有不少问题随便哪个窗口中按F12键都能呼出,还会造成程序的崩溃我用的是WIN2000如果是在WIN98中恐怕还会造成系统的崩溃吧?这可不行啊:(要让他只在指定的程序窗口中呼出,每次都进神迹的游戏客户端试验很麻烦我们就在记事本中试验,让他只能在记事本中呼出,最好还要能像真正的外挂那样对挂入的程序做点手脚,说做就做,开工!!!继续对钩子回调函数进行改造如下:LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam){//按F12弹起时呼出外挂BOOL bKeyUp = lParam & (1 << 31);if (bKeyUp && wParam == VK_F12 && nCode == HC_ACTION) {if (pCWndWGMain == NULL) {AFX_MANAGE_STATE(AfxGetStaticModuleState());CWnd *pCWnd = CWnd::GetForegroundWindow();//当前窗口是否为记事本窗口char buf[MAX_PATH];::GetClassName(pCWnd->GetSafeHwnd(), buf, MAX_PATH);if (lstrcmpi(buf, "notepad") == 0) {pCWndWGMain = new CS3DHookDlg();//创建"外挂呼出窗口"时把记事本窗口作为他的父窗口pCWndWGMain->Create(IDD_S3DHOOK_DIALOG, pCWnd);pCWndWGMain->ShowWindow(SW_SHOW);}}else {//根据当前呼出窗口的状态来显示或隐藏呼出窗口pCWndWGMain->ShowWindow(pCWndWGMain->IsWindowVisible() ? SW_HIDE : SW_SHOW);}}return ::CallNextHookEx(g_hhook, nCode, wParam ,lParam);}重新编译并运行,我们的"外挂呼出窗口"可以多个记事本中呼出如图,并还没有发现会造成程序崩溃,有发现的,请告诉我!后面会附上这里是重新编译的Main.exe和s3dhook.dll哈哈,解决了一个小问题,爽!!!!!!!!!!!!!下面让我们的外挂对记事本做点小动作吧!做点什么呢?就让他在记事本的窗口中画个圆,怎么样?来试试看了为CS3DHookDlg添加WM_INITDIALOG的消息处理器并在其中添加一个定时器,同时窗口关闭时要销毁定时器~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~设置BOOL CS3DHookDlg::OnInitDialog() {CDialog::OnInitDialog();// TODO: Add extra initialization hereSetTimer(1000,100,0);return TRUE;  // return TRUE unless you set the focus to a control              // EXCEPTION: OCX Property Pages should return FALSE}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~销毁,先要添加WM_CLOSE消息的处理器void CS3DHookDlg::OnClose() {// TODO: Add your message handler code here and/or call defaultKillTimer(1000);CDialog::OnClose();}响应CS3DHookDlg的WM_TIMER消息代码如下:void CS3DHookDlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call default//得到父窗口也就是记事本的指针CWnd *pCWnd = GetParent();//得到记事本的窗口设备上下文指针CDC *pDC = pCWnd->GetWindowDC();//画圆pDC->Ellipse(100,100,200,200);CDialog::OnTimer(nIDEvent);}在记事本中的实验非常成功,爽!!!!!!!!下面让我们的程序只在神迹中呼出主要是需要改造键盘钩子回调程序只需要把lstrcmpi(buf, "notepad")改为lstrcmpi(buf, "SG Engine")就可以了"SG Engine"是神迹客户端的窗口的类名重新编译运行,即可在神迹中呼出了,并且也在其中的窗口上画了个圆,但是画面在闪烁,具体解决方法还没有找到估计是因为:游戏使用DirectX作图,而我们这里是用GDI作图先不管它了,留在以后再解决了暂时我们还不需要在游戏里作图,把我们程序中刚才有关作图的部分都删除掉,1.OnInitDialog中的2.OnClose中的3.OnTimer删掉利用madCHook进行API挂接:如:WSASend,WSARecv等去这下载http://www.madshi.net/安装刚才下载的madCollection.exe,安装后注意到在C:/Program Files/madCollection/madCodeHook/Dll中有3个文件需要引入到我们的S3DHook.dll工程中去如下:madCHook - dynamic.hmadCHook - dynamic - microsoft.libmadCHook.dll为了便于使用,把他们的名字改一下,改为:madCHook.hmadCHook.libmadCHook.dll把.h和.lib放到S3DHook工程所在的文件夹中在S3DHook.cpp中包含madCHook.h头文件,加入#include "madCHook.h"在Project->Settings->Link->Object/library modules中加入madCHook.lib下面就可以在我们的DLL中使用madCHook对API进行挂接了注意:编译后要把Main.exe,S3DHook.dll和madCHook.dll放在一起才能运行下面,正式开始加入代码对WSASend进行挂接首先在S3DHook.cpp中加入#include "Winsock2.h"然后加入对原始API函数的指针及自定义API HOOK函数的原形的声明:int (WINAPI *oWSASend)(SOCKET,LPWSABUF,DWORD,LPDWORD,DWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE);int cWSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);这个一定要和原始的API函数WSASend的形参一致才行,可以参看MSDN为了把截获的数据显示出来,用资源编辑器在S3DHook中的外挂呼出窗口中加入一个ListBox,将其ID改为IDC_LIST_SEND,将其SORT属性去掉,然后加入自定义API钩子的实现int cWSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent, DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine){char buf[1024];lstrcpyn(buf,lpBuffers->buf,lpBuffers->len);CListBox *pListBox = (CListBox *)pCWndWGMain->GetDlgItem(IDC_LIST_SEND);pListBox->AddString(buf);                //API钩子返回之前,对原始的API进行调用,return oWSASend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine);}非常感谢!行舟的支持,其实在(一)中我就说过,其实我也是个菜鸟去年的这个时候在玩传奇2的私服时,当时那个私服用了"乐都"的客户端,现成的外挂一般都用不了,于是到处找外挂,无意中看到了个WS2_32.DLL的外包的源代码(C++写的),还有相关的一些文章,刚好又懂点VC,于是就利用这个改了下,在发送数据是做了点手脚,实现了如双倍魔法,攻击,通买,通卖,刷钱等等通过修改封包就可以实现的功能自己写的外挂,自己用,别人没有,自己有,那怎一个爽字了得啊:)哈哈,由于菜的原因,那个外包是WIN32的DLL,里面全部都用WIN32 API编写,麻烦,基本的对话框,控件都不知道怎么用WIN32 API去控制,弄了很久终于在里面弄了对话框可以显示出来,但是也很是兴奋了一段时间今年玩神迹的时候,也是在找外挂的时候,无意中发现了无影的神迹外挂源代码同时发现了我们这个GAMERES论坛,为了看看怎么弄的,半夜下载了个DELPHI 7.0装上,发现原来他利用的madCHook的组件,这个组件在DELPHI里用很方便,可是我不会pascal更不会DELPHI,于是又用了几天才弄明白怎么在VC中用这个madCHook.在近一个月的时间里经过多次的试验,终于大致上(有些东西还不是很清楚)知道了怎么注入在游戏进程,怎么编MFC Regular dll(可以在里面使用MFC了,比纯WIN32的DLL方便多了),怎么在里面使用对话框等资源,再加上madCHook怎么挂接API,终于自己编的东西,也勉勉强强有那么点"像"个外挂了于是心中充满了喜悦:)!!!!!!!!!!!!!!!!决定把从头把所有的东西都放到一起来,重新做了一次(以前那些都是分开试验的),也萌生了把它贴出来让大家一起分享我的喜悦:),自己一边写程序,一边帖帖子,于是就有了现在的这个帖子<菜鸟的VC6神迹外挂的DIY之路>现在回到我们的程序中来,下面我们利用madCHook安装WSASend这个API的钩子成功后,游戏每次调用WSASend这个API的时候,都会去先执行我们写的cWSASend,在这里,我们就可以截取到游戏发往服务器的数据封包,然后用游戏调用到cWSASend时使用的参数去调用我们刚才写的指向原始WSASend的函数指针oWSASend去调用原始的API将数据发到服务器,这样才能保证游戏能继续正常运行,否则游戏很有可能会掉线在CS3DHookDlg::OnInitDialog() 加入这一句来安装API钩子HookAPI("Ws2_32.dll", "WSASend", cWSASend, (PVOID *) &oWSASend);参数说明:1.要挂接的API所在的DLL2.要挂接的API3.自定义的函数,用来替换要挂接的API:cWSASend//游戏每次调用Ws2_32.dll中的WSASend,就会先进入我们自定义的cWSASend4.指向原始API函数WSASend的指针//自定义的cWSASend截取封包并进行必要处理后,通过这个指针去调用原始的WSASend@Ws2_32.dll,以保证游戏的正常运行BOOL CS3DHookDlg::OnInitDialog() {CDialog::OnInitDialog();// TODO: Add extra initialization hereHookAPI("Ws2_32.dll", "WSASend", cWSASend, (PVOID *) &oWSASend);return TRUE;  // return TRUE unless you set the focus to a control              // EXCEPTION: OCX Property Pages should return FALSE}编译之后,把Main.exe S3DHook.dll madCHook.dll放在一起,看看效果运行Main.exe,启动进入神迹,按F12呼出令人激动的时刻啊!看到没有?截获的数据封包已经在ListBox控件中显示出来了!!!其实这才是刚刚开始,要想有强大的功能,后面还要做许多工作另外,创建“外挂呼出窗口”时,要注意为它选好父窗口,不同的游戏不一样,记得传奇2中把游戏界面的那个窗口作为“外挂呼出窗口”就不行,要选他的父窗口才行,具体情况要自己用SPY++多看看

返回顶部
查看电脑版