搜索文章:

首页  |  Java技术  |  Asp.net  |  Asp编程  |  VC/C++  |  Delphi  |  VB编程

riijj Crackme (4)的详解 1

【破文标题】riijj Crackme (4) 的详解
【对  象】中级新手
【下载地址】http://bbs.pediy.com/upload/file/2004/12/riijj_cm_20041217.zip_783.zip
【破解工具】OD, softice
【保护方式】序号
【任  务】找出序号
【破文作者】riijj
【组  织】没有
【破解声明】我的破解很菜,写这篇东西是给对这个 crackme 有兴趣的兄弟们,分享一下破解心得
【电  邮】je6543@yahoo.com
【调试环境】w2k
【破解过程】

  
  这个 crackme 是一个自调试程序的例子。当一个程序被调试时,其它程序不可以对它进行调试,这种做法是防止破解者用 ring3 调试器加载。

  这篇文章会讨论这个 crackme 使用的方法与结构,希望让不熟悉自调试的兄弟们有一点初部印象。



[ Part I.  观察 ]


  刚下载了这个 crackme,看见它包含 5 个档案,其中一个是执行档 Crackme4.exe (外表像一只魔鬼),另外有 3 个 sub 档,还有一个 zip 档,它是一张图片的压缩文件,只要破解成功便可以取得解压的密码。


  我们尝试用 OD 打开 Crackme4.exe ,只忽略 KERNEL32 内存异常, F9 运行,程序很顺利地打开,似乎这个 crackme 没有设置反调试 (的确是这样)

  我们输入注册名字 "riijj" ,序号 "AAAABBBB"


  现在开始动手,先试试简单的断点

  bp GetWindowTextA

  现在输入序号,按下 register,没有反应。

  我们怀疑这个程序的真正核心不是在 Crackme4.exe 里,我们现在检查一下,在 OD 里按一下 F12 (暂停程序)

  很奇怪,OD 显示程序是停止了,现在身处 ntdll 的 77F82870 ,可是 crackme 依然正常运作,窗口和 resgister 按钮也有反应。我们按 OD 上方的 View > Threads  (查看线程),看见这个 crackme4.exe 只有一个线程,现在这个线程已经停止了。

  我们打开工作管理员,可以看见 sub1.ooo sub2.ooo 和 sub3.ooo 的名字,很明显它们才是真正运行的东西。


[ Part II.  结构分析 ]



  我们把 crackme 再新加载,设定断点

  bp CreateProcessA

  现在 F9 运行

KERNEL32
  
77E73F8F > 55               PUSH EBP   <------ 停在这里
77E73F90   8BEC             MOV EBP,ESP
77E73F92   FF75 2C          PUSH DWORD PTR SS:[EBP+2C]
77E73F95   FF75 28          PUSH DWORD PTR SS:[EBP+28]
77E73F98   FF75 24          PUSH DWORD PTR SS:[EBP+24]
77E73F9B   FF75 20          PUSH DWORD PTR SS:[EBP+20]

  按 Alt + F9 返回 crackme

