-
-
moofy's keyme #1 破解
-
发表于:
2006-4-12 17:05
5715
-
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和我自己写的注册机,供大家参考。
谢谢!
[注意]APP应用上架合规检测服务,协助应用顺利上架!