首页
社区
课程
招聘
moofy's keyme #1 破解
2006-4-12 17:05 5334

moofy's keyme #1 破解

2006-4-12 17:05
5334
moofy's keyme #1是crackmes.de上发布的一个crackme。拿到moofy's keyme #1 (mfykm1.exe)后,先用PEiD看一下,是用UPX加过壳的,别的不说,先用UPXShell脱掉壳。

脱壳之后,运行,随便输入key,显示“Try again”,使用OllyICE,查找所有文本字串,可以找到 00401524 就是显示“Try again”的语句,与之相近的一段语句(1)如下:

004014FF  |.  C70424 AB0044>mov     dword ptr [esp], 004400AB        ; ||ASCII "%d"
00401506  |.  E8 D5F20000   call    <jmp.&msvcrt.scanf>              ; |\scanf
0040150B  |.  8B45 FC       mov     eax, [ebp-4]                     ; |
0040150E  |.  3B05 10444400 cmp     eax, [444410]                    ; |
00401514  |.  75 0E         jnz     short 00401524                   ; |
00401516  |.  C70424 B00044>mov     dword ptr [esp], 004400B0        ; |ASCII LF,LF,"Good Job! Make a keygen and tutorial and send it in to crackmes.de",LF
0040151D  |.  E8 CEF20000   call    <jmp.&msvcrt.printf>             ; \printf
00401522  |.  EB 0C         jmp     short 00401530
00401524  |>  C70424 F60044>mov     dword ptr [esp], 004400F6        ; |ASCII LF,LF,"Try again, sorry!",LF

很明显,
00401514  |.  75 0E         jnz     short 00401524                   ; |
就是比较后跳转的语句,如果是暴破,把75 0E换成90 90(NOP,NOP)就可以了。下面我们继续寻找key是如何产生的。随便输入几次key,可以发现[ebp-4]([0022FF74])是变化的,而[444410]是不变的。初步推定[0022FF74]是随我们输入的key变化的值,而[444410]则是相对应的正确值。

首先,我们先来看看正确的key值是如何产生的。

在444410上设写入断点,可以找到下列语句(2):

004014AD  |.  A1 58454400   mov     eax, [444558]                    ; ||||
004014B2  |.  0FAF05 544544>imul    eax, [444554]                    ; ||||
004014B9  |.  0305 5C454400 add     eax, [44455C]                    ; ||||
004014BF  |.  89C2          mov     edx, eax                         ; ||||
004014C1  |.  2B15 58454400 sub     edx, [444558]                    ; ||||
004014C7  |.  A1 5C454400   mov     eax, [44455C]                    ; ||||
004014CC  |.  69C0 DD0C0000 imul    eax, eax, 0CDD                   ; ||||
004014D2  |.  8D0402        lea     eax, [edx+eax]                   ; ||||
004014D5  |.  0305 5C454400 add     eax, [44455C]                    ; ||||
004014DB  |.  A3 10444400   mov     [444410], eax                    ; ||||

可以看到,[444410]的值与[444558],[444554],[44455C]有关,在这几个地址上设写入断点,找到下列语句(3):

77E80D8D    50              push    eax
77E80D8E    E8 9D000000     call    GetVersionExW
77E80D93    85C0            test    eax, eax
77E80D95  ^ 74 DE           je      short 77E80D75
77E80D97    8B85 D8FEFFFF   mov     eax, [ebp-128]
77E80D9D    393E            cmp     [esi], edi
77E80D9F    8946 04         mov     [esi+4], eax
77E80DA2    8B85 DCFEFFFF   mov     eax, [ebp-124]
77E80DA8    8946 08         mov     [esi+8], eax
77E80DAB    8B85 E0FEFFFF   mov     eax, [ebp-120]
77E80DB1    8946 0C         mov     [esi+C], eax
77E80DB4    8B85 E4FEFFFF   mov     eax, [ebp-11C]
77E80DBA    8946 10         mov     [esi+10], eax

[444558],[444554],[44455C]的值就是在这里更改的,仔细跟踪,就发现[esi+4],[esi+8],[esi+C]分别是[444554],[444558],[44455C]。而这些值又分别来自[ebp-128]([0022FD90]),[ebp-124]([0022FD94])和[ebp-120]([0022FD98])。另外,通过跟踪分析,可以发现在调用GetVersionExW之前,push eax时eax的值为0022FD8C。通常,在调用一个function之前push的值为该function的参数。查询与GetVersionExW相关的知识,可以得知,其参数为指向OSVERSIONINFO的一个指针(关于GetVersionExW和OSVERSIONINFO,请查阅相关文档)。观察[0022FD90],[0022FD94],[0022FD98],[0022FD9C],发现其中的值恰好对应执行GetVersionExW后,参数OSVERSIONINFO成员dwMajorVersion,dwMinorVersion,dwBuildNumber及dwPlatformId的值。因此,可以得知[444554],[444558],[44455C]的值就分别是dwMajorVersion,dwMinorVersion,dwBuildNumber。再根据语句段(2),可以得知[444410]=dwMinorVersion*dwMajorVersion+dwBuildNumber-dwMinorVersion+dwBuildNumber*0CDD+dwBuildNumber。

这样,[444410]的值,就可以确定下来了。

下面,我们来看[ebp-4]([0022FF74])的值是如何随输入的key变化的。

004014FF  |.  C70424 AB0044>mov     dword ptr [esp], 004400AB        ; ||ASCII "%d"
00401506  |.  E8 D5F20000   call    <jmp.&msvcrt.scanf>              ; |\scanf
0040150B  |.  8B45 FC       mov     eax, [ebp-4]                     ; |

可以看到[ebp-4]([0022FF74])紧随scanf,这个scanf即是读入key值的,因此推定输入的key没有经过太多运算,即输入[ebp-4],另外,看到"%d",推定输入只能是数字而不能是字符。实际上,如果跟进那个scanf,可以看到其中有对输入key值进行判断的语句,如果是字符,则退出,判定key值错误。输入几次key值,可以看到[ebp-4]中就是我们输入的key值,只不过我们输入十进制,[ebp-4]中保存为十六进制。

这样,我们的分析就完成了,我们输入的key值只要等于dwMinorVersion*dwMajorVersion+dwBuildNumber-dwMinorVersion+dwBuildNumber*0CDD+dwBuildNumber就可以了。也可以根据这个写出注册机。

下面是我用VC编写注册机的核心代码:

LPOSVERSIONINFO p_OSVersionInfo=new OSVERSIONINFO;
p_OSVersionInfo->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(p_OSVersionInfo);
m_KEY=p_OSVersionInfo->dwMinorVersion*p_OSVersionInfo->dwMajorVersion+p_OSVersionInfo->dwBuildNumber-p_OSVersionInfo->dwMinorVersion+p_OSVersionInfo->dwBuildNumber*0XCDD+p_OSVersionInfo->dwBuildNumber;
UpdateData(FALSE);

最后,是这个crackme和我自己写的注册机,供大家参考。

谢谢!

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (1)
雪    币: 50
活跃值: (145)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
zhaoocn 7 2006-4-12 23:14
2
0
MSDN真有用啊
游客
登录 | 注册 方可回帖
返回