首页
社区
课程
招聘
[原创]HappyTowns 41th CrackMe 算法分析及注册机
发表于: 2007-5-21 23:49 6714

[原创]HappyTowns 41th CrackMe 算法分析及注册机

2007-5-21 23:49
6714

HappyTowns 41th CrackMe 算法分析

今天心情好!最近很忙,很久没练手了,刚好HappyTown又放出一个CrackMe,就试试吧。

用PEiD查壳,显示
Microsoft Visual C++ 6.0
经验证,确实没有加壳。

用PEiD的Krypto ANAlyzer插件检查,结果如下:
RC5 / RC6 [Init, -Delta] :: 00001BF4 :: 00401BF4

用IDA载入,并加载常用的sig。找到注册验证的关键函数,初步分析的结果如下:

.text:00401100 ; int __cdecl OnCheck(HWND hDlg)
.text:00401100 OnCheck         proc near               ; CODE XREF: DialogFunc+4Dp
.text:00401100
.text:00401100 hashout         = dword ptr -914h
.text:00401100 var_90F         = dword ptr -90Fh
.text:00401100 var_90B         = dword ptr -90Bh
.text:00401100 var_907         = word ptr -907h
.text:00401100 var_905         = byte ptr -905h
.text:00401100 var_904         = dword ptr -904h
.text:00401100 var_900         = dword ptr -900h
.text:00401100 var_8FC         = dword ptr -8FCh
.text:00401100 var_8F8         = dword ptr -8F8h
.text:00401100 var_8F4         = byte ptr -8F4h
.text:00401100 _ctx            = dword ptr -8F0h
.text:00401100 szTeam          = byte ptr -8D0h
.text:00401100 szSerial        = byte ptr -6DCh
.text:00401100 szTemp          = byte ptr -4E8h
.text:00401100 szName          = byte ptr -2F4h
.text:00401100 rc4key          = dword ptr -100h
.text:00401100 hDlg            = dword ptr  4
.text:00401100
.text:00401100                 sub     esp, 914h
.text:00401106                 push    ebx
.text:00401107                 push    ebp
.text:00401108                 push    esi
.text:00401109                 push    edi
.text:0040110A                 xor     dl, dl
.text:0040110C                 mov     ecx, 124
.text:00401111                 xor     eax, eax
.text:00401113                 lea     edi, [esp+631h]
.text:0040111A                 mov     [esp+924h+szName], dl
.text:00401121                 mov     [esp+924h+szTeam], dl
.text:00401125                 rep stosd
.text:00401127                 stosw
.text:00401129                 stosb
.text:0040112A                 mov     ecx, 124
.text:0040112F                 xor     eax, eax
.text:00401131                 lea     edi, [esp+55h]
.text:00401135                 mov     [esp+924h+szSerial], dl
.text:0040113C                 rep stosd
.text:0040113E                 stosw
.text:00401140                 stosb
.text:00401141                 mov     ecx, 124
.text:00401146                 xor     eax, eax
.text:00401148                 lea     edi, [esp+249h]
.text:0040114F                 mov     [esp+924h+szTemp], dl
.text:00401156                 rep stosd
.text:00401158                 stosw
.text:0040115A                 stosb
.text:0040115B                 mov     ecx, 124
.text:00401160                 xor     eax, eax
.text:00401162                 lea     edi, [esp+43Dh]
.text:00401169                 mov     esi, [esp+924h+hDlg]
.text:00401170                 rep stosd
.text:00401172                 stosw
.text:00401174                 stosb
.text:00401175                 xor     eax, eax
.text:00401177                 mov     ecx, dword_40D050
.text:0040117D                 mov     [esp+924h+hashout+1], eax
.text:00401181                 mov     edi, ds:GetDlgItemTextA
.text:00401187                 mov     [esp+924h+var_90F], eax
.text:0040118B                 mov     byte ptr [esp+924h+hashout], dl
.text:0040118F                 mov     [esp+924h+var_90B], eax
.text:00401193                 mov     edx, dword_40D054
.text:00401199                 mov     [esp+924h+var_907], ax
.text:0040119E                 push    501             ; nMaxCount
.text:004011A3                 mov     [esp+928h+var_905], al
.text:004011A7                 mov     eax, dword_40D058
.text:004011AC                 mov     [esp+928h+var_8FC], eax
.text:004011B0                 lea     eax, [esp+928h+szName]
.text:004011B7                 mov     [esp+928h+var_904], ecx
.text:004011BB                 mov     ecx, dword_40D05C
.text:004011C1                 mov     [esp+928h+var_900], edx
.text:004011C5                 mov     dl, byte_40D060
.text:004011CB                 push    eax             ; lpString
.text:004011CC                 push    1000            ; nIDDlgItem
.text:004011D1                 push    esi             ; hDlg
.text:004011D2                 mov     [esp+934h+var_8F8], ecx
.text:004011D6                 mov     [esp+934h+var_8F4], dl
.text:004011DA                 call    edi ; GetDlgItemTextA ; 取用户名
.text:004011DC                 lea     ecx, [esp+924h+szTeam]
.text:004011E0                 push    501             ; nMaxCount
.text:004011E5                 push    ecx             ; lpString
.text:004011E6                 push    1001            ; nIDDlgItem
.text:004011EB                 push    esi             ; hDlg
.text:004011EC                 mov     ebx, eax
.text:004011EE                 call    edi ; GetDlgItemTextA ; 取组织名
.text:004011F0                 cmp     ebx, 3
.text:004011F3                 mov     ebp, eax
.text:004011F5                 jl      loc_4012F9
.text:004011FB                 cmp     ebp, 2
.text:004011FE                 jl      loc_4012F9
.text:00401204                 lea     edx, [esp+924h+szSerial]
.text:0040120B                 push    501             ; nMaxCount
.text:00401210                 push    edx             ; lpString
.text:00401211                 push    1002            ; nIDDlgItem
.text:00401216                 push    esi             ; hDlg
.text:00401217                 call    edi ; GetDlgItemTextA ; 取注册码
.text:00401219                 cmp     eax, 32
.text:0040121C                 jnz     loc_4012F9
.text:00401222                 lea     eax, [esp+924h+szTemp]
.text:00401229                 lea     ecx, [esp+924h+szSerial]
.text:00401230                 push    eax
.text:00401231                 push    32
.text:00401233                 push    ecx
.text:00401234                 call    str2bytes       ; 16进制字符串转换为字节序列
.text:00401239                 lea     edx, [esp+930h+szTemp]
.text:00401240                 push    16              ; size_t
.text:00401242                 lea     eax, [esp+934h+szSerial]
.text:00401249                 push    edx             ; char *
.text:0040124A                 push    eax             ; char *
.text:0040124B                 call    _strncpy        ; 再放回原处
.text:00401250                 lea     ecx, [esp+93Ch+_ctx]
.text:00401254                 push    ecx
.text:00401255                 call    hash_init       ; 修改过的hash算法
.text:0040125A                 lea     edx, [esp+940h+szName]
.text:00401261                 push    ebx
.text:00401262                 lea     eax, [esp+944h+_ctx]
.text:00401266                 push    edx
.text:00401267                 push    eax
.text:00401268                 call    hash_update
.text:0040126D                 lea     ecx, [esp+94Ch+_ctx]
.text:00401271                 lea     edx, [esp+94Ch+hashout]
.text:00401275                 push    ecx
.text:00401276                 push    edx
.text:00401277                 call    hash_final
.text:0040127C                 lea     eax, [esp+954h+szTeam]
.text:00401283                 push    ebp
.text:00401284                 lea     ecx, [esp+958h+rc4key]
.text:0040128B                 push    eax
.text:0040128C                 push    ecx
.text:0040128D                 call    rc4_set_key
.text:00401292                 lea     edx, [esp+960h+szTeam]
.text:00401299                 lea     eax, [esp+960h+hashout]
.text:0040129D                 push    edx
.text:0040129E                 push    16
.text:004012A0                 lea     ecx, [esp+968h+rc4key]
.text:004012A7                 push    eax
.text:004012A8                 push    ecx
.text:004012A9                 call    rc4             ; RC4算法
.text:004012AE                 add     esp, 4Ch
.text:004012B1                 lea     edx, [esp+924h+var_904]
.text:004012B5                 push    16
.text:004012B7                 push    edx
.text:004012B8                 call    rc6_set_key
.text:004012BD                 lea     eax, [esp+92Ch+szTemp]
.text:004012C4                 lea     ecx, [esp+92Ch+szSerial]
.text:004012CB                 push    eax
.text:004012CC                 push    ecx
.text:004012CD                 call    rc6_decrypt     ; RC6算法
.text:004012D2                 lea     edx, [esp+934h+szTemp]
.text:004012D9                 push    16              ; size_t
.text:004012DB                 lea     eax, [esp+938h+szTeam]
.text:004012DF                 push    edx             ; char *
.text:004012E0                 push    eax             ; char *
.text:004012E1                 call    _strncmp        ; 这里是关键比较
.text:004012E6                 add     esp, 1Ch
.text:004012E9                 neg     eax
.text:004012EB                 pop     edi
.text:004012EC                 pop     esi
.text:004012ED                 sbb     eax, eax
.text:004012EF                 pop     ebp
.text:004012F0                 inc     eax
.text:004012F1                 pop     ebx
.text:004012F2                 add     esp, 914h
.text:004012F8                 retn
.text:004012F9 ; ---------------------------------------------------------------------------
.text:004012F9
.text:004012F9 loc_4012F9:                             ; CODE XREF: OnCheck+F5j
.text:004012F9                                         ; OnCheck+FEj ...
.text:004012F9                 pop     edi
.text:004012FA                 pop     esi
.text:004012FB                 pop     ebp
.text:004012FC                 xor     eax, eax
.text:004012FE                 pop     ebx
.text:004012FF                 add     esp, 914h
.text:00401305                 retn
.text:00401305 OnCheck         endp

