首页
社区
课程
招聘
[原创](某游戏登录流程)(自己没有耐心搞下去了)(祝大家虎年行大运)
发表于: 2010-2-11 16:13 11068

[原创](某游戏登录流程)(自己没有耐心搞下去了)(祝大家虎年行大运)

2010-2-11 16:13
11068

//  这里是游戏界面的加解密
__declspec(naked) VOID EnDePackEx(PBYTE pbyBuffer, int nLen, PBYTE pbyKEY, int nKeyLen)
{
    __asm
    {
        mov     eax, dword ptr [esp+8]
        xor     ecx, ecx
        xor     edx, edx
        test    eax, eax
        jbe     RETURN
        push    ebx
        push    ebp
        mov     ebp, dword ptr [esp+0x14]
        push    esi
        mov     esi, dword ptr [esp+0x10]
        push    edi
        mov     edi, dword ptr [esp+0x20]
        lea     esp, dword ptr [esp]

LABEL:

        mov     bl, byte ptr [ecx+ebp]
        xor     byte ptr [edx+esi], bl
        add     ecx, 1
        cmp     ecx, edi
        jb      LABEL1
        xor     ecx, ecx

LABEL1:

        add     edx, 1
        cmp     edx, eax
        jb      LABEL
        pop     edi
        pop     esi
        pop     ebp
        pop     ebx

RETURN:

        retn
    }
}

//  这里是登录界面的加解密
__declspec(naked) VOID EnDePack(PBYTE pbyBuffer, int nLen, PBYTE pbyKEY, int nKeyLen)
{
    __asm
    {
        push    esi                          
        mov     esi, dword ptr [esp+0xC]
        shr     esi, 1
        mov     eax, 0
        mov     ecx, eax
        je      RETURN
        mov     edx, dword ptr [esp+8]
        push    ebx
        mov     ebx, dword ptr [esp+0x14]
        push    ebp
        push    edi
        mov     edi, dword ptr [esp+0x20]
        shr     edi, 1

LABLE:

        mov     bp, word ptr [ebx+eax*2]
        xor     word ptr [edx+ecx*2], bp
        add     eax, 1
        cmp     eax, edi
        jb      LABLE1
        xor     eax, eax

LABLE1:

        add     ecx, 1
        cmp     ecx, esi
        jb      LABLE
        pop     edi
        pop     ebp
        pop     ebx

RETURN:

        lea     eax, dword ptr [esi+esi]
        pop     esi
        retn
    }
}

//  效验封包头
DWORD WINAPI GetCheckPack(PBYTE pbyBuffer)
{
    DWORD   dwResult = 0;
    WORD    nLen = *(PWORD)ULongToPtr(&pbyBuffer[0]);

    int i = 0;
    if ( nLen > 0 )
    {
        do
        {
            dwResult += *(PBYTE)ULongToPtr(&pbyBuffer[i]);
            --nLen;
            i ++;
        } while (nLen);
    }

    return dwResult;
}

//  修改KEY
VOID WINAPI ChangeKEY(PBYTE pbyKEY)
{
    for ( int i = 0; i < 0x10; i ++ )
        pbyKEY[i] = pbyKEY[i] + i;
}

//  加密发送封包
VOID CGameSend::EnSend(PSOCKET_ENGINE pSE, PBYTE pbyBuffer, int nLen)
{
    DWORD dwResult = GetCheckPack(pbyBuffer);

    *(PWORD)ULongToPtr(&pSE->bySendBuffer[0])   = nLen + 8;
    *(PWORD)ULongToPtr(&pSE->bySendBuffer[2])   = 0x0007;
    *(PDWORD)ULongToPtr(&pSE->bySendBuffer[4])  = dwResult;

    memcpy(&pSE->bySendBuffer[8], pbyBuffer, nLen);

    ((VOID (*)(PBYTE, int, PBYTE, int))ULongToPtr(pSE->pEnDeCode))(&pSE->bySendBuffer[4], nLen + 4, pSE->bySendKEY, 0x10);

    pSE->nSendLen = nLen + 8;

    send(pSE->Socket, (const char *)pSE->bySendBuffer, pSE->nSendLen, 0);
    ChangeKEY(pSE->bySendKEY);
}

//  发送加密解密KEY
VOID CGameSend::OnSendKEY(PSOCKET_ENGINE pSE)
{
#pragma pack(1)
    typedef struct
    {
        WORD  wSize;
        WORD  wHead;
        BYTE   byKEY[0x10];
        DWORD dwUnknow;
    } SEND_ENDEKEY, *PSEND_ENDEKEY;
#pragma pack()

    SEND_ENDEKEY    SENK;

    SENK.wSize      = 0x0018;
    SENK.wHead      = 0x0008;

    //  自己创建一个KEY发送给服务器
    for ( int i = 0; i < 0x10; i ++ )
    {
        SENK.byKEY[i] = 1;
    }

    SENK.dwUnknow = 0x01010101;

    //  记录这个KEY
    memcpy(pSE->bySendKEY, (BYTE *)&SENK, 0x10);

    send(pSE->Socket, (const char *)&SENK, 0x18, 0);

}

