美文网首页
How to Crack App by Self-Keygen

How to Crack App by Self-Keygen

作者: Mr_Xiao | 来源:发表于2017-10-27 01:31 被阅读0次

    本次练习破解注册码使用的是一款商业软件,所以没有提供下载地址。这里简记为xxx.app。运行后,有注册License的界面。输入邮箱和Serial即可。注册后的效果如图。

    Snip20171026_2.png

    这个序列号是怎么算出来的呢?这里使用了一个通用的技巧——self-keygen,或者叫auto-keygen。即通过动态运行程序,让程序自己告诉我们Serial。能这样做的原因在于,通常,程序会根据输入的条件如邮箱,计算出正确的Serial,保存在内存某处,然后和输入的Serial比较。如果相等,就通过验证。所以,只要在内存中偷出这Serial,便可以得出注册码,不用研究如何去复制Serial的生成算法。

    0x1 代码静态分析

    在Hopper中打开目标程序。很容易找到判断是否为注册的地方。
    在程序的入口有如下代码。即initializeWithLicenseSecret方法中判断。

    0000000100001e64         mov        rsi, r15                                    ; argument "selector" for method _objc_msgSend
    0000000100001e67         call       r14                                         ; _objc_msgSend
    0000000100001e6a         mov        rdi, rax                                    ; argument "instance" for method imp___stubs__objc_retainAutoreleasedReturnValue
    0000000100001e6d         call       imp___stubs__objc_retainAutoreleasedReturnValue
    0000000100001e72         mov        rbx, rax
    0000000100001e75         mov        rsi, qword [0x1000ad508]                    ; @selector(initializeWithLicenseSecret:storeURL:daysForTrial:), argument "selector" for method _objc_msgSend
    0000000100001e7c         lea        rdx, qword [cfstring_secretPa__wordForXXX] ; @"secretd*****"
    0000000100001e83         lea        rcx, qword [cfstring_http_xxx_php] ; @"xxx.php"
    0000000100001e8a         mov        r8d, 0x7
    0000000100001e90         mov        rdi, rbx                                    ; argument "instance" for method _objc_msgSend
    0000000100001e93         call       r14                                         ; _objc_msgSend
    0000000100001e96         mov        rdi, rbx                                    ; argument "instance" for method _objc_release
    0000000100001e99         call       qword [_objc_release_1000881e8]             ; _objc_release
    0000000100001e9f         mov        rdi, qword [rbp+var_30]                     ; argument "instance" for method _objc_release
    0000000100001ea3         mov        rax, qword [_objc_release_1000881e8]
    0000000100001eaa         add        rsp, 0x8
    0000000100001eae         pop        rbx
    0000000100001eaf         pop        r12
    0000000100001eb1         pop        r13
    0000000100001eb3         pop        r14
    0000000100001eb5         pop        r15
    0000000100001eb7         pop        rbp
    0000000100001eb8         jmp        rax                                         ; _objc_release
                            ; endp
    

    但是在程序其他部分,却找不到initializeWithLicenseSecret实现。后来发现原来是Framework中的方法。即程序将验证逻辑放入了专门的Framework中。见下图Framework文件夹。

    Snip20171027_1.png

    在Hopper中打开Framework,发现isLicensed方法有如下代码。loc_61e78 中licenseForEmailAddress为计算Serial的方法,然后调用isEqualToString方法比较是否与输入相等。接着看此licenseForEmailAddress方法,发现最终调用licenseForEmailAddress:withSecret:计算注册码。所以在动态运行时,只要获取此函数的输出即可。

    0000000000061e55         mov        rbx, rdi
    0000000000061e58         call       qword [_objc_msgSend_25b2e8]                ; _objc_msgSend
    0000000000061e5e         cmp        rax, 0x3
    0000000000061e62         jae        loc_61e78
    
    0000000000061e64         xor        r12d, r12d
    0000000000061e67         jmp        loc_61db3
    
                        loc_61e6c:
    0000000000061e6c         xor        r12d, r12d                                  ; CODE XREF=-[License isLicensed]+574
    0000000000061e6f         mov        rdi, qword [rbp+var_30]
    0000000000061e73         jmp        loc_61db6
    
                        loc_61e78:
    0000000000061e78         mov        rsi, qword [0x2c3c48]                       ; @selector(licenseForEmailAddress:), argument "selector" for method _objc_msgSend, CODE XREF=-[HSLicense isLicensed]+640
    0000000000061e7f         mov        rdi, r14                                    ; argument "instance" for method _objc_msgSend
    0000000000061e82         mov        rdx, r13
    0000000000061e85         call       r15                                         ; _objc_msgSend
    0000000000061e88         mov        rdi, rax                                    ; argument "instance" for method imp___stubs__objc_retainAutoreleasedReturnValue
    0000000000061e8b         call       imp___stubs__objc_retainAutoreleasedReturnValue
    0000000000061e90         mov        r14, rax
    0000000000061e93         mov        rsi, qword [0x2c0b28]                       ; @selector(isEqualToString:), argument "selector" for method _objc_msgSend
    0000000000061e9a         mov        rdi, r14                                    ; argument "instance" for method _objc_msgSend
    0000000000061e9d         mov        rdx, rbx
    0000000000061ea0         call       r15                                         ; _objc_msgSend
    0000000000061ea3         mov        r12b, al
    0000000000061ea6         mov        rdi, r14                                    ; argument "instance" for method _objc_release
    0000000000061ea9         call       qword [_objc_release_25b2f8]                ; _objc_release
    0000000000061eaf         jmp        loc_61db3
    
    

    0x2 动态分析

    由于需要调试的代码位于Framework中,不方便动态运行调试,所以选择了Mac OS X自带的lldb debug工具。唯一的区别是没有操作界面,纯Command Line。
    首先运行lldb,启动程序,并输入邮箱。使用下面命令设置好BreakPoint。

    br s -n licenseForEmailAddress:withSecret:
    
    Snip20171027_4.png

    接着使用di命令,反汇编当前函数。

    Snip20171027_6.png

    可以看到 0x100467a01 uppercaseString方法为计算Serial的最后一步。所以在此处设置断点。

     br s -a 0x100467a01
    

    单步运行,根据Hopper静态代码分析,知r15保存最终结果。
    使用lldb memory read命令打印内存,在输出中即可得到注册码。如下图中B9D3C9-816381-FC5AA0-75B626-C7564D。

    0x1098a4b90: 22 42 39 44 33 43 39 2d 38 31 36 33 38 31 2d 46  "B9D3C9-816381-F
    0x1098a4ba0: 43 35 41 41 30 2d 37 35 42 36 32 36 2d 43 37 35  C5AA0-75B626-C75
    0x1098a4bb0: 36 34 44 00 00 00 00 00 00 00 00 00 00 00 00 00  64D.............
    
    8.png

    代入程序验证Success。:)!

    相关文章

      网友评论

          本文标题:How to Crack App by Self-Keygen

          本文链接:https://www.haomeiwen.com/subject/ikglpxtx.html