上一篇:riijj Crackme (4)的详解 2 >>
riijj Crackme (4)的详解 1
【对 象】中级新手
【下载地址】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 的名字不可以改 )
下一篇:benbentaiyang 的CRACKME4反跟踪分析 >>
相关文章:
- · 如何在DB2上为AIX5L设置unixODBC
- · 配置 IBM DB2 通用数据库以构建 SQL 过程
- · 设置DB UDB版本8中的混合字…
- · DB2 V8 连通性快捷表
- · 从 Microsoft SQL Server 2000 移植
- · 升级到 Informix Dynamic Server 9.40FC1
- · 利用您的 Oracle 9i
- · 使用 IBM DB2 Migration To…
- · IBM DB2 Universal Database V8.1
- · 培养商业智能技能
- · DB2 认证 — 认证须知
- · 灵活有效的数据仓库解决方案: 第 1 部分
- · DB2 for z/OS: DB2 数据库设计
- · 初始调优和设计方面的考虑
- · 决策支持系统(DSS)应用程序处理
- · (Query Patroller)V7.2 规划资源需求
- · 工程实施及项目管理
- · DB2 UDB Stinger 与自主计算
- · SMART 程度更高的 DB2
- · 自动化的将来
- · 网格揭密
- · Susan Malaika 讨论 XML 标准和网格计算
- · 对 Enterprise Replication 使用主复制
- · 崩溃恢复的基石
- · CommonStore 和 SAP 归档接…
- · 管理 XPS 数据库服务器上的…
- · DB2 重定向恢复脚本
- · 为 DB2 编写基于 Web 的表编辑器 GUI
- · DB2 UDB Express 的 GUI 工具简介第 1 部分
- · DB2 命令行处理器(CLP)中…
- · 测试您的 DB2 数据库: 用 JMeter 测量性能
- · IBM DB2 Everyplace Sync Server V8.2
- · DB2 Everyplace Version 8.2 同步水平过滤
- · 构建基于 DB2 Everyplace 的 MIDP 应用程序
- · 同步服务器的三种典型管理方式
- · 为 Palm 设备创建移动应用程序
- · 创建访问 DB2 Everyplace 的 JSP 应用程序
- · 使用 DB2 Everyplace 使无线应用程序数据同步
