如何生成CrackMe注册机之MSJ Challenge #1

本破解练习来自MSJ2009 Challenge#1,下载地址如下:https://reverse.put.as/wp-content/uploads/2010/05/MSJ20091.zip
破解起来稍显麻烦,主要是Keygen的算法比较晦涩难懂。
打开运行,如下。输入正确的Name及Serial才能注册。

Snip20171021_2.png
Snip20171021_1.png

0x1 代码分析

在Hopper中打开Challenge #1,可以看到关键校验代码如下。



        ; ================ B E G I N N I N G   O F   P R O C E D U R E ================

        ; Variables:
        ;    arg_C: 20
        ;    arg_8: 16
        ;    _cmd: void *12
        ;    self: void *8
        ;    var_1C: -28
        ;    var_20: -32
        ;    var_24: -36
        ;    var_28: -40
        ;    var_2C: -44
        ;    var_30: -48
        ;    var_3C: -60
        ;    var_40: -64
        ;    var_44: -68
        ;    var_48: -72


             -[Level1 validateSerial:forName:]:
00002a9e         push       ebp                                                 ; Objective C Implementation defined at 0x40f4 (instance method)
00002a9f         mov        ebp, esp
00002aa1         push       edi
00002aa2         push       esi
00002aa3         push       ebx
00002aa4         sub        esp, 0x3c
00002aa7         mov        eax, dword [objc_msg_length]                        ; @selector(length)
00002aac         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002ab0         mov        eax, dword [ebp+arg_8]
00002ab3         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002ab6         call       imp___jump_table__objc_msgSend
00002abb         cmp        eax, 0x8
00002abe         jne        loc_2c4e

00002ac4         mov        eax, dword [objc_msg_lossyCString]                  ; @selector(lossyCString)
00002ac9         mov        esi, 0x4
00002ace         xor        ebx, ebx
00002ad0         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002ad4         mov        eax, dword [ebp+arg_C]
00002ad7         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002ada         call       imp___jump_table__objc_msgSend
00002adf         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__strlen
00002ae2         mov        edi, eax
00002ae4         call       imp___jump_table__strlen
00002ae9         xor        ecx, ecx
00002aeb         mov        dword [ebp+var_30], eax
00002aee         jmp        loc_2b27

             loc_2af0:
00002af0         movsx      eax, byte [edi+ebx]                                 ; CODE XREF=-[Level1 validateSerial:forName:]+140
00002af4         inc        ebx
00002af5         imul       eax, esi
00002af8         add        esi, 0x4
00002afb         mov        edx, eax
00002afd         shl        edx, 0x4
00002b00         sub        edx, eax
00002b02         mov        eax, 0x68db8bad
00002b07         lea        ecx, dword [edx+ecx+0x29a]
00002b0e         imul       ecx
00002b10         mov        eax, ecx
00002b12         sar        eax, 0x1f
00002b15         sar        edx, 0xc
00002b18         sub        edx, eax
00002b1a         mov        eax, ecx
00002b1c         imul       edx, edx, 0x2710
00002b22         sub        eax, edx
00002b24         mov        dword [ebp+var_20], eax

             loc_2b27:
00002b27         cmp        dword [ebp+var_30], ebx                             ; CODE XREF=-[Level1 validateSerial:forName:]+80
00002b2a         ja         loc_2af0

00002b2c         mov        eax, dword [ebp+var_20]
00002b2f         mov        esi, 0x4
00002b34         xor        ebx, ebx
00002b36         mov        dword [esp+0x48+var_40], 0x3078                     ; @"%i"
00002b3e         mov        dword [esp+0x48+var_3C], eax
00002b42         mov        eax, dword [objc_msg_stringWithFormat_]             ; @selector(stringWithFormat:)
00002b47         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002b4b         mov        eax, dword [cls_NSString]                           ; cls_NSString
00002b50         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002b53         call       imp___jump_table__objc_msgSend
00002b58         mov        dword [esp+0x48+var_48], edi                        ; argument #1 for method imp___jump_table__strlen
00002b5b         mov        dword [ebp+var_28], eax
00002b5e         call       imp___jump_table__strlen
00002b63         xor        ecx, ecx
00002b65         mov        dword [ebp+var_2C], eax
00002b68         jmp        loc_2b9c

             loc_2b6a:
00002b6a         movsx      eax, byte [edi+ebx]                                 ; CODE XREF=-[Level1 validateSerial:forName:]+257
00002b6e         inc        ebx
00002b6f         imul       eax, esi
00002b72         add        esi, 0x8
00002b75         lea        edx, dword [eax+eax*4]
00002b78         lea        edx, dword [eax+edx*2+0x2d]
00002b7c         mov        eax, 0x68db8bad
00002b81         add        ecx, edx
00002b83         imul       ecx
00002b85         mov        eax, ecx
00002b87         sar        eax, 0x1f
00002b8a         sar        edx, 0xc
00002b8d         sub        edx, eax
00002b8f         mov        eax, ecx
00002b91         imul       edx, edx, 0x2710
00002b97         sub        eax, edx
00002b99         mov        dword [ebp+var_1C], eax

             loc_2b9c:
00002b9c         cmp        ebx, dword [ebp+var_2C]                             ; CODE XREF=-[Level1 validateSerial:forName:]+202
00002b9f         jb         loc_2b6a