//  发送心跳包
VOID CGameSend::OnKeepLive(PSOCKET_ENGINE pSE, PPACK_INFOEX pPI)
{
#pragma pack(1)
    typedef struct
    {
        WORD wSize;
        WORD wHead;
        WORD wNum;
        WORD wUnknow;
    } SEND_DATA, *PSEND_DATA;
#pragma pack()

    SEND_DATA SD;
    SD.wSize    =   0x0008;
    SD.wHead    =   0x000B;
    SD.wNum     =   (WORD)pPI->dwPackCheck;
    SD.wUnknow  =   0;

    send(pSE->Socket, (const char *)&SD, sizeof(SD), 0);
}

//  发送登录帐号包
VOID CGameSend::OnSendAccount(PSOCKET_ENGINE pSE)
{
#pragma pack(1)
    typedef struct
    {
        WORD   wSize;
        WORD   wHead;
        DWORD  dwVersion;
        char   szAccount[51];
        char   szPassword[21];
    } SEND_ACCOUNT_PACK, *PSEND_ACCOUNT_PACK;
#pragma pack()

    SEND_ACCOUNT_PACK SAP;

    memset(&SAP, 0, sizeof(SAP));

    SAP.wSize       = 0x0050;
    SAP.wHead       = 0x0201;
    SAP.dwVersion   = m_dwVersion;
    memcpy(SAP.szAccount, m_LC.szName, lstrlen(m_LC.szName));
    memcpy(SAP.szPassword, m_LC.szPass, lstrlen(m_LC.szPass));

    EnSend(pSE, (PBYTE)&SAP, sizeof(SAP));
}

//  选择线路
VOID CGameSend::OnSelectLine(PSOCKET_ENGINE pSE)
{
//  0x05, 0x00, 0x07, 0x02, 0x09
#pragma pack(1)
    typedef struct
    {
        WORD wSize;
        WORD wHead;
        BYTE byLine;
    } SEND_DATA, *PSEND_DATA;
#pragma pack()

    SEND_DATA SD;

    SD.wSize    = 0x0005;
    SD.wHead    = 0x0207;
    SD.byLine   = m_LC.bySelectLine;

    EnSend(pSE, (PBYTE)&SD, sizeof(SD));
   
}

//  开始游戏
VOID CGameSend::OnStartGame(PSOCKET_ENGINE pSE, PPACK_INFO pPI)
{
#pragma pack(1)
    typedef struct
    {
        WORD    wLen;
        WORD    wHead;
        DWORD   dwUnknow1;
        DWORD   dwUnknow2;
        WORD    wUnknow3;

        WORD    wNum;

        struct
        {
            DWORD   dwAccID;
            DWORD   dwSID;
            char    szName[24];
            DWORD   dwUnknow4;
            DWORD   dwProfessional; //  职业
            BYTE    byUnknow5[59];

        } LIST[8];  //  最多8个人物

    } RECV_DATA, *PRECV_DATA;
#pragma pack()

#pragma pack(1)
    typedef struct
    {
        WORD    wLen;
        WORD    wHead;
        DWORD   dwAccID1;
        DWORD   dwAccID2;

    } SEND_DATA, *PSEND_DATA;
#pragma pack()

    PRECV_DATA pRD = (PRECV_DATA)pPI;

    SEND_DATA  SD;
    SD.wLen         = sizeof(SD);
    SD.wHead        = 0x030A;
    SD.dwAccID1     = pRD->LIST[m_LC.bySelectPlayerLocation].dwAccID;
    SD.dwAccID2     = pRD->LIST[m_LC.bySelectPlayerLocation].dwSID;

    EnSend(pSE, (PBYTE)&SD, sizeof(SD));

}

//  进入游戏
VOID CGameSend::OnEnterGame(PSOCKET_ENGINE pSE)
{

#pragma pack(1)
    typedef struct
    {
        WORD    wSize;
        WORD    wHead;
        DWORD   dwEnterID1;
        DWORD   dwEnterID2;
        DWORD   dwVersion;
        BYTE    byGMID[16];

    } SEND_DATA, *PSEND_DATA;
#pragma pack()

    SEND_DATA       SD;
   
    SD.wSize        = 0x0020;
    SD.wHead        = 0x0301;
    SD.dwEnterID1   = m_dwEnterID1;
    SD.dwEnterID2   = m_dwEnterID2;
    SD.dwVersion    = m_dwVersion;

    //  这个是进入游戏包,版本更新也得更新
    BYTE byBuffer[16] = {   0xC4, 0x75 ,0x29, 0xF0, 0xB2, 0x76, 0x24, 0x81, 0xE2, 0x21,
                            0x01, 0x5F, 0x84, 0xB0, 0x70, 0x2A};

    memcpy(SD.byGMID, byBuffer, 16);

    EnSend(pSE, (PBYTE)&SD, sizeof(SD));
}