整个验证过程还比较简单,没有使用任何的密码学库,只用到了Hash算法、RC4算法和RC6算法。

那么这几种密码学算法是如何识别出来的呢?其实也没什么技巧,主要靠经验了。
Hash算法根据初始化的参数可大致判断出来,然后再对照输入输出,知道当中有修改,不是标准的sha算法。
RC4算法比较简单,以前分析过,很容易就识别出来了。
RC6算法前面用PEiD的密码学插件已经基本看出来了,然后对照源码可判断是RC6算法。再仔细看看发现
HappyTown改变了RC6算法中的一个常数。假如HappyTown将另一个重要常数也给改了,那么PEiD的密码学插件
可能就识别不了它,这样难度估计要大不少,我也不会这么快就搞定它。这是后话。

上述代码中的hash函数是经过修改的sha1函数,直接从CrackMe中提取汇编代码即可,无须自己逆向。

由以上分析可知注册验证过程如下:
1、读取用户名name,至少3个字符。读取组织名team,至少2个字符。
2、读取注册码serial,它应该是由32个16进制字符组成的字符串。将serial转化为对应的字节串serial2,长度是16个字节。
2、检查rc4(hash(name),team) ?= rc6_decrypt(serial2, key)。如果相同则注册成功,否则失败。
其中key是给定的一个128位的RC6密钥。
  
