如何完美破解AquaticPrime License

本练习对象为Exces,一款小工具软件。下载地址:http://excesapp.com。作者本人其实已经描述了如何破解Exces,只是文中方法是暴力破解。笔者认为稍显简单粗暴——技不止于此!因此,尝试从真正注册license入手,实现完美破解!
Exces是如何注册的呢?运行Exces,见下图,可以看到注册license方法。在Preferences弹出框中,拖入一个有效的license文件。

Snip20171031_6.png

Snip20171031_4.png

那这个license文件是怎么样的呢?我们在Hopper中分析。

0x1 代码分析

在Hopper中打开Exces,找到verifyLicenseFile:方法。



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

        ; Variables:
        ;    arg_8: 16
        ;    _cmd: 12
        ;    self: 8
        ;    var_1C: -28
        ;    var_34: -52
        ;    var_38: -56
        ;    var_3C: -60
        ;    var_40: -64
        ;    var_44: -68
        ;    var_48: -72


             -[SSExcesAppController verifyLicenseFile:]:
000051fc         push       ebp                                                 ; Objective C Implementation defined at 0x14ef8 (instance method)
000051fd         mov        ebp, esp
000051ff         push       edi
00005200         push       esi
00005201         push       ebx
00005202         sub        esp, 0x3c
00005205         mov        eax, dword [ebp+arg_8]
00005208         mov        edi, dword [ebp+self]
0000520b         mov        dword [ebp+var_1C], eax
0000520e         mov        dword [esp+0x48+var_40], eax
00005212         mov        eax, dword [objc_msg_verifyPath_]                   ; @selector(verifyPath:)
00005217         mov        dword [esp+0x48+var_48], edi                        ; argument #1 for method imp___jump_table__objc_msgSend
0000521a         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
0000521e         call       imp___jump_table__objc_msgSend
00005223         test       eax, eax
00005225         je         loc_530d

0000522b         mov        eax, dword [objc_msg_alloc]                         ; @selector(alloc)
00005230         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005234         mov        eax, dword [cls_NSTask]                             ; cls_NSTask
00005239         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
0000523c         call       imp___jump_table__objc_msgSend
00005241         mov        edx, dword [objc_msg_init]                          ; @selector(init)
00005247         mov        dword [esp+0x48+var_44], edx                        ; argument #2 for method imp___jump_table__objc_msgSend
0000524b         mov        dword [esp+0x48+var_48], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
0000524e         call       imp___jump_table__objc_msgSend
00005253         mov        dword [esp+0x48+var_40], 0x12418                    ; @"/bin/cp"
0000525b         mov        ebx, eax
0000525d         mov        eax, dword [objc_msg_setLaunchPath_]                ; @selector(setLaunchPath:)
00005262         mov        dword [esp+0x48+var_48], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005265         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005269         call       imp___jump_table__objc_msgSend
0000526e         mov        eax, dword [objc_msg_stringByExpandingTildeInPath]  ; @selector(stringByExpandingTildeInPath)
00005273         mov        esi, dword [cls_NSArray]                            ; cls_NSArray
00005279         mov        dword [esp+0x48+var_48], 0x123b8                    ; @"~/Library/Preferences/com.seosoft.exces.licence.excli", argument #1 for method imp___jump_table__objc_msgSend
00005280         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005284         call       imp___jump_table__objc_msgSend
00005289         mov        dword [esp+0x48+var_34], 0x0
00005291         mov        dword [esp+0x48+var_38], eax
00005295         mov        eax, dword [ebp+var_1C]
00005298         mov        dword [esp+0x48+var_40], 0x12428                    ; @"-r"
000052a0         mov        dword [esp+0x48+var_3C], eax
000052a4         mov        eax, dword [objc_msg_arrayWithObjects_]             ; @selector(arrayWithObjects:)
000052a9         mov        dword [esp+0x48+var_48], esi                        ; argument #1 for method imp___jump_table__objc_msgSend
000052ac         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000052b0         call       imp___jump_table__objc_msgSend
000052b5         mov        dword [esp+0x48+var_40], eax
000052b9         mov        eax, dword [objc_msg_setArguments_]                 ; @selector(setArguments:)
000052be         mov        dword [esp+0x48+var_48], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000052c1         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000052c5         call       imp___jump_table__objc_msgSend
000052ca         mov        eax, dword [objc_msg_launch]                        ; @selector(launch)
000052cf         mov        dword [esp+0x48+var_48], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000052d2         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000052d6         call       imp___jump_table__objc_msgSend
000052db         mov        ebx, dword [edi+0xc]
000052de         mov        byte [edi+0x2c], 0x1
000052e2         mov        eax, dword [objc_msg_selectedToolbarItem]           ; @selector(selectedToolbarItem)
000052e7         mov        dword [esp+0x48+var_48], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000052ea         mov        dword [esp+0x48+var_44], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000052ee         call       imp___jump_table__objc_msgSend
000052f3         mov        dword [ebp+arg_8], eax
000052f6         mov        eax, dword [objc_msg_toolbarHit_]                   ; @selector(toolbarHit:)
000052fb         mov        dword [ebp+self], ebx
000052fe         mov        dword [ebp+_cmd], eax
00005301         add        esp, 0x3c
00005304         pop        ebx
00005305         pop        esi
00005306         pop        edi
00005307         leave
00005308         jmp        imp___jump_table__objc_msgSend
                        ; endp

             loc_530d:
