手把手教你如何破解付费MacApp

目录截图.png Typora的自带内容目录截图

复杂方案解决结果--->破解版传送门

前提准备

  • Hopper Disassembler(X,G,Esc,Space...,度娘/谷歌,后面简称Hopper

  • Xcode(App Store)

  • frida(前置条件配置好 python环境,下载好pip,随后用pip下载,具体度娘/谷歌找攻略即可)

  • 汇编指令基础掌握(je,jne,jmp,jle,mov,call,ret,nop,xor,lea,rax,rdi,rsi,rcx....)

  • lldb指令基础掌握(bt, image lookup --address ,p, c...)

  • 终端操作(codesign *,frida *)

  • 具备一定的编程思想

  • 基础逆向工程思维基础掌握(Executable,重签,覆盖entitlements)

小目标:学习下一些简单汇编知识以及市面上的一些付费App的付费模块的代码思路然后顺便逆向破解 PDF Expert

第一步

  • 目的---体验原装PDF Expert 修改任意pdf文件后保存查看效果

1.1体验未破解版流程

image

第二步

在保存操作前是没有提示升级到完整版这个弹窗的,所以我们在Xcode attach成功后可以尝试增加个符号断点windowWillLoad查看调用栈的关系

  • 目的---查看调用图层间的调用关系,从而尝试去定位到关键代码。

2.1 Xcode新建个工程

image

2.2 attach查看对应图层关系

2.2.1 Attach App
image

2.2.2 Debug View Hierarchy

image

查看图层关系 在增加符号断点windowWillLoad后在修改后的pdf界面触发保存操作出现弹窗发现没有停下断点,说明这条路行不通。

但是我们也获取到了一个关键信息:最上面的控件名称为 DMTrialController

第三步

  • 目的---使用frida通过已知弹出升级框的类 DMTrialController ,查找出具体调用的方法堆栈

3.1 frida-trace 查看对应方法调用关系

在终端上输入 frida-trace -m "-[DMActivationController *]" PDF\ Expert

​
 22103 ms  -[DMTrialController trialObject]
​
 23074 ms  -[DMTrialController trialObject]
​
 23074 ms  -[DMActivationController performActivationStepWithStep:0x66]
​
 23074 ms     | -[DMActivationController isRunning]
​
 23074 ms     | -[DMActivationController setNextPerformStep:0x66]
​
 23074 ms     | -[DMActivationController updateStepControllerForCurrentStep]
​
 23074 ms     |    | -[DMActivationController nextPerformStep]
​
 23074 ms     |    | -[DMActivationController confirmedNextPerformStep:0x66] </pre>

分析log输出在点击保存时触发的方法为-[DMActivationController performActivationStepWithStep:0x66]

记录下来回到第二步操作的2.4查看付费弹窗堆栈信息。

3.2 增加符号断点查看

image

再次保存操作后触发断点终端查看到嫌疑关键代码如下

 frame #1: 0x000000010227846c PDF Expert`___lldb_unnamed_symbol15828$PDF Expert + 380
 frame #2: 0x00000001022c5263 PDF Expert`___lldb_unnamed_symbol16722$PDF Expert + 371
 frame #3: 0x00000001022a1e37 PDF Expert`___lldb_unnamed_symbol16128$PDF Expert + 39 

随后 image寻址找到具体App调用时的地址信息

 (lldb) image lookup --address 0x0000000103818a7c
 Address: DevMateKit[0x0000000000029a7c] (DevMateKit.__TEXT.__text + 165540)
 Summary: DevMateKit`-[DMActivationController performActivationStepWithStep:]
(lldb) image lookup --address 0x00000001022c5263
 Address: PDF Expert[0x00000001003ff263] (PDF Expert.__TEXT.__text + 4180867)
 Summary: PDF Expert`___lldb_unnamed_symbol16722$PDF Expert + 371
(lldb) image lookup --address 0x00000001022a1e37
 Address: PDF Expert[0x00000001003dbe37] (PDF Expert.__TEXT.__text + 4036439)
 Summary: PDF Expert`___lldb_unnamed_symbol16128$PDF Expert + 39</pre>

得到可疑地址

A:0x0000000000029a7c

B:0x00000001003ff263

C:0x00000001003dbe37

第四步

  • 目的---使用Hooper查看可疑地址A,B,C。

4.1 科普使用Hooper

4.1.1 直接拽

image
image

4.1.2 稍等一会Hopper加载完成

4.1.3 追查付费弹窗底细

加载完成后在界面左侧输入刚才Xcode Attach控件名 DMTrialController

image

分析搜索结果发现并没有直接匹配的 DMTrialController 这玩意,猜想这个空间不是直接在主工程实现的,随后看跟 DMTrialController 命名类似的DMTrialWelcomeStepController 看上图可以找到文件路径并且发现关键字DevMateKit,其实早在Xcode Attach时查看图层就可以发现 这个付费弹窗的命名前缀是DMT 而主工程的命名前缀是PDF_Expert,很大概率付费弹窗是用的第三方库.

DevMateKit传送门

4.1.4 简单了解DevmateKit有哪些功能

这个就不在这介绍了,通过传送门下载的demo大概了解到DevMateKit是做一些付费弹窗,举报弹窗,kevlar代码混淆。

4.2 逐个排查可疑地址

4.2.1 地址A:0x0000000000029a7cHopper 信息分析

image

image

根据Hopper分析结果看出可疑地址A主要是在做一些绘制UI操作,我们主要目的是要改掉App中一个凭证字段信息类似 isActiva , isRegis 之类的字眼。排除掉可疑地址A。

4.2.2 地址B:0x00000001003ff263Hopper 信息分析
image

发现定位到的地址操作符是test,这个有着重大嫌疑,大概率是此地址去做是否注册判断。我们继续去排查可疑地址C。

4.2.3 地址C:0x00000001003dbe37Hopper 信息分析

image

由分析结果得知可疑地址C主要是做saveDocument:操作,并且看上图左边红色框可以得知这一顿操作没有做一些test或者是cmp或者是提前ret之类的操作,基本也可以排除掉可疑地址C。

4.3 主要调查重点嫌疑地址

4.3.1 重新查看可疑地址B:0x00000001003ff263的hopper数据,切换至控制流图(Control Flow Graph)

备注:快捷键 Space

image

查看上图分析一处逻辑判断为 al0x1test运算,但是此处逻辑地址为loc_1003ff259是由loc_1003ff11e的尾部的je跳转过来的。

je的来源是上一层的al0x1test运算,再往上看可以知道al是通过call sub_1003b21b0的返回值赋值的。

4.3.2 解析第一层梦境function sub_1003b21b0

双击进入 sub_1003b21b0的function实现的控制流图。进入目标func的控制流图后发现是个蛮庞大的函数,缩放一下页面看到整个流程图如下

image

分析上图控制流图结构,猜想如果是已购买用户的判断逻辑应该是一条清晰的流程也就是右侧箭头所指的通道。

接着着重看如何才可以走到阳光大道上

image

分析上图控制流图重点是通过cmp r13b, 0x3je loc_1003b22cd,翻译过来也就是判断r13b是不是0x3如果是0x3就去阳光大道,那么我们现在就想办法把r13b变成0x3

image

继续往上看得知r13beax怼过来的,而eax是通过function sub_100382d70 返回的。

那么现在关键就是这个sub_100382d70

4.3.3 解析第二层梦境function sub_100382d70

双击进入sub_100382d70的function。

image

分析下第二层梦境的大概实现,首先第一眼嫌疑最大的是_O7RH3WAr7wAQMdz5Xv这个是被call的function是被混淆过的,其次通过这个_O7RH3WAr7wAQMdz5Xv 返回的al最后是跟0x1test

那么现在冷静下思考有以下两个解决思路

  • 简单方案-直接改sub_100382d70提前返回0x3然后去走阳光大道(如果忘记了为何要返回0x3,可以复习下4.3.2章节)

  • 复杂方案-修改_O7RH3WAr7wAQMdz5Xv 内部实现,继续深究,改最根部判断。

第五步

  • 目的---使用Hooper修改关键汇编运算逻辑。

5.1 简单方案解法尝试

5.1.1 修改sub_100382d70实现

根据上述操作我们得知sub_100382d70做了一串操作,先push,后mov后push…,我们现在其实只要返回个0x3即可,那直接选中sub_100382d70第一行修改,输入mov rax,0x3 ,点Assemble and Go Next,再继续输入ret,继续Assemble and Go Next

image

修改后的结果如下,随后保存新的Executable文件

image

5.1.2 保存Executable文件

image

保存Executable文件时点Cancel

image

接下来就是验证简单方案是否可行了,把刚生成的新Executable文件替换我们目标App内的旧Executable文件,具体操作如下

image

5.1.3 覆盖entitlements文件

原版entitlements文件数据如下,随后吧identifier对应的那几行干掉

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
 <key>com.apple.application-identifier</key>
 <string>3L68KQB4HG.com.readdle.PDFExpert-Mac</string>
 <key>com.apple.developer.team-identifier</key>
 <string>3L68KQB4HG</string>
 <key>com.apple.security.get-task-allow</key>
 <true/>
 </dict>
</plist> 

修改后

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
 <key>com.apple.security.get-task-allow</key>
 <true/>
 </dict>
</plist> 

保存后覆盖目标App的entitlements文件

 codesign -f -s - --entitlements entitlementsFilePathPrefix/Entitlements.plist appPathPrefix/PDF\ Expert.app 

执行完终端输出提示/Applications/PDF Expert 3.app: replacing existing signature即表示完成替换

5.1.4 检验简单方案处理结果

随后重新打开目标App,首先检查当前App的是否注册状态如下图

image

随后尝试修改任意pdf文件保存,保存成功!

5.2 复杂方案解决尝试

5.2.1 _O7RH3WAr7wAQMdz5Xv的前世今生

早在上文4.1.4 简单了解目标App所用的到第三方库kevlar能支持代码混淆,我们先简单看看_O7RH3WAr7wAQMdz5Xv的函数结构大概如下

image

看不是很懂,我们切换至伪代码视角看看

image

这里我们发现个关键字符串 kevlar,那基本可以认定此处的混淆代码的出处是DevMateKit了。

DevMateKit提供的demo工程我们搜索kevlar

image

继续怼进DMKevlarApplication.h看看代码

//! Function help with running timer for advanced check
#define DMKRunNewIntegrityCheckTimer DzVpwUg0VXKMIfCPA
FOUNDATION_EXTERN void DMKRunNewIntegrityCheckTimer(NSUInteger num, NSTimeInterval checkFrequency);
​
//! Checks if applicaion activated
#define DMKIsApplicationActivated PfCuPgJSp5KVlvc8W1
FOUNDATION_EXTERN BOOL DMKIsApplicationActivated(DMKevlarError *outKevlarError);
​
//! Returns user license info
#define DMKCopyLicenseUserInfo dReea3NiUFGwgD52YPa
FOUNDATION_EXTERN CFDictionaryRef DMKCopyLicenseUserInfo(void) CF_RETURNS_RETAINED;
​
//! Forces license validation request on DevMate server
#define DMKValidateLicense i2rRAQi8BfdE2G9geRSu
FOUNDATION_EXTERN void DMKValidateLicense(void (^completionHandler)(NSError *errorOrNil));
​
//! Deactivates application and invalidates license info
#define DMKInvalidateLicense kLLTbFMUP234v8xDp6Uck
FOUNDATION_EXTERN BOOL DMKInvalidateLicense(void);
​
/**
 This category will extend functionality of NSApplication to be complies with Kevlar concept of protection.
 Rigth now, some helper inteface have been declare there, because it is kind of complicated to load category.
 */
#define com_devmate_Kevlar YC2eXYjMnR
@interface NSApplication (com_devmate_Kevlar) 

发现好多混淆函数,简单看注释//! Checks if applicaion activated 理论上这个函数应该是我们要找的最关键函数。

  • 那么如何核实FOUNDATION_EXTERN BOOL DMKIsApplicationActivated(DMKevlarError *outKevlarError);就是我们要找的function呢?

现在手头上有下载好的DevMateKit的demo工程,那么直接run一个.app文件出来丢到Hopper分析对比就可以了

image

上图是run的CustomTrialExample这个target后的截图,此时记录下可疑函数的混淆标记为PfCuPgJSp5KVlvc8W1

随后把这个CustomTrialExample.app丢到Hopper一顿分析后直接搜索混淆标记PfCuPgJSp5KVlvc8W1

image

这下就基本上真相大白了,根据下图对比得知

image

也就是我们基本核实

FOUNDATION_EXTERN BOOL DMKIsApplicationActivated(DMKevlarError *outKevlarError)

就是函数_O7RH3WAr7wAQMdz5Xv上辈子的初始形态了。

5.2.2 _O7RH3WAr7wAQMdz5Xv重写

  • DMKIsApplicationActivated主要做了两个事

    • 完整函数返回了BOOL

    • 传入指针DMKevlarError *outKevlarError 内部可能做修改

  • 我们要重写成什么样子?

    • 鉴于此function是要返回个是否已激活/付费,那尝试下完整函数返回固定为0x1

    • 常规来说已激活/付费的用户调此function理论上不应该有error存在,也就是我们需要把传入指针对应的地址的内容变成0x0

那么改成下图的样子也就基本上没啥毛病了

image

转成伪代码一看就懂了

int _O7RH3WAr7wAQMdz5Xv(int arg0) {
    rdi = arg0;
    if (rdi != 0x0) {
            *rdi = 0x0;
    }
    return 0x1;
}

那么我们就把我们重写的目的都实现了,接下来就是见证奇迹的时刻了

5.2.3 检验复杂方案处理结果

重写 _O7RH3WAr7wAQMdz5Xv后和上文5.1.25.1.35.1.4做法一致,最后验证出来结果也是一样的可以保存成功!

总结

快捷键补充(windows/Mac)

hopper修改 alt+a / option+a

hopper保存 win+shift+e / cmd+shift+e

hopper寻址 g

hopper查引用 x

声明:此文仅用于学习用途,请勿用于非法用途。

转载请注明出处。谢谢!


逆向技术积累相关链接

破解<Cornerstone> by Chen华锋 //本人逆向编程的引路人


YY Flutter技术积累相关链接

flutter多实例实战 by共田君

一行代码教你解决FlutterPlatformViews内存泄露 by
AShawn

手把手教你在Flutter项目优雅的使用ORM数据库 by
williamwen1986

flutter通用基础库flutter_luakit_plugin by
williamwen1986

github - flutter_luakit_plugin使用例子 by
williamwen1986

手把手教你编译Flutter engine by 共田君

手把手教你解决 Flutter engine 内存泄漏 by 共田君

github - 编译产物下载 修复内存泄漏后的flutter engine(可直接使用)by 共田君

github demo - 修复内存泄漏后的flutter engine by 共田君

持续更新中...

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

推荐阅读更多精彩内容