• VC6神迹外挂的DIY


     

    2014年09月05日 ⁄ 综合 ⁄ 共 8724字 ⁄ 字号    ⁄ 评论关闭

    (一)外挂一般都能在游戏的界面中按一个热键(比如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 here
    InstallHook
    UninstallHook
    如此,问题便得到解决!

    把有关外挂功能的代码和“钩子”函数一起放到同一个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放到同一个文件夹中,运行
    这个是DLLsf_20046314251.rar 
    这个是EXEsf_200463142551.rar

    下面我们在S3DHook这个DLL工程中添加一个从CDialog派生的CS3DHookDlg类

    把DIALOG ID改为IDD_S3DHOOK_DIALOG

    添加的对话框类的操作如下
    主菜单->Insert->New Form

    为了方便,把CS3DHookDlg的源程序文件名字分别改为
    s3dhook.h
    s3dhook.cpp

    操作:点上图中的Chang

    把刚才自动生成的对话框的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());
    更多说明请参看
    这里
    当关掉外挂的主程序时,还要做点善后工作
    重载CS3DHookApp类的ExitInstance函数,在其中删除对话框
    int CS3DHookApp::ExitInstance() 
    {
    // TODO: Add your specialized code here and/or call the base class
    delete pCWndWGMain;
    return CWinApp::ExitInstance();
    }
    重新编译生成S3DHOOK.dll并和Main.exe放到一起,运行它试试看

    运行后,随便打开一个其他的什么窗口,按F12,看到什么了?

    哈哈,我们的"外挂呼出窗口"呼出来了,真是千呼万唤始出来啊

    我在记事本中试了试:


    Main.exe和s3dhook.dll在这里: sf_200463194336.rar
    要让他只在指定的程序窗口中呼出,每次都进神迹的游戏客户端试验很麻烦
    我们就在记事本中试验,让他只能在记事本中呼出,最好还要能像真正的外挂那样
    对挂入的程序做点手脚,
    说做就做,开工!!!
    继续对钩子回调函数进行改造
    如下:
    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

    本主题包含附件: sf_200463202334.rar

    哈哈,解决了一个小问题,爽!!!!!!!!!!!!!
    下面让我们的外挂对记事本做点小动作吧!
    做点什么呢?
    就让他在记事本的窗口中画个圆,怎么样?
    来试试看了
    为CS3DHookDlg添加WM_INITDIALOG的消息处理器
    并在其中添加一个定时器,同时窗口关闭时要销毁定时器
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    设置
    BOOL CS3DHookDlg::OnInitDialog() 
    {
    CDialog::OnInitDialog();

    // TODO: Add extra initialization here
    SetTimer(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 default
    KillTimer(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);
    }

    效果如图:

    下面是重新编译过的程序

    本主题包含附件: sf_200463212057.rar

    在记事本中的实验非常成功,爽!!!!!!!!
    下面让我们的程序只在神迹中呼出
    主要是需要改造键盘钩子回调程序
    只需要把
    lstrcmpi(buf, "notepad")
    改为
    lstrcmpi(buf, "SG Engine")
    就可以了
    "SG Engine"是神迹客户端的窗口的类名
    重新编译运行,即可在神迹中呼出了,并且也在其中的窗口上画了个圆,
    但是画面在闪烁,具体解决方法还没有找到
    估计是因为:游戏使用DirectX作图,而我们这里是用GDI作图
    先不管它了,留在以后再解决了
    暂时我们还不需要在游戏里作图
    ,把我们程序中刚才有关作图的部分都删除掉,
    1.OnInitDialog中的
    2.OnClose中的
    3.OnTimer删掉

    利用madCHook进行API挂接:如:WSASend,WSARecv等

    到这里去下载
    安装刚才下载的madCollection.exe,安装后注意到在
    C:/Program Files/madCollection/madCodeHook/Dll
    中有3个文件需要引入到我们的S3DHook.dll工程中去
    如下:
    madCHook - dynamic.h
    madCHook - dynamic - microsoft.lib
    madCHook.dll
    为了便于使用,把他们的名字改一下,改为:
    madCHook.h
    madCHook.lib
    madCHook.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);
    }
    下面我们利用madCHook安装WSASend这个API的钩子
    成功后,游戏每次调用WSASend这个API的时候,都会去先执行我们写的
    cWSASend,在这里,我们就可以截取到游戏发往服务器的数据封包,然后用游戏调用到cWSASend时使用的参数去调用我们刚才写的指向原始WSASend的函数指针oWSASend去调用原始的API将数据发到服务器,这样才能保证游戏能继续正常运行,否则游戏很有可能会掉线

    在CS3DHookDlg::OnInitDialog() 加入这一句来安装API钩子
    HookAPI("Ws2_32.dll", "WSASend", cWSASend, (PVOID *) &oWSASend);
    参数说明:
    1.要挂接的API所在的DLL
    2.要挂接的API
    3.自定义的函数,用来替换要挂接的API:cWSASend//游戏每次调用Ws2_32.dll中的WSASend,就会先进入我们自定义的cWSASend
    4.指向原始API函数WSASend的指针//自定义的cWSASend截取封包并进行必要处理后,通过这个指针去调用原始的WSASend@Ws2_32.dll,以保证游戏的正常运行
    BOOL CS3DHookDlg::OnInitDialog() 
    {
    CDialog::OnInitDialog();

    // TODO: Add extra initialization here
    HookAPI("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控件中显示出来了!!!

    其实这才是刚刚开始,要想有强大的功能,后面还要做许多工作

  • 相关阅读:
    【Codecs系列】之NVIDIA Jetson TX1简介
    【Life系列】之工作与生活的关系《赢在下班后》
    【Bugs系列】之could not find or load the Qt platform plugin windows解决方案
    【Books系列】之第一本书:大冰《好吗好的》读书笔记和读后感
    【Qt系列】之Qt之打包发布
    【Life系列】之我在底层的生活
    【Life系列】之关于工作和生活的思考与反思
    【Tools系列】之WORD转成PDF并生成书签
    【Tools系列】之Excel冻结窗格
    【Script系列】之CMake学习总结
  • 原文地址:https://www.cnblogs.com/cfas/p/5112061.html
Copyright © 2020-2023  润新知