吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 18420|回复: 58
收起左侧

[其他原创] 讲一下逆向分析在编程中的应用吧

 关闭 [复制链接]
datochan 发表于 2009-2-17 12:04
本文适合还没有入门的新朋友上手用的,所以,各位大牛就可以飘过不看它了!

     游戏的服务器列表更新了,而存服务器信息的XML在游戏的更新服务器上加密保存的,没能力分析它的解密算法,就想写个程序,从内存里读出来,工作量就是那么多,不如索性做成教程,分享给像我一样刚刚入门的朋友,说不定就又能混一篇精华,哈哈……

       其实真的不知道该给这个破烂起个什么名字了,怎么看怎么感觉在教人做外挂¥%#¥%
界面.jpg

      不多废话,进入主题,我现在要找服务器列表,当然就要先从内存里搜一个服务器的名字(别的信息不知道,只能搜名字了!)
搜索.jpg

OD里的数据区中看一下这几个地址,确定,第一个地址也就是:01329F6C
就是我们像要的地址了,至于为什么,你看一下就可以知道了(因为第一个在一个结构体数组里,其他的都是独立的,所以第一个是!)。

好了,在OD里,来到01329F6C这个地址,在第一个DWORD上下内存访问断点:
内存断点.jpg

来到这里:
断下的地方.jpg

现在我们需要知道的是,EAX的内容是从哪里来的,所以向上看:
0040CA3B  |> \8BC2          |mov     eax, edx                        ;  1
是EDX给的EAX,再向上:
0040CA17  |.  8B83 18010000   |mov     eax, dword ptr [ebx+118]
0040CA1D  |.  8B34A8            |mov     esi, dword ptr [eax+ebp*4]
0040CA20  |.  8D04A8            |lea     eax, dword ptr [eax+ebp*4]
0040CA23  |.  8D57 04            |lea     edx, dword ptr [edi+4]          ;  1
0040CA26  |.  85D2                |test    edx, edx
0040CA28  |.  C746 3C 01000>  |mov     dword ptr [esi+3C], 1
0040CA2F  |.  8D9E 8C000000  |lea     ebx, dword ptr [esi+8C]
0040CA35  |.  75 04                |jnz     short 0040CA3B
这个流程应该是比较简单的,我就从头分析一下:
0040C8C0  /$  6A FF         push    -1
0040C8C2  |.  68 08184600   push    00461808                         ;  咐|g; SE 处理程序安装
0040C8C7  |.  64:A1 0000000>mov     eax, dword ptr fs:[0]
0040C8CD  |.  50            push    eax
0040C8CE  |.  64:8925 00000>mov     dword ptr fs:[0], esp
0040C8D5  |.  83EC 24       sub     esp, 24
0040C8D8  |.  53            push    ebx
0040C8D9  |.  8BD9          mov     ebx, ecx
0040C8DB  |.  8B83 78010000 mov     eax, dword ptr [ebx+178]         ;  取出返回值,如果是-1就不做处理!
0040C8E1  |.  83F8 FF       cmp     eax, -1
0040C8E4  |.  895C24 08     mov     dword ptr [esp+8], ebx
0040C8E8  |.  0F84 89000000 je      0040C977
0040C8EE  |.  55            push    ebp
0040C8EF  |.  57            push    edi
0040C8F0  |.  8D4C24 2C     lea     ecx, dword ptr [esp+2C]
0040C8F4  |.  51            push    ecx
0040C8F5  |.  8D5424 2C     lea     edx, dword ptr [esp+2C]
0040C8F9  |.  52            push    edx
0040C8FA  |.  50            push    eax
0040C8FB  |.  8D8B 58010000 lea     ecx, dword ptr [ebx+158]
0040C901  |.  E8 0ACAFFFF   call    00409310
0040C906  |.  33ED          xor     ebp, ebp
0040C908  |.  3BC5          cmp     eax, ebp                         ;  如果函数返回值是0,就走人~~~
0040C90A  |.  74 69         je      short 0040C975
0040C90C  |.  8B78 04       mov     edi, dword ptr [eax+4]
0040C90F  |.  3BFD          cmp     edi, ebp
0040C911  |.  74 62         je      short 0040C975
0040C913  |.  56            push    esi                              ;  ESI和EBX的值都是004812A8
0040C914  |.  8BB3 DC000000 mov     esi, dword ptr [ebx+DC]
跟进ESI看下:
[code]011A21E8  0D F0 AD BA 70 5C 32 01 58 7D 32 01 2C 7F 32 01  .瓠簆\2 X}2 ,2 
011A21F8  0D F0 AD BA 88 31 32 01 A8 31 32 01 A8 31 32 01  .瓠簣12 ?2 ?2 
011A2208  0D F0 AD BA 28 01 30 01 42 01 30 01 42 01 30 01  .瓠? 0 B 0 B 0 
011A2218  0D F0 AD BA 28 23 1A 01 00 00 00 00 0D F0 AD BA  .瓠?#  .....瓠 
011A2228  80 23 1A 01 00 00 00 00 00 F0 AD BA 0D F0 AD BA
继续:
0040C91A  |.  8B46 04       mov     eax, dword ptr [esi+4]           ;  取出了各个大区的序号•~~
0040C91D  |.  3BC5          cmp     eax, ebp
到这里可以知道,大区的地址指针+偏移的形式应该在:[004812A8+DC]+4]

