如何生成CrackMe注册机之Doughnuts

本练习破解的CrackMe可以在此处下载:https://reverse.put.as/wp-content/uploads/2010/05/CrackMe.1.by_.James_.Moriarty.zip。运行截图如下。当然,此CrackMe相对简单,仅作为破解入门练习,抛砖引玉。因为简单,如果暴力破解,相对容易,但是这不是破解CrackMe的目的。这里主要从代码分析入手,一步一步理解CrackMe注册码的生成规则,从而达到完美产生注册码的目的—— Keygen,所以,本文乃注册机生成之旅。

如何生成CrackMe注册机之Doughnuts_第1张图片
Snip20171013_8.jpg

0x1 代码静态分析

在Hopper 中反汇编CrackMe,很容易看到validar:方法(validar 为西班牙语,对应英语validate),因为简单,不用怀疑,这就是验证name和serial的方法。代码如下:

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

        ; Variables:
        ;    _cmd: 12
        ;    self: 8
        ;    var_10: -16
        ;    var_24: -36
        ;    var_28: -40
        ;    var_2C: -44
        ;    var_3C: -60
        ;    var_40: -64
        ;    var_44: -68
        ;    var_48: -72


             -[Control validar:]:
000025d8         push       ebp                                                 ; Objective C Implementation defined at 0x4314 (instance method)
000025d9         mov        ebp, esp
000025db         push       ebx
000025dc         push       edi
000025dd         push       esi
000025de         sub        esp, 0x3c
000025e1         mov        eax, dword [___stack_chk_guard_301c]                ; ___stack_chk_guard_301c
000025e6         mov        eax, dword [eax]
000025e8         mov        dword [ebp+var_10], eax
000025eb         mov        esi, dword [ebp+self]
000025ee         mov        eax, dword [esi+8]
000025f1         mov        ecx, dword [objc_msg_stringValue]                   ; @selector(stringValue)
000025f7         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000025fb         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000025fe         call       imp___symbol_stub__objc_msgSend
00002603         mov        edi, eax
00002605         mov        eax, dword [esi+4]
00002608         mov        ecx, dword [objc_msg_stringValue]                   ; @selector(stringValue)
0000260e         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002612         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002615         call       imp___symbol_stub__objc_msgSend
0000261a         mov        dword [ebp+var_28], eax
0000261d         mov        eax, dword [objc_msg_length]                        ; @selector(length)
00002622         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002626         mov        eax, dword [ebp+var_28]
00002629         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000262c         call       imp___symbol_stub__objc_msgSend
00002631         mov        esi, eax
00002633         mov        eax, dword [objc_msg_length]                        ; @selector(length)
00002638         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000263c         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000263f         call       imp___symbol_stub__objc_msgSend
00002644         mov        dword [ebp+var_2C], eax
00002647         mov        eax, dword [objc_msg_length]                        ; @selector(length)
0000264c         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002650         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002653         call       imp___symbol_stub__objc_msgSend
00002658         mov        ecx, dword [objc_msg_substringFromIndex_]           ; @selector(substringFromIndex:)
0000265e         add        eax, 0xfffffffe
00002661         mov        dword [esp+0x48+var_40], eax
00002665         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002669         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000266c         call       imp___symbol_stub__objc_msgSend
00002671         mov        ecx, dword [objc_msg_intValue]                      ; @selector(intValue)
00002677         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000267b         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000267e         call       imp___symbol_stub__objc_msgSend
00002683         mov        ebx, eax
00002685         cmp        dword [ebp+var_28], 0x0
00002689         je         loc_28d4

0000268f         mov        eax, dword [objc_msg_isEqual_]                      ; @selector(isEqual:)
00002694         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002698         mov        eax, dword [ebp+var_28]
0000269b         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000269e         mov        dword [esp+0x48+var_40], 0x3058                     ; @""
000026a6         call       imp___symbol_stub__objc_msgSend
000026ab         test       al, al
000026ad         jne        loc_28d4

000026b3         cmp        esi, 0x4
000026b6         jl         loc_28d4

