-
-
[旧帖] [原创]爆破riijj_cm_20041217.zip_783 0.00雪花
-
发表于: 2016-2-4 23:54 1431
-
CrackMe提供者:riijj
原帖:http://bbs.pediy.com/showthread.php?t=8541
工具:od
平台:winxpsp3
这是一个多进程程序。主程序非常简单清晰。主要是创建进程sub3.ooo,
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 0040504C ; |ModuleFileName = "sub3.ooo"
00401036 |. FF15 08404000 call dword ptr [<&KERNEL32.CreateProc>; \CreateProcessA
然后等待该进程退出。
00401077 |> /8D4424 5C /lea eax, dword ptr [esp+5C]
0040107B |. |6A FF |push -1
0040107D |. |50 |push eax
0040107E |. |FFD6 |call esi ; kernel32.WaitForDebugEvent
00401080 |. 8B4424 5C |mov eax, dword ptr [esp+5C]
00401084 |. 48 |dec eax ; Switch (cases 5..5)
00401085 |. 74 05 |je short 0040108C
00401087 |. 83E8 04 |sub eax, 4
0040108A |. 74 13 |je short 0040109F
0040108C |> 8B4C24 64 |mov ecx, dword ptr [esp+64] ; Default case of switch 00401084
00401090 |. 8B5424 60 |mov edx, dword ptr [esp+60]
00401094 |. 68 02000100 |push 10002 ; UNICODE "LLUSERSPROFILE=C:\Documents and Settings\All Users"
00401099 |. 51 |push ecx
0040109A |. 52 |push edx
0040109B |. FFD7 |call edi ; kernel32.ContinueDebugEvent
0040109D |.^ EB D8 \jmp short 00401077
0040109F |> \5F pop edi ; Case 5 of switch 00401084
004010A0 |. 33C0 xor eax, eax
004010A2 |. 5E pop esi
004010A3 |. 81C4 B4000000 add esp, 0B4
004010A9 \. C2 1000 retn 10
sub3.ooo进程和主程序一样啥事不做,创建进程sub2.ooo,
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 00405030 ; |ModuleFileName = "sub2.ooo"
00401036 |. FF15 08404000 call dword ptr [<&KERNEL32.CreateProc>; \CreateProcessA
在sub2.ooo进程中作者开始使用编程技巧,这种技巧类似于我曾看到的一些壳编程技巧,就是不直接调用API函数,改用函数指针的形式调用。表现在汇编代码中就是不能直接看到函数名,要走到调用处才能看到。同时作者尝试了对申请的虚拟内存写指令,并且运行中调用使用的技术。
sub2.ooo仍然是创建一个进程sub1.ooo,
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 00406030 ; ASCII "sub1.ooo"
0040118F |. FF15 D4674000 call dword ptr [4067D4] ;\CreateProcessA
然后是一个类似的自定义调试循环,不同的是该循环不再是简单响应sub1.ooo退出消息,而是对某些特定情况进行了响应。当我试图分析有价值的响应时,发现sub1.ooo窗口出现不久,该程序收到了退出信息,所有进程退出了。
这说明sub1.ooo有反调试代码。载入sub1.ooo,发现程序是SDK框架,vc编译。sdk框架的程序结构是非常清晰的,看样子作者并不想太为难我们。
00401E13 |. 50 push eax ; /pWndClassEx
00401E14 |. FF15 BC504000 call dword ptr [<&USER32.RegisterClas>; \RegisterClassExA
00401E1A |. E8 41FFFFFF call 00401D60
00401E1F |. E8 0CFFFFFF call 00401D30 ;设置定时器
在定时器函数中,
00401C69 . 50 push eax ; /lppe
00401C6A . 57 push edi ; |hSnapshot
00401C6B . E8 06030000 call <jmp.&KERNEL32.Process32First> ; \Process32First
00401C70 > 8D4C24 3C lea ecx, dword ptr [esp+3C]
00401C74 . 6A 5C push 5C
00401C76 . 51 push ecx
00401C77 . E8 14040000 call 00402090
00401C7C . 83C4 08 add esp, 8
00401C7F . 8D70 01 lea esi, dword ptr [eax+1]
00401C82 . 85C0 test eax, eax
00401C84 . 75 04 jnz short 00401C8A
00401C86 . 8D7424 3C lea esi, dword ptr [esp+3C]
00401C8A > 68 5C614000 push 0040615C ; ASCII "SUB1.OOO"
00401C8F . 56 push esi
00401C90 . E8 6B030000 call 00402000
00401C95 . 83C4 08 add esp, 8
00401C98 . 85C0 test eax, eax
00401C9A . 75 05 jnz short 00401CA1
00401C9C . BB 01000000 mov ebx, 1
00401CA1 > 68 50614000 push 00406150 ; ASCII "SUB2.OOO"
00401CA6 . 56 push esi
00401CA7 . E8 54030000 call 00402000
00401CAC . 83C4 08 add esp, 8
00401CAF . 85C0 test eax, eax
00401CB1 . 75 05 jnz short 00401CB8
00401CB3 . BD 01000000 mov ebp, 1
00401CB8 > 68 44614000 push 00406144 ; ASCII "SUB3.OOO"
00401CBD . 56 push esi
00401CBE . E8 3D030000 call 00402000
00401CC3 . 83C4 08 add esp, 8
00401CC6 . 85C0 test eax, eax
00401CC8 . 75 08 jnz short 00401CD2
00401CCA . C74424 14 010>mov dword ptr [esp+14], 1
00401CD2 > 68 34614000 push 00406134 ; ASCII "CRACKME4.exe"
00401CD7 . 56 push esi
00401CD8 . E8 23030000 call 00402000
00401CDD . 83C4 08 add esp, 8
00401CE0 . 85C0 test eax, eax
00401CE2 . 75 08 jnz short 00401CEC
00401CE4 . C74424 10 010>mov dword ptr [esp+10], 1
00401CEC > 8D5424 18 lea edx, dword ptr [esp+18]
00401CF0 . 52 push edx ; /lppe
00401CF1 . 57 push edi ; |hSnapshot
00401CF2 . E8 79020000 call <jmp.&KERNEL32.Process32Next> ; \Process32Next
很明显的检测进程代码。作者采用定时器函数简单检查4个进程是否存在,不是全部存在(意味着如我们这样进程被单独调试)就退出。爆破掉。现在可以专心看流程了。
随意输入用户名和密码,点注册按钮。不用我们找,程序自己就断在响应处理函数处。
00401F40 /. 55 push ebp
00401F41 |. 8BEC mov ebp, esp
00401F43 |. 8B45 0C mov eax, dword ptr [ebp+C]
00401F46 |. 53 push ebx
00401F47 |. 56 push esi
00401F48 |. 3D 11010000 cmp eax, 111
00401F4D |. 57 push edi
00401F4E |. 75 10 jnz short 00401F60
00401F50 |. 66:817D 10 EA>cmp word ptr [ebp+10], 3EA
00401F56 |. 75 08 jnz short 00401F60
00401F58 |. 60 pushad
00401F59 |. B8 01000000 mov eax, 1
00401F5E |. CC int3
00401F5F |. 61 popad
00401F60 |> 5F pop edi
00401F61 |. 5E pop esi
00401F62 |. 33C0 xor eax, eax
00401F64 |. 5B pop ebx
00401F65 |. 5D pop ebp
00401F66 \. C2 1000 retn 10
问题是该处理函数从上到下也不见真正的处理过程。显然是利用函数中的软中断和sub2.ooo交互。可是我们没法同时调试两个进程。至此,调试陷入了困境。我也曾再次调试sub2.ooo,但是程序捕获注册调试事件后的处理我没能独立分析清楚。主要是作者使用的SetThreadContex函数完全是空白。
在此,向daxia200N表示感谢。看了daxia200N的回帖,寥寥几句就把程序精华部分解析的清清楚楚。查了Msdn和winnt.h,结合程序反复学习,终于对该函数有了基本的了解。在此,同时向作者表示感谢。这个程序显示的一些技巧让我获益良多。
作为初学者,继续简单解析一下。
sub1.ooo进程分别在4处设置了软中断,每处利用eax寄存器标识事件,然后sub2.ooo根据eax标识进行相应处理。因为是直接利用eax,我猜想部分代码应该是使用的内联汇编代码。
eax=0ff 传递注册响应函数入口地址。
eax=0fe 传递用户名和注册码地址。
eax=0 传递输入的用户名和注册码。
eax=1 通知父进程用户点击了注册按钮。
当sub2.ooo接到注册通知后,
0040123E |. 68 80674000 |push 00406780 ; Case 1 of switch 0040121D
00401243 |. E8 E8FDFFFF |call 00401030 ;计算用户名
00401248 |. 68 A0674000 |push 004067A0
0040124D |. E8 AEFDFFFF |call 00401000 ;计算注册码
程序对输入的用户名和注册码分别计算,安然写回sub1.ooo,并且利用SetThreadContext函数调整sub1.ooo进程指令寄存器指向真正的响应函数。该函数貌似比较复杂,直接爆破。在第一个跳转处爆破即可。由于作者在sub2.ooo中计算用户名使用了除法运算,我仅爆破了验证部分,所以用户名不能为空。很晚了,到此为止。
原帖:http://bbs.pediy.com/showthread.php?t=8541
工具:od
平台:winxpsp3
这是一个多进程程序。主程序非常简单清晰。主要是创建进程sub3.ooo,
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 0040504C ; |ModuleFileName = "sub3.ooo"
00401036 |. FF15 08404000 call dword ptr [<&KERNEL32.CreateProc>; \CreateProcessA
然后等待该进程退出。
00401077 |> /8D4424 5C /lea eax, dword ptr [esp+5C]
0040107B |. |6A FF |push -1
0040107D |. |50 |push eax
0040107E |. |FFD6 |call esi ; kernel32.WaitForDebugEvent
00401080 |. 8B4424 5C |mov eax, dword ptr [esp+5C]
00401084 |. 48 |dec eax ; Switch (cases 5..5)
00401085 |. 74 05 |je short 0040108C
00401087 |. 83E8 04 |sub eax, 4
0040108A |. 74 13 |je short 0040109F
0040108C |> 8B4C24 64 |mov ecx, dword ptr [esp+64] ; Default case of switch 00401084
00401090 |. 8B5424 60 |mov edx, dword ptr [esp+60]
00401094 |. 68 02000100 |push 10002 ; UNICODE "LLUSERSPROFILE=C:\Documents and Settings\All Users"
00401099 |. 51 |push ecx
0040109A |. 52 |push edx
0040109B |. FFD7 |call edi ; kernel32.ContinueDebugEvent
0040109D |.^ EB D8 \jmp short 00401077
0040109F |> \5F pop edi ; Case 5 of switch 00401084
004010A0 |. 33C0 xor eax, eax
004010A2 |. 5E pop esi
004010A3 |. 81C4 B4000000 add esp, 0B4
004010A9 \. C2 1000 retn 10
sub3.ooo进程和主程序一样啥事不做,创建进程sub2.ooo,
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 00405030 ; |ModuleFileName = "sub2.ooo"
00401036 |. FF15 08404000 call dword ptr [<&KERNEL32.CreateProc>; \CreateProcessA
在sub2.ooo进程中作者开始使用编程技巧,这种技巧类似于我曾看到的一些壳编程技巧,就是不直接调用API函数,改用函数指针的形式调用。表现在汇编代码中就是不能直接看到函数名,要走到调用处才能看到。同时作者尝试了对申请的虚拟内存写指令,并且运行中调用使用的技术。
sub2.ooo仍然是创建一个进程sub1.ooo,
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 00406030 ; ASCII "sub1.ooo"
0040118F |. FF15 D4674000 call dword ptr [4067D4] ;\CreateProcessA
然后是一个类似的自定义调试循环,不同的是该循环不再是简单响应sub1.ooo退出消息,而是对某些特定情况进行了响应。当我试图分析有价值的响应时,发现sub1.ooo窗口出现不久,该程序收到了退出信息,所有进程退出了。
这说明sub1.ooo有反调试代码。载入sub1.ooo,发现程序是SDK框架,vc编译。sdk框架的程序结构是非常清晰的,看样子作者并不想太为难我们。
00401E13 |. 50 push eax ; /pWndClassEx
00401E14 |. FF15 BC504000 call dword ptr [<&USER32.RegisterClas>; \RegisterClassExA
00401E1A |. E8 41FFFFFF call 00401D60
00401E1F |. E8 0CFFFFFF call 00401D30 ;设置定时器
在定时器函数中,
00401C69 . 50 push eax ; /lppe
00401C6A . 57 push edi ; |hSnapshot
00401C6B . E8 06030000 call <jmp.&KERNEL32.Process32First> ; \Process32First
00401C70 > 8D4C24 3C lea ecx, dword ptr [esp+3C]
00401C74 . 6A 5C push 5C
00401C76 . 51 push ecx
00401C77 . E8 14040000 call 00402090
00401C7C . 83C4 08 add esp, 8
00401C7F . 8D70 01 lea esi, dword ptr [eax+1]
00401C82 . 85C0 test eax, eax
00401C84 . 75 04 jnz short 00401C8A
00401C86 . 8D7424 3C lea esi, dword ptr [esp+3C]
00401C8A > 68 5C614000 push 0040615C ; ASCII "SUB1.OOO"
00401C8F . 56 push esi
00401C90 . E8 6B030000 call 00402000
00401C95 . 83C4 08 add esp, 8
00401C98 . 85C0 test eax, eax
00401C9A . 75 05 jnz short 00401CA1
00401C9C . BB 01000000 mov ebx, 1
00401CA1 > 68 50614000 push 00406150 ; ASCII "SUB2.OOO"
00401CA6 . 56 push esi
00401CA7 . E8 54030000 call 00402000
00401CAC . 83C4 08 add esp, 8
00401CAF . 85C0 test eax, eax
00401CB1 . 75 05 jnz short 00401CB8
00401CB3 . BD 01000000 mov ebp, 1
00401CB8 > 68 44614000 push 00406144 ; ASCII "SUB3.OOO"
00401CBD . 56 push esi
00401CBE . E8 3D030000 call 00402000
00401CC3 . 83C4 08 add esp, 8
00401CC6 . 85C0 test eax, eax
00401CC8 . 75 08 jnz short 00401CD2
00401CCA . C74424 14 010>mov dword ptr [esp+14], 1
00401CD2 > 68 34614000 push 00406134 ; ASCII "CRACKME4.exe"
00401CD7 . 56 push esi
00401CD8 . E8 23030000 call 00402000
00401CDD . 83C4 08 add esp, 8
00401CE0 . 85C0 test eax, eax
00401CE2 . 75 08 jnz short 00401CEC
00401CE4 . C74424 10 010>mov dword ptr [esp+10], 1
00401CEC > 8D5424 18 lea edx, dword ptr [esp+18]
00401CF0 . 52 push edx ; /lppe
00401CF1 . 57 push edi ; |hSnapshot
00401CF2 . E8 79020000 call <jmp.&KERNEL32.Process32Next> ; \Process32Next
很明显的检测进程代码。作者采用定时器函数简单检查4个进程是否存在,不是全部存在(意味着如我们这样进程被单独调试)就退出。爆破掉。现在可以专心看流程了。
随意输入用户名和密码,点注册按钮。不用我们找,程序自己就断在响应处理函数处。
00401F40 /. 55 push ebp
00401F41 |. 8BEC mov ebp, esp
00401F43 |. 8B45 0C mov eax, dword ptr [ebp+C]
00401F46 |. 53 push ebx
00401F47 |. 56 push esi
00401F48 |. 3D 11010000 cmp eax, 111
00401F4D |. 57 push edi
00401F4E |. 75 10 jnz short 00401F60
00401F50 |. 66:817D 10 EA>cmp word ptr [ebp+10], 3EA
00401F56 |. 75 08 jnz short 00401F60
00401F58 |. 60 pushad
00401F59 |. B8 01000000 mov eax, 1
00401F5E |. CC int3
00401F5F |. 61 popad
00401F60 |> 5F pop edi
00401F61 |. 5E pop esi
00401F62 |. 33C0 xor eax, eax
00401F64 |. 5B pop ebx
00401F65 |. 5D pop ebp
00401F66 \. C2 1000 retn 10
问题是该处理函数从上到下也不见真正的处理过程。显然是利用函数中的软中断和sub2.ooo交互。可是我们没法同时调试两个进程。至此,调试陷入了困境。我也曾再次调试sub2.ooo,但是程序捕获注册调试事件后的处理我没能独立分析清楚。主要是作者使用的SetThreadContex函数完全是空白。
在此,向daxia200N表示感谢。看了daxia200N的回帖,寥寥几句就把程序精华部分解析的清清楚楚。查了Msdn和winnt.h,结合程序反复学习,终于对该函数有了基本的了解。在此,同时向作者表示感谢。这个程序显示的一些技巧让我获益良多。
作为初学者,继续简单解析一下。
sub1.ooo进程分别在4处设置了软中断,每处利用eax寄存器标识事件,然后sub2.ooo根据eax标识进行相应处理。因为是直接利用eax,我猜想部分代码应该是使用的内联汇编代码。
eax=0ff 传递注册响应函数入口地址。
eax=0fe 传递用户名和注册码地址。
eax=0 传递输入的用户名和注册码。
eax=1 通知父进程用户点击了注册按钮。
当sub2.ooo接到注册通知后,
0040123E |. 68 80674000 |push 00406780 ; Case 1 of switch 0040121D
00401243 |. E8 E8FDFFFF |call 00401030 ;计算用户名
00401248 |. 68 A0674000 |push 004067A0
0040124D |. E8 AEFDFFFF |call 00401000 ;计算注册码
程序对输入的用户名和注册码分别计算,安然写回sub1.ooo,并且利用SetThreadContext函数调整sub1.ooo进程指令寄存器指向真正的响应函数。该函数貌似比较复杂,直接爆破。在第一个跳转处爆破即可。由于作者在sub2.ooo中计算用户名使用了除法运算,我仅爆破了验证部分,所以用户名不能为空。很晚了,到此为止。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
谁下载
看原图
赞赏
雪币:
留言: