復(fù)雜方案解決結(jié)果--->破解版?zhèn)魉烷T
前提準(zhǔn)備
-
Hopper Disassembler
(X,G,Esc,Space...,度娘/谷歌,后面簡稱Hopper
) Xcode
(App Store)frida
(前置條件配置好 python環(huán)境雇锡,下載好pip逛钻,隨后用pip下載,具體度娘/谷歌找攻略即可)匯編指令基礎(chǔ)掌握
(je,jne,jmp,jle,mov,call,ret,nop,xor,lea,rax,rdi,rsi,rcx....)lldb指令基礎(chǔ)掌握
(bt, image lookup --address ,p, c...)終端操作
(codesign *锰提,frida *)具備一定的編程思想
基礎(chǔ)逆向工程思維基礎(chǔ)掌握
(Executable,重簽,覆蓋entitlements)
小目標(biāo):學(xué)習(xí)下一些簡單匯編知識以及市面上的一些付費(fèi)App的付費(fèi)模塊的代碼思路然后順便逆向破解 PDF Expert
第一步
- 目的---體驗(yàn)原裝PDF Expert 修改任意pdf文件后保存查看效果
1.1體驗(yàn)未破解版流程
第二步
在保存操作前是沒有提示升級到完整版這個(gè)彈窗的曙痘,所以我們在Xcode attach成功后可以嘗試增加個(gè)符號斷點(diǎn)windowWillLoad查看調(diào)用棧的關(guān)系
- 目的---查看調(diào)用圖層間的調(diào)用關(guān)系,從而嘗試去定位到關(guān)鍵代碼欲账。
2.1 Xcode新建個(gè)工程
2.2 attach
查看對應(yīng)圖層關(guān)系
2.2.1 Attach App
image
2.2.2 Debug View Hierarchy
查看圖層關(guān)系 在增加符號斷點(diǎn)windowWillLoad
后在修改后的pdf界面觸發(fā)保存操作出現(xiàn)彈窗發(fā)現(xiàn)沒有停下斷點(diǎn)屡江,說明這條路行不通。
但是我們也獲取到了一個(gè)關(guān)鍵信息:最上面的控件名稱為 DMTrialController
赛不。
第三步
- 目的---使用
frida
通過已知彈出升級框的類DMTrialController
,查找出具體調(diào)用的方法堆棧
3.1 frida-trace 查看對應(yīng)方法調(diào)用關(guān)系
在終端上輸入 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輸出在點(diǎn)擊保存時(shí)觸發(fā)的方法為-[DMActivationController performActivationStepWithStep:0x66]
記錄下來回到第二步操作的2.4查看付費(fèi)彈窗堆棧信息罢洲。
3.2 增加符號斷點(diǎn)查看
再次保存操作后觸發(fā)斷點(diǎn)終端查看到嫌疑關(guān)鍵代碼如下
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調(diào)用時(shí)的地址信息
(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 直接拽
4.1.2 稍等一會(huì)Hopper
加載完成
4.1.3 追查付費(fèi)彈窗底細(xì)
加載完成后在界面左側(cè)輸入剛才Xcode Attach控件名 DMTrialController
分析搜索結(jié)果發(fā)現(xiàn)并沒有直接匹配的 DMTrialController
這玩意,猜想這個(gè)空間不是直接在主工程實(shí)現(xiàn)的惹苗,隨后看跟 DMTrialController
命名類似的DMTrialWelcomeStepController
看上圖可以找到文件路徑并且發(fā)現(xiàn)關(guān)鍵字DevMateKit
殿较,其實(shí)早在Xcode Attach時(shí)查看圖層就可以發(fā)現(xiàn) 這個(gè)付費(fèi)彈窗的命名前綴是DMT
而主工程的命名前綴是PDF_Expert
,很大概率付費(fèi)彈窗是用的第三方庫.
4.1.4 簡單了解DevmateKit
有哪些功能
這個(gè)就不在這介紹了,通過傳送門下載的demo大概了解到DevMateKit
是做一些付費(fèi)彈窗桩蓉,舉報(bào)彈窗淋纲,kevlar
代碼混淆。
4.2 逐個(gè)排查可疑地址
4.2.1 地址A:0x0000000000029a7c
Hopper 信息分析
image
根據(jù)Hopper
分析結(jié)果看出可疑地址A主要是在做一些繪制UI操作院究,我們主要目的是要改掉App中一個(gè)憑證字段信息類似 isActiva , isRegis 之類的字眼洽瞬。排除掉可疑地址A。
4.2.2 地址B:0x00000001003ff263
Hopper 信息分析
image
發(fā)現(xiàn)定位到的地址操作符是test业汰,這個(gè)有著重大嫌疑伙窃,大概率是此地址去做是否注冊判斷。我們繼續(xù)去排查可疑地址C样漆。
4.2.3 地址C:0x00000001003dbe37
Hopper 信息分析
由分析結(jié)果得知可疑地址C主要是做saveDocument:
操作,并且看上圖左邊紅色框可以得知這一頓操作沒有做一些test或者是cmp或者是提前ret之類的操作为障,基本也可以排除掉可疑地址C。
4.3 主要調(diào)查重點(diǎn)嫌疑地址
4.3.1 重新查看可疑地址B:0x00000001003ff263
的hopper數(shù)據(jù)放祟,切換至控制流圖(Control Flow Graph
)
備注:快捷鍵 Space
image
查看上圖分析一處邏輯判斷為 al
和 0x1
做test
運(yùn)算鳍怨,但是此處邏輯地址為loc_1003ff259
是由loc_1003ff11e
的尾部的je
跳轉(zhuǎn)過來的。
而je
的來源是上一層的al
和0x1
做test
運(yùn)算,再往上看可以知道al
是通過call sub_1003b21b0
的返回值賦值的跪妥。
4.3.2 解析第一層夢境function sub_1003b21b0
雙擊進(jìn)入 sub_1003b21b0
的function實(shí)現(xiàn)的控制流圖鞋喇。進(jìn)入目標(biāo)func的控制流圖后發(fā)現(xiàn)是個(gè)蠻龐大的函數(shù),縮放一下頁面看到整個(gè)流程圖如下
分析上圖控制流圖結(jié)構(gòu)骗奖,猜想如果是已購買用戶的判斷邏輯應(yīng)該是一條清晰的流程也就是右側(cè)箭頭所指的通道确徙。
接著著重看如何才可以走到陽光大道上
分析上圖控制流圖重點(diǎn)是通過cmp r13b, 0x3
后 je loc_1003b22cd
醒串,翻譯過來也就是判斷r13b
是不是0x3
如果是0x3
就去陽光大道,那么我們現(xiàn)在就想辦法把r13b
變成0x3
。
繼續(xù)往上看得知r13b
是eax
懟過來的鄙皇,而eax
是通過function sub_100382d70
返回的芜赌。
那么現(xiàn)在關(guān)鍵就是這個(gè)sub_100382d70
4.3.3 解析第二層夢境function sub_100382d70
雙擊進(jìn)入sub_100382d70
的function。
分析下第二層夢境的大概實(shí)現(xiàn)伴逸,首先第一眼嫌疑最大的是_O7RH3WAr7wAQMdz5Xv
這個(gè)是被call的function是被混淆過的缠沈,其次通過這個(gè)_O7RH3WAr7wAQMdz5Xv
返回的al
最后是跟0x1
做test
。
那么現(xiàn)在冷靜下思考有以下兩個(gè)解決思路
簡單方案-直接改
sub_100382d70
提前返回0x3
然后去走陽光大道(如果忘記了為何要返回0x3
,可以復(fù)習(xí)下4.3.2章節(jié))復(fù)雜方案-修改
_O7RH3WAr7wAQMdz5Xv
內(nèi)部實(shí)現(xiàn)错蝴,繼續(xù)深究洲愤,改最根部判斷。
第五步
- 目的---使用
Hooper
修改關(guān)鍵匯編運(yùn)算邏輯顷锰。
5.1 簡單方案解法嘗試
5.1.1 修改sub_100382d70
實(shí)現(xiàn)
根據(jù)上述操作我們得知sub_100382d70
做了一串操作柬赐,先push,后mov后push…官紫,我們現(xiàn)在其實(shí)只要返回個(gè)0x3
即可肛宋,那直接選中sub_100382d70
第一行修改,輸入mov rax,0x3
束世,點(diǎn)Assemble and Go Next
,再繼續(xù)輸入ret
,繼續(xù)Assemble and Go Next
酝陈。
修改后的結(jié)果如下,隨后保存新的Executable文件
5.1.2 保存Executable文件
保存Executable
文件時(shí)點(diǎn)Cancel
接下來就是驗(yàn)證簡單方案是否可行了毁涉,把剛生成的新Executable文件替換我們目標(biāo)App內(nèi)的舊Executable文件沉帮,具體操作如下
5.1.3 覆蓋entitlements文件
原版entitlements文件數(shù)據(jù)如下,隨后吧identifier對應(yīng)的那幾行干掉
<?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>
保存后覆蓋目標(biāo)App的entitlements文件
codesign -f -s - --entitlements entitlementsFilePathPrefix/Entitlements.plist appPathPrefix/PDF\ Expert.app
執(zhí)行完終端輸出提示/Applications/PDF Expert 3.app: replacing existing signature
即表示完成替換
5.1.4 檢驗(yàn)簡單方案處理結(jié)果
隨后重新打開目標(biāo)App贫堰,首先檢查當(dāng)前App的是否注冊狀態(tài)如下圖
隨后嘗試修改任意pdf文件保存穆壕,保存成功!
5.2 復(fù)雜方案解決嘗試
5.2.1 _O7RH3WAr7wAQMdz5Xv
的前世今生
早在上文4.1.4
簡單了解目標(biāo)App所用的到第三方庫kevlar
能支持代碼混淆严嗜,我們先簡單看看_O7RH3WAr7wAQMdz5Xv
的函數(shù)結(jié)構(gòu)大概如下
看不是很懂粱檀,我們切換至偽代碼視角看看
這里我們發(fā)現(xiàn)個(gè)關(guān)鍵字符串 kevlar
,那基本可以認(rèn)定此處的混淆代碼的出處是DevMateKit
了。
DevMateKit提供的demo工程我們搜索kevlar
繼續(xù)懟進(jìn)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)
發(fā)現(xiàn)好多混淆函數(shù)漫玄,簡單看注釋//! Checks if applicaion activated
理論上這個(gè)函數(shù)應(yīng)該是我們要找的最關(guān)鍵函數(shù)茄蚯。
- 那么如何核實(shí)
FOUNDATION_EXTERN BOOL DMKIsApplicationActivated(DMKevlarError *outKevlarError);
就是我們要找的function呢?
現(xiàn)在手頭上有下載好的DevMateKit
的demo工程睦优,那么直接run一個(gè).app
文件出來丟到Hopper
分析對比就可以了
上圖是run的CustomTrialExample這個(gè)target后的截圖渗常,此時(shí)記錄下可疑函數(shù)的混淆標(biāo)記為PfCuPgJSp5KVlvc8W1
隨后把這個(gè)CustomTrialExample.app
丟到Hopper
一頓分析后直接搜索混淆標(biāo)記PfCuPgJSp5KVlvc8W1
這下就基本上真相大白了,根據(jù)下圖對比得知
也就是我們基本核實(shí)
FOUNDATION_EXTERN BOOL DMKIsApplicationActivated(DMKevlarError *outKevlarError)
就是函數(shù)_O7RH3WAr7wAQMdz5Xv
上輩子的初始形態(tài)了汗盘。
5.2.2 _O7RH3WAr7wAQMdz5Xv
重寫
-
DMKIsApplicationActivated
主要做了兩個(gè)事完整函數(shù)返回了BOOL
傳入指針
DMKevlarError *outKevlarError
內(nèi)部可能做修改
-
我們要重寫成什么樣子皱碘?
鑒于此function是要返回個(gè)是否已激活/付費(fèi),那嘗試下完整函數(shù)返回固定為
0x1
常規(guī)來說已激活/付費(fèi)的用戶調(diào)此function理論上不應(yīng)該有error存在,也就是我們需要把傳入指針對應(yīng)的地址的內(nèi)容變成
0x0
那么改成下圖的樣子也就基本上沒啥毛病了
轉(zhuǎn)成偽代碼一看就懂了
int _O7RH3WAr7wAQMdz5Xv(int arg0) {
rdi = arg0;
if (rdi != 0x0) {
*rdi = 0x0;
}
return 0x1;
}
那么我們就把我們重寫的目的都實(shí)現(xiàn)了隐孽,接下來就是見證奇跡的時(shí)刻了
5.2.3 檢驗(yàn)復(fù)雜方案處理結(jié)果
重寫 _O7RH3WAr7wAQMdz5Xv
后和上文5.1.2
癌椿,5.1.3
健蕊,5.1.4
做法一致,最后驗(yàn)證出來結(jié)果也是一樣的可以保存成功踢俄!
總結(jié)
快捷鍵補(bǔ)充(windows/Mac)
hopper修改 alt+a / option+a
hopper保存 win+shift+e / cmd+shift+e
hopper尋址 g
hopper查引用 x
聲明:此文僅用于學(xué)習(xí)用途缩功,請勿用于非法用途。
轉(zhuǎn)載請注明出處都办。謝謝嫡锌!
逆向技術(shù)積累相關(guān)鏈接
破解<Cornerstone> by Chen華鋒 //本人逆向編程的引路人
YY Flutter技術(shù)積累相關(guān)鏈接
flutter多實(shí)例實(shí)戰(zhàn) by共田君
一行代碼教你解決FlutterPlatformViews內(nèi)存泄露 by
AShawn
手把手教你在Flutter項(xiàng)目優(yōu)雅的使用ORM數(shù)據(jù)庫 by
williamwen1986
flutter通用基礎(chǔ)庫flutter_luakit_plugin by
williamwen1986
github - flutter_luakit_plugin使用例子 by
williamwen1986
手把手教你解決 Flutter engine 內(nèi)存泄漏 by 共田君
github - 編譯產(chǎn)物下載 修復(fù)內(nèi)存泄漏后的flutter engine(可直接使用)by 共田君
github demo - 修復(fù)內(nèi)存泄漏后的flutter engine by 共田君
持續(xù)更新中...