000026bc         test       edi, edi
000026be         je         loc_28d4

000026c4         mov        eax, dword [objc_msg_isEqual_]                      ; @selector(isEqual:)
000026c9         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000026cd         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000026d0         mov        dword [esp+0x48+var_40], 0x3058                     ; @""
000026d8         call       imp___symbol_stub__objc_msgSend
000026dd         test       al, al
000026df         jne        loc_28d4

000026e5         cmp        dword [ebp+var_2C], 0xf
000026e9         jne        loc_28d4

000026ef         cmp        esi, ebx
000026f1         jne        loc_28d4

000026f7         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
000026fc         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002700         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002703         mov        dword [esp+0x48+var_3C], 0x1
0000270b         mov        dword [esp+0x48+var_40], 0xa
00002713         call       imp___symbol_stub__objc_msgSend
00002718         mov        esi, eax
0000271a         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
0000271f         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002723         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002726         mov        dword [esp+0x48+var_3C], 0xa
0000272e         mov        dword [esp+0x48+var_40], 0x0
00002736         call       imp___symbol_stub__objc_msgSend
0000273b         mov        ebx, eax
0000273d         mov        eax, dword [objc_msg_isEqualToString_]              ; @selector(isEqualToString:)
00002742         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002746         mov        dword [esp+0x48+var_48], esi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002749         mov        dword [esp+0x48+var_40], 0x3038                     ; @"k"
00002751         call       imp___symbol_stub__objc_msgSend
00002756         test       al, al
00002758         je         loc_28d4

0000275e         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
00002763         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002767         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000276a         mov        dword [esp+0x48+var_3C], 0x1
00002772         mov        dword [esp+0x48+var_40], 0xb
0000277a         call       imp___symbol_stub__objc_msgSend
0000277f         mov        ecx, dword [objc_msg_isEqualToString_]              ; @selector(isEqualToString:)
00002785         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002789         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000278c         mov        dword [esp+0x48+var_40], 0x3048                     ; @"n"
00002794         call       imp___symbol_stub__objc_msgSend
00002799         test       al, al
0000279b         je         loc_28d4

000027a1         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
000027a6         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027aa         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027ad         mov        dword [esp+0x48+var_3C], 0x1
000027b5         mov        dword [esp+0x48+var_40], 0xc
000027bd         call       imp___symbol_stub__objc_msgSend
000027c2         mov        ecx, dword [objc_msg_isEqualToString_]              ; @selector(isEqualToString:)
000027c8         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027cc         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027cf         mov        dword [esp+0x48+var_40], 0x3038                     ; @"k"
000027d7         call       imp___symbol_stub__objc_msgSend
000027dc         test       al, al
000027de         je         loc_28d4

000027e4         mov        eax, dword [objc_msg_dataUsingEncoding_]            ; @selector(dataUsingEncoding:)
000027e9         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000027ed         mov        eax, dword [ebp+var_28]
000027f0         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000027f3         mov        dword [esp+0x48+var_40], 0x4
000027fb         call       imp___symbol_stub__objc_msgSend
00002800         mov        esi, eax
00002802         mov        eax, dword [objc_msg_length]                        ; @selector(length)
00002807         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000280b         mov        dword [esp+0x48+var_48], esi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000280e         call       imp___symbol_stub__objc_msgSend
00002813         mov        edi, eax
00002815         mov        eax, dword [objc_msg_bytes]                         ; @selector(bytes)
0000281a         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
0000281e         mov        dword [esp+0x48+var_48], esi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002821         call       imp___symbol_stub__objc_msgSend
00002826         lea        ecx, dword [ebp+var_24]
00002829         mov        dword [esp+0x48+var_40], ecx                        ; argument "md" for method imp___symbol_stub__CC_SHA1
0000282d         mov        dword [esp+0x48+var_44], edi                        ; argument "len" for method imp___symbol_stub__CC_SHA1
00002831         mov        dword [esp+0x48+var_48], eax                        ; argument "data" for method imp___symbol_stub__CC_SHA1
00002834         call       imp___symbol_stub__CC_SHA1
00002839         mov        eax, dword [cls_NSMutableString]                    ; cls_NSMutableString
0000283e         mov        ecx, dword [objc_msg_string]                        ; @selector(string)
00002844         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002848         mov        dword [esp+0x48+var_48], eax                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000284b         xor        esi, esi
0000284d         call       imp___symbol_stub__objc_msgSend
00002852         mov        edi, eax

             loc_2854:
