首页
社区
课程
招聘
[原创]是男人就上120层 Patch
发表于: 2007-4-26 13:13 9291

[原创]是男人就上120层 Patch

2007-4-26 13:13
9291

【文章标题】: 是男人就上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


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (4)
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
2
LZ的方向该不会是游戏辅助吧。。。。

另外。。。发两个帖,居然显示发帖数为1。。。BUG?
2007-4-26 17:15
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
3
哈哈, 那力气大得,小人一直在飞
2007-4-26 18:33
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我这边运行有问题,有假死状态
2007-4-26 18:51
0
雪    币: 328
活跃值: (10)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
5
咿?我没注意到还可以朝这方向发展,最近努力学五笔以备将来没工作了开个打字社来着.... 


我忘了说了,游戏改了之后,变成“有耐心就上1200层”了,完全是另一个游戏 


我也很新,对于为什么会出现你这种情况完全没有头绪。一起等高手来解释...
2007-4-26 22:10
0
游客
登录 | 注册 方可回帖
返回
//