【文章标题】: 是男人就上120层 破解
【文章作者】: Nukou.G
【软件名称】: 是男人就上120层
【软件大小】: 480K
【下载地址】: 黑客X档案4月份附书光盘中
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: VC4.0
【使用工具】: OllyDBG
【操作平台】: WinXP
【软件介绍】: 这个游戏没玩过也该听过吧
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  当输入的注册码不正确时弹出一个对话框提示错误。在MessageBoxA上下断点,输入注册码
  会断在这里:
  00402FE1   .  8D85 FCFDFFFF lea     eax, dword ptr [ebp-204]
  00402FE7   .  50            push    eax
  00402FE8   .  E8 C0010000   call    004031AD                                ;  验证注册码的函数
  00402FED   .  83C4 04       add     esp, 4
  00402FF0   .  85C0          test    eax, eax
  00402FF2   .  0F85 37000000 jnz     0040302F
  00402FF8   .  68 00010000   push    100                                     ; /Count = 100 (256.)
  00402FFD   .  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]                ; |
  00403003   .  50            push    eax                                     ; |Buffer
  00403004   .  6A 04         push    4                                       ; |RsrcID = STRING "Registration number is incorrect."
  00403006   .  A1 98D24000   mov     eax, dword ptr [40D298]                 ; |
  0040300B   .  50            push    eax                                     ; |hInst => NULL
  0040300C   .  FF15 BCF34000 call    dword ptr [<&USER32.LoadStringA>]       ; \LoadStringA
  00403012   .  6A 10         push    10                                      ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
  00403014   .  68 6CC24000   push    0040C26C                                ; |Title = "NS-TOWER"
  00403019   .  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]                ; |
  0040301F   .  50            push    eax                                     ; |Text
  00403020   .  8B45 08       mov     eax, dword ptr [ebp+8]                  ; |
  00403023   .  50            push    eax                                     ; |hOwner
  00403024   .  FF15 B8F34000 call    dword ptr [<&USER32.MessageBoxA>]       ; \MessageBoxA
  可见004031AD就是验证注册码的函数了
  来到004031AD 处:
  004031AD   $  55            push    ebp
  004031AE   .  8BEC          mov     ebp, esp
  004031B0   .  83EC 04       sub     esp, 4
  004031B3   .  53            push    ebx
  004031B4   .  56            push    esi
  004031B5   .  57            push    edi
  004031B6   .  8B45 08       mov     eax, dword ptr [ebp+8]
  004031B9   .  33C9          xor     ecx, ecx
  004031BB   .  8A48 07       mov     cl, byte ptr [eax+7]                    ;  注册码的长度要小于8
  004031BE   .  85C9          test    ecx, ecx
  004031C0   .  0F84 07000000 je      004031CD
  .......
  00403315   .  C9            leave
  00403316   .  C3            retn
  中间的汇编代码略去,该段代码等价于:
  {
    ...
      int i = 0;
    while(i < 0x7)
    {
      if (fun(serial[i]) > 24)
      {
        return(0);
      }
      i++;
    }
  
    if ((( fun(serial[5])*2 +  fun(serial[2]) + 0x1C) % 0x24) == fun(serial[0]))
    {
      if ((( fun(serial[4])*2 +  fun(serial[1])+ 0x1C) % 0x24) == fun(serial[6]))
      {
        if ((( fun(serial[6])*2 +  fun(serial[0]) + 0x1C) % 0x24) == fun(serial[3]))
        {
          return(1);
        }
      }
    }
    
    return(0);
  }
  其中fun()函数是00403317处的函数,其代码等价于:
  char fun(char key)
  {
    if (key >= 0x61)
    {
      key  -= 0x20;
    }
    else if (key >= 0x41)
    {
      key -= 0x7;
    }
  
    key -= 0x30;
  
    return(key);
  }
  
  一切都很明显了。
  ==========
  注册机编写
  当然是穷举,不过在这之前仔细观察一下3个条件:
  (( fun(serial[5])*2 +  fun(serial[2]) + 0x1C) % 0x24) == fun(serial[0])
  (( fun(serial[4])*2 +  fun(serial[1])+ 0x1C) % 0x24) == fun(serial[6])
  (( fun(serial[6])*2 +  fun(serial[0]) + 0x1C) % 0x24) == fun(serial[3])
  看出来了吧?serial[6]和serial[0]是两个关键位,先确定这两个位,剩下的就简单了:
  #include <stdio.h>
  #include <stdlib.h>
  
  char defun(char key)
  {
    key += 0x30;
    
    if (key >= 0x41-0x7)
    {
      key += 0x7;
    }
    else if (key >= 0x61-0x20)
    {
      key += 0x20;
    }
    
    return(key);
  }
  
  void main()
  {
    char serial[7];
    int i;
  
    serial[5] = 0;
    serial[4] = 0;
    for (serial[6] = 0; serial[6] < 0x24; serial[6]++)
    {
      for (serial[0] = 0; serial[0] < 0x24; serial[0]++)
      {
        serial[3] = ((serial[6]*2 + serial[0])+ 0x1C) % 0x24;
        for (serial[2] = 0; serial[2] < 0x24; serial[2]++)
        {
          if (serial[6] == (serial[2]+ 0x1C) % 0x24)
            for (serial[1] = 0; serial[1] < 0x24; serial[1]++)
            {
              if (serial[4] == (serial[1]+ 0x1C) % 0x24)
              {
                for (i = 0; i < 7; i++)
                {
                  serial[i] = defun(serial[i]);
                  printf("%c", serial[i]);
                }
                system("pause");
                printf("\n");
              }
            }
        }
      }
    }
  }
  
