• 308阅读
  • 0回复

任鸟飞游戏安全之<魔域>扫拍 [复制链接]

上一主题 下一主题
离线任鸟飞
 

之前,我们讲了内存遍历商行数据进行扫拍。

但是天下武功,唯快不破,1-2ms的延时都会决定成败,所以更多的外挂高手,在写扫拍挂,抢怪挂和躲避技能挂等极度追求速度的外挂时,往往都是从收包函数入手的。
为什么呢?快!客户端是先收到封包,然后对封包解密,再将信息分配写入内存,最后通过写屏等函数显示到我们面前的。
由此可见,收包最快,内存次之,模拟最慢。


以扫拍为例
处理的思路很简单,开两条线程
一条线程不断的发送刷新拍卖行封包(不懂怎么发送封包?不懂怎么分析封包?以后会有专题讲解),注意频率,一般情况下服务器都会有验证,高频率发包会被踢下线。10ms刷新一次 ,还是30ms刷新一次 要自己测试服务器的设定,魔域应该是低于40ms,一会就会掉线。细心的同学应该会想到,那这个刷新延时40ms没有办法去掉吗?这是个不短的时间啊,只有一个办法,开多个账号同时扫拍,概率学告诉我们,如果10个账号同时扫拍,那么每个刷新封包的间隔就变成了4ms左右。


另外一条线程,HOOK收包函数,对收到的封包进行解密,判断到是我们需要的封包信息时发送购买封包。

  1. hook recv 我们不需要HOOK函数本身,hook函数调用结束的位置即可,返回的eax是真实接收的包长,buffer里是接收到的封包。

  2. 封包解密,我们需要找到游戏的解密CALL,方法很简单,在加密封包上下访问断,游戏想解密加密封包,就一定会访问加密封包,在断下的位置一一分析即可,当然不排除多次的memmove,那样我们就要到新的内存上继续下访问断。
    值得提的是,如果解密CALL没有被严重VM那么还是把功能偷出来自己解密更效率也更妥当。

  3. 判断封包就很简单了,通过包头字节可以判断出来封包的信息,封包里会有商行物品的所有信息,满足我们要求的物品,毫不犹豫,买!当然解密之后的封包也有可能不是一个包,可能存在粘包,我们还需要根据包头的buffersize 进行拆包等等简单的操作。

做了以上的所有操作,在网络足够优秀的前提下,扫拍,抢怪,躲避技能是多么简单的一件事,例如<魔域>扫拍,天涯明月刀抢怪,LOL躲避技能,都是一样的思路。




***************************************刷新商行信息线程


void Refresh()
{
    byte p[]={0x10, 0x00, 0xF7, 0x03, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x01, 0x01,\
        0x03, 0x30, 0x20, 0x30, 0x00}; //刷新商行封包
    HMODULE 窗口句柄=GetModuleHandleA("3DRole.dll");
    DWORD Base=(DWORD)窗口句柄+0x837318;
    DWORD CallAddr=(DWORD)窗口句柄+0x25E9C2;
    char * P=(char *)p;


    __asm //调用明文发包CALL 进行发包
    {
        pushad
            push 0x10
            push P
            mov ecx,Base
            mov eax,CallAddr
            call eax
            popad
    }
    DbgPrint_Mine("发送刷新封包");
}
void 刷新线程()
{
    AAA=0;
    while (AAA==0)
    {
        Refresh();
        Sleep(45);//控制在 40以上  否则会掉线
    }
}




********************************************HOOK recv



void Hook() //HOOK收包
{
    DWORD dwHookAddr = (DWORD)Handle+0x263A4C;
    DWORD dwTargetAddr = (DWORD)HookCall;
    EnableDebugPrivilege(TRUE);//提升EXE权限
    DWORD h窗口句柄=*(DWORD*)((DWORD)Handle+0x88E9B4);
    DbgPrint_Mine("窗口句柄:%x",h窗口句柄);
    DWORD pid=NULL;
    DWORD WriteSize=NULL;
    GetWindowThreadProcessId((HWND)h窗口句柄,&pid);//获得进程ID
    g_进程ID=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);//打开进程
    DbgPrint_Mine("进程ID:%x",g_进程ID);
    byte Temp=0xE9;
    WriteProcessMemory(g_进程ID,(LPDWORD)(dwHookAddr + 0x00),&Temp,1,&WriteSize);
    DWORD Temp1=dwTargetAddr - dwHookAddr - 5;
    WriteProcessMemory(g_进程ID,(LPDWORD)(dwHookAddr + 0x01),&Temp1,4,&WriteSize);
    byte Temp2=0x90;
    WriteProcessMemory(g_进程ID,(LPDWORD)(dwHookAddr + 0x05),&Temp2,1,&WriteSize);
}


************************************************信息判断


__declspec(naked) void HookCall()//裸函数    HOOK明文包子程序
{
    __asm
    {
        push eax
            mov eax,[ebp-0x8]
        mov g_包地址,eax
            mov eax,[ebp-0x24]
        add g_包地址,eax
            add g_包地址,0xC
            mov eax,[ebp-0x4]
        mov g_包长,eax
            pop eax
            pushad
    }
    do
    {
        w标志位1=*(WORD*)(g_包地址+0x2);
        w标志位2=*(WORD*)(g_包地址+0x8);
        if (w标志位1==0x03F7&&w标志位2==0x01EA)
        {
            w标志位3=*(WORD*)(g_包地址+0xC);
            if (w标志位3==0x2030)
            {
                //DbgPrint_Mine("包 最低价格是系统!!!");
                i=0;
                do
                {
                    b标志位4=*(BYTE*)(g_包地址+0xE+i);    
                    i=i+1;        
                } while (b标志位4!=0x20);


                ID=atoi((char*)(g_包地址+0xE));
                金币=atoi((char*)(g_包地址+0xE+i+0x7));
                if (金币<5000&&金币>0)
                {
                    DbgPrint_Mine("包  i:%d   ID:%d  金币:%d ",i,ID,金币);
                    WORD 包长A=0x17;
                    BYTE 包长B=0xA;
                    if (i==3)
                    {
                        包长A=0x18;
                        包长B=0xB;
                    }
                    if (i==4)
                    {
                        包长A=0x19;
                        包长B=0xC;
                    }


...
...
...
这里只展示部分技术研究测试代码,以防止对游戏造成伤害。
有兴趣的同学可以自行研究。
不懂的地方可以留言 会一一解答。


关注微信公众号:任鸟飞逆向
快速回复
限100 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
上一个 下一个