0000530d         add        esp, 0x3c                                           ; CODE XREF=-[SSExcesAppController verifyLicenseFile:]+41
00005310         pop        ebx
00005311         pop        esi
00005312         pop        edi
00005313         leave
00005314         ret
                        ; endp

其中,关键点为调用的verifyPath:方法;如果verifyPath方法通过,便将License文件cp(拷贝) 到~/Library/Preferences/com.seosoft.exces.licence.excli。由此得到 一点提示,即licence 文件为excli后缀。

接下来看verifyPath:方法。

00005315         push       ebp                                                 ; Objective C Implementation defined at 0x14eec (instance method)
00005316         mov        ebp, esp
00005318         push       edi
00005319         push       esi
0000531a         push       ebx
0000531b         sub        esp, 0x1c
0000531e         mov        eax, dword [objc_msg_string]                        ; @selector(string)
00005323         mov        edi, dword [ebp+self]
00005326         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
0000532a         mov        eax, dword [cls_NSMutableString]                    ; cls_NSMutableString
0000532f         mov        dword [esp+0x28+var_28], eax                        ; argument #1 for method imp___jump_table__objc_msgSend
00005332         call       imp___jump_table__objc_msgSend
00005337         mov        dword [esp+0x28+var_20], 0x12438                    ; @"0xE6242CBE8E7686CB4AFB143FAF6D"
0000533f         mov        ebx, eax
00005341         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005346         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005349         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
0000534d         call       imp___jump_table__objc_msgSend
00005352         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005357         mov        dword [esp+0x28+var_20], 0x12448                    ; @"6B7805475B6D856812"
0000535f         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005362         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005366         call       imp___jump_table__objc_msgSend
0000536b         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005370         mov        dword [esp+0x28+var_20], 0x12458                    ; @"9"
00005378         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
0000537b         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
0000537f         call       imp___jump_table__objc_msgSend
00005384         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005389         mov        dword [esp+0x28+var_20], 0x12458                    ; @"9"
00005391         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005394         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005398         call       imp___jump_table__objc_msgSend
0000539d         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
000053a2         mov        dword [esp+0x28+var_20], 0x12468                    ; @"1D6547D406"
000053aa         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000053ad         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000053b1         call       imp___jump_table__objc_msgSend
000053b6         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
000053bb         mov        dword [esp+0x28+var_20], 0x12478                    ; @"A2C26"
000053c3         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000053c6         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000053ca         call       imp___jump_table__objc_msgSend
000053cf         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
000053d4         mov        dword [esp+0x28+var_20], 0x12488                    ; @"3"
000053dc         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000053df         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000053e3         call       imp___jump_table__objc_msgSend
000053e8         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
000053ed         mov        dword [esp+0x28+var_20], 0x12488                    ; @"3"
000053f5         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
000053f8         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
000053fc         call       imp___jump_table__objc_msgSend
00005401         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005406         mov        dword [esp+0x28+var_20], 0x12498                    ; @"BE7F9494B188D12EE391D7A"
0000540e         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005411         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005415         call       imp___jump_table__objc_msgSend
0000541a         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
0000541f         mov        dword [esp+0x28+var_20], 0x124a8                    ; @"9C9E84B05"
00005427         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
0000542a         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
0000542e         call       imp___jump_table__objc_msgSend
00005433         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005438         mov        dword [esp+0x28+var_20], 0x124b8                    ; @"8"
00005440         mov        dword [esp+0x28+var_28], ebx                        ; argument #1 for method imp___jump_table__objc_msgSend
00005443         mov        dword [esp+0x28+var_24], eax                        ; argument #2 for method imp___jump_table__objc_msgSend
00005447         call       imp___jump_table__objc_msgSend
0000544c         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)  
.....
.....

