【文章标题】: 一个非常简单的有提示的crackMe
【文章作者】: shaochem
【作者邮箱】: xiaoqing325@gmail.com
【软件名称】: NBS-#1 CrackMe
【软件大小】: 44k
【下载地址】: 自己搜索下载
【加壳方式】: 无
【保护方式】: 无
【编写语言】: vc++
【使用工具】: PEiD,OD
【操作平台】: Win9x/NT/2000/XP
【软件介绍】: 随便下的一个CrackMe,算法比较简单,适合初学者
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
用peid查了下,无壳,vc++编写。
打开程序,点击Register,直接点“ok”,弹出“please enter u name and key.. ”,还好,基本上都有检测并给有提示。
直接OD载入,直接“查找”--“所有字符串参考”,下断点,F9运行,输入:
name:asdfg
key:01234567890
下一步,被段下后,我们先来看看代码:
00401B7E . C2 1000 retn 10
00401B81 > 8B3D A8704000 mov edi, dword ptr [<&KERNEL32.lstrl>; kernel32.lstrlenA
00401B87 . 8D9424 1C0200>lea edx, dword ptr [esp+21C]
00401B8E . 52 push edx ; /String
00401B8F . FFD7 call edi ; \lstrlenA
00401B91 . 83F8 03 cmp eax, 3
00401B94 . 7D 29 jge short 00401BBF
00401B96 > 8B8424 200600>mov eax, dword ptr [esp+620]
00401B9D . 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401B9F . 68 80824000 push 00408280 ; |Title = "Error"
00401BA4 . 68 88894000 push 00408988 ; |Text = "Invalid name/key, please try again."
00401BA9 . 50 push eax ; |hOwner
00401BAA . FF15 F0704000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00401BB0 . 5F pop edi
00401BB1 . 5E pop esi
00401BB2 . 5D pop ebp
00401BB3 . 33C0 xor eax, eax
00401BB5 . 5B pop ebx
00401BB6 . 81C4 0C060000 add esp, 60C
00401BBC . C2 1000 retn 10
00401BBF > 8D8C24 1C0400>lea ecx, dword ptr [esp+41C]
00401BC6 . 51 push ecx
00401BC7 . FFD7 call edi
00401BC9 . 83F8 22 cmp eax, 22 ; 比较你输入的key与34的大小
00401BCC . 74 29 je short 00401BF7 ; 等于就跳,否则就完蛋
00401BCE > 8B9424 200600>mov edx, dword ptr [esp+620]
00401BD5 . 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401BD7 . 68 80824000 push 00408280 ; |Title = "Error"
00401BDC . 68 88894000 push 00408988 ; |Text = "Invalid name/key, please try again."
00401BE1 . 52 push edx ; |hOwner
00401BE2 . FF15 F0704000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
它首先取用户名和3比较,不能小于3,小于3就完蛋了,然后取key的长度,并判断key的位数是否为34,否则就完蛋,那我们明白了,我输入的key有问题。
继续,重新载入程序,运行输入:
name:asdfg
key:0123456789012345678900123456789001234
继续下一步,我们还是先来看看代码:
00401BF7 > \8D8424 1C0400>lea eax, dword ptr [esp+41C]
00401BFE . 33ED xor ebp, ebp
00401C00 . 50 push eax
00401C01 . 32DB xor bl, bl
00401C03 . 896C24 1C mov dword ptr [esp+1C], ebp
00401C07 . FFD7 call edi ; 取key的长度
00401C09 . 85C0 test eax, eax
00401C0B . 7E 45 jle short 00401C52
00401C0D . 33F6 xor esi, esi
00401C0F > 8A8434 1C0400>mov al, byte ptr [esp+esi+41C] ; 取第一位
00401C16 . FEC3 inc bl ; 应该是个计数器
00401C18 . 3C 2D cmp al, 2D ; 每一位和-号比较
00401C1A . 74 1D je short 00401C39 ; 相同则跳
00401C1C . 0FBF4C24 18 movsx ecx, word ptr [esp+18]
00401C21 . 50 push eax
00401C22 . 88440C 20 mov byte ptr [esp+ecx+20], al ; 不等就往后移位,存在后面
00401C26 . E8 E5080000 call 00402510
00401C2B . 84C0 test al, al
00401C2D .^ 0F85 63FFFFFF jnz 00401B96
00401C33 . FF4424 18 inc dword ptr [esp+18] ; 取下一位
00401C37 . EB 07 jmp short 00401C40 ; 直接跳走
00401C39 > 80FB 05 cmp bl, 5 ; 然后把"-"号的位置与5比较
00401C3C . 75 2A jnz short 00401C68 ; 不等就跳,这里跳走就完蛋
00401C3E . 32DB xor bl, bl ; bl清零
00401C40 > 8D9424 1C0400>lea edx, dword ptr [esp+41C]
00401C47 . 45 inc ebp
00401C48 . 52 push edx
00401C49 . 0FBFF5 movsx esi, bp
00401C4C . FFD7 call edi
00401C4E . 3BF0 cmp esi, eax ; 这里应该是循环的条件
00401C50 .^ 7C BD jl short 00401C0F ; 小于继续循环,大则继续执行
00401C52 > \0FBF5424 18 movsx edx, word ptr [esp+18]
00401C57 . 8D4424 1C lea eax, dword ptr [esp+1C] ;这里取出除掉“-”号的key
00401C5B . 50 push eax
00401C5C . C64414 20 00 mov byte ptr [esp+edx+20], 0
00401C61 . FFD7 call edi
00401C63 . 83F8 1C cmp eax, 1C ; 这里判断key里是否有6个“-”号
00401C66 . 74 29 je short 00401C91 ; 有就跳走,没有就完蛋
00401C68 > 8B8C24 200600>mov ecx, dword ptr [esp+620]
00401C6F . 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401C71 . 68 80824000 push 00408280 ; |Title = "Error"
00401C76 . 68 88894000 push 00408988 ; |Text = "Invalid name/key, please try again."
00401C7B . 51 push ecx ; |hOwner
00401C7C . FF15 F0704000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
它首先一个循环取每一位key来判断key里是否存在“-”号,如果存在“-”号就把“-”号的位置与5比较,不等就完蛋了,不存在就把该位后移保存,继续取下一位,直到key取完,取完后取出去掉“-”号的key,
判断它的长度是否为28,也就是里面是否有6个“-”号,没有就完蛋了,有就继续,这说明我的key还是有问题的。继续。
我们先继续看代码:
00401C95 . 6A 03 push 3 ; /n = 3
00401C97 . 8D4424 14 lea eax, dword ptr [esp+14] ; |
00401C9B . 52 push edx ; |String2
00401C9C . 50 push eax ; |String1
00401C9D . FF15 30704000 call dword ptr [<&KERNEL32.lstrcpynA>>; \lstrcpynA
00401CA3 . 8D4C24 10 lea ecx, dword ptr [esp+10] ; 取前2个字符
00401CA7 . 51 push ecx
00401CA8 . E8 56090000 call 00402603
00401CAD . 8BF8 mov edi, eax ; 把字符变数字
00401CAF . 83C4 04 add esp, 4
00401CB2 . 33D2 xor edx, edx
00401CB4 . 66:83FF 0C cmp di, 0C ; 把该数字与12比较
00401CB8 . 0F9FC2 setg dl ; 大则置1
00401CBB . 33C0 xor eax, eax
00401CBD . 66:83FF 02 cmp di, 2 ; 把该数和2比较
00401CC1 . 0F9CC0 setl al ; 小则置1
00401CC4 . 0BD0 or edx, eax ; 把结果与0或运算
00401CC6 .^ 75 A0 jnz short 00401C68 ; 不=0则跳,跳走就完蛋
这里又是一个判断,取你注册码key里面的前2位并转换为数字,并判断它必须大于2小于12,否则就完蛋,到这里对输入的验证基本上算是完毕了,好累啊。
好,我们继续看代码:
00401CC8 . 8B35 34704000 mov esi, dword ptr [<&KERNEL32.lstrc>; kernel32.lstrcpyA
00401CCE . 8D5424 10 lea edx, dword ptr [esp+10]
00401CD2 . 68 E4924000 push 004092E4 ; /String2 = ""
00401CD7 . 52 push edx ; |String1
00401CD8 . FFD6 call esi ; \lstrcpyA
00401CDA . 8D4424 16 lea eax, dword ptr [esp+16]
00401CDE . 68 E4924000 push 004092E4 ; /String2 = ""
00401CE3 . 50 push eax ; |String1
00401CE4 . FFD6 call esi ; \lstrcpyA
00401CE6 . 0FBFF7 movsx esi, di ; 注意这个长度就是你注册码的前2位数字,用于控制后面取字符
00401CE9 . 0FBE8424 1C02>movsx eax, byte ptr [esp+21C] ; 取用户名第一个字母
00401CF1 . 8A4C34 1C mov cl, byte ptr [esp+esi+1C] ; 取注册码的前2位长度的字符
00401CF5 . 8A5434 1D mov dl, byte ptr [esp+esi+1D] ; 接着后面的字符
00401CF9 . 8B3D 08714000 mov edi, dword ptr [<&USER32.wsprint>; USER32.wsprintfA
00401CFF . 884C24 10 mov byte ptr [esp+10], cl
00401D03 . 50 push eax ; /<%X>
00401D04 . 8D4C24 1A lea ecx, dword ptr [esp+1A] ; |这里开始构造字符串了
00401D08 . 32DB xor bl, bl ; |
00401D0A . 68 84894000 push 00408984 ; |Format = "%X"
00401D0F . 51 push ecx ; |s
00401D10 . 885424 1D mov byte ptr [esp+1D], dl ; |
00401D14 . 885C24 1E mov byte ptr [esp+1E], bl ; |
00401D18 . FFD7 call edi ; \wsprintfA
00401D1A . 8B2D 2C704000 mov ebp, dword ptr [<&KERNEL32.lstrc>; kernel32.lstrcmpA
00401D20 . 83C4 0C add esp, 0C
00401D23 . 8D5424 16 lea edx, dword ptr [esp+16] ; 用户名的第一位字符
00401D27 . 8D4424 10 lea eax, dword ptr [esp+10] ; 刚才取的2位字符
00401D2B . 52 push edx ; /string2=61
00401D2C . 50 push eax ; |String1
00401D2D . FFD5 call ebp ; \lstrcmpA
00401D2F . 85C0 test eax, eax
00401D31 . 75 02 jnz short 00401D35 ; 比较,不同则跳,跳走就完蛋
00401D33 . B3 01 mov bl, 1 ; 这里应该是个计数的标志位
00401D35 > 0FBE8424 1D02>movsx eax, byte ptr [esp+21D] ; 用户名的第二位
00401D3D . 8A4C74 1C mov cl, byte ptr [esp+esi*2+1C] ; 又要开始截取2位进行比较了
00401D41 . 8A5474 1D mov dl, byte ptr [esp+esi*2+1D]
00401D45 . 884C24 10 mov byte ptr [esp+10], cl
00401D49 . 50 push eax
00401D4A . 8D4C24 1A lea ecx, dword ptr [esp+1A]
00401D4E . 68 84894000 push 00408984 ; ASCII "%X"
00401D53 . 51 push ecx
00401D54 . 885424 1D mov byte ptr [esp+1D], dl
00401D58 . C64424 1E 00 mov byte ptr [esp+1E], 0
00401D5D . FFD7 call edi
00401D5F . 83C4 0C add esp, 0C
00401D62 . 8D5424 16 lea edx, dword ptr [esp+16] ; 用户名的第二位
00401D66 . 8D4424 10 lea eax, dword ptr [esp+10] ; 截取的2位注册码
00401D6A . 52 push edx
00401D6B . 50 push eax
00401D6C . FFD5 call ebp ; 开始比较了
00401D6E . 85C0 test eax, eax
00401D70 . 75 02 jnz short 00401D74 ; 不等就跳了,这里跳走就完蛋
00401D72 . FEC3 inc bl ; 相等,计数器就+1
00401D74 > 8B35 A8704000 mov esi, dword ptr [<&KERNEL32.lstrl>; kernel32.lstrlenA
00401D7A . 8D4C24 1C lea ecx, dword ptr [esp+1C]
00401D7E . 51 push ecx ; /String
00401D7F . FFD6 call esi ; \lstrlenA
00401D81 . 0FBFD0 movsx edx, ax
00401D84 . 8A4C14 1A mov cl, byte ptr [esp+edx+1A] ; cl取倒数第2位
00401D88 . C64424 12 00 mov byte ptr [esp+12], 0
00401D8D . 8D4414 1C lea eax, dword ptr [esp+edx+1C]
00401D91 . 884C24 10 mov byte ptr [esp+10], cl
00401D95 . 8A50 FF mov dl, byte ptr [eax-1] ; 取注册码倒数第一位
00401D98 . 8D8424 1C0200>lea eax, dword ptr [esp+21C]
00401D9F . 50 push eax ; /String
00401DA0 . 885424 15 mov byte ptr [esp+15], dl ; |
00401DA4 . FFD6 call esi ; \lstrlenA
00401DA6 . 0FBFC8 movsx ecx, ax
00401DA9 . 8D4424 16 lea eax, dword ptr [esp+16]
00401DAD . 0FBE940C 1B02>movsx edx, byte ptr [esp+ecx+21B]
00401DB5 . 52 push edx ; 又开始构造字符了
00401DB6 . 68 84894000 push 00408984 ; ASCII "%X"
00401DBB . 50 push eax
00401DBC . FFD7 call edi
00401DBE . 83C4 0C add esp, 0C
00401DC1 . 8D4C24 16 lea ecx, dword ptr [esp+16] ; 用户名的最后一位
00401DC5 . 8D5424 10 lea edx, dword ptr [esp+10] ; 最后取的2位注册码
00401DC9 . 51 push ecx
00401DCA . 52 push edx
00401DCB . FFD5 call ebp ; 比较
00401DCD . 85C0 test eax, eax
00401DCF . 75 02 jnz short 00401DD3 ; 不等就跳,跳走就完蛋的
00401DD1 . FEC3 inc bl ; 相等计数器就+1
00401DD3 > 80FB 03 cmp bl, 3 ; 判断你是否经过3次比较
00401DD6 .^ 0F85 F2FDFFFF jnz 00401BCE ; 不是就挂了
00401DDC . 8BAC24 200600>mov ebp, dword ptr [esp+620]
00401DE3 . 8B1D F0704000 mov ebx, dword ptr [<&USER32.Message>; USER32.MessageBoxA
00401DE9 . 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401DEB . 68 78894000 push 00408978 ; |Title = "Key valid!"
00401DF0 . 68 34894000 push 00408934 ; |Text = "Thank you for your purchase, the software is now fully functional."
00401DF5 . 55 push ebp ; |hOwner
00401DF6 . FFD3 call ebx ; \MessageBoxA
00401DF8 . 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401DFA . 68 28894000 push 00408928 ; |Title = "Excellent!"
00401DFF . 68 04894000 push 00408904 ; |Text = "CONGRATULATIONS! You have made it!"
00401E04 . 55 push ebp ; |hOwner
00401E05 . FFD3 call ebx ; \MessageBoxA
它在这里,首先取你输入的用户名,再取key前面的前2位数字作为长度,在key里面截取那个长度的后2位字符并拼接起来,来把它和用户名第一位做比较。不等就完蛋。
然后取用户名的第二位,与key里面再取两位字符拼接起来做比较,要相等,最后取用户名的最后一位和key的最后2位做比较,不等就完蛋。
大概的算法就是这样了。本人第一次写文章,分析crackme。不对之处还请大家指出!
--------------------------------------------------------------------------------
【经验总结】
整个过程就是首先判断你输入的数据是否合符要求,符合要求后再取用户名的一位,然后在key里取2位拼接为字符串来比较
。这个crackme很简单,算法也很清晰,非常适合新手朋友,来学习练习。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2010年03月30日 下午 04:43:19
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!