VOID CGameRecv::DeRecvPack(PSOCKET_ENGINE pSE, PPACK_INFOEX pPIEX)
{
    switch ( pPIEX->wTag + -1  )
    {
        //  5的标志不用解密,用于心跳
        case 0x0005:
        {
            OnKeepLive(pSE, pPIEX);
        }
        break;
        //  接收验证KEY
        case 0x0007:
        {
            memcpy(pSE->byRecvKEY, (PBYTE)pPIEX, 0x10);

            //  发送加解密KEY给游戏
            OnSendKEY(pSE);
        }
        break;

        //  只需要解密
        case 0x0006:
        {
            ((VOID (*)(PBYTE, int, PBYTE, int))ULongToPtr(pSE->pEnDeCode))((BYTE *)&pPIEX->dwPackCheck, pPIEX->wSize - 4,  pSE->byRecvKEY, 0x10);
            ChangeKEY(pSE->byRecvKEY);
            OnRecv(pSE, (PPACK_INFO)&pPIEX->wLen);
        }
        break;

        //  需要解密并解压缩
        case 0x000D:
        {
            ((VOID (*)(PBYTE, int, PBYTE, int))ULongToPtr(pSE->pEnDeCode))((BYTE *)&pPIEX->dwPackCheck, pPIEX->wSize - 4,  pSE->byRecvKEY, 0x10);

            PBYTE pbyBuffer = new BYTE[pPIEX->wLen];

            uncompress(pbyBuffer, (ULONG *)&pPIEX->wLen, (LPVOID)&pPIEX->wHead, pPIEX->wSize - 0xA);

            ChangeKEY(pSE->byRecvKEY);

            OnRecv(pSE, (PPACK_INFO)pbyBuffer);

            
            
            delete pbyBuffer;

            

        }
        break;

    }

}

//  获得进入游戏ID
VOID CGameRecv::OnGetEnterID(PSOCKET_ENGINE pSE, PPACK_INFO pPI)
{
    m_dwEnterID1 = *(PDWORD)(&pPI->byBuffer[8]);
    m_dwEnterID2 = *(PDWORD)(&pPI->byBuffer[0]);
}

VOID CGameRecv::OnRecv(PSOCKET_ENGINE pSE, PPACK_INFO pPI)
{

    //ClientMain->PackPrint("接收", (PBYTE)pPI, pPI->wLen);

    switch (pPI->wHead)
    {
        //  登录状态处理
        case 0x0202:
            //  数据开始 作为标识
            //  C 代表线路堵塞?
            //  D 代表版本好错误
            //  2 代表密码错误
            //  6 代表人物还在游戏中
            
        break;
        //  发送帐号进入消息
        case 0x0206:
            OnSendAccount(pSE);
        break;
        //  选择线路
        case 0x0205:
            OnSelectLine(pSE);
        break;

        //  开始游戏
        case 0x0208:
            OnGetEnterID(pSE, pPI);
        break;

        //  进入游戏
        case 0x0302:
            OnEnterGame(pSE);
        break;

        //  开始游戏
        case 0x0307:
            OnStartGame(pSE, pPI);
        break;

        //  开始游戏成功
        case 0x0303:
        break;

        //  初始化人物数据
        case 0x0310:
        break;

        //  自身或周围玩家信息
        case 0x1501:
        break;

    }
}

具体登录流程
连接服务器->接收服务器发来的解密KEY->本地生成一个解密KEY(用于服务器解密客户发送过去的封包)->发送给服务器->发送登录包(上面代码里有)->服务器返回人物信息(部分封包都采用压缩函数去压缩的,所以还需要解压缩封包才能使用,使用"zlib1.dll"的"uncompress"函数)->然后就各显神威吧.

搞这游戏真是觉得有点耐不住性子了..
希望这些代码对有些人有用..
准备过年了...祝大家虎年行大运,财源滚滚,虎气冲天,天天开心!


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 2242
活跃值: (488)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
2
过年了大家都喜欢爆料这些
2010-2-11 16:17
0
雪    币: 152
活跃值: (106)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
恩!~强大...
2010-2-11 20:55
0
雪    币: 293
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
是Wof......?
2010-2-11 22:10
0
雪    币: 200
活跃值: (307)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
是。。。。。。。。。。。。。d*f
2010-2-11 22:16
0
雪    币: 215
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
猛人啊
2010-2-12 11:13
0
雪    币: 197
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
厉害
2010-2-12 13:42
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
8
太厉害了~~
2010-2-12 16:57
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
强大的水牛。。
2010-2-12 17:18
0
雪    币: 262
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
强大的水牛。。
2011-1-14 06:33
0
雪    币: 190
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
mark记录一下!
2011-7-5 17:52
0
雪    币: 241
活跃值: (67)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
mark记录一下!
2011-7-8 09:08
0
雪    币: 255
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
强大,感谢楼主分享精神,mark一下有精力的时候再研究
2011-7-17 07:20
0
游客
登录 | 注册 方可回帖
返回
//