青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

聚星亭

吾笨笨且懶散兮 急須改之而奮進
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
非常好的資料 ,

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美亚洲在线| 免费观看欧美在线视频的网站| 午夜视频精品| 亚洲一区尤物| 久久久亚洲精品一区二区三区| 在线电影院国产精品| 影音先锋成人资源站| 亚洲国产国产亚洲一二三| 最新国产精品拍自在线播放| 99热精品在线| 午夜日韩av| 麻豆精品视频在线观看视频| 亚洲高清av在线| 欧美国产先锋| 一本色道久久88综合日韩精品 | 中日韩视频在线观看| 亚洲图片激情小说| 久久精品视频va| 欧美日韩国产在线观看| 国产亚洲一级高清| 亚洲伦理中文字幕| 欧美一级免费视频| 欧美夫妇交换俱乐部在线观看| 夜夜嗨av一区二区三区网站四季av| 校园春色综合网| 欧美精品大片| 国产一区二区欧美日韩| 日韩一级片网址| 久久国产一区二区| 亚洲国内高清视频| 久久久久久夜| 国产精品久久久久aaaa| 亚洲激精日韩激精欧美精品| 香蕉久久a毛片| 亚洲黄一区二区三区| 欧美在线视频导航| 欧美日韩一区二区三区视频| 国内一区二区三区| 性色av一区二区三区红粉影视| 亚洲国产精品t66y| 久久久久国产精品厨房| 国产欧美日韩精品专区| 亚洲视频在线观看网站| 亚洲国产精品va在看黑人| 欧美在线91| 国产精品网站视频| 亚洲一区二区三区视频播放| 亚洲欧洲视频在线| 蜜臀av性久久久久蜜臀aⅴ四虎| 国产精品腿扒开做爽爽爽挤奶网站| 99这里有精品| 亚洲日本视频| 男人天堂欧美日韩| 亚洲第一毛片| 蜜臀av在线播放一区二区三区| 亚洲一区在线播放| 国产精品日本精品| 亚洲欧美日韩在线观看a三区| 亚洲精华国产欧美| 欧美日韩不卡视频| 久久精视频免费在线久久完整在线看| 亚洲精品一二区| 裸体歌舞表演一区二区| 在线成人h网| 你懂的亚洲视频| 久久免费一区| 亚洲国产中文字幕在线观看| 亚洲成人资源| 欧美日韩国产小视频| 亚洲视频一区在线观看| 亚洲午夜激情免费视频| 国产欧美欧美| 免费成人av在线看| 久久亚洲精品视频| 日韩视频一区二区三区在线播放| 亚洲电影在线播放| 欧美视频一区在线| 久久精品二区三区| 久久久99国产精品免费| 亚洲精品国产精品国自产观看浪潮| 亚洲大片在线观看| 欧美日韩另类视频| 久久狠狠一本精品综合网| 久久婷婷av| 中文网丁香综合网| 亚洲欧美综合精品久久成人| 一区二区三区在线看| 亚洲美女少妇无套啪啪呻吟| 国产精品区一区二区三| 你懂的国产精品永久在线| 欧美日韩中文字幕在线| 欧美一区二区三区四区高清| 久久久久久欧美| 亚洲精品老司机| 亚洲一区精彩视频| 亚洲国产免费| 亚洲影院免费| 亚洲欧洲日本一区二区三区| 在线亚洲+欧美+日本专区| 影音先锋亚洲一区| 在线视频精品| 亚洲人人精品| 久久大香伊蕉在人线观看热2| 亚洲精品一区二区三区不| 午夜在线观看欧美| 一区二区三区黄色| 久久久精品日韩欧美| 亚洲午夜一区二区三区| 久久亚洲精品一区二区| 欧美中文在线视频| 欧美日韩一区二区三区在线观看免| 久久综合五月| 国产精品自拍三区| 99v久久综合狠狠综合久久| 亚洲缚视频在线观看| 午夜亚洲视频| 亚洲欧美在线视频观看| 欧美精品久久久久a| 另类成人小视频在线| 国产精品久久久久一区| 亚洲精品九九| 亚洲电影av| 久久久久亚洲综合| 亚洲精品国产日韩| 午夜精品久久久久久久蜜桃app | 欧美一级久久久| 一区二区三区 在线观看视频| 久久亚洲精选| 蘑菇福利视频一区播放| 国产一区av在线| 亚洲专区一二三| 亚洲欧美大片| 欧美色图麻豆| 亚洲乱码国产乱码精品精| 亚洲激情在线| 免费不卡在线视频| 亚洲第一网站| 亚洲精品乱码久久久久久黑人| 老色批av在线精品| 美女爽到呻吟久久久久| 亚洲国产精品久久久久秋霞影院| 久久成人人人人精品欧| 美女免费视频一区| 亚洲第一中文字幕在线观看| 欧美成人激情视频免费观看| 亚洲国产高清一区| 中国av一区| 国产精品丝袜久久久久久app| 亚洲自拍偷拍色片视频| 久久丁香综合五月国产三级网站| 国产精品色婷婷| 久久国产天堂福利天堂| 久久av红桃一区二区小说| 狠狠久久亚洲欧美| 欧美成人在线免费观看| 一区二区三区精密机械公司 | 蜜臀av国产精品久久久久| 欧美激情在线| 亚洲图片欧洲图片日韩av| 国产精品免费看片| 久久精品亚洲一区| 亚洲国产欧美一区二区三区久久| 亚洲激情视频网站| 欧美日韩三级| 欧美亚洲日本网站| 亚洲高清在线播放| 午夜一级在线看亚洲| 黄色日韩网站视频| 欧美精品久久久久a| 亚洲欧美视频一区二区三区| 免费成人高清在线视频| 亚洲精品影院在线观看| 国产伦精品一区二区三区在线观看 | 亚洲视频在线二区| 黄色日韩在线| 国产精品第一区| 久久久久久久久久久久久9999| 91久久精品美女| 欧美在线视频不卡| 亚洲免费av片| 国产午夜精品美女毛片视频| 欧美华人在线视频| 久久国内精品自在自线400部| 亚洲精品一区二| 久久久噜噜噜久久中文字免| 一本久久综合| 久久久人人人| 亚洲午夜av电影| 国产精品夜夜嗨| 另类成人小视频在线| 在线午夜精品| 亚洲精品国产精品久久清纯直播| 久久久久久自在自线| 亚洲手机在线| 日韩视频免费大全中文字幕| 韩国三级电影久久久久久| 国产精品久久久久一区二区三区 | 亚洲人成在线免费观看| 国产一区二区三区成人欧美日韩在线观看| 欧美成人亚洲|