代码太长,看伪代码就比较清晰了。

void * -[SSExcesAppController verifyPath:](void * self, void * _cmd, void * arg_8) {
    edi = self;
    ebx = [NSMutableString string];
    [ebx appendString:@"0xE6242CBE8E7686CB4AFB143FAF6D"];
    [ebx appendString:@"6B7805475B6D856812"];
    [ebx appendString:@"9"];
    [ebx appendString:@"9"];
    [ebx appendString:@"1D6547D406"];
    [ebx appendString:@"A2C26"];
    [ebx appendString:@"3"];
    [ebx appendString:@"3"];
    [ebx appendString:@"BE7F9494B188D12EE391D7A"];
    [ebx appendString:@"9C9E84B05"];
    [ebx appendString:@"8"];
    [ebx appendString:@"8"];
    [ebx appendString:@"742EAE04CFE6831F338"];
    [ebx appendString:@"B2D"];
    [ebx appendString:@"9"];
    [ebx appendString:@"9"];
    [ebx appendString:@"E4AC7202CE86FEDDF170EF6AE"];
    [ebx appendString:@"1"];
    [ebx appendString:@"D"];
    [ebx appendString:@"D"];
    [ebx appendString:@"50DC8A8EDE47CA3EC1B11B86BED"];
    [ebx appendString:@"945AB07989D"];
    [ebx appendString:@"B"];
    [ebx appendString:@"B"];
    [ebx appendString:@"A634511AE20B8ADFC"];
    [ebx appendString:@"501D130BE"];
    [ebx appendString:@"4"];
    [ebx appendString:@"4"];
    [ebx appendString:@"EDF1DC6129A929A12A8"];
    [ebx appendString:@"506739EE47871476D5"];
    esi = [[AquaticPrime aquaticPrimeWithKey:ebx] dictionaryForLicenseFile:arg_8];
    if (([[esi objectForKey:@"Expires"] isEqualToString:@"never"] == 0x0) && ([[NSCalendarDate calendarDate] isGreaterThan:[NSCalendarDate dateWithString:[esi objectForKey:@"Expires"] calendarFormat:@"%d/%m/%Y"]] != 0x0)) {
            esi = 0x0;
    }
    else {
            if (*(edi + 0xc) == 0x0) {
                    *(edi + 0xc) = [SSExcesPrefController new];
            }
            [*(edi + 0xc) setLicenseDictionary:esi];
    }
    eax = esi;
    return eax;
}

从代码可以看出,先拼接出Key,因此这个Key是写死在APP里面的。然后调用[AquaticPrime aquaticPrimeWithKey],通过dictionaryForLicenseFile方法从license文件中读出Expires字段。如果Expires为never或者Expires定义的日期在当前日期后面,则校验通过。所以,看来验证的逻辑比较简单。但如何伪装一份license让APP接受,那就要看AquaticPrime调用的aquaticPrimeWithKey方法。

0x2 AquaticPrime Framework

AquaticPrime是什么?Google一下,就知道AquaticPrime为Mac OS X上流行的利用RSA加密算法进行license验证的Framework。大概原理是生成RSA公钥、私钥对,用私钥加密生成license文件。公钥则放APP里,用来解密和检验license。由于RSA具有非对称性,使用私钥加密的字符,配对的公钥(即上述拼接的Key)才能解密,并且从公钥无法得到私钥,所以具备很好的保密性。由于APP无法知道私钥,无从知道license怎么来的,也无法解密任意的license。看到这里,似乎非暴力破解此APP是无望了。开始笔者也是这么认为的。还好,AquaticPrime为开源软件,在github找到AquaticPrimeFramework源代码,看到了希望的曙光。

0x3 破解AquaticPrime

AquaticPrimeFramework源码提供了生成license文件的APP,可以生成出一对RSA钥匙和对应的license文件。所以,破解的思路就是自制一份license文件和RSA公、私钥,然后将APP中的公钥替换为自制公钥 。

(1)生成license和RSA公、私钥

如下图。根据代码分析,license中的Expires字段设为never,后缀名为excli。


Snip20171101_9.png
Snip20171101_8.png

(2)使用自制的公钥替换APP公钥

