How to Crack App by Self-Keygen

本次练习破解注册码使用的是一款商业软件,所以没有提供下载地址。这里简记为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。:)!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • 在上一篇《How to Crack App by Self-Keygen》中,通过打印内存获取到了Serial,但...
    Mr_Xiao阅读 334评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,463评论 25 707
  • LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用Xc...
    CoderSC阅读 1,346评论 0 2
  • 据说高温已经达到四十度之巨,倒是一直后知后觉来着,因为这个假期已经宅成了精,如非必须几乎都没有出门的时候。...
    此时木棉阅读 160评论 1 0