00002854         movzx      eax, byte [ebp+esi+var_24]                          ; CODE XREF=-[Control validar:]+675
00002859         mov        ecx, dword [objc_msg_appendFormat_]                 ; @selector(appendFormat:)
0000285f         mov        dword [esp+0x48+var_3C], eax
00002863         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002867         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
0000286a         mov        dword [esp+0x48+var_40], 0x3068                     ; @"%02x"
00002872         call       imp___symbol_stub__objc_msgSend
00002877         inc        esi
00002878         cmp        esi, 0x14
0000287b         jne        loc_2854

0000287d         mov        eax, dword [objc_msg_substringWithRange_]           ; @selector(substringWithRange:)
00002882         mov        dword [esp+0x48+var_44], eax                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
00002886         mov        dword [esp+0x48+var_48], edi                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
00002889         mov        dword [esp+0x48+var_3C], 0xa
00002891         mov        dword [esp+0x48+var_40], 0x0
00002899         call       imp___symbol_stub__objc_msgSend
0000289e         mov        ecx, dword [objc_msg_isEqualToString_]              ; @selector(isEqualToString:)
000028a4         mov        dword [esp+0x48+var_40], eax
000028a8         mov        dword [esp+0x48+var_44], ecx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000028ac         mov        dword [esp+0x48+var_48], ebx                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000028af         call       imp___symbol_stub__objc_msgSend
000028b4         test       al, al
000028b6         je         loc_28d4

000028b8         mov        eax, dword [ebp+self]
000028bb         mov        ecx, dword [eax+0xc]
000028be         mov        edx, dword [objc_msg_orderFront_]                   ; @selector(orderFront:)
000028c4         mov        dword [esp+0x48+var_40], eax
000028c8         mov        dword [esp+0x48+var_44], edx                        ; argument "selector" for method imp___symbol_stub__objc_msgSend
000028cc         mov        dword [esp+0x48+var_48], ecx                        ; argument "instance" for method imp___symbol_stub__objc_msgSend
000028cf         call       imp___symbol_stub__objc_msgSend

             loc_28d4:
000028d4         mov        eax, dword [___stack_chk_guard_301c]                ; ___stack_chk_guard_301c, CODE XREF=-[Control validar:]+177, -[Control validar:]+213, -[Control validar:]+222, -[Control validar:]+230, -[Control validar:]+263, -[Control validar:]+273, -[Control validar:]+281, -[Control validar:]+384, -[Control validar:]+451, -[Control validar:]+518, -[Control validar:]+734
000028d9         mov        eax, dword [eax]
000028db         cmp        eax, dword [ebp+var_10]
000028de         jne        loc_28e8

000028e0         add        esp, 0x3c
000028e3         pop        esi
000028e4         pop        edi
000028e5         pop        ebx
000028e6         pop        ebp
000028e7         ret
                        ; endp

             loc_28e8:
000028e8         call       imp___symbol_stub____stack_chk_fail                 ; CODE XREF=-[Control validar:]+774
                        ; endp 

这个方法比较长,看伪代码就比较清晰了:

