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

聚星亭

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

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

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

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

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

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

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
非常好的資料 ,
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            一区二区日韩欧美| 狠狠做深爱婷婷久久综合一区| 尤物在线精品| 蜜桃久久精品乱码一区二区| 久久噜噜噜精品国产亚洲综合| 在线播放亚洲| 欧美国产一区二区| 欧美精品一线| 欧美在线播放| 久热精品视频在线观看一区| 亚洲人成啪啪网站| 在线亚洲高清视频| 国产综合色产| 亚洲精品日韩综合观看成人91| 国产精品久久久久久久久免费樱桃| 欧美一区二区三区精品| 久久久久久久综合狠狠综合| 99精品国产福利在线观看免费| 亚洲一区二区三区精品动漫| 在线观看国产精品网站| 99香蕉国产精品偷在线观看| 狠狠色狠色综合曰曰| 亚洲人体1000| 国产精品入口麻豆原神| 欧美激情片在线观看| 国产精品一二| 亚洲国产欧美日韩| 国产亚洲va综合人人澡精品| 亚洲国产日本| 国产一区二区无遮挡| 亚洲免费播放| 亚洲激情小视频| 欧美亚洲一区二区在线观看| 99精品99| 欧美激情精品久久久六区热门 | 老司机成人在线视频| 欧美精品久久99久久在免费线| 欧美在线影院| 国产精品福利在线观看| 欧美激情女人20p| 黄色综合网站| 亚洲视频一区在线观看| 鲁大师影院一区二区三区| 欧美在线国产精品| 欧美视频一区二区三区四区| 欧美激情中文字幕乱码免费| 国产伊人精品| 亚洲欧美亚洲| 性久久久久久| 欧美色视频在线| 亚洲美洲欧洲综合国产一区| 亚洲免费观看在线视频| 美女尤物久久精品| 免费在线亚洲欧美| 狠狠色狠色综合曰曰| 久久久.com| 麻豆av一区二区三区久久| 国内精品久久久久久久影视麻豆| 亚洲一级二级| 欧美一区二区视频观看视频| 国产精品美女一区二区| 亚洲一区二区少妇| 亚洲欧美日韩国产中文| 国产精品夜色7777狼人| 午夜伦理片一区| 久久九九免费| 国产综合精品| 久久综合狠狠综合久久激情| 欧美成年人视频网站欧美| 亚洲国产精品ⅴa在线观看| 久久中文字幕导航| 亚洲国产精品成人一区二区| 99这里只有精品| 欧美日韩在线一区二区| 9色porny自拍视频一区二区| 午夜日韩在线观看| 国内视频精品| 欧美.www| 亚洲视频免费在线| 久久精品国产第一区二区三区| 国语精品中文字幕| 欧美国产大片| 亚洲视频在线免费观看| 久久成人综合视频| 黄色亚洲精品| 每日更新成人在线视频| 日韩视频三区| 久久久久久久一区二区三区| 亚洲国产精品悠悠久久琪琪 | 亚洲欧美不卡| 免费久久精品视频| 亚洲视频免费在线观看| 国产日韩欧美一区二区| 久久一区二区视频| 日韩视频免费观看高清在线视频 | 欧美激情第8页| 亚洲欧美成人在线| 在线观看亚洲精品视频| 欧美激情第二页| 欧美一区二区免费| 亚洲国产日韩一区| 欧美伊人久久久久久久久影院| 亚洲国产日韩综合一区| 国产精品国产精品| 蜜臀av一级做a爰片久久| 亚洲午夜精品国产| 欧美黄色网络| 久久福利精品| 国产精品分类| 欧美成年人在线观看| 午夜精品婷婷| 一区二区三区视频观看| 欧美va亚洲va日韩∨a综合色| 亚洲一区在线免费| 91久久精品美女高潮| 国产一区二区剧情av在线| 欧美日韩第一区日日骚| 美女精品视频一区| 欧美在线观看你懂的| 一区二区三区四区精品| 欧美**人妖| 久久久久久69| 欧美影院在线播放| 中文精品99久久国产香蕉| 影音先锋亚洲一区| 韩国欧美国产1区| 欧美日韩一区二区在线观看视频| 麻豆精品国产91久久久久久| 欧美亚洲综合另类| 亚洲一区二区免费视频| 99在线精品视频在线观看| 亚洲国产欧美在线| 亚洲高清不卡在线观看| 欧美成年人视频| 欧美成人激情视频免费观看| 久久人人97超碰国产公开结果 | 亚洲人成毛片在线播放| 精品白丝av| 影音先锋久久久| 亚洲电影av| 亚洲精品久久久蜜桃| 91久久一区二区| av不卡在线看| 一区二区久久久久久| 在线一区二区三区四区| 亚洲视频一区二区| 亚洲小说欧美另类婷婷| 亚洲视频视频在线| 亚洲男人的天堂在线观看| 午夜一区不卡| 久久久蜜桃精品| 欧美成人免费视频| 亚洲高清123| 亚洲久久视频| 亚洲欧美激情四射在线日| 亚洲一区二区三区午夜| 欧美亚洲视频| 美国十次成人| 国产精品久久久久久超碰| 国产精品少妇自拍| 黑丝一区二区| 亚洲片国产一区一级在线观看| 亚洲乱码国产乱码精品精可以看| 一区二区三区欧美亚洲| 午夜视频在线观看一区| 免费成人激情视频| 亚洲国产精品一区| 一区二区三区福利| 欧美在线视频一区二区| 蜜臀av在线播放一区二区三区| 欧美日本精品| 国产综合久久| 亚洲视频999| 久久久一区二区三区| 亚洲国产另类精品专区| 亚洲影院在线| 蜜桃av一区二区| 国产精品久久久久久户外露出| 精品成人久久| 亚洲一区二区三区中文字幕在线 | 日韩写真视频在线观看| 欧美一级在线视频| 欧美精品高清视频| 国产亚洲毛片在线| 99精品视频一区| 一区免费在线| 亚洲男女自偷自拍| 亚洲国产日韩欧美在线动漫| 亚洲欧美中文日韩v在线观看| 欧美 日韩 国产 一区| 国产精品久久9| 亚洲精品极品| 久久在线精品| 亚洲一区二区三区在线视频| 欧美福利小视频| 在线观看不卡| 久久久一二三| 欧美在线黄色| 国产精品久久久久久久电影| 日韩特黄影片|