--------------------------------------------------------------------------------
【经验总结】
  以前没耐心看汇编代码,很少能独立解决一个软件。经过一段时间的锻炼,阅读汇编不是那么痛苦的事情了,能独立解决的
  问题也多了起来了。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

【文章标题】: 是男人就上120层 Patch
【文章作者】: Nukou.G
【软件名称】: 是男人就上120层
【软件大小】: 480K
【下载地址】: 黑客X档案4月份附书光盘中
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: VC4.0
【使用工具】: OllyDBG
【操作平台】: WinXP
【软件介绍】: 这个游戏没玩过也该听过吧
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  每次这个程序启动都会显示一个对话框:“BGM1.MID was not found.  Please put it in the same folder as application file.”很烦人,没有这个文件程序一样运行,所以把这个对话框跳过去。顺便再给游戏加一个功能:1-=键分别对应12个弹跳力度,不用按住空格键蓄力了(当然这样难度降低了)。
  
  先是去掉那恼人的对话框:在MessageBoxA函数上下断点,运行会断在
  0040495F  |. /0F85 4E000000 jnz     004049B3
  00404965  |. |68 00010000   push    100                              ; /Count = 100 (256.)
  0040496A  |. |8D85 00FFFFFF lea     eax, dword ptr [ebp-100]         ; |
  00404970  |. |50            push    eax                              ; |Buffer
  00404971  |. |6A 05         push    5                                ; |RsrcID = STRING "NS-TOWER Error"
  00404973  |. |A1 98D24000   mov     eax, dword ptr [40D298]          ; |
  00404978  |. |50            push    eax                              ; |hInst => 00400000
  00404979  |. |FF15 BCF34000 call    dword ptr [<&USER32.LoadStringA>>; \LoadStringA
  0040497F  |. |68 00010000   push    100                              ; /Count = 100 (256.)
  00404984  |. |8D85 00FEFFFF lea     eax, dword ptr [ebp-200]         ; |
  0040498A  |. |50            push    eax                              ; |Buffer
  0040498B  |. |6A 06         push    6                                ; |RsrcID = STRING "BGM1.MID was not found.  Please put it in the same folder as application file."
  0040498D  |. |A1 98D24000   mov     eax, dword ptr [40D298]          ; |
  00404992  |. |50            push    eax                              ; |hInst => 00400000
  00404993  |. |FF15 BCF34000 call    dword ptr [<&USER32.LoadStringA>>; \LoadStringA
  00404999  |. |6A 30         push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
  0040499B  |. |8D85 00FFFFFF lea     eax, dword ptr [ebp-100]         ; |
  004049A1  |. |50            push    eax                              ; |Title
  004049A2  |. |8D85 00FEFFFF lea     eax, dword ptr [ebp-200]         ; |
  004049A8  |. |50            push    eax                              ; |Text
  004049A9  |. |8B45 08       mov     eax, dword ptr [ebp+8]           ; |
  004049AC  |. |50            push    eax                              ; |hOwner
  004049AD  |. |FF15 B8F34000 call    dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
  
  把
  0040495F  |. /0F85 4E000000 jnz     004049B3
  处的jnz改成jmp就可以
  
  然后是给程序加上快捷键:先要找到游戏的过程函数,起初我想在NewGame那个按钮上找找,结果什么也找不到=.=。然后我注意到WINMM.sndPlaySoundA这个函数,蓄力时是不是用这个函数发出声音的?在这个函数上下断点后断在:
  00406E47  |.  FF15 58F44000 call    dword ptr [<&WINMM.sndPlaySoundA>;  WINMM.sndPlaySoundA
  00406E4D  |.  817D 0C 9D000>cmp     dword ptr [ebp+C], 9D
  00406E54  |.  0F87 1B000000 ja      00406E75
  哈哈,我们到游戏的过程里了!给这个函数改名为MakeSnd(在这个函数的开始位置00406E3D上右键>编辑标签>输入名称),给这个大函数(004067DA )命名为Fun
  跟着这个函数返回到一个开始于004067DA结束于00406DA2的函数。那这个函数做了些什么呢?这个函数调用的函数们又都做了什么呢?你肯定不愿意去读这么长的汇编代码,而且不知道它是不是真的是我们要找的函数,当然我也是:P。
  这里我有个小技巧:把OllyDBG的窗口和游戏窗口分开,不要让OllyDBG的窗口盖住游戏窗口,然后在每个CALL之前都下断(MakeSnd函数就算了,我们知道它做什么的了),多按几次F9,会发现游戏总是在下面4个地方被断:
  0040681B  |.  E8 44FCFFFF   call    00406464
  00406837  |.  E8 6FF7FFFF   call    00405FAB
  00406D24  |.  E8 EAE3FFFF   call    00405113
  00406D30  |.  E8 DAEEFFFF   call    00405C0F
  而且每次执行
  00406D24  |.  E8 EAE3FFFF   call    00405113
  这句之后小人就会向前走一步,那我们就给这个函数命名为Walk,然后把所有call Walk处的断点去掉。
  但是程序依然一直在剩下的3个位置中断,这是因为我们没有对游戏窗口进行任何输入。而我们要收集更多的信息来了解程序,所以把这3个函数分别命名为Fun1、Fun2、Fun3,然后去掉这些断点。F9,现在游戏没有被中断。
  切到游戏窗口,按一下空格,这次程序中断在
  004068F1  |.  E8 9DF1FFFF   call    00405A93
  我们F8一下,如果你的游戏窗口位置放的合适的话,你会发现POWER槽涨了一格!把这个函数命名为ChgPow。存放力度的内存地址很有可能在这个函数里找到。先看看函数的参数(我这里是0x144108):00144108  C2 05 01 00不是很象。只有跟进去了,好在这个函数不是很长,然后我第一眼就看到了可疑的BitBlt的可疑的参数:
  00405ABA  |.  8B45 08       mov     eax, dword ptr [ebp+8]           ; |
  00405ABD  |.  8B80 A8110000 mov     eax, dword ptr [eax+11A8]        ; |<这里的时候看看EAX
  00405AC3  |.  C1E0 04       shl     eax, 4                           ; |
  00405AC6  |.  05 A0000000   add     eax, 0A0                         ; |
  00405ACB  |.  50            push    eax                              ; |YSrc
  跟踪的时候注意寄存器,在执行mov     eax, dword ptr [eax+11A8]后看看EAX的值,再看看力度槽,我们找到存放力度的内存了!就是距ChgPow函数的唯一的参数指向的位置+11A8的地方,现在我们回到刚才的函数看看给ChgPow传了什么:
  004068ED  |.  8B45 08       mov     eax, dword ptr [ebp+8]
  004068F0  |.  50            push    eax
  004068F1  |.  E8 9DF1FFFF   call    <ChgPow>
  原来是这个函数的第一个参数。
  现在我们继续我们的分析,把call ChgPow处的断点去掉,回到游戏中按一下空格,程序又中断了:
  00406AE7  |.  E8 BFF4FFFF   call    <Fun2>
  又见Fun2,不过除了几个寄存器,画面和力度都没有改变,它到底是干什么的呢?刚才我就在想:小人能跑能跳,跑的函数我找到了,跳的函数跑哪里去了啊?其实刚才调试的过程中我们的小人已经跳了好几下了,而程序会断的几个函数我们都识别出来了,这个Fun2除外,不用想了,它就是Jump函数了。如果你需要我证明的话,你进去游戏按住空格蓄力试试:蓄力的过程中程序没有中断,而松开的时候程序中断在Fun2这个位置,而这个时候就是小人起跳的时候。
  多玩一会你就会认出
  00406A47  |.  E8 72F8FFFF   call    004062BE
  处的是移动屏幕的MovScr函数
  00406CB2  |.  E8 57DCFFFF   call    0040490E
  处的是玩家死亡的Die函数
  不过由于它们与我们的目标毫无关联,这里就不赘述了,有兴趣的朋友可以自己跟一下。
  现在我们要找的是检查玩家按键的地方,到哪里找?还是刚才我们分析的那个函数。仔细想想:肯定是我们按了蓄力键才会调用ChgPow函数,那我们没按键的时候一定有一个跳转跳过ChgPow函数。从004068F1  call    <ChgPow>处向上检查各个跳转。我们够幸运,遇到的第一跳转就那么可疑:
  004068B3  |> \8B45 08       mov     eax, dword ptr [ebp+8]
  004068B6  |.  83B8 08130000>cmp     dword ptr [eax+1308], 1
  004068BD  |.  0F85 66000000 jnz     00406929
  看来[ebp+8]+1308就是传说中的标记了,找到该内存地址并下内存写断点。F9,游戏正常运行,我们切过去按一下空格,断在
  00404352  |.  C780 08130000>mov     dword ptr [eax+1308], 1
  现在我们找到了判断按键的地方了!把这个语句所在的函数命名为CheKey,在这附近很有可能有修改力度的语句,力度放在距ChgPow函数的参数指向的位置+11A8的地方,有意思的是CheKey的第一参数指向的也是那个位置...
  因为我们要给CheKey做手术,所以需要弄明白它的流程,这个函数等价于:
  void CheKey(PDWORD pPower, DWORD key, DWORD flag, DWORD, DWORD)
  {
    if (key == ' ')
    {
      if (flag == 0)
      {
        KeyIsPressed = 0;
      }
      else
      {
        KeyIsPressed = 1;
  
        if (*(pPower+0x1190) == 0x3)
        {
          Pause(pPower);
        }
      }
    }
    else if (key == 0x1B)
    {//0x1B是哪个键...
      if (flag != 0)
      {
        if (*(pPower+0x1190) == 0x3)
        {
          Pause(pPower);
        }
      }
    }
  }
  出乎意料的是这个函数没有修改力度,我们得到别处去找到底是哪个位置修改了力度(必须知道游戏原来是怎么做的,我们才能在那基础上修改而不造成错误)。在存放力度的内存下内存写断点,F9,进游戏蓄力,断在:
  004068B6  |.  83B8 08130000>cmp     dword ptr [eax+1308], 1
  004068BD  |.  0F85 66000000 jnz     00406929
  004068C3  |.  8B45 08       mov     eax, dword ptr [ebp+8]
  004068C6  |.  C780 AC110000>mov     dword ptr [eax+11AC], 1
  004068D0  |.  8B45 08       mov     eax, dword ptr [ebp+8]
  004068D3  |.  B9 0C000000   mov     ecx, 0C
  004068D8  |.  8B80 A8110000 mov     eax, dword ptr [eax+11A8]
  004068DE  |.  99            cdq
  004068DF  |.  F7F9          idiv    ecx
  004068E1  |.  8D42 01       lea     eax, dword ptr [edx+1]
  004068E4  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]
  004068E7  |.  8981 A8110000 mov     dword ptr [ecx+11A8], eax <断在这里
  看来他是判断是否KeyIsPressed标志来给力度加一的。
  现在需要知道的都知道了,只剩写代码了。我的策略是:在各个新加的功能键的事件里,把力度修改成原计划的力度-1(1对0,2对1...-对10,=对11)并把KeyIsPressed置1,这样004068E7处加以后就达成了原来的目标了(我不想说的这么拗口的=.=!!!)。
  把CheKey改成这样:
  void CheKey(PDWORD pPower, DWORD key, DWORD flag, DWORD, DWORD)
  {
    if (key == ' ')
    {
      if (flag == 0)
      {
        KeyIsPressed = 0;
      }
      else
      {
        KeyIsPressed = 1;
  
        if (*(pPower+0x1190) == 0x3)
        {
          00407157(pPower);
        }
      }
    }
    else if (key == '1')
    {
      POWER = 1;
      if (flag == 0)
      {
        KeyIsPressed = 0;
      }
      else
      {
        KeyIsPressed = 1;
  
        if (*(pPower+0x1190) == 0x3)
        {
          Pause(pPower);
        }
      }
    }
    else if (key == '2')
  ....
    else if (key == 0x1B)
    {//0x1B是哪个键...
      if (flag != 0)
      {
        if (*(pPower+0x1190) == 0x3)
        {
          Pause(pPower);
        }
      }
    }
  }
  回游戏试一试,令人失望的是没象我们预想的那样按键之后就跳,依然是以前那样的停止蓄力才跳。看来我们还得找一个信息:他什么条件下才跳(我不是说跳转...)。找这个自然要从Jump函数入手,有两处调用Jump:
  00406837  |.  E8 6FF7FFFF   call    <Jump>
  与
  00406AE7  |.  E8 BFF4FFFF   call    <Jump>
  其中00406837处始终被断,不用考虑了。现在研究哪个跳转会决定00406AE7处的语句是否会被执行。这次没省力气的方法了(至少我不知道),我只好在函数Fun的入口开始跟踪,然后我就只发现了1处:
  00406823  |.  8B45 08       mov     eax, dword ptr [ebp+8]
  00406826  |.  83B8 B0110000>cmp     dword ptr [eax+11B0], 0
  0040682D  |.  0F85 E4010000 jnz     00406A17
  它离Fun入口不远,找起来没想象的困难。
  这里又多了个pPower+0x11B0,当他是WanaJump标志了:P
  再加上修改WanaJump的语句,运行测试一下功能键。结果依然令人失望:能听见跳的声音,但是小人完全没动作....
  我们在看看正常跳的时候程序是什么情况:
  00406AC9  |> \33C0          xor     eax, eax
  00406ACB  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]
  00406ACE  |.  8B89 A0110000 mov     ecx, dword ptr [ecx+11A0]<看看ECX的值
  00406AD4  |.  03C9          add     ecx, ecx
  00406AD6  |.  2BC1          sub     eax, ecx
  00406AD8  |.  F7D8          neg     eax
  00406ADA  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]
  00406ADD  |.  2981 98110000 sub     dword ptr [ecx+1198], eax
  00406AE3  |>  8B45 08       mov     eax, dword ptr [ebp+8]
  00406AE6  |.  50            push    eax
  00406AE7  |.  E8 BFF4FFFF   call    <Jump>
  在00406AC9处下断点(在这里下断点的原因是我怀疑它之后的语句对Jump的参数有影响),回游戏按空格正常蓄力,注意到pPower+11A0处的值与力度相同。然后让游戏运行,按一下我们的功能键:pPower+11A0的值是0?
  再加上修改pPower+11A0处数据的语句。回到游戏,测试一下,成了!
  这里是各数据的偏移量(相对于pPower也就是[ebp+8]):
  11A8 POWER
  11B0 WanaJump
  1308 IsKerPressed
  11A0 NoName
  这里是OllyDBG中的代码:
  0040433F   . /0F85 74690000 jnz     0040ACB9
  =======
  0040ACB9   > \33C0          xor     eax, eax
  0040ACBB   .  837D 0C 31    cmp     dword ptr [ebp+C], 31
  0040ACBF   .  75 05         jnz     short 0040ACC6
  0040ACC1   .  B8 01000000   mov     eax, 1
  0040ACC6   >  837D 0C 32    cmp     dword ptr [ebp+C], 32
  0040ACCA   .  75 05         jnz     short 0040ACD1
  0040ACCC   .  B8 02000000   mov     eax, 2
  0040ACD1   >  837D 0C 33    cmp     dword ptr [ebp+C], 33
  0040ACD5   .  75 05         jnz     short 0040ACDC
  0040ACD7   .  B8 03000000   mov     eax, 3
  0040ACDC   >  837D 0C 34    cmp     dword ptr [ebp+C], 34
  0040ACE0   .  75 05         jnz     short 0040ACE7
  0040ACE2   .  B8 04000000   mov     eax, 4
  0040ACE7   >  837D 0C 35    cmp     dword ptr [ebp+C], 35
  0040ACEB   .  75 05         jnz     short 0040ACF2
  0040ACED   .  B8 05000000   mov     eax, 5
  0040ACF2   >  837D 0C 36    cmp     dword ptr [ebp+C], 36
  0040ACF6   .  75 05         jnz     short 0040ACFD
  0040ACF8   .  B8 06000000   mov     eax, 6
  0040ACFD   >  837D 0C 37    cmp     dword ptr [ebp+C], 37
  0040AD01   .  75 05         jnz     short 0040AD08
  0040AD03   .  B8 07000000   mov     eax, 7
  0040AD08   >  837D 0C 38    cmp     dword ptr [ebp+C], 38
  0040AD0C   .  75 05         jnz     short 0040AD13
  0040AD0E   .  B8 08000000   mov     eax, 8
  0040AD13   >  837D 0C 39    cmp     dword ptr [ebp+C], 39
  0040AD17   .  75 05         jnz     short 0040AD1E
  0040AD19   .  B8 09000000   mov     eax, 9
  0040AD1E   >  837D 0C 30    cmp     dword ptr [ebp+C], 30
  0040AD22   .  75 05         jnz     short 0040AD29
  0040AD24   .  B8 0A000000   mov     eax, 0A
  0040AD29   >  817D 0C BD000>cmp     dword ptr [ebp+C], 0BD
  0040AD30   .  75 05         jnz     short 0040AD37
  0040AD32   .  B8 0B000000   mov     eax, 0B
  0040AD37   >  817D 0C BB000>cmp     dword ptr [ebp+C], 0BB
  0040AD3E   .  75 05         jnz     short 0040AD45
  0040AD40   .  B8 0C000000   mov     eax, 0C
  0040AD45   >  85C0          test    eax, eax
  0040AD47   .^ 0F84 4196FFFF je      0040438E
  0040AD4D   .  8B5D 08       mov     ebx, dword ptr [ebp+8]
  0040AD50   .  837D 10 01    cmp     dword ptr [ebp+10], 1
  0040AD54   .  75 00         jnz     short 0040AD56
  0040AD56   >  8983 A8110000 mov     dword ptr [ebx+11A8], eax
  0040AD5C   .  C783 08130000>mov     dword ptr [ebx+1308], 0
  0040AD66   .  C783 B0110000>mov     dword ptr [ebx+11B0], 1
  0040AD70   .  8983 A0110000 mov     dword ptr [ebx+11A0], eax
  0040AD76   .^ E9 4F96FFFF   jmp     004043CA
  
  玩了一下发现:用功能键的时候不是跳,是飞!不踩地板都往上升....
  大家还是把新加的功能键当作救命用的吧,不然就跟我一样不想玩它了.....
  
--------------------------------------------------------------------------------
【经验总结】
  看来动手之前的观察是很重要的,要通过观察程序的表现推测程序的运行原理,进而判断我们需要收集的信息,这样动手的
  时候就有的方向,可以少走不少弯路。而我这次就走了几次弯路。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年04月26日 13:07:33