本文是我個人在對逆向工程強烈的興趣驅使下,拜讀《iOS應用逆向工程》,所實現的一個好玩的功能,與大家分享,也是對自己學習的一個簡單總結。BTW iOS逆向論壇 iOSRe 是一個很好的iOS逆向交流社區。
所有文章中工具和代碼都托管到GitHub,歡迎訪問:項目地址:https://github.com/jackrex/FakeWeChatLoc
iOS系統越獄,其實說白了,和Android的Root類似,相當於對手機權限的提升,使得讓你可以操縱之前你操縱不了的事物。
由於Objective-C 是面向對象的高級語言,iOS 采用的文件格式 Mach-O 包含了很多metadata 信息可以讓我們使用 class-dump 還原其頭文件,這個為iOS 的逆向有了很好的開端。
MobileSubstrate 是一個能夠讓iOS 開發方便hook的一個framework,MobileSubstrate由如下三部分組成:
由此可見 有了MobileSubstrate 作為基石,加上逆向工程,我們幾乎可以完成我們想做的任何事情MobileSubstrate
1. MobileHooker 利用iOS Runtime 動態替換函數,轉發消息達到所謂的hook技術
2. MobileLoader 主要用來加載第三方動態庫 即是tweak/*.dylib
3. Safe Mode 安全模式,防止第三方插件的Crash對主體App造成的影響
這種基於Unix 衍生的操作系統一般目錄層級都有相通之初,不妨可以對比Android 以及 MacOS,會發現好多目錄名是一致的,我麼來挑一些簡單講解下:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
/bin binnary ,系統常用的基本二進制文件 例如 cd, ls, ps 等
/usr 包含大多用戶工具庫
/var variable 存放經常更改的東西,例如 logs,用戶數據,/var/mobile/Applications 是紡織AppStore 下載的 App
/Applications 存放所有系統App,以及從Cydia下載的App路徑
/Library 存放了系統App的數據,其中有一個/Library/MobileSubstrate 目錄,MobileSubstrate 是一個hook 功能開發平台,其中內容如下圖所示,我們所開發的插件都被放置到這個裡面
/Library/MobileSubstrate 裡面文件類型主要有 dylib,plist
dylib 是動態加載庫,就是tweak
plist 配合dylib 使用的filter 文件,指定注入目標,及hook的目標
/System 存放iOS 各種系統framework
/User 指向 /var/mobile 即是我們一般用戶的主目錄
iOS 安裝包格式
ipa 蘋果推出的iOS 專有安裝包,一般從AppStore下載的包格式,安裝路徑/var/mobile/Applications,長按可刪除 deb 是屬於Debain系(使用過debain linux 系統的都知道)特有的安裝包,iOS 系統起源於Unix,所以兼容deb安裝包,Cydia下載的App就是deb格式的,安裝路徑為到 /Applications ,長按不可刪除,必須使用root 權限的命令行或者Cydia移除 pxl (這種格式起源於Mac上的pkg,現在已經廢棄)iOS 安裝包對比
其實各大軟件包雖然格式不一樣,諸如 .apk, .ipa .deb .app 等等,其實實質都是一個zip 將二進制和資源文件合理的規劃羅列出來
Payload文件夾:裡面包含了app使用的圖片以及二進制文件等
iTunesArtwork:實際上是無後綴的png圖片,在iTunes等上顯示用
iTunesMetadata.plist記錄購買者的信息,軟件版本,售價等
com.apple.ZipMetadata.plist 是
Deb 結構其實是對Library Applications gzip 為 data.tar.gz裡面
control 文件放到 control.tar.gz 中
Deb 文件的安裝方式就例如把本身自己文件路徑完全拷貝到iOS 系統中
其他iOS程序類型 Dynamic Library在逆向工程中常見的 動態調試和靜態分析使用的工具:
- class-dump
class-dump 用來dump 出越獄後的App 所有頭文件的工具
IDA
IDA 是最好的反編譯工具,其實簡單的逆向只用IDA就可以完全搞定了
LLDB
動態調試的利器 配合 IDA 一動一靜
Reveal
一個方便UI調試定位的Debug的工具,我們可以快速的對應某個App界面對應的是某個類
iFunBox
方便的文件管理輔助軟件
OpenSSH
OpenSSH 可以讓你的電腦遠程登錄你的手機
Cycript
非常強大的工具,可以讓開發者在命令行下和應用交互,在運行時查看和修改應用
iFile
一個在手機方便管理文件系統的軟件,猶如iFunbox ,Android 的Re管理器,可以方便的修改文件 安裝Deb二進制文件
AppSync
同步App,讓安裝的Deb App icon 出現在桌面
根據上述所理解的情況,由於我們是想在微信中模擬定位,所以我們把微信作為我們的分析對象。
使用 class-dump 導出微信的頭文件, 雖然我們在class-dump 官網上看到 直接導出的方式 class-dump -H xxx -o output/ 但是我們直接解壓ipa 中的wechat 裡面 去dump 是不行,我們會發現在output 文件夾裡只有 CDStructures.h文件,而且是空的
這個原因是因為在上傳AppStore 之後,AppStore自動給所有的ipa 進行了加密處理,所以我們要dump之前需要對微信的二進制文件進行砸殼處理
我們需要一個dumpdecrypted.dylib 這樣一個工具對我們的App 砸殼
我們 先ssh 到我們的iOS手機上,我們把所有的程序都結束掉,單單開微信一個然後執行
ps -e //列出當前運行的進程
TODO
可以看到以/var/mobile/Containers/ 開頭列出的進程就是WeChat進程,我們知道所有App的的沙盒路徑在 /var/mobile/Containers/Bundle/Application/03B61840-2349-4559-B28E-0E2C6541F879/ 中,但是我們並不知道 03B61840-2349-4559-B28E-0E2C6541F879 到底是哪一個App ,如果我們去目錄中一個一個找的話,就太不容易了
這時候 cycript 就派上用處了,執行
cycript -p WeChat
cy# [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]
#"file:///var/mobile/Containers/Data/Application/D41C4343-63AA-4BFF-904B-2146128611EE/Documents/"
這樣我們就得到了微信Documents 目錄,接下來使用scp 或者 ifunbox 吧拷貝到微信的Documents目錄下 dumpdecrypted.dylib
開始砸殼
DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /path/to/executable
當前目錄下會生成WeChat.decrypted
這個就是砸過殼的WeChat,我們可以對它進行dump
執行
./class-dump -H WeChat.decrypted --arch armv7 -o output/
在當前目錄下生成一個Output文件夾裡面具有微信導出所有的頭文件,包括第三方sdk等,我們把這些所有頭文件放到一個空的Xcode 工程中方便查看。
我們根據直覺發現 Appdelegate 是微信的MircoMessengerAppDelegate,可以大概看到微信的項目結構等,其實逆向也是學習的一種方式
接著我們來想想我們要實現的功能,我們要改變我們的位置從而改變附近的人,我們大致可以猜想這個類應該交 Nearby Location 之類的,我們可以搜索對應的頭文件。
我們發現搜Nearby 之後有這麼多,到底哪一個是呢
其實我們除了排除法和一個一個推測之外,我們可以使用Reaveal 這個強大的工具幫我們定位
可以說class-dump 幫我們列出了整個header 文件,讓我們對項目的整體結構有了一個大概的認識,但是對應具體.m 中的實現方案是哪一種,對於我們來說還是黑盒。這個時候我們就需要使用IDA強大的工具 進行分析。
打開IDA,選擇new
我們把從Wechat.app 裡面的WeChat 二進制拿出來,拖到上面IDA中,
由於我使用的是itouch 5 cpu 架構是armv7 所有用第一個,如果用錯的話,則打斷點得到的offset 是錯誤的,從而不能正常的debg
處理完成後如下圖所示
其中我們可以輕易的看到 MicroMessengerAppDelegate 裡面具體方法的實現,按空格鍵展開到視圖模式
這裡我們就可以看到.m中的實現了
動態調試是我們沒有源碼的情況下,使用lldb 對代碼的位置設斷點進行調試,主要是算得相應代碼的執行地址,以及如何Debug 獲取我們想要的值。更具上述所說我們使用IDA的反編譯結果
iOS 開啟debugserver 監聽1234端口
debugserver *:1234 -a “WeChat”
Mac端運行lldb 和iOS server保持連接
運行 lldb
process connect connect://iOSIP:1234
offset 是 0xd000
獲取斷點地址
br s -a 0xd000+0x649D8 // 下斷點
開始調試
ni po 等調試命令
直接啟動一個App :debugserver -x backboard *:1234 /path/to/app/executable
libsubstrate.dylib
Tweak 在單詞中的意思是”微調”的意思,其實就是第三方動態鏈接庫dylib
Tweak 是基於MobileSubstrate 編寫的,可以在運行時更改hook的App
Theos 是一個越獄開發工具包,在《iOS應用逆向工程書中》也是介紹了這種方式,但是我個人更喜歡使用iOSOpenDev 的方式去創建項目(ps: 就和熟悉了git 命令行之後覺得用sourceTree 更直觀),所以這裡簡單提及一下,感覺iOSOpenDev 像是把命令行式的NIC模板變成了可視化的,其實差不多都沒有多難。
安裝完成後,創建新項目會在template 中iOS出現 iOSOpenDev
在這裡我們選擇Logos Tweak,創建完成如下
其中有一個fakeloc.xm 的文件,這個就是我們要進行代碼編寫的地方。打開fakeloc.xm文件我們可以看到裡面的代碼使用 logos 完成的,對於logos 這種新的一門語言,大家不用擔心,其基本的語法和Objc類似,有幾個特定的語法需要特別注意下:
Logos 基本語法 :
%hook 指定需要hook的類, 必須和 %end 結尾
%log 將函數信息寫入syslog 進行打印信息
%orig 執行被hook住的函數,只能在 %hook 具體方法內執行
fakeloc.xm 對應的是 fakeloc.mm
我們在上述
在build Settings 上可以看到,底下有一欄是User-Define,這裡是我們自定義的部分,在 iOSOpenDevDevice 的地方寫上我們iOS 設備的ip地址 (局域網地址 如 192.168.1.103),前提是iOS 設備安裝 OpenSSH
ssh 認證錯誤
iosod sshkey -h 192.168.1.109
最開始還以為創建越獄的App 都要用 Logos 語法去寫,嚇死寶寶了,其實iOS 越獄App的開發幾乎和正常App 一模一樣
首先我們還是創建一個工程,和普通創建工程一樣,也可以用CocoaPods來管理你對於的第三方庫
先創建一個新的項目和正常一樣,按照如下方法配置後更改Build Settings。
增加Run Script,把control 從copy bundle resources 移除
項目整體結構
Build for Profiling 執行程序
在生成了App 和 Tweak 之後,那我們App 中如何調用Tweak 呢?
答案是采用 dlopen
void *handle = dlopen(TWEAK_PATH, RTLD_LAZY); //TWEAK_PATH 是dylib 的地址
if (handle) {
NSLog(@"handle");
if (0 != dlclose(handle)) {
printf("dlclose failed! %s\n", dlerror());
}else {
}
} else {
NSLog(@"nohandle");
printf("dlopen failed! %s\n", dlerror());
}
然後動態的獲取對應的自定義類
Class TweakBridge = NSClassFromString(@”TweakBridge”);
這個問題最開始我也百思不得其解,最後采用了最穩定,最為簡單的方法實現,就是往同一個文件中讀寫數據,這個文件可以作為傳輸數據的媒介。
但是剛開始筆者把文件放到 /var/mobile/xxx.plist, tweak 總是讀取不到值,糾其原因是因為tweak 和我們的App 權限不一樣,所以需要找到一個可以公共寫的地方,這個地方是 /var/mobile/Library/Preferences/ 所以我們App 和 Tweak 信息交互采用一個寫,另一個讀的方式達到傳輸的目的,如果你有更好更直接的方法,可以提出來大家一起討論
所以最後的代碼是:
- (void)setLocWithLat:(double)lat andLng:(double)lng {
NSLog(@"set lat & lng is %f &&&& %f", lat, lng);
Class TweakBridge = NSClassFromString(@"TweakBridge");
void *handle = dlopen(TWEAK_PATH, RTLD_LAZY);
if (handle) {
NSLog(@"handle");
TweakBridge = NSClassFromString(@"TweakBridge");
NSDictionary *dict = @{@"lat":[NSNumber numberWithDouble:lat], @"long":[NSNumber numberWithDouble:lng]};
BOOL isSuccess = [dict writeToFile:LOCATION_PATH atomically:YES];
NSLog(@"isSuccess, %d", isSuccess);
CLLocation *location = [[TweakBridge shareInstance] getCoreLocation];
if (0 != dlclose(handle)) {
printf("dlclose failed! %s\n", dlerror());
}else {
}
} else {
NSLog(@"nohandle");
printf("dlopen failed! %s\n", dlerror());
}
}
那我們如何將我們的Tweak 和 我們的App 結合在一起,讓用戶安裝後就可以直接使用呢,鑒於我們上文說到的deb 格式,打包的方式和結構和zip 其實是一致的
iOS 系統可安裝的包格式和結構我們在上文已經闡述過,現在是如何生成Deb 包
我們分別取出 dylib 和 app 的生成的目錄
統一都放到一個單獨的Package 目錄下,最後的目錄結構如下圖
我們按照Deb 排布的目錄結構把所有的文件按照下圖層級排放,然後使用 dpkg-deb 方式進行打包,注意打包的時候deb 中最好不要有 .DS_Store 文件,我寫了如下的腳本去去除,同時生成Deb文件
#!/bin/bash
find ./Package -name ".DS_Store" -depth -exec rm {} \;
dpkg-deb -Zgzip -b Package fakeLoc.deb
生成的安裝包如下,然後我們scp 到設備中
我們使用iFunbox 把生成好的fakeLoc .deb 拖到根目錄下,然後在手機上打開iFile,點擊fakeLoc.deb 安裝程序,安裝完之後我們把AppSync 重新安裝一遍重啟手機,然後就能打開我們的App了,同時發現長按我們的App 和系統應用, Cydia 等一樣,是不可以卸載的,應
為我們是安裝到了/Applications 下面,卸載可以使用命令行刪除,或者使用Cydia。
安裝完成,之後重啟設備就行
打開App 讓我們輸入精度和緯度,然後執行,最後打開微信附近的人看看,是不是附近的人發生了改變,如果做的更好,精度緯度在地圖上選取,當讓我們的核心功能就講解到這裡為止了,我們簡單的測試結果如下:
我們可以在 地圖選址器 選擇不同的位置,進行測試
首先我們先輸入北京的坐標可以看到大部分人都是北京的
成功模擬了微信附近的人
這可不向發布到AppStore那樣,首先你需要一個托管源,如果不想自己搭建則可以采用
http://blog.csdn.net/jackrex/article/details/thebigboss.org/hosting-repository-cydia/submit-your-app
填寫相關信息,這些就不再敘述了。
如果你的App被拒,你就郵件和回郵件的人溝通(一般是管理員 optimo),對方挺Nice的,你只要按照他們說的要求改,堅持自己正確的原則,一般是沒有問題的~
本文拋磚引玉,希望你對iOS越獄有一個初步的理解,能夠完成自己的任意App,開發出更好玩的Tweak,比如微信搶紅包的插件是不是就看似也不難實現了呢,本示例工程都托管在Github上,其中fakeloc 是 dylib 即tweak TestFakeTweak是app 工程,HackAppTool 我們上述文章描述需要用的第三方工具
項目地址:https://github.com/jackrex/FakeWeChatLoc
重新安裝下AppSync 並重啟SpringBoard
iOS6 系統Crash
由於iOS7之後引入一些新的類庫等,在iOS6設備上的兼容性一般,所以在工程的framework 中把 require 改為 option
iOS 越獄後忘記了root 密碼
root密碼文件存放地方:/etc/master.passwd
用iFile的文本編輯功能打開master.passwd,更改之前記得權限
你會找到類似這樣的一行字符——root:UlD3amElwHEpc:0:0::0:0:System
UlD3amElwHEpc就是加密過的密碼
把它更替為ab3z4hnHA5WdU,這是對應的密碼就是abc123。
保存,重啟。
有了密碼abc123你就可以進一步修改成其它的密碼了