宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 3965|回复: 1

[转贴] 通过调试寄存器不修改代码实现网络游戏中的bt功能

[复制链接]
  • TA的每日心情
    开心
    2024-12-9 18:45
  • 签到天数: 124 天

    [LV.7]常住居民III

    admin 发表于 2010-9-28 21:03:39 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
    首先分析要中断的位置

        .text:00588F78 mov    ecx, [esp+30h+arg_0]
        .text:00588F7C push    esi            ; size_t
        .text:00588F7D push    ecx            ; void *
        .text:00588F7E push    eax            ; void *
        .text:00588F7F call    ds:memmove

    上面是发包函数里的部分代码,其中00588F7D位置ecx存储封包数据地址,00588F7C位置esi存储封包大小。
    如果在此处将程序中断,并将所需数据读取出来,目的就达到了。

    对于变态功能,以空中漫步为例:

        .text:00461792 mov    eax, [ecx+5E0h]
        .text:00461798 fild    [esp+10h+var_8]
        .text:0046179C cmp    eax, ebx
        .text:0046179E fmul    ds:flt_85EC2C
        .text:004617A4 fstp    [esp+10h+arg_0]
        .text:004617A8 jz      short loc_461828

    修改004617A8处的跳转就可以空中漫步,如果在0046179C处中断,然后修改eax或者ebx的值,也可以实现相应功能但不需要修改指令(注意跳转过后要记得恢复寄存器的值,隐藏建筑和跳跃飞天也可以这样实现)。


    下面是封包截取的实现过程,修改一下即可实现bt功能。

    1.CreateProcess或者FindWindow或者完美进程ID(dwW2iProcessId)

    2.调试进程DebugActiveProcess(dwW2iProcessId)

    3.进入调试循环体等待调试事件产生WaitForDebugEvent(&DebugEv, 10)

    4.接收到CREATE_PROCESS_DEBUG_EVENT事件时,对全部线程设立断点。
    (我可能复杂了,用CREATE_THRAD_DEBUG_EVENT事件可能简单些,刚会用就不错了呵呵,开始我只在主线程里设置了断点,死活断不下来)

    下面是设置断点的方法,使用GetThreadContext和SetThreadContext函数
    对于bt功能,修改寄存器的值,也通过这两个函数来实现。

        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadInfo.th32ThreadID);
        SuspendThread(hThread);

        CONTEXT Regs = {0};
        Regs.ContextFlags = CONTEXT_DEBUG_REGISTERS; //CONTEXT_DEBUG
        ::GetThreadContext(hThread, &Regs);

        Regs.Dr0 = W2I_SENDCALL_ADDR1; //中断地址
        Regs.Dr7 = BREAK_DR7_FLAG; //0x401启用dr0断点

        ::SetThreadContext(hThread, &Regs);

        ResumeThread(hThread);
        CloseHandle(hThread);

    5.当在所需地址处中断时,来进行我们真正的功能操作,读取数据或者设置数据,同时设置数据改回处的断点。

        ReadProcessMemory(hW2iProcess, (void*)Regs.Ecx, buf, len, &len);

    6.当在数据改回处中断时,将寄存器值恢复,并设置修改处断点(其实可以一起设置好,但是要占用两个dr寄存器。dr寄存器一共4个,所以节省下只用一个,这样最多也只可以实现4个中断功能,不知道说清楚没)

    7.当完美进程结束时,响应EXIT_PROCESS_DEBUG_EVENT事件,也退出。

    注意每次中断时要用ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus)继续。

    这就是整个过程,其实修改代码也不一定不防封。个人理解游戏协议分为两大类,封包是其实现,一类是正常的游戏所需数据,一类是防止辅助的检测协议。(始终要记得,网络游戏,服务器所需的一切数据必是通过网络来传输,必是通过封包来运载。)如果是检测协议,就回复一个正常结果的检测包,必能防封,所以说脱机挂是最难封的,因为这建立在全部协议破解的基础上。想当初传神和赤月挂,因为技术上无法封杀,只好派人去抓程序员了。

    不修改代码也不一定防封,反调试的技术也很多,具体我还不清楚呵呵。



    下面是截包程序的代码:


    #include <windows.h>
    #include <stdio.h>
    #include <tlhelp32.h>
    #include <conio.h>

    #define W2I_WINDOW_TITLE TEXT("Element Client")
    #define W2I_WINDOW_CLASS TEXT("ElementClient Window")

    //#define W2I_WINDOW_TITLE NULL
    //#define W2I_WINDOW_CLASS TEXT("Notepad")

    #define W2I_SENDCALL      0x00588EF0

    #define W2I_SENDCALL_ADDR1      (W2I_SENDCALL+0x8E)
    #define W2I_SENDCALL_ADDR2      (W2I_SENDCALL+0x8F)

    #define BREAK_DR7_FLAG          0x401

    int main(int argc, char* argv[])
    {
        HANDLE hW2iProcess;
        DWORD dwW2iProcessId;
        HWND hW2iWnd;
        DWORD Count = 0;


        //查找窗口,并且获取窗口进程线程ID
        hW2iWnd = ::FindWindow(W2I_WINDOW_CLASS, W2I_WINDOW_TITLE);

        if( hW2iWnd>0 && ::GetWindowThreadProcessId(hW2iWnd, &dwW2iProcessId)
            && dwW2iProcessId && ( hW2iProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwW2iProcessId) )
            && DebugActiveProcess(dwW2iProcessId) )
        {
            DEBUG_EVENT DebugEv;
            DWORD dwContinueStatus;

            while(TRUE)
            {
                if(WaitForDebugEvent(&DebugEv, 10))
                {
                    dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

                    switch(DebugEv.dwDebugEventCode)
                    {
                    case EXCEPTION_DEBUG_EVENT:
                        {
                            if((DWORD)DebugEv.u.Exception.ExceptionRecord.ExceptionAddress==W2I_SENDCALL_ADDR1)
                            {
                                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEv.dwThreadId);
                                SuspendThread(hThread);

                                CONTEXT Regs = {0};
                                Regs.ContextFlags = CONTEXT_DEBUG_REGISTERS|CONTEXT_INTEGER;
                                ::GetThreadContext(hThread, &Regs);

                                Regs.Dr0 = W2I_SENDCALL_ADDR2;
                                Regs.Dr7 = BREAK_DR7_FLAG;

                                printf("%d\n", Count++);
                                //Regs.Esi - len
                                //Regs.Ecx - buf
                                BYTE buf[1024];
                                SIZE_T len = (Regs.Esi<512 ? Regs.Esi : 512);
                                if( ReadProcessMemory(hW2iProcess, (void*)Regs.Ecx, buf, len, &len) )
                                {
                                    FILE * fp = fopen("Cap.txt", "a+");
                                    for(SIZE_T i=0; i<len; i++)
                                    {
                                        printf("%02X ", buf);
                                        if(fp)
                                            fprintf(fp, "%02X ", buf);
                                    }
                                    printf("\n\n");
                                    if(fp)
                                    {
                                        fprintf(fp, "\n\n");
                                        fclose(fp);
                                    }
                                }

                                ::SetThreadContext(hThread, &Regs);

                                ResumeThread(hThread);
                                CloseHandle(hThread);
                            }

                            if((DWORD)DebugEv.u.Exception.ExceptionRecord.ExceptionAddress==W2I_SENDCALL_ADDR2)
                            {
                                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEv.dwThreadId);
                                SuspendThread(hThread);

                                CONTEXT Regs = {0};
                                Regs.ContextFlags = CONTEXT_DEBUG_REGISTERS; //CONTEXT_DEBUG
                                ::GetThreadContext(hThread, &Regs);

                                Regs.Dr0 = W2I_SENDCALL_ADDR1;
                                Regs.Dr7 = BREAK_DR7_FLAG;

                                ::SetThreadContext(hThread, &Regs);

                                ResumeThread(hThread);
                                CloseHandle(hThread);
                            }

                            dwContinueStatus = DBG_CONTINUE;
                            break;
                        }

                    case CREATE_PROCESS_DEBUG_EVENT:
                        {
                            HANDLE hSnapshot = NULL;
                            THREADENTRY32 ThreadInfo = { sizeof(THREADENTRY32) };

                            hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
                            if(hSnapshot>0)
                            {
                                if(Thread32First(hSnapshot, &ThreadInfo))
                                {
                                    do {
                                        if(ThreadInfo.th32OwnerProcessID==dwW2iProcessId)
                                        {
                                            //printf("%08x %08x\n", ThreadInfo.th32ThreadID, ThreadInfo.th32OwnerProcessID);

                                            HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadInfo.th32ThreadID);
                                            SuspendThread(hThread);

                                            CONTEXT Regs = {0};
                                            Regs.ContextFlags = CONTEXT_DEBUG_REGISTERS; //CONTEXT_DEBUG
                                            ::GetThreadContext(hThread, &Regs);

                                            Regs.Dr0 = W2I_SENDCALL_ADDR1;
                                            Regs.Dr7 = BREAK_DR7_FLAG;

                                            ::SetThreadContext(hThread, &Regs);

                                            ResumeThread(hThread);
                                            CloseHandle(hThread);
                                        }
                                    } while(Thread32Next(hSnapshot, &ThreadInfo));
                                }
                                CloseHandle(hSnapshot);
                            }


                            printf("附加到完美进程成功!\n截获文件将保存到Cap.txt\n\n");

                            break;
                        }

                    case EXIT_PROCESS_DEBUG_EVENT:
                        {
                            return 0;
                            break;
                        }
                    }

                    ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus);
                }
            }
        }
        else
        {
            printf("附加到完美进程失败!\n\n");
        }

        printf("\n按任意键退出!\n");
        getch();

        return 0;
    }

    该用户从未签到

    jianxirn2010 发表于 2010-10-23 23:33:54 | 显示全部楼层
    很好很强大就是看不懂
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 22:59 , File On Powered by Discuz! X3.49

    快速回复 返回顶部 返回列表