• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            聚星亭

            吾笨笨且懶散兮 急須改之而奮進
            posts - 74, comments - 166, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

                   聲明:本文是好久以前發在吾愛破解論壇上的,由于它有一定的紀念意義,故將它轉發到這里留念之用……

                   游戲的服務器列表更新了,而存服務器信息的XML在游戲的更新服務器上加密保存的,沒能力分析它的解密算法,就想寫個程序,從內存里讀出來,工作量就是那么多,不如索性做成教程,分享給像我一樣剛剛入門的朋友,說不定就又能混一篇精華,哈哈…… 

                   其實這個的道理跟找游戲中遍歷怪物啊,地面物品啊,都是都差不多的,而且,這個的數據不會想怪一下死了消失了,也不會像在游戲里,你中斷的時間太長游戲會掉線,而且這個的負責程度相當于一個普通沒有任何保護的游戲,比較簡單,但是,在這里提醒大家,如果要做外掛的話,大家自己搗鼓搗鼓,學習一下就可以了,不要靠這個來賺錢,不安全的,尤其是TX的游戲,所以請大家自重! 

            本文適合還沒有入門的新朋友上手用的,所有,各位大牛就可以飄過不看它了!
               
               
            不多廢話,進入主題,我現在要找服務器列表,當然就要先從內存里搜一個服務器的名字(別的信息不知道,只能搜名字了!)

            像上圖,就搜葫蘆山了,結果如下:

            OD里的數據區中看一下這幾個地址,確定,第一個地址也就是:01329F6C 就是我們像要的地址了,至于為什么,你看一下就可以知道了(因為第一個在一個結構體數組里,其他的都是獨立的,所以第一個是!)。

             好了,在OD里,來到01329F6C這個地址,在第一個DWORD上下內存訪問斷點:

            來到這里:

            現在我們需要知道的是,EAX的內容是從哪里來的,所以向上看:

            0040CA3B  |> \8BC2          |mov     eax, edx                        ;  1

            EDX給的EAX,再向上:

            0040CA17  |.  8B83 18010000   |mov     eaxdword ptr [ebx+118]
            0040CA1D  |.  8B34A8            |mov     esidword ptr [eax+ebp*4]
            0040CA20  |.  8D04A8            |lea     eaxdword ptr [eax+ebp*4]
            0040CA23  |.  8D57 04            |lea     edxdword ptr [edi+4]          ;  1
            0040CA26  |.  85D2                |test    edxedx
            0040CA28  |.  C746 3C 01000>  |mov     dword ptr [esi+3C], 1
            0040CA2F  |.  8D9E 8C000000  |lea     ebxdword 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     eaxdword 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     ebxecx
            0040C8DB  |.  8B83 78010000 mov     eaxdword 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     ecxdword ptr [esp+2C]
            0040C8F4  |.  51            push    ecx
            0040C8F5  |.  8D5424 2C     lea     edxdword ptr [esp+2C]
            0040C8F9  |.  52            push    edx
            0040C8FA  |.  50            push    eax
            0040C8FB  |.  8D8B 58010000 lea     ecxdword ptr [ebx+158]
            0040C901  |.  E8 0ACAFFFF   call    00409310
            0040C906  |.  33ED          xor     ebpebp
            0040C908  |.  3BC5          cmp     eaxebp                         ;  
            如果函數返回值是0,就走人~~~
            0040C90A  |.  74 69         je      short 0040C975
            0040C90C  |.  8B78 04       mov     edidword ptr [eax+4]
            0040C90F  |.  3BFD          cmp     ediebp
            0040C911  |.  74 62         je      short 0040C975
            0040C913  |.  56            push    esi                              ;  ESI
            EBX的值都是004812A8
            0040C914  |.  8BB3 DC000000 mov     esidword ptr [ebx+DC]

             

            跟進ESI看下:

            011A21E8  0D F0 AD BA 70 5C 32 01 58 7D 32 01 2C 7F 32 01  .瓠簆\2X}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  .?0B0B0

            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     eaxdword ptr [esi+4]           ;  取出了各個大區的序號·~~
            0040C91D  |.  3BC5          cmp     eaxebp

            到這里可以知道,大區的地址指針+偏移的形式應該在:[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  ....dwP20..

            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  10..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  x0.8204.06...

            這個就是服務器大區的大概的結構了,里面各個數據的含義還不是很清楚,不過不用著急,通過代碼,我們都會弄明白的!

            繼續回到代碼中分析:

            0040C91F  |.  C74424 1C FFF>     mov          dword ptr [esp+1C], -1
            0040C927  |.  75 04                            jnz           short 0040C92D
            0040C929  |.  33C0                         xor            eaxeax
            0040C92B  |.  EB 18                         jmp          short 0040C945
            0040C92D  |>  8B4E 08                   mov          ecxdword 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     ecxeax
            0040C932  |.  B8 8DC0088C                    mov     eax8C08C08D
            0040C937  |.  F7E9                                  imul    ecx
            0040C939  |.  03D1                                  add     edxecx
            0040C93B  |.  C1FA 08                             sar     edx, 8
            0040C93E  |.  8BC2                                 mov     eaxedx
            0040C940  |.  C1E8 1F                            shr     eax1F
            0040C943  |.  03C2                                  add     eaxedx              ;
            這里就是大區的數量了OD顯示的是0x12,即有0x12個大區

            好了,到這里,EAX里存的就是有多少個大區了

            繼續看

            0040C945  |>  33C9                                 xor     ecxecx
            0040C947  |.  3BC5                                   cmp     eaxebp
            0040C949  |.  76 29                                   jbe     short 0040C974
            0040C94B  |.  8B97 84000000                  mov     edxdword ptr [edi+84]           ;  
            取出我們選擇的大區的序號
            0040C951  |.  8B76 04                             mov     esidword ptr [esi+4]            ;  
            取出大區的首個元素:序號

             

            下面開始循環,遍歷各個大區,我們取大區的信息也主要就依靠這個循環了~~~

            0040C954  |.  33FF                          xor     ediedi
            0040C956  |.  897424 24                 mov     dword ptr [esp+24], esi
            0040C95A  |.  897C24 10               mov     dword ptr [esp+10], edi
            0040C95E  |.  8BFF                        mov     ediedi
            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     ecxeax
            0040C96E  |.^ 72 F0         \             jb      short 0040C960
            0040C970  |.  897C24 10                 mov     dword ptr [esp+10], edi

            根據這個循環,我們可以很輕松的寫出遍歷所有大區的代碼了,不過不用太著急,在這里標記一下,因為,這個大區的結構中很多的數據成員,我們都不清楚,現在只知道第一個成員是大區的ID,第二個是名字而且結構的大小要湊夠0x1D4,其他的都還未知,繼續分析,或許等下就清晰了,嘿嘿!

                  

            繼續看代碼:

            0040C98B  |> \8B8437 C80100>   mov     eaxdword ptr [edi+esi+1C8]       看到了吧,大區數構中偏移第1C8的成員是個最小值
            0040C992  |.  3BC5                         cmp     eaxebp
            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     ecxdword ptr [edi+esi+1CC]      ;  
            大區數構中偏移第1CC的成員是個最大值
            0040C9A7  |.  2BC8                       sub     ecxeax                          ;  
            同算大區的數量一樣,計算服務器的數量
            0040C9A9  |.  B8 E1830F3E           mov     eax, 3E0F83E1
            0040C9AE  |.  F7E9                         imul    ecx                               ;  3E0F83E1*(
            最大值-最小值)
            0040C9B0  |.  C1FA 06                    sar     edx, 6                            ;  
            取其積的高32位值右移6
            0040C9B3  |.  8BC2                         mov     eaxedx
            0040C9B5  |.  C1E8 1F                   shr     eax1F                           ;  
            再移動0x1F
            0040C9B8  |.  03C2                         add     eaxedx                          ;  
            取他們的和OD顯示是4,即4個服務器,循環4
            0040C9BA  |.  894424 20                mov     dword ptr [esp+20], eax           ;  
            把結果保存一下

            哈哈,結構越來越清晰,思路越來越明確,大家猜下,接下來是要干什么了啊~~~~

             

            0040C9BE  |> \8B83 1C010000 mov     eaxdword ptr [ebx+11C]          還不清楚它的作用,OD顯示是6,先不管它
            0040C9C4  |.  33D2                  xor     edxedx
            0040C9C6  |.  85C0          test    eaxeax
            0040C9C8  |.  894424 18     mov     dword ptr [esp+18], eax
            0040C9CC  |.  0F8E 95010000 jle     0040CB67
            0040C9D2  |.  33C9          xor     ecxecx
            0040C9D4  |.  EB 0A         jmp     short 0040C9E0                    ;  
            下面的代碼應該很眼熟吧,典型的For循環
            0040C9D6  |>  8B4C24 2C     /mov     ecxdword ptr [esp+2C]
            0040C9DA  |.  8B5424 28     |mov     edxdword ptr [esp+28]
            0040C9DE  |.  8BFF          |mov     ediedi
            0040C9E0  |>  3B5424 20      cmp     edxdword ptr [esp+20]          ;  
            將計數器EDX跟服務器的數量進行比較,看看循環是否結束
            0040C9E4  |.  0F83 42010000 |jnb     0040CB2C
            0040C9EA  |.  8B8437 C80100>|mov     eaxdword ptr [edi+esi+1C8]     ;  
            取出第一個服務器的信息結構的首地址

                  

            不如我們跟進去看看,服務器結構是什么樣子,哈哈

            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  .....|@.?

            0132A5D8  FF FF 01 00 00 00 1A 01 64 77 94 7C 98 FA 17 04  ...dw攟橔

            0132A5E8  A7 C6 98 7C 00 00 1A 01 00 00 00 00 30 2E 31 01  榺......0.1

            0132A5F8  00 00 1A 01 38 2E 31 01 94 FA 17 04 F8 FA 17 04  ..8.1 

            0132A608  00 E9 92 7C 00 00 00 00 00 00 1A 01 00 00 00 00  .|..........

            0132A618  08 FB 17 04 B0 D9 98 7C 08 06 1A 01 94 D9 98 7C  ? 百榺斮榺
            0132A628  00 00 1A 01 38 2E 31 01 60 00 00 40 30 5B 27 01  ..8.1`..@0['

            0132A638  F8 D6 2C 01 31 31 39 2E 31 34 37 2E 31 36 2E 31  ,119.147.16.1

            0132A648  33 38 3A 33 31 30 30 00 00 00 00 00 00 00 00 00  38:3100.........

                  

            不多介紹了,繼續看下面的代碼:

            0040C9F1  |.  8D3C01                     |lea     edidword ptr [ecx+eax]         ;  ECX是結構偏移的計數器,大家都應該能看明白的
            0040C9F4  |.  42                              |inc     edx                              ;  
            循環計數器了,不用我講的·~~
            0040C9F5  |.  81C1 08010000        |add     ecx, 108                        
            每個服務器信息結構的大小是0x108,指到數組的下個成員
            0040C9FB  |.  85ED                       |test    ebpebp
            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     ebpdword ptr [ebx+11C]         ;  
            看來這個0x11C很關鍵哦,
            0040CA11  |.  0F8D 9D020000      |jge     0040CCB4                         ;  
            大于等于就跳走了~~~

             

            這里用到了這個0x11C這個變量,根據上面代碼的最后兩行,如果服務器數量大于等于6就跳走,估計是個用來防止異常的,有興趣的朋友可以跟一下,這里就不多說了!

            繼續看代碼:

            0040CA17  |.  8B83 18010000 |mov     eaxdword ptr [ebx+118]         ;  取出第一個服務器結構的首地址
            0040CA1D  |.  8B34A8        |mov     esidword ptr [eax+ebp*4]
            0040CA20  |.  8D04A8        |lea     eaxdword ptr [eax+ebp*4]       ;  dword ptr [eax+ebp*4]
            不會被看糊涂吧,取結構體成員的基本方法!
            0040CA23  |.  8D57 04       |lea     edxdword ptr [edi+4]            
            還記得EDI里存的是什么吧,哈哈,偏移+4就是取服務器名字了~
            0040CA26  |.  85D2          |test    edxedx
            0040CA28  |.  C746 3C 01000>|mov     dword ptr [esi+3C], 1
            0040CA2F  |.  8D9E 8C000000 |lea     ebxdword ptr [esi+8C]
            0040CA35  |.  75 04         |jnz     short 0040CA3B
            0040CA37  |.  33C0          |xor     eaxeax
            0040CA39  |.  EB 14         |jmp     short 0040CA4F
            0040CA3B  |>  8BC2          |mov     eaxedx                         ;  1
            0040CA3D  |.  8D48 01       |lea     ecxdword ptr [eax+1]
            0040CA40  |.  894C24 30     |mov     dword ptr [esp+30], ecx
            0040CA44  |>  8A08          |/mov     clbyte ptr [eax]              ;  
            斷在了這里,也就是說,這里取了服務器的列表信息!
            0040CA46  |.  40            ||inc     eax                              
            眼熟不?哈哈
            0040CA47  |.  84C9          ||test    clcl
            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  .....|@.?

            0132A5D8  FF FF 01 00 00 00 1A 01 64 77 94 7C 98 FA 17 04  ...dw攟橔

            0132A5E8  A7 C6 98 7C 00 00 1A 01 00 00 00 00 30 2E 31 01  榺......0.1

            0132A5F8  00 00 1A 01 38 2E 31 01 94 FA 17 04 F8 FA 17 04  ..8.1 

            0132A608  00 E9 92 7C 00 00 00 00 00 00 1A 01 00 00 00 00  .|..........

            0132A618  08 FB 17 04 B0 D9 98 7C 08 06 1A 01 94 D9 98 7C  ? 百榺斮榺

            0132A628  00 00 1A 01 38 2E 31 01 60 00 00 40 30 5B 27 01  ..8.1`..@0['

            0132A638  F8 D6 2C 01 31 31 39 2E 31 34 37 2E 31 36 2E 31  ,119.147.16.1

            0132A648  33 38 3A 33 31 30 30 00 00 00 00 00 00 00 00 00  38:3100.........

                          我們需要的數據很少,只需要名字和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     eax8C08C08D
            0040C937  |.  F7E9                                  imul    ecx
            0040C939  |.  03D1                                  add     edxecx
            0040C93B  |.  C1FA 08                             sar     edx, 8
            0040C93E  |.  8BC2                                 mov     eaxedx
            0040C940  |.  C1E8 1F                             shr     eax1F
            0040C943  |.  03C2                                  add     eaxedx

            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     eaxedx
            0040C9B5  |.  C1E8 1F        shr     eax1F                           ;  
            再移動0x1F
            0040C9B8  |.  03C2            add     eaxedx          ;  OD
            顯示是4,即有4個服務器,循環次數為4
            0040C9BA  |.  894424 20     mov     dword ptr [esp+20], eax           ;  
            把結果保存一下

                      5.         基址:004812A8 加上0x11C 中的值是最大的服務器數量,若算出來的服務器數量大于等于這個數,就是出錯了,應該加容錯處理!

                      好了,現在我們正式的開始寫程序,程序可以寫成DLL的方式,也可以寫成EXE的方式,由于DLL的調試不是很方便,我就只貼一下DLL方式的代碼,至于EXE方式的,大家可以看附件的程序,不多說了,大家看代碼就好

            /************************************************************************/
            /* 
            函數名:GetAreaInfo
            /* 
              數:無
            /* 
            返回值:返回一個指向大區結構的指針
            /* 
              能:獲取服務器列表中大區的結構體指針
            /* 
              者:bester @ 2/17/2009
            /************************************************************************/

            __declspec(naked) PGAME_AREA_INFO WINAPI GetAreaInfo()
            {
                __asm
                {
                        mov        eaxdword ptr [XXUPDATE_BASE_ADDR+0xDC]
                        test    eaxeax
                        je        NULL_POINT
                        mov        eaxdword ptr [eax]
                        test    eaxeax
                        je        NULL_POINT
                        mov        eaxdword ptr [eax+0x4]
            NULL_POINT:
                    retn;
                }
            }

             

            /************************************************************************/
            /* 
            函數名:GetAreaNum
            /* 
              數:無
            /* 
            返回值:返回游戲更新列表中大區的個數
            /* 
              能:獲取游戲更新列表中大區的個數
            /* 
              者:bester @ 2/17/2009
            /************************************************************************/

            __declspec(naked) int WINAPI GetAreaNum()
            {
                _asm
                {
                    mov        eaxdword ptr [XXUPDATE_BASE_ADDR+0xDC]
                    test    eaxeax
                    je        NULL_POINT
                    mov        eaxdword ptr [eax]
                    test    eaxeax
                    je        NULL_POINT
                    mov        eaxdword ptr [eax+0x4]
                    test    eaxeax
                    je        NULL_POINT
                    mov        ecxdword ptr [XXUPDATE_BASE_ADDR+0xDC]
                    test    ecxecx
                    je        NULL_POINT
                    mov        ecxdword ptr [ecx]
                    test    ecxecx
                    je        NULL_POINT
                    mov        ecxdword ptr [eax+0x8]
                    test    ecxecx
                    je        NULL_POINT
                    sub        ecx,eax
                    mov     eax, 0x8C08C08D
                    imul    ecx
                    add     edxecx
                    sar     edx, 0x8
                    mov     eaxedx
                    shr     eax, 0x1F
                    add     eaxedx
            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     eaxedx
                    shr     eax, 0x1F         ;  
            再移動0x1F
                    add     eaxedx          ;  OD
            顯示是4,即有4個服務器,循環次數為4
                    mov        TheServerNum,eax
                }
                return    TheServerNum;
            }

            /************************************************************************/
            /* 
            函數名:GetTheMaxServerNum
            /* 
              數:無
            /* 
            返回值:返回游戲指定的每個區最多可擁有服務器的數量
            /* 
              能:如果取到的服務器個數大于等于這個數就說明出錯了
            /* 
              者:bester @ 2/17/2009
            /************************************************************************/

            __declspec(naked) int WINAPI GetTheMaxServerNum()
            {
                __asm
                {
                    mov        eaxdword ptr [XXUPDATE_BASE_ADDR+0x11C]
                    test    eaxeax
                    je        NULL_POINT
                    mov        eaxdword 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("
            遍歷服務器列表時,出現異常……");
                }
            }

                   最后看下效果吧:

            總的來說,還是不錯的,是嗎?

            哈哈,本人才疏學淺,也只能講點這些簡單的東西了,僅希望能以此拋磚引玉,引來大牛的分享……

            Feedback

            # re: [原創]曾經寫的一個遍歷尋仙游戲服務器列表的文章(基礎)  回復  更多評論   

            2009-10-29 10:56 by 得到
            看不懂誒...

            # re: [原創]曾經寫的一個遍歷尋仙游戲服務器列表的文章(基礎)  回復  更多評論   

            2010-05-10 10:09 by zpeng
            非常好的資料 ,
            狠狠色丁香久久婷婷综合| 欧洲国产伦久久久久久久| 久久精品国产秦先生| 久久99精品国产99久久| 国产成人精品久久| 婷婷久久综合九色综合九七| 久久精品成人欧美大片| 久久精品国产亚洲av水果派 | 综合网日日天干夜夜久久| 无遮挡粉嫩小泬久久久久久久| 久久精品国产免费| 欧洲国产伦久久久久久久| 久久久久人妻一区精品性色av | 久久久久久伊人高潮影院| 99久久精品毛片免费播放| 久久久久亚洲AV无码去区首| 亚洲精品乱码久久久久久| 亚洲综合精品香蕉久久网97| 久久人做人爽一区二区三区| 91精品国产乱码久久久久久| 久久久久久久综合综合狠狠| 蜜臀av性久久久久蜜臀aⅴ麻豆| 伊人久久大香线蕉影院95| 狠狠色综合网站久久久久久久高清| 国产精品久久久久9999高清| 久久经典免费视频| 国产精品狼人久久久久影院 | 人妻精品久久久久中文字幕| 国内精品久久国产大陆| 久久精品青青草原伊人| 国产精品热久久无码av| 五月丁香综合激情六月久久| 午夜精品久久久久久久无码| 国产精品欧美久久久久无广告 | 久久久久久毛片免费播放| 无码人妻少妇久久中文字幕| 丰满少妇人妻久久久久久4| 国内精品久久久久影院优| 国产免费久久精品99re丫y| 久久精品亚洲福利| 人人狠狠综合久久亚洲婷婷|