00002ba1         mov        eax, dword [ebp+var_1C]
00002ba4         mov        esi, 0x4
00002ba9         xor        ebx, ebx
00002bab         mov        dword [esp+0x48+var_40], 0x3078                     ; @"%i"
00002bb3         mov        edi, 0x4
00002bb8         mov        dword [esp+0x48+var_3C], eax
00002bbc         mov        eax, dword [objc_msg_stringWithFormat_]             ; @selector(stringWithFormat:)
00002bc1         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002bc5         mov        eax, dword [cls_NSString]                           ; cls_NSString
00002bca         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002bcd         call       imp___jump_table__objc_msgSend
00002bd2         mov        dword [esp+0x48+var_40], ebx
00002bd6         mov        dword [esp+0x48+var_3C], esi
00002bda         mov        dword [ebp+var_24], eax
00002bdd         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
00002be2         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002be6         mov        eax, dword [ebp+arg_8]
00002be9         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002bec         call       imp___jump_table__objc_msgSend
00002bf1         mov        dword [esp+0x48+var_40], esi
00002bf5         mov        dword [esp+0x48+var_3C], edi
00002bf9         mov        ebx, eax
00002bfb         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
00002c00         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002c04         mov        eax, dword [ebp+arg_8]
00002c07         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00002c0a         call       imp___jump_table__objc_msgSend
00002c0f         mov        dword [esp+0x48+var_48], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00002c12         mov        esi, eax
00002c14         mov        eax, dword [ebp+var_28]
00002c17         mov        dword [esp+0x48+var_40], eax
00002c1b         mov        eax, dword [objc_msg_isEqual_]                      ; @selector(isEqual:)
00002c20         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002c24         call       imp___jump_table__objc_msgSend
00002c29         test       al, al
00002c2b         je         loc_2c4e

00002c2d         mov        eax, dword [ebp+var_24]
00002c30         mov        dword [esp+0x48+var_48], esi                        ; argument #1 for method imp___jump_table__objc_msgSend
00002c33         mov        dword [esp+0x48+var_40], eax
00002c37         mov        eax, dword [objc_msg_isEqual_]                      ; @selector(isEqual:)
00002c3c         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00002c40         call       imp___jump_table__objc_msgSend
00002c45         mov        edx, 0x1
00002c4a         test       al, al
00002c4c         jne        loc_2c50

             loc_2c4e:
00002c4e         xor        edx, edx                                            ; CODE XREF=-[Level1 validateSerial:forName:]+32, -[Level1 validateSerial:forName:]+397

             loc_2c50:
00002c50         add        esp, 0x3c                                           ; CODE XREF=-[Level1 validateSerial:forName:]+430
00002c53         mov        eax, edx
00002c55         pop        ebx
00002c56         pop        esi
00002c57         pop        edi
00002c58         leave
00002c59         ret
                        ; endp


首先,判断Serial的长度是否为8位,见下面代码。如不是8位,则失败,如果等于8位则继续下一步。

00002ab6         call       imp___jump_table__objc_msgSend
00002abb         cmp        eax, 0x8
00002abe         jne        loc_2c4e

接着, loc_2af0 代码段为一段循环,遍历输入的Name,取其中每一位字符ASCII码计算,算法见loc_2af0。计算的结果为Serial的第一部分Part1。loc_2b6a代码段为第二个循环,同样遍历输入的Name,取其中每一位字符ASCII码计算,算法见loc_2b6a。计算的结果为Serial的第二部分Part2。

最后一段【00002ba1-00002c4c】代码,分别取输入的Serial的前4位和后4位字符串与上面计算等到的Part1 、Part2比较,相等则验证通过。

0x2 Keygen算法

根据分析,可以得出Keygen算法。具体的实现,使用一个小技巧,就是用高级语言完全复制上述计算Part1、Part2的汇编代码。这里用Objective C示例如下。


- (NSString*)part1ByName:(NSString *)name {
    signed long esi = 0x4;
    signed long ecx = 0;
    signed long edx = 0;
    signed long eax = 0;
    for (int i = 0; i<name.length;i++) {
        eax = [name characterAtIndex:i];
        eax *= esi;
        esi += 0x4;
        edx = eax;
        edx = edx<<0x4;
        edx -= eax;
        eax = 0x68db8bad;
        ecx = edx + ecx + 0x29a;
        eax = ((ecx * 0x68db8bad) & 0x00000000ffffffff)>>32>>0x1f;
        eax = ecx;
        eax = eax>>0x1f;
        edx =((ecx * 0x68db8bad) & 0xffffffff00000000)>>32>>(0xc);
        edx = edx - eax;
        eax = ecx;
        edx *= 0x2710;
        eax = eax - edx;
    }
    return [NSString stringWithFormat:@"%d",eax];
}
- (NSString*)part2ByName:(NSString *)name {
    signed long esi = 0x4;
    signed long ecx = 0;
    signed long edx = 0;
    signed long eax = 0;
    for (int i = 0; i<name.length;i++) {
        eax = [name characterAtIndex:i];
        eax  *= esi;
        esi += 0x8;
        edx = eax + eax*4;
        edx = eax + edx*2 + 0x2d;
        eax = 0x68db8bad;
        ecx += edx;
        eax = ((ecx * 0x68db8bad) & 0x00000000ffffffff)>>32>>0x1f;
        eax = ecx;
        eax = eax>>0x1f;
        edx =((ecx * 0x68db8bad) & 0xffffffff00000000)>>32>>(0xc);
        edx = edx - eax;
        eax = ecx;
        edx *= 0x2710;
        eax = eax - edx;
    }
    return [NSString stringWithFormat:@"%d",eax];
}
- (NSString *)keyGen:(id)sender {
    NSString *name = @"qwer";
    NSString *serial = [NSString stringWithFormat:@"%@%@",
                     [self part1ByName:name],
                     [self part2ByName:name]];
  return serial;
}

0x3 程序验证

设输入的Name为qwer,根据上述Keygen算法得Serial为92648192,代入程序,验证Success,:)!

Snip20171022_3.png
Snip20171022_4.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容