看下EAX的内容:
01325C70  01 00 00 00 B9 E3 B6 AB C7 F8 00 00 58 F8 17 04   ...广东区..X? 
01325C80  00 00 00 00 58 F8 17 04 EA 76 94 7C 00 00 1A 01  ....X? 陃攟..  
01325C90  64 77 94 7C D0 31 30 01 00 00 1A 01 D8 31 30 01  dw攟?0 ..  ?0 
01325CA0  00 00 00 00 64 77 94 7C 50 32 30 01 00 00 1A 01  ....dw攟P20 ..  
01325CB0  98 83 1A 01 C0 30 30 01 00 00 1A 01 00 00 00 00  槂  ?0 ..  ....
01325CC0  06 00 00 00 B0 4E 31 01 0F 00 00 00 A8 4E 31 01   ...癗1  ...∟1 
01325CD0  A8 4E 31 01 30 18 00 00 78 01 1A 01 28 03 1A 01  ∟1 0 ..x   (   
01325CE0  01 00 00 00 40 05 1A 01 38 00 00 00 48 32 30 01   ...@   8...H20 
01325CF0  78 01 1A 01 30 2E 38 32 30 34 2E 30 36 00 00 00  x   0.8204.06...
这个就是服务器大区的大概的结构了,里面各个数据的含义还不是很清楚,不过不用着急,通过代码,我们都会弄明白的!
继续回到代码中分析:
0040C91F  |.  C74424 1C FFF>         mov             dword ptr [esp+1C], -1
0040C927  |.  75 04                         jnz             short 0040C92D
0040C929  |.  33C0                           xor             eax, eax
0040C92B  |.  EB 18                         jmp             short 0040C945
0040C92D  |>  8B4E 08                        mov             ecx, dword ptr [esi+8]
看一下ECX的内容吧:
0132D048  0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA  .瓠?瓠?瓠?瓠 
0132D058  0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA  .瓠?瓠?瓠?瓠 
0132D068  0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA  .瓠?瓠?瓠?瓠 
0132D078  0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA  .瓠?瓠?瓠?瓠 
都是同一个数字,暂且不多考虑,估计接下来应该是遍历大区的信息啊,想下,我们在写程序的时候,循环需要什么来着,对,就是循环多少次啊,接下来的代码就是计算有多少个大区,以控制循环多少次了!
0040C930  |.  2BC8                                  sub     ecx, eax
0040C932  |.  B8 8DC0088C                   mov     eax, 8C08C08D
0040C937  |.  F7E9                                  imul    ecx
0040C939  |.  03D1                                  add     edx, ecx
0040C93B  |.  C1FA 08                               sar     edx, 8
0040C93E  |.  8BC2                                  mov     eax, edx
0040C940  |.  C1E8 1F                               shr     eax, 1F
0040C943  |.  03C2                                  add     eax, edx                ;这里就是大区的数量了OD显示的是0x12,即有0x12个大区
好了,到这里,EAX里存的就是有多少个大区了
继续看
0040C945  |>  33C9                                  xor     ecx, ecx
0040C947  |.  3BC5                                  cmp     eax, ebp
0040C949  |.  76 29                                 jbe     short 0040C974
0040C94B  |.  8B97 84000000                 mov     edx, dword ptr [edi+84]           ;  取出我们选择的大区的序号
0040C951  |.  8B76 04                               mov     esi, dword ptr [esi+4]            ;  取出大区的首个元素:序号
下面开始循环,遍历各个大区,我们取大区的信息也主要就依靠这个循环了~~~
0040C954  |.  33FF                          xor     edi, edi
0040C956  |.  897424 24                     mov     dword ptr [esp+24], esi
0040C95A  |.  897C24 10                     mov     dword ptr [esp+10], edi
0040C95E  |.  8BFF                          mov     edi, edi
0040C960  |>  391437        /                cmp     dword ptr [edi+esi], edx         ;  循环比较,看看取那个区下的服务器
0040C963  |.  74 26                         |je      short 0040C98B                           ;  只要是我们选的区,拿就跳走,不是就继续循环
0040C965  |.  41            |                inc     ecx
0040C966  |.  81C7 D4010000 |        add     edi, 1D4                                  ;  在内存里,每个大区信息的结构体大小为0x1D4
0040C96C  |.  3BC8          |                cmp     ecx, eax
0040C96E  |.^ 72 F0         \                jb      short 0040C960
0040C970  |.  897C24 10                     mov     dword ptr [esp+10], edi
根据这个循环,我们可以很轻松的写出遍历所有大区的代码了,不过不用太着急,在这里标记一下,因为,这个大区的结构中很多的数据成员,我们都不清楚,现在只知道第一个成员是大区的ID,第二个是名字,而且结构的大小要凑够0x1D4,其他的都还未知,继续分析,或许等下就清晰了,嘿嘿!

       继续看代码:
0040C98B  |> \8B8437 C80100>        mov     eax, dword ptr [edi+esi+1C8]      ;  看到了吧,大区数构中偏移第1C8的成员是个最小值
0040C992  |.  3BC5                          cmp     eax, ebp
0040C994  |.  897C24 10                     mov     dword ptr [esp+10], edi
0040C998  |.  75 06                         jnz     short 0040C9A0
0040C99A  |.  896C24 20                     mov     dword ptr [esp+20], ebp
0040C99E  |.  EB 1E                         jmp     short 0040C9BE
0040C9A0  |>  8B8C37 CC0100> mov     ecx, dword ptr [edi+esi+1CC]      ;  大区数构中偏移第1CC的成员是个最大值
0040C9A7  |.  2BC8                          sub     ecx, eax                          ;  同算大区的数量一样,计算服务器的数量
0040C9A9  |.  B8 E1830F3E           mov     eax, 3E0F83E1
0040C9AE  |.  F7E9                          imul    ecx                               ;  3E0F83E1*(最大值-最小值)
0040C9B0  |.  C1FA 06                       sar     edx, 6                            ;  取其积的高32位值右移6位
0040C9B3  |.  8BC2                          mov     eax, edx
0040C9B5  |.  C1E8 1F                       shr     eax, 1F                           ;  再移动0x1F位
0040C9B8  |.  03C2                          add     eax, edx                          ;  取他们的和OD显示是4,即4个服务器,循环4次
0040C9BA  |.  894424 20                     mov     dword ptr [esp+20], eax           ;  把结果保存一下
哈哈,结构越来越清晰,思路越来越明确,大家猜下,接下来是要干什么了啊~~~~
0040C9BE  |> \8B83 1C010000 mov     eax, dword ptr [ebx+11C]          ; 还不清楚它的作用,OD显示是6,先不管它
0040C9C4  |.  33D2                     xor     edx, edx
0040C9C6  |.  85C0          test    eax, eax
0040C9C8  |.  894424 18     mov     dword ptr [esp+18], eax
0040C9CC  |.  0F8E 95010000 jle     0040CB67
0040C9D2  |.  33C9          xor     ecx, ecx
0040C9D4  |.  EB 0A         jmp     short 0040C9E0                    ;  下面的代码应该很眼熟吧,典型的For循环
0040C9D6  |>  8B4C24 2C     /mov     ecx, dword ptr [esp+2C]
0040C9DA  |.  8B5424 28     |mov     edx, dword ptr [esp+28]
0040C9DE  |.  8BFF          |mov     edi, edi
0040C9E0  |>  3B5424 20      cmp     edx, dword ptr [esp+20]          ;  将计数器EDX跟服务器的数量进行比较,看看循环是否结束
0040C9E4  |.  0F83 42010000 |jnb     0040CB2C
0040C9EA  |.  8B8437 C80100>|mov     eax, dword ptr [edi+esi+1C8]     ;  取出第一个服务器的信息结构的首地址
[ 本帖最后由 bester 于 2009-2-17 13:07 编辑 ]

免费评分

参与人数 1威望 +2 收起 理由
zapline + 2

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| datochan 发表于 2009-2-17 12:56

真郁闷,这一个帖子发了N遍了·~~

好了,现在我们正式的开始写程序,程序可以写成DLL的方式,也可以写成EXE的方式,由于DLL的调试不是很方便,我就只贴一下DLL方式的代码,至于EXE方式的,大家可以看附件的程序,不多说了,大家看代码就好:
/************************************************************************/
/* 函数名:GetAreaInfo
/* 参  数:无
/* 返回值:返回一个指向大区结构的指针
/* 功  能:获取服务器列表中大区的结构体指针
/* 作  者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) PGAME_AREA_INFO WINAPI GetAreaInfo()
{
    __asm
    {
            mov        eax, dword ptr [XXUPDATE_BASE_ADDR+0xDC]
            test    eax, eax
            je        NULL_POINT
            mov        eax, dword ptr [eax]
            test    eax, eax
            je        NULL_POINT
            mov        eax, dword ptr [eax+0x4]
NULL_POINT:
        retn;
    }
}

/************************************************************************/
/* 函数名:GetAreaNum
/* 参  数:无
/* 返回值:返回游戏更新列表中大区的个数
/* 功  能:获取游戏更新列表中大区的个数
/* 作  者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) int WINAPI GetAreaNum()
{
    _asm
    {
        mov        eax, dword ptr [XXUPDATE_BASE_ADDR+0xDC]
        test    eax, eax
        je        NULL_POINT
        mov        eax, dword ptr [eax]
        test    eax, eax
        je        NULL_POINT
        mov        eax, dword ptr [eax+0x4]
        test    eax, eax
        je        NULL_POINT
        mov        ecx, dword ptr [XXUPDATE_BASE_ADDR+0xDC]
        test    ecx, ecx
        je        NULL_POINT
        mov        ecx, dword ptr [ecx]
        test    ecx, ecx
        je        NULL_POINT
        mov        ecx, dword ptr [eax+0x8]
        test    ecx, ecx
        je        NULL_POINT
        sub        ecx,eax
        mov     eax, 0x8C08C08D
        imul    ecx
        add     edx, ecx
        sar     edx, 0x8
        mov     eax, edx
        shr     eax, 0x1F
        add     eax, edx
NULL_POINT:
        retn;
    }
}

/************************************************************************/
/* 函数名:GetServerInfo
/* 参  数:无
/* 返回值:返回一个指向服务器结构体的指针
/* 功  能:获取服务器列表中服务器的结构体指针
/* 作  者:bester @ 2/17/2009
/************************************************************************/
PGAME_SERVERLIST_INFO CMyForm::GetServerInfo(PGAME_AREA_INFO    pAreaInfo)
{
    return pAreaInfo->pServerListOfFirst;
}

/************************************************************************/
/* 函数名:GetServerNum
/* 参  数:指定的大区结构体指针
/* 返回值:返回指定的大区中服务器的数量
/* 功  能:获取指定的大区中服务器的个数
/* 作  者:bester @ 2/17/2009
/************************************************************************/
int WINAPI GetServerNum(PGAME_AREA_INFO pAreaInfo)
{
    DWORD    TheServerNum    =    0;
    TheServerNum    =    (DWORD)pAreaInfo->pTheEndData - (DWORD)pAreaInfo->pServerListOfFirst;

    _asm
    {
        mov        ECX,TheServerNum
        mov     eax, 0x3E0F83E1
        imul    ecx               ;  3E0F83E1*(最大值-最小值)
        sar     edx, 0x6          ;  取其积的高32位值右移6位
        mov     eax, edx
        shr     eax, 0x1F         ;  再移动0x1F位
        add     eax, edx          ;  OD显示是4,即有4个服务器,循环次数为4次
        mov        TheServerNum,eax
    }
    return    TheServerNum;
}

/************************************************************************/
/* 函数名:GetTheMaxServerNum
/* 参  数:无
/* 返回值:返回游戏指定的每个区最多可拥有服务器的数量
/* 功  能:如果取到的服务器个数大于等于这个数就说明出错了
/* 作  者:bester @ 2/17/2009
/************************************************************************/
__declspec(naked) int WINAPI GetTheMaxServerNum()
{
    __asm
    {
        mov        eax, dword ptr [XXUPDATE_BASE_ADDR+0x11C]
        test    eax, eax
        je        NULL_POINT
        mov        eax, dword ptr [eax]
NULL_POINT:
        retn;
    }
}

/************************************************************************/
/* 函数名:OnBtnRefurbish
/* 参  数:无
/* 返回值:无
/* 功  能:获取游戏更新程序的服务器列表中的数据并更新到程序的列表视图中
/* 作  者:bester @ 2/17/2009
/************************************************************************/
void CMyForm::OnBtnRefurbish() 
{

    CString        szTemp    =    "";
    int AreaNum            =    GetAreaNum();
    szTemp.Format("获取到大区的数量是0x%08X",AreaNum);
    MessageBox(szTemp);
    try
    {
        PGAME_SERVERLIST_INFO    pServerListInfo    = NULL;
        PGAME_AREA_INFO            pAreaInfo    =    GetAreaInfo();
        if (pAreaInfo != NULL)
        {
            for (int x=0; x<=AreaNum; x++,pAreaInfo++)
            {
                pServerListInfo    = pAreaInfo->pServerListOfFirst;
                if (pServerListInfo != NULL)
                {
                    for (int y=0; y<=GetServerNum(pAreaInfo); y++, pServerListInfo++)
                    {
                        //序号
                        szTemp.Format(_T("%.2d"), y+1);
                        m_ServerList.InsertItem(y,szTemp);
                        //大区的名字
                        m_ServerList.SetItemText(y,1,pServerListInfo->szName);
                        //服务器的名字
                        m_ServerList.SetItemText(y,2,pServerListInfo->szName);
                        //IP和Port
                        m_ServerList.SetItemText(y,3,pServerListInfo->sServerIpPort);
                    }
                }
            }
        }
        UpdateData();
        delete    pServerListInfo;
        delete    pAreaInfo;
    }catch(...)
    {
        ::AfxMessageBox("遍历服务器列表时,出现异常……");
    }
}
最后看下效果吧:

效果.jpg

总的来说,还是不错的,是吗?
哈哈,本人才疏学浅,也只能讲点这些简单的东西了,仅希望能以此抛砖引玉,引来大牛的分享……

[ 本帖最后由 bester 于 2009-2-18 02:25 编辑 ]

分析笔记.rar

586.65 KB, 下载次数: 71, 下载积分: 吾爱币 -1 CB

GetServerList[EXE].rar

5.01 KB, 下载次数: 32, 下载积分: 吾爱币 -1 CB

GetServerList[SRC].rar

30.92 KB, 下载次数: 37, 下载积分: 吾爱币 -1 CB

 楼主| datochan 发表于 2009-2-17 12:42

发一个帖子里,就自动给截断了,不知道什么原因,希望管理员查一下~~~

不如我们跟进去看看,服务器结构是什么样子,哈哈
0132A5B8  0A 00 00 00 BA F9 C2 AB C9 BD 00 40 A0 F9 17 04  ....葫芦山.@狔  
0132A5C8  94 FA 17 04 00 00 00 00 00 E9 92 7C 40 00 93 01  旡  .....閽|@.?
不多介绍了,继续看下面的代码:
0040C9F1  |.  8D3C01                        |lea     edi, dword ptr [ecx+eax]         ;  ECX是结构偏移的计数器,大家都应该能看明白的
0040C9F4  |.  42                                    |inc     edx                              ;  循环计数器了,不用我讲的•~~
0040C9F5  |.  81C1 08010000         |add     ecx, 108                       ;  每个服务器信息结构的大小是0x108,指到数组的下个成员
0040C9FB  |.  85ED                          |test    ebp, ebp
0040C9FD  |.  895424 28                      |mov     dword ptr [esp+28], edx          ;  保存服务器的序号信息
0040CA01  |.  894C24 2C                     |mov     dword ptr [esp+2C], ecx          ;  保存服务器信息结构的偏移信息
0040CA05  |.  0F8C A9020000         |jl      0040CCB4
0040CA0B  |.  3BAB 1C010000         |cmp     ebp, dword ptr [ebx+11C]         ;  看来这个0x11C很关键哦, 
0040CA11  |.  0F8D 9D020000         |jge     0040CCB4                         ;  大于等于就跳走了~~~
这里用到了这个0x11C这个变量,根据上面代码的最后两行,如果服务器数量大于等于6就跳走,估计是个用来防止异常的,有兴趣的朋友可以跟一下,这里就不多说了!
继续看代码:
0040CA17  |.  8B83 18010000 |mov     eax, dword ptr [ebx+118]         ;  取出第一个服务器结构的首地址
0040CA1D  |.  8B34A8        |mov     esi, dword ptr [eax+ebp*4]
0040CA20  |.  8D04A8        |lea     eax, dword ptr [eax+ebp*4]       ;  dword ptr [eax+ebp*4]不会被看糊涂吧,取结构体成员的基本方法!
0040CA23  |.  8D57 04       |lea     edx, dword ptr [edi+4]           ;  还记得EDI里存的是什么吧,哈哈,偏移+4就是取服务器名字了~
0040CA26  |.  85D2          |test    edx, edx
0040CA28  |.  C746 3C 01000>|mov     dword ptr [esi+3C], 1
0040CA2F  |.  8D9E 8C000000 |lea     ebx, dword ptr [esi+8C]
0040CA35  |.  75 04         |jnz     short 0040CA3B
0040CA37  |.  33C0          |xor     eax, eax
0040CA39  |.  EB 14         |jmp     short 0040CA4F
0040CA3B  |>  8BC2          |mov     eax, edx                         ;  1
0040CA3D  |.  8D48 01       |lea     ecx, dword ptr [eax+1]
0040CA40  |.  894C24 30     |mov     dword ptr [esp+30], ecx
0040CA44  |>  8A08          |/mov     cl, byte ptr [eax]              ;  断在了这里,也就是说,这里取了服务器的列表信息!
0040CA46  |.  40            ||inc     eax                                  ;眼熟不?哈哈
0040CA47  |.  84C9          ||test    cl, cl
0040CA49  |.^ 75 F9         |\jnz     short 0040CA44
好了,分析就基本上到此结束了,没有必要再继续分析了,接下来就是分析一下,我们需要什么东西,然后就是怎么把我们分析得到的东西转换成代码!

先想想我们现在需要的东西:各个大区的序号,还有大区的名字,服务器的名字,服务器的IP和端口号,需要的数据就这么多了,接下来看看我们现在分析到了什么数据~

先看下服务器的结构中,我们已经知道了哪些数据
1.         每个服务器信息结构的大小是0x108
2.        直接引用服务器的数据,如下:

0132A5B8  0A 00 00 00 BA F9 C2 AB C9 BD 00 40 A0 F9 17 04  ....葫芦山.@狔  
0132A5C8  94 FA 17 04 00 00 00 00 00 E9 92 7C 40 00 93 01  旡  .....閽|@.?


我们需要的数据很少,只需要名字和IP及端口就OK了,所以直接看数据段,来肉眼来定一下就可以了
这样,我们定义的结构体,如下:
//    游戏服务器的数据结构定义
typedef struct    _GAME_SERVERLIST_INFO
{
    DWORD             dwServerNo;                  //    服务器的序号 0
    char                   szName[8];                   //    名字offset 4
    DWORD             dwUnknow1[30];            //    未知offset C            
    char                   sServerIpPort[20];         //    IP和端口 offset 1C8
    DWORD             dwUnknow2[28];            //    结尾的数据 offset 1CC    用来补齐0x108的结构大小
} GAME_SERVERLIST_INFO, *PGAME_SERVERLIST_INFO;
再看大区的数据结构中,我们知道的数据:

1.        现在只知道第一个成员是大区的ID,第二个是名字,而且结构的大小要凑够0x1D4
2.        看到了吧,大区数构中偏移第1C8的成员是个最小值
3.        大区数构中偏移第1CC的成员是个最大值


好了,现在我们来定义大区的结构体,如下:
//    游戏大区的数据结构定义
typedef struct    _GAME_AREA_INFO
{
    DWORD                                            dwTheAreaNo;            //    大区的序号 0
    char                                                    szName[8];                //    名字offset 4
    DWORD                                            dwUnknow1[111];            //    未知offset C            这些数据对我们不重要,直接掠过
    _GAME_SERVERLIST_INFO            *pServerListOfFirst;    //    首个服务器 offset 1C8
    PDWORD                                          pTheEndData;            //    结尾的数据 offset 1CC
    PDWORD                                            pTheEndData2;            //    结尾的数据 1D0            用来补齐0x1D4的结构大小
} GAME_AREA_INFO, *PGAME_AREA_INFO;
到现在,数据已经整理好了,应该可以写代码了,在写代码以前呢,我们整理总结一下我们收集到的数据:

1.        这个程序的基址是:004812A8
2.        大区的地址指针+偏移的形式应该在:[004812A8+DC]+4]
3.        计算大区数量的算法如下:
[004812A8]+DC]+8] 减去 [004812A8]+DC]+4] 然后在:
0040C932  |.  B8 8DC0088C                   mov     eax, 8C08C08D
0040C937  |.  F7E9                                  imul    ecx
0040C939  |.  03D1                                  add     edx, ecx
0040C93B  |.  C1FA 08                               sar     edx, 8
0040C93E  |.  8BC2                                  mov     eax, edx
0040C940  |.  C1E8 1F                               shr     eax, 1F
0040C943  |.  03C2                                  add     eax, edx
4.        计算每个区服务器数量的算法如下:
用GAME_AREA_INFO:: pTheEndData 减去GAME_AREA_INFO::pServerListOfFirst 然后再如下计算:
0040C9A9  |.  B8 E1830F3E   mov     eax, 3E0F83E1
0040C9AE  |.  F7E9            imul    ecx                               ;  3E0F83E1*(最大值-最小值)
0040C9B0  |.  C1FA 06        sar     edx, 6                            ;  取其积的高32位值右移6位
0040C9B3  |.  8BC2            mov     eax, edx
0040C9B5  |.  C1E8 1F        shr     eax, 1F                           ;  再移动0x1F位
0040C9B8  |.  03C2            add     eax, edx          ;  OD显示是4,即有4个服务器,循环次数为4次
0040C9BA  |.  894424 20     mov     dword ptr [esp+20], eax           ;  把结果保存一下

5.        基址:004812A8 加上0x11C 中的值是最大的服务器数量,若算出来的服务器数量大于等于这个数,就是出错了,应该加容错处理!

[ 本帖最后由 bester 于 2009-2-17 12:54 编辑 ]
creantan 发表于 2009-2-17 13:02
oh_lucifer 发表于 2009-2-17 13:11
相当不错的文章hoho~~~

支持啊....

内存读。
省的解密了~
lawry 发表于 2009-2-17 13:12
学习了
谢谢楼主
mingjie_520 发表于 2009-2-17 13:35
粗粗的看了一边,能理解个40%还的努力啊
zapline 发表于 2009-2-17 14:52
:funk: 我再努力几年
追上你;P
Squn 发表于 2009-2-17 15:30
我晕.好东西..
IsQun 发表于 2009-2-17 15:35
支持原创:D :D
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 11:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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