void -[Control validar:](void * self, void * _cmd, void * arg2) {
    var_10 = *___stack_chk_guard;
    edi = [*(self + 0x8) stringValue];
    var_28 = [*(self + 0x4) stringValue];
    esi = [var_28 length];
    var_2C = [edi length];
    ebx = [[edi substringFromIndex:[edi length] + 0xfffffffe] intValue];
    if (((((((var_28 != 0x0) && ([var_28 isEqual:@""] == 0x0)) && (esi >= 0x4)) && (edi != 0x0)) && ([edi isEqual:@""] == 0x0)) && (var_2C == 0xf)) && (esi == ebx)) {
            esi = [edi substringWithRange:0xa];
            ebx = [edi substringWithRange:0x0];
            if ([esi isEqualToString:@"k"] != 0x0) {
                    if ([[edi substringWithRange:0xb] isEqualToString:@"n"] != 0x0) {
                            if ([[edi substringWithRange:0xc] isEqualToString:@"k"] != 0x0) {
                                    esi = [var_28 dataUsingEncoding:0x4];
                                    edi = [esi length];
                                    eax = [esi bytes];
                                    CC_SHA1(eax, edi, var_24);
                                    esi = 0x0;
                                    edi = [NSMutableString string];
                                    do {
                                            [edi appendFormat:@"%02x"];
                                            esi = esi + 0x1;
                                    } while (esi != 0x14);
                                    if ([ebx isEqualToString:[edi substringWithRange:0x0]] != 0x0) {
                                            [*(self + 0xc) orderFront:self];
                                    }
                            }
                    }
            }
    }
    if (*___stack_chk_guard != var_10) {
            __stack_chk_fail();
    }
    return;
  }

可以看出,先取了输入的name ,serial的值放在edi ,var_28,然后分别计算length。
后面是校验,判断edi的长度为15,var_28的长度不小于4,截取后面edi(substringFromIndex) 存入ebx,比较ebx的值与var_28的长度是否相等, 然后取edi的0xa 、0xb 、 0xc 处的substring,分别比较k,n,k,看是否相等。如这些条件都满足,对var_28 进行CC_SHA1加密,分别截取edi、截取CC_SHA1加密后的字符串,比较两者是否相等。如果相等,则是合法的注册码。
name是edi?,serial是var_28?这些截取子串的范围是多少呢?下面动态调试分析。

0x2动态分析

此CrackMe有反debug的措施,见如下的方法。

     sub_2556:
00002556         push       ebp                                                 ; CODE XREF=EntryPoint+48
00002557         mov        ebp, esp
00002559         sub        esp, 0x18
0000255c         mov        dword [esp+0x18+var_C], 0x0                         ; argument "data" for method imp___symbol_stub__ptrace
00002564         mov        dword [esp+0x18+var_10], 0x0                        ; argument "addr" for method imp___symbol_stub__ptrace
0000256c         mov        dword [esp+0x18+var_14], 0x0                        ; argument "pid" for method imp___symbol_stub__ptrace
00002574         mov        dword [esp+0x18+var_18], 0x1f                       ; argument "request" for method imp___symbol_stub__ptrace
0000257b         call       imp___symbol_stub__ptrace
00002580         add        esp, 0x18
00002583         pop        ebp
00002584         jmp        imp___symbol_stub__NSApplicationMain

此方法会检测ptrace,所以先将
0000257b call imp___symbol_stub__ptrace
改为:
0000257b nop dword [eax+eax]
去掉反debug,这样便可以在Hopper中直接debug运行了。运行如下:

如何生成CrackMe注册机之Doughnuts_第2张图片
Snip20171013_7.jpg
如何生成CrackMe注册机之Doughnuts_第3张图片
Snip20171013_5.png
如何生成CrackMe注册机之Doughnuts_第4张图片
Snip20171013_6.png

经单步调试,得知:
name 存var_28, serial 存edi, name的长度不少于4,serial的长度为15。其中serial后两位为name的长度值,serial 的11,12,13位为k、n、k,serial剩下的前10位为SHA1加密name后的字符串的前10位。因此,Keygen算法如下:

1. name.length >= 4
2. searial.length = 15
3. searial =SHA1(name).subStringWithRange(0,10) +"k"+"n"+"k"+(name).length

例如输入name 为qwer,则name的SHA1加密为:1161e6ffd3637b302a5cd74076283a7bd1fc20d3。按照上述算法,得出serial:
1161e6ffd3knk04
验证测试,结果正确:

如何生成CrackMe注册机之Doughnuts_第5张图片
Snip20171012_3.png

你可能感兴趣的:(如何生成CrackMe注册机之Doughnuts)