这里使用了Hex Fiend二进制编辑工具。用Hex Fiend打开APP,找到公钥字符串,全部替换为自制的公钥。如下二图。

替换前:


Snip20171101_11.png

替换后:

Snip20171101_12.png

(3)修改verifyPath方法,导入自制的公钥

在Hopper中编辑verifyPath方法,只保留第一个objc_msg_appendString_ 0x12438方法,然后在0x12438定义的字符串中将length设为0x102。即一次性将公钥导入,省去混淆公钥的过程(代码太长,省略部分)。

...
...
0000531e         mov        eax, dword [objc_msg_string]                        ; @selector(string)
00005323         mov        edi, dword [ebp+8]
00005326         mov        dword [esp+4], eax                                  ; argument #2 for method imp___jump_table__objc_msgSend
0000532a         mov        eax, dword [cls_NSMutableString]                    ; cls_NSMutableString
0000532f         mov        dword [esp], eax                                    ; argument #1 for method imp___jump_table__objc_msgSend
00005332         call       imp___jump_table__objc_msgSend
00005337         mov        dword [esp+8], 0x12438                              ; @"0xDC24E2A5B7C87320A6663704670BC09E4B6AE5301D40CDCCE5F79259AAD0765A4BB5ED02ABBECCC6323852E44ACB97BA6D9AEEFE7AE420AD2991803853D76741F5118C36878E0A5C1067A2705788D1A5145430D3BA4B37469BF2F48A5EE210529A238ED86296B4563EBA56D23BC15D7980586079F58A83C24E0B73BE4336DE…"
0000533f         mov        ebx, eax
00005341         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005346         mov        dword [esp], ebx                                    ; argument #1
00005349         mov        dword [esp+4], eax                                  ; argument #2
0000534d         call       imp___jump_table__objc_msgSend
00005352         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005357         mov        dword [esp+8], 0x12448                              ; @"09E4B6AE5301D40CDCCE5F79259AAD0765A4BB5ED02ABBECCC6323852E44ACB97BA6D9AEEFE7AE420AD2991803853D76741F5118C36878E0A5C1067A2705788D1A5145430D3BA4B37469BF2F48A5EE210529A238ED86296B4563EBA56D23BC15D7980586079F58A83C24E0B73BE4336DE959EE47871476D5"
0000535f         mov        dword [esp], ebx                                    ; argument #1
00005362         mov        dword [esp+4], eax                                  ; argument #2
00005366         nop        dword [eax+eax]
0000536b         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005370         mov        dword [esp+8], 0x12458                              ; @"E5F79259AAD0765A4BB5ED02ABBECCC6323852E44ACB97BA6D9AEEFE7AE420AD2991803853D76741F5118C36878E0A5C1067A2705788D1A5145430D3BA4B37469BF2F48A5EE210529A238ED86296B4563EBA56D23BC15D7980586079F58A83C24E0B73BE4336DE959EE47871476D5"
00005378         mov        dword [esp], ebx                                    ; argument #1
0000537b         mov        dword [esp+4], eax                                  ; argument #2
0000537f         nop        dword [eax+eax]
00005384         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
00005389         mov        dword [esp+8], 0x12458                              ; @"E5F79259AAD0765A4BB5ED02ABBECCC6323852E44ACB97BA6D9AEEFE7AE420AD2991803853D76741F5118C36878E0A5C1067A2705788D1A5145430D3BA4B37469BF2F48A5EE210529A238ED86296B4563EBA56D23BC15D7980586079F58A83C24E0B73BE4336DE959EE47871476D5"
00005391         mov        dword [esp], ebx                                    ; argument #1
00005394         mov        dword [esp+4], eax                                  ; argument #2
00005398         nop        dword [eax+eax]
0000539d         mov        eax, dword [objc_msg_appendString_]                 ; @selector(appendString:)
000053a2         mov        dword [esp+8], 0x12468                              ; @"F79259AAD0765A4BB5ED02ABBECCC6323852E44ACB97BA6D9AEEFE7AE420AD2991803853D76741F5118C36878E0A5C1067A2705788D1A5145430D3BA4B37469BF2F48A5EE210529A238ED86296B4563EBA56D23BC15D7980586079F58A83C24E0B73BE4336DE959EE47871476D5"
000053aa         mov        dword [esp], ebx                                    ; argument #1
000053ad         mov        dword [esp+4], eax                                  ; argument #2
...
...

0x4 程序验证

将自制的license文件拖入Exces,验证成功!:)!

Snip20171031_3.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容