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

目錄截圖.png Typora的自帶內容目錄截圖


前提準備

  • Hopper Disassembler(X,G,Esc,Space...,度娘/谷歌,後面簡稱Hopperpython

  • Xcode(App Store)git

  • frida(前置條件配置好 python環境,下載好pip,隨後用pip下載,具體度娘/谷歌找攻略便可)github

  • 彙編指令基礎掌握(je,jne,jmp,jle,mov,call,ret,nop,xor,lea,rax,rdi,rsi,rcx....)數據庫

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

  • 終端操做(codesign *,frida *)windows

  • 具有必定的編程思想sass

  • 基礎逆向工程思惟基礎掌握(Executable,重籤,覆蓋entitlements)bash

小目標:學習下一些簡單彙編知識以及市面上的一些付費App的付費模塊的代碼思路而後順便逆向破解 PDF Expertapp


複雜方案解決結果--->破解版傳送門

第一步

  • 目的---體驗原裝PDF Expert 修改任意pdf文件後保存查看效果

1.1體驗未破解版流程

image

第二步

在保存操做前是沒有提示升級到完整版這個彈窗的,因此咱們在Xcode attach成功後能夠嘗試增長個符號斷點windowWillLoad查看調用棧的關係ide

  • 目的---查看調用圖層間的調用關係,從而嘗試去定位到關鍵代碼。

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 共田君

持續更新中...

相關文章
相關標籤/搜索