首页
社区
课程
招聘
moofy's keyme #1的分析(为什么一定要写标题啊!)
发表于: 2006-8-22 19:14 5125

moofy's keyme #1的分析(为什么一定要写标题啊!)

2006-8-22 19:14
5125

这个Crackme的提交时间比较早,大约是3月份的,我翻看了本版3月前后的文章,没找到关于它的破解。
也有可能是我粗心,如果有人破解过,希望你告诉我一声。

下载地址:http://www.crackmes.de/users/moofy/moofys_keyme_1/
使用工具:OllyDbg

  这个程序加了点壳,由于脱壳过程比较简单,并且也不是重点,这里只简单地提一下:壳的
入口点在地址44C560处,往下翻页很快就能找到“Magic jump”位于44C6C3处(貌似UPX的壳,不
过没有PEID过),只要在这一行上按F4再按F7,就能定位到OEP了。

  OEP在地址401220处,往下看在401261处就出现了“msvcrt.atexit”字样,说明这已经是打
算退出程序了,因此程序的main函数应该就在call 00401100里边。跟进第一个call 00401100,
看到4011E2处的call 0040147E以后已经出现了“_cexit”和“ExitProcess”字样,如果程序有
关键内容,那也基本上只能是在这个call里了,跟进这个call,果然已经定位到了算法的核心:

=============================================================
0040147E    55              push    ebp
0040147F    89E5            mov     ebp, esp
00401481    83EC 18         sub     esp, 18
00401484    83E4 F0         and     esp, FFFFFFF0
00401487    B8 00000000     mov     eax, 0
0040148C    83C0 0F         add     eax, 0F
0040148F    83C0 0F         add     eax, 0F
00401492    C1E8 04         shr     eax, 4
00401495    C1E0 04         shl     eax, 4
00401498    8945 F8         mov     [ebp-8], eax
0040149B    8B45 F8         mov     eax, [ebp-8]
0040149E    E8 3DBD0000     call    0040D1E0
004014A3    E8 78B90000     call    0040CE20
004014A8    E8 E3FEFFFF     call    00401390
004014AD    A1 58454400     mov     eax, [444558]
004014B2    0FAF05 54454400 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
004014E0    C70424 24004400 mov     dword ptr [esp], 00440024        ; ASCII "Welcome to moofy's keyme

#1.",LF,"The object of this is to find out what makes up the key and make a keygen.",LF,"NO PATCHING!",LF
004014E7    E8 04F30000     call    004107F0                         ; jmp 到 msvcrt.printf
004014EC    C70424 9A004400 mov     dword ptr [esp], 0044009A        ; ASCII "Enter your key: "
004014F3    E8 F8F20000     call    004107F0                         ; jmp 到 msvcrt.printf
004014F8    8D45 FC         lea     eax, [ebp-4]
004014FB    894424 04       mov     [esp+4], eax
004014FF    C70424 AB004400 mov     dword ptr [esp], 004400AB        ; ASCII "%d"
00401506    E8 D5F20000     call    004107E0                         ; jmp 到 msvcrt.scanf
0040150B    8B45 FC         mov     eax, [ebp-4]
0040150E    3B05 10444400   cmp     eax, [444410]
00401514    75 0E           jnz     short 00401524
00401516    C70424 B0004400 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    004107F0                         ; jmp 到 msvcrt.printf
00401522    EB 0C           jmp     short 00401530
00401524    C70424 F6004400 mov     dword ptr [esp], 004400F6        ; ASCII LF,LF,"Try again, sorry!",LF
0040152B    E8 C0F20000     call    004107F0                         ; jmp 到 msvcrt.printf
00401530    C70424 0B014400 mov     dword ptr [esp], 0044010B        ; ASCII "PAUSE"
00401537    E8 94F20000     call    004107D0                         ; jmp 到 msvcrt.system
0040153C    B8 00000000     mov     eax, 0
00401541    C9              leave
00401542    C3              retn
=============================================================

这里一眼就能看到关键跳转在401514处,[ebp-4]是scanf函数的参数,也就是用来接受输入的
Key的地方,而比较用的真序列号是存放在[444410]中的。再往上看,[444410]的值是根据
[444554],[444558]和[44455C]三个双字内存的值算出来的,因此关键就在于确定这三个双字
在参与此处运算之前最后一次被改写是在什么地方(注意:这里最好是自己手动单步跟踪并且
监视相关内存单元。下内存断点效果并不好,因为我们所关心的只是最后一次改写,而在这之
前可能也改写过甚至是很多次,但不是我们所关心的,断在这些地方毫无意义。何况内存断点
还有可能断在系统的API里)。用F8键粗跟踪发现上一次改写是发生在4014A8处的
call 00401390处,因此跟进这个call中。仍然继续用寻找最后一次改写的方法,发现除了在
4013FE处的call 00410A90处对上述三个双字改写过以外,其他地方再未改写过。那么这个call
的内容是什么呢?看一下:

=============================================================
004013ED    C705 50454400 9>mov     dword ptr [444550], 94
004013F7    C70424 50454400 mov     dword ptr [esp], 00444550
004013FE    E8 8DF60000     call    00410A90                         ; jmp 到 kernel32.GetVersionExA
=============================================================

原来就是调用GetVersionEx这个API,MSDN里对这个函数的原型说明是:

BOOL GetVersionEx(struct OSVERSIONINFO * lpVersionInfo);

而这里调用所给的参数是00444550,这应该就是一个OSVERSIONINFO结构体变量的首地址了,
再来看OSVERSIONINFO结构体的声明:

typedef struct _OSVERSIONINFO{
    DWORD dwOSVersionInfoSize;
    DWORD dwMajorVersion;
    DWORD dwMinorVersion;
    DWORD dwBuildNumber;
    DWORD dwPlatformId;
    TCHAR szCSDVersion[ 128 ];
} OSVERSIONINFO;

至此我们得出结论:

  [444554] == stMyOSVersion.dwMajorVersion  // 我的系统主版本号
  [444558] == stMyOSVersion.dwMinorVersion  // 我的系统次版本号
  [44455C] == stMyOSVersion.dwBuildNumber   // 我的系统编译序数

于是,可以写个生成序列号的函数如下:

int KeyGen(void)  /* 前提是int的字长为32位 */

{
   OSVERSIONINFO OSVer;

   GetVersionEx(&OSVer);
   /* 用乘法的分配律把算法代码优化成下面这样 */
   return OSVer.dwMinorVersion * (OSVer.dwMajorVersion - 1) + OSVer.dwBuildNumber * 0xCDF;
}

笔者用的系统是WinXP,GetVersionEx执行后三个字段的值分别为5、1和0xA28,于是计算出
Key为0x82B8DC也就是十进制的8567004(注意根据scanf的格式符,输入的序号会被解释成带
符号十进制整数)。

我是怕重复上传


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 721
活跃值: (350)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
2
把那个CrackMe作为附件添加上,方便以后整理。
2006-8-22 20:16
0
游客
登录 | 注册 方可回帖
返回
//