00401012  |. 50             PUSH EAX                                 ; /pStartupinfo
00401013  |. FF15 0C404000  CALL DWORD PTR DS:[<&KERNEL32.GetStartup>; \GetStartupInfoA
00401019  |. 8D4C24 00      LEA ECX,DWORD PTR SS:[ESP]
0040101D  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]
00401021  |. 51             PUSH ECX                                 ; /pProcessInfo
00401022  |. 52             PUSH EDX                                 ; |pStartupInfo
00401023  |. 6A 00          PUSH 0                                   ; |CurrentDir = NULL
00401025  |. 6A 00          PUSH 0                                   ; |pEnvironment = NULL
00401027  |. 6A 03          PUSH 3                                   ; |CreationFlags = DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
00401029  |. 6A 00          PUSH 0                                   ; |InheritHandles = FALSE
0040102B  |. 6A 00          PUSH 0                                   ; |pThreadSecurity = NULL
0040102D  |. 6A 00          PUSH 0                                   ; |pProcessSecurity = NULL
0040102F  |. 6A 00          PUSH 0                                   ; |CommandLine = NULL
00401031  |. 68 4C504000    PUSH Crackme4.0040504C                   ; |ModuleFileName = "sub3.ooo"  <---看见这个
00401036  |. FF15 08404000  CALL DWORD PTR DS:[<&KERNEL32.CreateProc>; \CreateProcessA
0040103C  |. 85C0           TEST EAX,EAX                            <-------我们在这里
0040103E  |. 75 09          JNZ SHORT Crackme4.00401049
00401040  |. 81C4 B4000000  ADD ESP,0B4
00401046  |. C2 1000        RETN 10
00401049  |> 56             PUSH ESI
0040104A  |. 57             PUSH EDI
0040104B  |. 68 30504000    PUSH Crackme4.00405030                   ; /Title = "Riijj Crackme - 20041217"
00401050  |. 6A 00          PUSH 0                                   ; |Class = 0
00401052  |. FF15 A4404000  CALL DWORD PTR DS:[<&USER32.FindWindowA>>; \FindWindowA
00401058  |. 6A 03          PUSH 3                                   ; /Flags = SWP_NOSIZE|SWP_NOMOVE
0040105A  |. 6A 00          PUSH 0                                   ; |Height = 0
0040105C  |. 6A 00          PUSH 0                                   ; |Width = 0
0040105E  |. 6A 00          PUSH 0                                   ; |Y = 0
00401060  |. 6A 00          PUSH 0                                   ; |X = 0
00401062  |. 6A 00          PUSH 0                                   ; |InsertAfter = HWND_TOP
00401064  |. 50             PUSH EAX                                 ; |hWnd
00401065  |. FF15 A0404000  CALL DWORD PTR DS:[<&USER32.SetWindowPos>; \SetWindowPos
0040106B  |. 8B35 04404000  MOV ESI,DWORD PTR DS:[<&KERNEL32.WaitFor>;  KERNEL32.WaitForDebugEvent
00401071  |. 8B3D 54404000  MOV EDI,DWORD PTR DS:[<&KERNEL32.Continu>;  KERNEL32.ContinueDebugEvent
00401077  |> 8D4424 5C      /LEA EAX,DWORD PTR SS:[ESP+5C]
0040107B  |. 6A FF          |PUSH -1

  这个 crackme4.exe 创建新进程,档案是 sub3.ooo ,以 DEBUG_PROCESS 的方式产生,也就是说现在 crackme4.exe 是它的调试程序。

  一般调试程序的方法有两种,分别是以 CreateProcess 产生,或以 DebugActiveProcess 连接到运行中的程序。一般来说调试程序在使用 CreateProcess 后,便会使用 WaitForDebugEvent 来等待被调试者的 debug 事件发生 (例如 exception,进程开始或进程结束等 ) ,在处理事件后,用 ContinueDebugEvent 使被调试的程序继续运行

  我们在 0040106B 看见了 WaitForDebugEvent ,当程序执行到这里的时候,便会进入睡眠状态,即使我们停止它,也影响不到 sub3.ooo

  我们用 OD 把 sub3.ooo 加载,看看可不可以单独运行。


  加载后, F9 运行,果然我们看见了 crackme 的初始画面,可是运行了不久,程序便终止了。

77F8EE0F   C2 0800          RETN 8
77F8EE12   803D 0403FD77 00 CMP BYTE PTR DS:[77FD0304],0
77F8EE19   0F85 3E430000    JNZ ntdll.77F9315D
77F8EE1F   834D FC FF       OR DWORD PTR SS:[EBP-4],FFFFFFFF
77F8EE23   E8 0F000000      CALL ntdll.77F8EE37
77F8EE28   8B4D F0          MOV ECX,DWORD PTR SS:[EBP-10]

  OD 的下方写上 Process terminated


  我们估计,这个 crackme 在运行的时候产生了某种 exception,使程序运行的时候会把执行权交到父进程里,并在父进程运时做了一些必要工作,如果我们单独把 crackme 的子程序 (例如 sub3.ooo) 运行,便会导致运行不正常。

  这时时候,我们把 sub3 重新加载,依旧设断点在 CreateProcess 

  bp CreateProcessA

  F9 运行

  果然,断下来了, alt+F9 返回 crackme ,看到

00401013  |. FF15 0C404000  CALL DWORD PTR DS:[<&KERNEL32.GetStartup>; \GetStartupInfoA
00401019  |. 8D4C24 00      LEA ECX,DWORD PTR SS:[ESP]
0040101D  |. 8D5424 10      LEA EDX,DWORD PTR SS:[ESP+10]
00401021  |. 51             PUSH ECX                                 ; /pProcessInfo
00401022  |. 52             PUSH EDX                                 ; |pStartupInfo
00401023  |. 6A 00          PUSH 0                                   ; |CurrentDir = NULL
00401025  |. 6A 00          PUSH 0                                   ; |pEnvironment = NULL
00401027  |. 6A 03          PUSH 3                                   ; |CreationFlags = DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
00401029  |. 6A 00          PUSH 0                                   ; |InheritHandles = FALSE
0040102B  |. 6A 00          PUSH 0                                   ; |pThreadSecurity = NULL
0040102D  |. 6A 00          PUSH 0                                   ; |pProcessSecurity = NULL
0040102F  |. 6A 00          PUSH 0                                   ; |CommandLine = NULL
00401031  |. 68 30504000    PUSH sub3.00405030                       ; |ModuleFileName = "sub2.ooo"
00401036  |. FF15 08404000  CALL DWORD PTR DS:[<&KERNEL32.CreateProc>; \CreateProcessA
0040103C  |. 85C0           TEST EAX,EAX
0040103E  |. 75 09          JNZ SHORT sub3.00401049
00401040  |. 81C4 B4000000  ADD ESP,0B4

  sub3 在调试 sub2,我们估计 sub2 会调试 sub1

  现在我们用 OD 加载 sub2.ooo,设断点在 CreateProcessA

  bp CreateProcessA

  F9 运行

  我们断下来了,按 Alt+F9 返回 crackme,我们身处

00401169  |. FF15 DC674000  CALL DWORD PTR DS:[4067DC]
0040116F  |. 8D4C24 10      LEA ECX,DWORD PTR SS:[ESP+10]
00401173  |. 8D9424 8000000>LEA EDX,DWORD PTR SS:[ESP+80]
0040117A  |. 51             PUSH ECX
0040117B  |. 52             PUSH EDX
0040117C  |. 6A 00          PUSH 0
0040117E  |. 6A 00          PUSH 0
00401180  |. 6A 03          PUSH 3
00401182  |. 6A 00          PUSH 0
00401184  |. 6A 00          PUSH 0
00401186  |. 6A 00          PUSH 0
00401188  |. 6A 00          PUSH 0
0040118A  |. 68 30604000    PUSH sub2.00406030                       ;  ASCII "sub1.ooo"
0040118F  |. FF15 D4674000  CALL DWORD PTR DS:[4067D4]
00401195  |. 85C0           TEST EAX,EAX                <---------- 我们在这里
00401197  |. 0F84 9F020000  JE sub2.0040143C
0040119D  |. 8B7424 0C      MOV ESI,DWORD PTR SS:[ESP+C]
004011A1  |. 8B7C24 0C      MOV EDI,DWORD PTR SS:[ESP+C]
004011A5  |. BB 01000100    MOV EBX,10001
004011AA  |> 8D4424 20      /LEA EAX,DWORD PTR SS:[ESP+20]
004011AE  |. 6A FF          |PUSH -1
004011B0  |. 50             |PUSH EAX
004011B1  |. FF15 D0674000  |CALL DWORD PTR DS:[4067D0]
004011B7  |. 8B4424 20      |MOV EAX,DWORD PTR SS:[ESP+20]

  我们看见了 sub1 ,可是这里比较奇怪的是,我们看不见 CreateProcessA 的名字

  我们知道 0040118F 呼叫的 call 是呼叫 CreateProcessA,这表示 [4067D4] 这里存放了 CreateProcessA 的 API 位置

  API 的呼叫看来是经过处理的


  现在我们知道  crackme4.exe -> sub3.ooo -> sub2.ooo -> sub1.ooo ,我们估计程序的真正部分在 sub1.ooo 里,我们尝试单独用 OD 加载 sub1

  这时候,程序运行了,可是发生了 int 3 异常

00401D60  /$ 55             PUSH EBP
00401D61  |. 8BEC           MOV EBP,ESP
00401D63  |. 51             PUSH ECX
00401D64  |. 68 00010000    PUSH 100
00401D69  |. C745 FC A01440>MOV DWORD PTR SS:[EBP-4],sub1.004014A0
00401D70  |. E8 0D020000    CALL sub1.00401F82
00401D75  |. 83C4 04        ADD ESP,4
00401D78  |. A3 E0674000    MOV DWORD PTR DS:[4067E0],EAX
00401D7D  |. 60             PUSHAD
00401D7E  |. B8 FF000000    MOV EAX,0FF
00401D83  |. 8B15 E0674000  MOV EDX,DWORD PTR DS:[4067E0]
00401D89  |. 8B4D FC        MOV ECX,DWORD PTR SS:[EBP-4]
00401D8C     CC             INT3           <---------在这里
00401D8D  |. 8BE5           MOV ESP,EBP
00401D8F  |. 5D             POP EBP
00401D90  \. C3             RETN


  我们想象,这个 int 3 是故意放进去的,目的是产生异常,当异常出现时, sub1 停止运行,sub2 的 WaitForDebugEvent 会返回, sub2 开始运行,对于 WaitForDebugEvent 接收到的异常进行处理,当处理完成后,便使用 ContinueDebugEvent 继续 sub1。 

  

[ Part III.  调试 ]

  
  对于这种多进程的防护,使用 softice 是比较直接的。

  从取得字符串的地方开始跟踪,Ctrl + D 打开 softice,设断点

:bpx getwindowtexta

  离开后,按一下 "Register" 按钮,可是 softice 没有反应,可能这个程序没有使用 GetWindowTextA 来得到字符串。

  一般 windows 程序 (除了 delphi 以外),文字方块的取得字符串方法有以下几种 :

  1. GetWindowTextA  (送出 WM_GETTEXT)
  2. GetDlgItemTextA (内里使用 GetWindowTextA )
  3. SendMessage 送出 WM_GETTEXT
  4. SendMessage 送出 EM_GETLINE
  5. 程序拦截 WM_KEYDOWN ,把使用者按键纪录
  6. 直接取得文字内存 handle,Lock 后读取

  我们尝试在内存搜索字符串, Ctrl+D 打开 softice,

  选择 sub1 的领空

:addr sub1

  搜索字符串从 0 至 ffffffff

:s 0 L ffffffff "AAAABBBB"

  这时候, softice 提示 

Pattern found at 0010:0012F5EC (0012F5EC)

  在 0012F5EC 发现了序号字符串,我们设定内存断点在那里

:bpm 0012f5ec
  
  离开 softice 后,立即断在

001B:77DFFE62  F3A5                REPZ MOVSD
001B:77DFFE64  FF7508              PUSH      DWORD PTR [EBP+08]  <---这里
001B:77DFFE67  8BC8                MOV       ECX,EAX
001B:77DFFE69  83E103              AND       ECX,03
001B:77DFFE6C  F3A4                REPZ MOVSB
001B:77DFFE6E  E8110D0000          CALL      77E00B84
001B:77DFFE73  5E                  POP       ESI
001B:77DFFE74  5F                  POP       EDI
001B:77DFFE75  8BC3                MOV       EAX,EBX
001B:77DFFE77  5B                  POP       EBX
001B:77DFFE78  5D                  POP       EBP
001B:77DFFE79  C21000              RET       0010
001B:77DFFE7C  880C1F              MOV       [EBX+EDI],CL
001B:77DFFE7F  EBCD                JMP       77DFFE4E
001B:77DFFE81  55                  PUSH      EBP
001B:77DFFE82  8BEC                MOV       EBP,ESP
001B:77DFFE84  83EC3C              SUB       ESP,3C
001B:77DFFE87  53                  PUSH      EBX

  看看 code window 上方的提示,我们身处 User32!DrawStateA 里,我们看看当前的 call stack

:stack
FrameEBP  RetEIP     Symbol
0012F56C  77E006AC   USER32!DrawStateA+1D08
0012F5A8  77E004EA   USER32!EditWndProc+00D5
0012F5CC  77DF597E   USER32!DrawStateA+238E
0012FDF8  77FA15EF   USER32!PostMessageA+00CA
0012FE74  77DF70F3   ntdll!KiUserCallbackDispatcher+0013
0012FEB8  00401BA0   USER32!GetWindowTextA+0089
00000000  00000000   sub1!.text+0BA0

  我们可以看见 sub1 呼叫 GetWindowTextA,位置在 00401BA0

  到那里看看

:u 00401BA0

001B:00401B84  E827FAFFFF          CALL      004015B0
001B:00401B89  8B1534684000        MOV       EDX,[00406834]
001B:00401B8F  83C408              ADD       ESP,08
001B:00401B92  6A14                PUSH      14
001B:00401B94  6860684000          PUSH      00406860
001B:00401B99  52                  PUSH      EDX
001B:00401B9A  FF15A4684000        CALL      [004068A4]
001B:00401BA0  A1A0674000          MOV       EAX,[004067A0]  <---- 这里
001B:00401BA5  6A14                PUSH      14
001B:00401BA7  6880684000          PUSH      00406880
001B:00401BAC  50                  PUSH      EAX
001B:00401BAD  FF15A4684000        CALL      [004068A4]
001B:00401BB3  60                  PUSHAD
001B:00401BB4  B800000000          MOV       EAX,00000000
001B:00401BB9  CC                  INT       3
001B:00401BBA  61                  POPAD
001B:00401BBB  8B0DAC684000        MOV       ECX,[004068AC]
001B:00401BC1  51                  PUSH      ECX
001B:00401BC2  E879F6FFFF          CALL      00401240
001B:00401BC7  8B15AC684000        MOV       EDX,[004068AC]
001B:00401BCD  52                  PUSH      EDX
001B:00401BCE  E8DDF9FFFF          CALL      004015B0
001B:00401BD3  83C408              ADD       ESP,08
001B:00401BD6  6A01                PUSH      01
001B:00401BD8  6A00                PUSH      00
001B:00401BDA  6A00                PUSH      00
001B:00401BDC  6A00                PUSH      00
001B:00401BDE  68C0674000          PUSH      004067C0

  往上看,没有找到 GetWindowTextA,只见 CALL [004068A4]。 很明显 [004068A4] 是 GetWindowTextA 的位置,我们尝试过在 GetWindowTextA 下断,可是断不下来,估计断点被程序自行清除了。



  
[ Part IV.   解开断点清除]

  调试器设置普通断点时,在断点处放置 int 3 (0xcc) 来达到中断的效果,如果程序在执行前把 0xcc 恢复,断点便会消失

  我们要找出 GetWindowTextA 被存取的一刻,在它的位置设置内存断点

:bpm getwindowtexta

  离开 softice 后,我们立即断在

001B:004011AF  90                  NOP
001B:004011B0  8B442404            MOV       EAX,[ESP+04]
001B:004011B4  56                  PUSH      ESI
001B:004011B5  57                  PUSH      EDI
001B:004011B6  8B3D48684000        MOV       EDI,[00406848]
001B:004011BC  3BC7                CMP       EAX,EDI
001B:004011BE  7221                JB        004011E1
001B:004011C0  8B0D50684000        MOV       ECX,[00406850]
001B:004011C6  8D1439              LEA       EDX,[EDI+ECX]
001B:004011C9  3BC2                CMP       EAX,EDX
001B:004011CB  7714                JA        004011E1
001B:004011CD  8B3540684000        MOV       ESI,[00406840]
001B:004011D3  8BD1                MOV       EDX,ECX
001B:004011D5  C1E902              SHR       ECX,02
001B:004011D8  F3A5                REPZ MOVSD        <-------这里
001B:004011DA  8BCA                MOV       ECX,EDX
001B:004011DC  83E103              AND       ECX,03
001B:004011DF  F3A4                REPZ MOVSB
001B:004011E1  8B3DE8684000        MOV       EDI,[004068E8]
001B:004011E7  3BC7                CMP       EAX,EDI
001B:004011E9  7221                JB        0040120C

  这里是 sub1 的领空,奇怪的是,这里对 getwindowtexta 的内容进行读写  (REPZ MOVSD , 复制内存 )

  你中断的地方可能跟我不相同,如果不相同的话,你可以略过这里的描述,往下找找有没有你中断的地方

  我们按一下 F12 到达 call 的返回

001B:0040123F  90                  NOP
001B:00401240  8B442404            MOV       EAX,[ESP+04]
001B:00401244  8B4801              MOV       ECX,[EAX+01]
001B:00401247  51                  PUSH      ECX
001B:00401248  E863FFFFFF          CALL      004011B0
001B:0040124D  59                  POP       ECX   <-------这里
001B:0040124E  C3                  RET
001B:0040124F  90                  NOP
001B:00401250  83EC5C              SUB       ESP,5C
001B:00401253  B9DEFFFFFF          MOV       ECX,FFFFFFDE
001B:00401258  53                  PUSH      EBX
001B:00401259  BAE9FFFFFF          MOV       EDX,FFFFFFE9
001B:0040125E  56                  PUSH      ESI
001B:0040125F  894C241C            MOV       [ESP+1C],ECX
001B:00401263  894C2428            MOV       [ESP+28],ECX
001B:00401267  BEEDFFFFFF          MOV       ESI,FFFFFFED
001B:0040126C  89542414            MOV       [ESP+14],EDX
001B:00401270  B8DFFFFFFF          MOV       EAX,FFFFFFDF

  我们尝试把 00401248 的一行 nop 掉

:a 00401248

 nop 掉 5 个元位

  现在离开 softice ,再中断在


001B:004014DF  33D2                XOR       EDX,EDX
001B:004014E1  F3A6                REPZ CMPSB    <------这里
001B:004014E3  7405                JZ        004014EA
001B:004014E5  1BD2                SBB       EDX,EDX
001B:004014E7  83DAFF              SBB       EDX,-01
001B:004014EA  8BF2                MOV       ESI,EDX
001B:004014EC  8B15E8684000        MOV       EDX,[004068E8]
001B:004014F2  3BC2                CMP       EAX,EDX
001B:004014F4  722A                JB        00401520
001B:004014F6  8B0DF0684000        MOV       ECX,[004068F0]
001B:004014FC  8D3C11              LEA       EDI,[EDX+ECX]
001B:004014FF  3BC7                CMP       EAX,EDI
001B:00401501  771D                JA        00401520
001B:00401503  8B3DE0684000        MOV       EDI,[004068E0]
001B:00401509  2BC8                SUB       ECX,EAX
001B:0040150B  2BFA                SUB       EDI,EDX
001B:0040150D  03CA                ADD       ECX,EDX

  这里是内存比较 (REPZ CMPSB ),程序把备份的内容与现在的内容比较,如果不相同,便可能不进行呼叫或干其它事。

  按一下 F12 ,来到

001B:00401560  56                  PUSH      ESI
001B:00401561  8B742408            MOV       ESI,[ESP+08]
001B:00401565  56                  PUSH      ESI
001B:00401566  E845FFFFFF          CALL      004014B0
001B:0040156B  83C404              ADD       ESP,04  <-----这里
001B:0040156E  85C0                TEST      EAX,EAX   <--看见这里有比较
001B:00401570  7413                JZ        00401585   <--- F8 单步,是跳的
001B:00401572  56                  PUSH      ESI
001B:00401573  E838FCFFFF          CALL      004011B0
001B:00401578  56                  PUSH      ESI
001B:00401579  E832FFFFFF          CALL      004014B0
001B:0040157E  83C408              ADD       ESP,08
001B:00401581  85C0                TEST      EAX,EAX
001B:00401583  75ED                JNZ       00401572
001B:00401585  80BEE0000000CC      CMP       BYTE PTR [ESI+000000E0],CC
001B:0040158C  7513                JNZ       004015A1
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
  
  我们按 F8 单步,发现在没有断点的情况下,JZ 是跳的。我们把 00401566 的 call 修改

:a 00401566

  改成 xor eax,eax 和 3 个 nop

  现在离开 softice,再次中断在


001B:00401585  80BEE0000000CC      CMP       BYTE PTR [ESI+000000E0],CC
001B:0040158C  7513                JNZ       004015A1    <---这里
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
  
  这一句  CMP BYTE PTR [ESI+000000E0],CC  是把 getwindowtexta 的第一个位跟 0xcc ( int 3) 比较,检查是否被设为断点

  我们把 00401585 (CMP) 和 0040158C (JNZ) 两句 nop 掉

:a 00401585
一直 nop 至 0040158C


  再离开 softice,又断在


001B:004011AF  90                  NOP
001B:004011B0  8B442404            MOV       EAX,[ESP+04]
001B:004011B4  56                  PUSH      ESI
001B:004011B5  57                  PUSH      EDI
001B:004011B6  8B3D48684000        MOV       EDI,[00406848]
001B:004011BC  3BC7                CMP       EAX,EDI
001B:004011BE  7221                JB        004011E1
001B:004011C0  8B0D50684000        MOV       ECX,[00406850]
001B:004011C6  8D1439              LEA       EDX,[EDI+ECX]
001B:004011C9  3BC2                CMP       EAX,EDX
001B:004011CB  7714                JA        004011E1
001B:004011CD  8B3540684000        MOV       ESI,[00406840]
001B:004011D3  8BD1                MOV       EDX,ECX
001B:004011D5  C1E902              SHR       ECX,02
001B:004011D8  F3A5                REPZ MOVSD        <-------这里
001B:004011DA  8BCA                MOV       ECX,EDX
001B:004011DC  83E103              AND       ECX,03
001B:004011DF  F3A4                REPZ MOVSB
001B:004011E1  8B3DE8684000        MOV       EDI,[004068E8]
001B:004011E7  3BC7                CMP       EAX,EDI
001B:004011E9  7221                JB        0040120C
  

  我们刚才来过的地方,看来是程序某一处也 call 这里

  按一下 F12 返回

001B:0040158D  90                  NOP
001B:0040158E  56                  PUSH      ESI
001B:0040158F  E81CFCFFFF          CALL      004011B0
001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0]  <--这里
001B:0040159A  83C404              ADD       ESP,04
001B:0040159D  3CCC                CMP       AL,CC
001B:0040159F  74ED                JZ        0040158E
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
001B:004015A8  90                  NOP

  把 0040158F 的 call nop 掉

:a 0040158F
 nop 5 个位

  再离开 softice,又断在刚刚的那里
  

001B:00401594  8A86E0000000        MOV       AL,[ESI+000000E0] 
001B:0040159A  83C404              ADD       ESP,04   <--我们在这里
001B:0040159D  3CCC                CMP       AL,CC   <-- 把 getwindowtexta 与 0xcc 比较
001B:0040159F  74ED                JZ        0040158E  <-- 如果是 0xcc 便跳
001B:004015A1  B801000000          MOV       EAX,00000001
001B:004015A6  5E                  POP       ESI
001B:004015A7  C3                  RET
001B:004015A8  90                  NOP

  今次我们把 00401594 的 mov ,0040159D 的 cmp,和 0040159F 的 jz 全部 nop 掉


  现在我们离开 softice,没有再跳出来,成功把检查和恢复断点的地方清除。

  尝试下断 getwindowtexta

:bc *
:bpx getwindowtexta

  离开 softice,断在


001B:77DF7067  C21C00              RET       001C
USER32!GetWindowTextA
001B:77DF706A  55                  PUSH      EBP   <--这里
001B:77DF706B  8BEC                MOV       EBP,ESP
001B:77DF706D  6AFF                PUSH      FF
001B:77DF706F  68F870DF77          PUSH      77DF70F8
001B:77DF7074  68B71FE477          PUSH      77E41FB7
001B:77DF7079  64A100000000        MOV       EAX,FS:[00000000]
001B:77DF707F  50                  PUSH      EAX
001B:77DF7080  64892500000000      MOV       FS:[00000000],ESP
  
  程序成功断在 getwindowtexta,现在我们把程序关掉,打开 OD 加载 sub1.ooo,把刚才修改的地方写到 sub1.ooo 里

  ( sub1.ooo 的名字不可以改 )

相关文章:
© 2006   www.java-asp.net