那么生成注册码的过程基本上也很清楚了:
1、读取用户名name,至少3个字符。读取组织名team,至少2个字符。
2、计算serial2 = rc6_encrypt(rc4(hash(name),team), key)
4、serial2长度是16个字节。将serial2转化为对应的16进制字符串serial,长度是32字节,即为所求注册码。

总结:
这个CrackMe综合运用了Hash算法、RC4算法和RC6算法。其难点在于算法的识别,以及对于算法是否被修改以及在何处修改的判断。
对于修改过的Hash算法,如果不想费力去还原它,那么可以直接提取汇编代码。
对于修改过的对称加密算法,只能根据源码对比着寻找被修改的地方,只有这样才能还原它。

这个CrackMe如果其中RC6算法的两个常数都被修改,以使插件不能识别,那么对于新手来说难度将增加很多。

附件中包含逆向出来的代码、注册机源码,以及编译过的可执行文件。

just for fun!


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

上传的附件:
收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 29235
活跃值: (7759)
能力值: ( LV15,RANK:3306 )
在线值:
发帖
回帖
粉丝
2
机机都出来了
2007-5-21 23:59
0
雪    币: 281
活跃值: (2940)
能力值: ( LV12,RANK:610 )
在线值:
发帖
回帖
粉丝
3
修正了一个小错误
2007-5-22 00:01
0
雪    币: 35
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
4
当然不是标准的sha算法,sha至少160位,这个算法只有128位,我跟过,里面的差异挺大的。也不是修改过的md5,没有表替换。happytown说这是他自己写的一个算法,让他贴出代码来,大家看看,不要小气,happytown。
2007-5-22 09:58
0
雪    币: 281
活跃值: (2940)
能力值: ( LV12,RANK:610 )
在线值:
发帖
回帖
粉丝
5
Ryosuke好像逆向过这个hash算法的吧?
http://bbs.pediy.com/showthread.php?t=25521
2007-5-22 14:50
0
雪    币: 721
活跃值: (350)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
6
说我小气的是在这里,呵呵。
Ryosuke逆向的那个是修改了5个常数的sha1,我自己写的这个128位的,我把它暂且称之为FHD算法,意为 Fash Hash Digest 。
唉,还是给出源代码吧,地址在这里:
http://bbs.pediy.com/showthread.php?t=45041
2007-5-22 15:31
0
游客
登录 | 注册 方可回帖
返回
//