系统 : Windows xp
程序 : CrackMe2016
程序下载地址 :http://pan.baidu.com/s/1dDOP2Xr
要求 : 找出正确密码
使用工具 : OD & IDA
可在看雪论坛中查找关于此程序的讨论,http://bbs.pediy.com/showthread.php?t=206850
打开IDA,翻找出提示匹配成功的字串“Good job”,并向上翻找出关键代码:
004010F0 /> \55 push ebp 004010F1 |. 8BEC mov ebp, esp 004010F3 |. 81EC 44040000 sub esp, 444 004010F9 |. 53 push ebx 004010FA |. 56 push esi 004010FB |. 57 push edi 004010FC |. 8DBD BCFBFFFF lea edi, dword ptr [ebp-444] 00401102 |. B9 11010000 mov ecx, 111 00401107 |. B8 CCCCCCCC mov eax, CCCCCCCC 0040110C |. F3:AB rep stos dword ptr es:[edi] 0040110E |. C745 FC 00000>mov dword ptr [ebp-4], 0 00401115 |> B8 01000000 /mov eax, 1 0040111A |. 85C0 |test eax, eax 0040111C |. 74 5A |je short 00401178 0040111E |. 68 CC504200 |push 004250CC ; ASCII "Please input password:" 00401123 |. E8 D8030000 |call 00401500 ; _printf 00401128 |. 83C4 04 |add esp, 4 ; 平衡堆栈 0040112B |. 8D8D FCFBFFFF |lea ecx, dword ptr [ebp-404] 00401131 |. 51 |push ecx 00401132 |. 68 C8504200 |push 004250C8 ; ASCII "%s" 00401137 |. E8 64030000 |call 004014A0 ; _scanf 0040113C |. 83C4 08 |add esp, 8 0040113F |. 8D95 FCFBFFFF |lea edx, dword ptr [ebp-404] ; 取password 00401145 |. 52 |push edx ; password入栈 00401146 |. E8 BAFEFFFF |call 00401005 0040114B |. 83C4 04 |add esp, 4 ; 平衡堆栈 0040114E |. 8945 FC |mov dword ptr [ebp-4], eax 00401151 |. 817D FC 53434>|cmp dword ptr [ebp-4], 474353 00401158 |. 75 0F |jnz short 00401169 0040115A |. 68 B8504200 |push 004250B8 ; ASCII 0A,"Good job!",LF 0040115F |. E8 9C030000 |call 00401500 00401164 |. 83C4 04 |add esp, 4 00401167 |. EB 0F |jmp short 00401178 00401169 |> 68 9C504200 |push 0042509C ; ASCII "Incorrect password!",LF,LF 0040116E |. E8 8D030000 |call 00401500 00401173 |. 83C4 04 |add esp, 4 00401176 |.^ EB 9D \jmp short 00401115 00401178 |> 68 94504200 push 00425094 ; ASCII "pause" 0040117D |. E8 0E020000 call 00401390 00401182 |. 83C4 04 add esp, 4 00401185 |. 5F pop edi 00401186 |. 5E pop esi 00401187 |. 5B pop ebx 00401188 |. 81C4 44040000 add esp, 444 0040118E |. 3BEC cmp ebp, esp 00401190 |. E8 BB010000 call 00401350 00401195 |. 8BE5 mov esp, ebp 00401197 |. 5D pop ebp 00401198 \. C3 retn
F7进入401500子程序:
00401005 $ /E9 16000000 jmp 00401020
继续跟进:
00401020 /> \55 push ebp 00401021 |. 8BEC mov ebp, esp 00401023 |. 81EC C0000000 sub esp, 0C0 00401029 |. 53 push ebx 0040102A |. 56 push esi 0040102B |. 57 push edi 0040102C |. 8DBD 40FFFFFF lea edi, dword ptr [ebp-C0] ; 取一段内存 00401032 |. B9 30000000 mov ecx, 30 00401037 |. B8 CCCCCCCC mov eax, CCCCCCCC 0040103C |. F3:AB rep stos dword ptr es:[edi] ; 重复拷贝将eax拷贝到【edi】中0x30次, 0040103E |. 8B45 08 mov eax, dword ptr [ebp+8] ; 取password 00401041 |. 50 push eax ; 入栈 00401042 |. 8D4D 80 lea ecx, dword ptr [ebp-80] ; 取一段内存 00401045 |. 51 push ecx ; 入栈 00401046 |. E8 15020000 call 00401260 ; 拷贝字串 0040104B |. 83C4 08 add esp, 8 ; 平衡堆栈 0040104E |. 68 6C504200 push 0042506C ; ‘看雪论坛的兄弟姐妹们,元旦快乐!’ 00401053 |. 8D55 80 lea edx, dword ptr [ebp-80] ; 取password 00401056 |. 52 push edx 00401057 |. E8 74010000 call 004011D0 ; _strcmp 0040105C |. 83C4 08 add esp, 8 ; 平衡堆栈 0040105F |. 8945 F8 mov dword ptr [ebp-8], eax ; 保存比较结果 00401062 |. 8B45 08 mov eax, dword ptr [ebp+8] ; 取password 00401065 |. 50 push eax ; password入栈 00401066 |. 8D4D A8 lea ecx, dword ptr [ebp-58] ; 取一段内存 00401069 |. 51 push ecx ; 入栈 0040106A |. E8 F1010000 call 00401260 ; 拷贝字串 0040106F |. 83C4 08 add esp, 8 ; 平衡堆栈 00401072 |. 68 44504200 push 00425044 ; ‘有可能被你发现密码了,加油加油’ 00401077 |. 8D55 A8 lea edx, dword ptr [ebp-58] ; 取password 0040107A |. 52 push edx ; password入栈 0040107B |. E8 50010000 call 004011D0 ; _strcmp 00401080 |. 83C4 08 add esp, 8 ; 平衡堆栈 00401083 |. 8945 F8 mov dword ptr [ebp-8], eax ; 保存比较结果 00401086 |. 8B45 08 mov eax, dword ptr [ebp+8] ; 取password 00401089 |. 50 push eax ; password入栈 0040108A |. 8D4D D0 lea ecx, dword ptr [ebp-30] ; 取一段内存 0040108D |. 51 push ecx ; 入栈 0040108E |. E8 CD010000 call 00401260 ; 拷贝字串 00401093 |. 83C4 08 add esp, 8 ; 平衡堆栈 00401096 |. 68 1C504200 push 0042501C ; ‘关键是如何输入,中文我也没办法!’ 0040109B |. 8D55 D0 lea edx, dword ptr [ebp-30] ; 取password 0040109E |. 52 push edx ; password入栈 0040109F |. E8 2C010000 call 004011D0 ; _strcmp 004010A4 |. 83C4 08 add esp, 8 ; 平衡堆栈 004010A7 |. 8945 FC mov dword ptr [ebp-4], eax ; 保存比较结果 004010AA |. 8B45 F8 mov eax, dword ptr [ebp-8] 004010AD |. 5F pop edi 004010AE |. 5E pop esi 004010AF |. 5B pop ebx 004010B0 |. 81C4 C0000000 add esp, 0C0 004010B6 |. 3BEC cmp ebp, esp 004010B8 |. E8 93020000 call 00401350 ; __chkesp 只检测ebp的当前值(函数入口点的栈顶地址)和函数释放栈上空间以后的esp是否一致 004010BD |. 8BE5 mov esp, ebp 004010BF |. 5D pop ebp 004010C0 \. C3 retn
程序最终根据eax的值进行判断,eax的值来源于[ebp-8]。对[ebp-8]下内存写入断点,发现最后在给eax赋值之前最后一次写入[ebp-8]的值是在
00401083 |. 8945 F8 mov dword ptr [ebp-8], eax ; 保存比较结果
比较结果是什么呢?我们跟入_strcmp:
004011D0 /$ 8B5424 04 mov edx, dword ptr [esp+4] ; 取password 004011D4 |. 8B4C24 08 mov ecx, dword ptr [esp+8] 004011D8 |. F7C2 03000000 test edx, 3 004011DE |. 75 3C jnz short 0040121C 004011E0 |> 8B02 /mov eax, dword ptr [edx] ; 将字串当做dword数值赋给eax 004011E2 |. 3A01 |cmp al, byte ptr [ecx] ; 与‘关键是如何输入,中文我也没办法!’逐个比较 004011E4 |. 75 2E |jnz short 00401214 004011E6 |. 0AC0 |or al, al ; 字符为空? 004011E8 |. 74 26 |je short 00401210 004011EA |. 3A61 01 |cmp ah, byte ptr [ecx+1] ; 取高位继续比较 004011ED |. 75 25 |jnz short 00401214 004011EF |. 0AE4 |or ah, ah ; 字符为空? 004011F1 |. 74 1D |je short 00401210 004011F3 |. C1E8 10 |shr eax, 10 ; 逻辑右移16位 004011F6 |. 3A41 02 |cmp al, byte ptr [ecx+2] ; 取低位继续比较 004011F9 |. 75 19 |jnz short 00401214 004011FB |. 0AC0 |or al, al ; 字符为空? 004011FD |. 74 11 |je short 00401210 004011FF |. 3A61 03 |cmp ah, byte ptr [ecx+3] ; 取高位继续比较 00401202 |. 75 10 |jnz short 00401214 00401204 |. 83C1 04 |add ecx, 4 00401207 |. 83C2 04 |add edx, 4 0040120A |. 0AE4 |or ah, ah ; 字符为空? 0040120C |.^ 75 D2 \jnz short 004011E0 0040120E |. 8BFF mov edi, edi 00401210 |> 33C0 xor eax, eax 00401212 |. C3 retn 00401213 | 90 nop 00401214 |> 1BC0 sbb eax, eax 00401216 |. D1E0 shl eax, 1 00401218 |. 40 inc eax 00401219 |. C3 retn
结果只可能是两个:0和FFFFFFFF。这意味着我们不能通过普通的手段来进行破解,只能修改程序结构(爆破)或是修改内存(越界攻击)。这里,我们查看[ebp-8]前后的内存区域:
执行到40108A时,[ebp-30]的内存地址是:12FAF4,相对于存放结果的位置[ebp-4]如上图所示。接下来的流程要将输入的password拷贝至[ebp-30],而程序对于password并没有做任何格式限制,这意味着理论上我们可以输入无限大的字串,直到将[ebp-4]的值覆盖掉。这里,我们随便输入40个字符就可以到达[ebp-4]的区域,对比流程,发现[ebp-4]的值应该为:53|43|47|00
最后一个字节作为字串结尾,前三个字节转化为ASCII码。最终可以通过验证的字串格式应为:任意40个占一字节的字符+"SCG"。
验证我们的猜想: