標籤:逆向工程 iOS
教你如何動態調試 iOS App(反編譯App)開篇
通過本文你能瞭解 iOS 逆向的基本知識,對 iOS App 的安全有一定瞭解。然後能舉一反三,在自家 App 找到危險漏洞加以預防,保證使用者資料安全。
在安全領域,攻與防永遠存在。哪怕是 iPhone 有著強大的安全防護機制,也擋不住那些極客們一次又一次的好奇,開發了很多強大且便利的工具。本文就是在這些極客們提供的工具的基礎上完成的!
準備工具
- Mac 電腦和越獄 iPhone 手機
- 查看手機系統目錄工具 iFunbox 或 iTools
- 網路分析工具 Charles
- 反編譯工具 Hopper, IDA Pro
- 查看標頭檔工具 class-dump
- 砸殼工具 dumpdecrypted, Clutch
- 調試器 lldb 或 gdb
- 調試工具:Cycript
HTTP(S) 抓包HTTP 抓包第一步:擷取 MAC IP
按下Option鍵,同時點擊 Mac 功能表列上的無線網 Icon,能看到當前電腦的 IP 位址。
或在終端輸入 ifconfig en0 也可查看。
第二步:設定代理
保證手機和電腦在同一 WIFI 下,在手機上,點擊“設定->無線區域網路->串連的WiFi”,設定HTTP代理:
伺服器:為 Mac 電腦 IP 位址(如192.168.1.122)
連接埠:8888
第三步:抓包
在電腦端,開啟 Charles。使手機發生網路請求,Charles 會彈出一個詢問的對話方塊
點擊“Allow”允許,Charles 會出現手機的 HTTP 要求記錄列表。
HTTPS 抓包第一步: 擷取認證安裝地址
安裝 SSL 憑證到手機裝置。點擊 Help -> SSL Proxying -> Install Charles Root Certificate on a Mobile Device
出現彈窗得到地址 chls.pro/ssl
第二步:iPhone 安裝認證
在手機 Safari 瀏覽器輸入地址 chls.pro/ssl,出現認證安裝頁面,點擊安裝,手機設定有密碼的輸入密碼進行安裝
第三步:配置代理 host
Charles 設定 Proxy。選擇 Proxy -> SSL Proxying Settings...
勾選 Enable SSL Proxying,點擊 Add
Host 設定要抓取的 HTTPS 介面,Port 填寫 443。
讓手機重新發送 HTTPS 請求,可看到抓包。
<b> 注意:不抓包請關閉手機 HTTP 代理,否則斷開與電腦串連後會連不上網! </b>
拿到 .h 標頭檔
從 AppStore 直接下載的 ipa, 蘋果公司對其做了 FairPlay DRM 技術進行加密保護,無法直接使用 class-dump 工具擷取標頭檔。但是如果是通過 development 打包出來的話的 App 的話,是可以直接使用 class-dump 查看所有標頭檔的,此部分介紹就是通過此情況來說明如何擷取 .h 檔案的。
此處不再介紹 class-dump 工具的安裝過程,具體步驟請直接百度。
進入到 appName.ipa 所在目錄,修改副檔名為 .zip,然後解壓檔案,得到 appName.app。
然後執行:
class-dump -H appName.app -o ./headers/
命令執行完成後,會在目前的目錄下的 headers 目錄裡看到 app 所有標頭檔。
如果添加參數 -A -S 會在標頭檔裡標記處類方法和屬性的 IMP 地址(模組位移前基地址)。
class-dump -H -A -S appName.app -o ./headers/
SSH 訪問手機檔案目錄
在你的越獄手機上使用 Cydia 應用市場安裝 OpenSSH,並保證 Mac 和 iPhone 處於同一個WIFI下,在 MAC 終端輸入:
ssh [email protected] ,IP 替換為 iPhone 的 IP 位址
輸入預設密碼:alpine
即可進入 iPhone 終端。
使用 Clutch 反編譯 App第一步:重新簽名 debugserver
取得 debugserver 有兩種方式。
第一種是在 Mac 電腦中拿到
進入路徑 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/8.3/DeveloperDiskImage.dmg(其中路徑裡 8.3,代表 iOS 系統版本,需與準備的越獄手機系統版本保持一致)。雙擊 DeveloperDiskImage.dmg,將目錄裡的 usr/bin/debugserver 複製到指定檔案夾中。
第二種是在越獄手機裡拿到
如果手機串連過手機並通過 XCode 調試過 app,會在手機裡的 /Developer/usr/bin/ 目錄下產生一個 debugserver 檔案。通過 iFunbox 匯出至 Mac 案頭。或使用 scp 命令 cpoy 出來。
重簽名 debugserver
即給 debugserver 添加 task_for_pid 許可權
建立 entitlements.plist,添加如下四個 key:
com.apple.springboard.debugapplicationsget-task-allowtask_for_pid-allowrun-unsigned-code
key 對應的 value 都設為設為 ture
將 entitlements.plist 和 debugserver 放在同一個目錄下,執行以下命令:
codesign -s - --entitlements entitlements.plist -f debugserver
此命令會重新簽名 debugserver,將簽名後的 debugserver 拷貝至手機系統的 /usr/bin/ 目錄下。
<b>注意:不要將 debugserver 拷貝至 /Developer/usr/bin/ 路徑下</b>
第二步: 通過 Clutch 拿到反編譯後的 App 可執行檔
將下載好的 Clutch 放入手機的 /usr/bin/ 路徑下。然後,給 Clutch 賦予許可權,通過 SSH 登入到手機,進入 /usr/bin/ 執行 chmod a+x ./Clutch。
通過命令 Clutch -i,列出所有的可被 Clutch 的應用。
對指定序號的應用進行脫殼,如企業,序號是1,命令是 Clutch -d 1。執行完成後,會得到脫殼後的 ipa。
第三步:使用 class-dump 拿到 .h 標頭檔
使用上文 <b>【拿到.h標頭檔】</b> 介紹的方法拿到脫殼後的 App 標頭檔和並記下要打斷點的方法的 IMP 地址。
動態調試 App
本文動態調試用到的調試器是 lldb。
第一步:使 iPhone 進入等待掛載狀態
SSH 登入到手機,執行 ps -e 命令得到 App PID 或項目名稱。
進入 /usr/bin/ 執行 ./debugserver IP:port -a PID|appProjectName。 其中第一個參數 IP 可以替換為 Mac 電腦 IP地址,或者使用 * 萬用字元,允許所有 IP 調試;第二個參數 port 隨便寫一個就行。第四個參數 可以指定要調試 App 的 PID 或項目名稱。比如要調試的 PID 為 6019 的搜狗IME項目名稱為SogouInput,則命令即為:
./debugserver *:1234 -a 6019 或 ./debugserver *:1234 -a ‘SogouInput’
此命令執行完成後,app會進入等到掛載狀態,app會被卡住點擊無反應。正常現象!
如果此命令報錯,如出現 Segmentation fault: 11 等情況,說明 App 做了反動態調試保護。遇到此種情況,需先確定 App 採用了哪種保護方案,然後進一步找到對應措施,幹掉它的反動態調試保護。
第二步:監聽進程,進入掛載狀態
重新開啟一個 Mac 終端執行 lldb 進入 lldb 調試狀態。然後輸入
process connect connect://iPhoneIP:port
iPhoneIP 替換為 iPhone 的 IP 位址;port 改為剛才指定的連接埠,即 1234。
待命令執行完成後,App 即進入掛載狀態。
第三步:擷取 App 的 ASLR 位移量
ASLR位移量其實就是虛擬記憶體的地址相對於模組基地址的位移量。有兩個概念需要熟悉一下:
- 模組在記憶體中的起始地址 ---- 模組基地址
- ASLR位移 ---- 虛擬記憶體起始地址與模組基地址的位移量
在 lldb 調試器模式下,執行 imge list -o -f
模組位移後的基地址 = ASLR 位移量 + 模組位移前基地址(方法的 IMP 地址)
上面這個公式是尤為重要的,因為 Class-dump 中顯示的都是“模組位移前基地址”,而 lldb 要操作的都是“模組位移後的基地址”。所以從 Class-dump 到 lldb 要做一個地址位移量的轉換。
至此,已得到了 App 的 ASLR 位移量和方法的 IMP 地址。
第四步:打斷點,調試
在 lldb 模式下執行,br s -a ‘ASLR 位移量+ IMP‘,然後執行 c,使 App 跑起來,觸發一個方法調用,就會進入斷點模式。輸入 po $arg1 列印第一個參數。
然後,配合著抓包工具 Charles(比如分析網路請求加密邏輯) 和 Class-dump(比如修改某個類的方法傳回值)等工具,你就可以隨意動態調試 App 了,就像在 XCode 裡調試一樣!
<b>br 命令說明</b>
br dis 1 -- 禁用(disable)編號為1的斷點
br en 1 -- 啟用(enable)編號為1的斷點
br dis -- 禁用所有斷點
br en -- 啟用所有斷點
br del 1 -- 刪除(delete)編號為1的斷點
br del -- 刪除所有斷點
br list -- 列出所有斷點
使用 dumpdecrypted 破殼 App
dumpdecrypted 脫殼工具的原理是:將應用程式運行起來(iOS 系統會先解密程式再啟動),然後將記憶體中的解密結果 dump 寫入檔案中,得到一個新的可執行程式。
第一步:產生 .dylib 檔案
在終端進入到下載後的目錄中,cd dumpdecrypted-master,然後執行 make,即可產生 dumpdecrypted.dylib
第二步:找到 App 的 Documents 檔案夾路徑
通過 SSH 登入到 iPhone,然後執行 ps -e 查看進程,擷取要破殼的進程 PID。然後執行 cycript -p PID 附加到 PID 進程上。最後執行 [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask][0]得到 Documents 檔案夾路徑。
第三步:開始破殼
將第一步產生的 dumpdecrypted.dylib 拷貝到第二步得到的 .../Documents/ 路徑下,命令如下:
scp ~/dumpdecrypted.dylib [email protected]:/var/mobile/Containers/Data/Application/2B4C6281-C015-4FF3-A8EC-5E5C7554D447/Documents(將路徑裡的 UDID 替換為你的要破殼的 App 的 UDID)
進入 Documents 目錄下,執行DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/<br/>Application/BFED82A3-3238-4F41-B797-C1CB584CBE05/appProjectName.app/appProjectName(將路徑裡的 UDID 替換為你的要破殼的 App 的 UDID;將 appProjectName 替換為要破殼 App 的項目名稱)
待命令執行完,會在目前的目錄產生一個名為 appProject.decrypted 的檔案,這個就是破殼後的 App 可執行檔,要的就是它!使用 Class-dump 即可得到標頭檔。或使用 Hopper 或 IDA Pro 進行反編譯。
給你的 App 添加反動態調試機制ptrace
為了方便應用軟體的開發和調試,從Unix的早期版本開始就提供了一種對運行中的進程進行跟蹤和控制的手段,那就是系統調用 ptrace()。
通過 ptrace 可以對另一個進程實現調試跟蹤,同時 ptrace 還提供了一個非常有用的參數那就是 PT_DENY_ATTACH,這個參數用來告訴系統,阻止調試器依附。
所以最常用的反調試方案就是通過調用ptrace來實現反調試。
sysctl
當一個進程被調試的時候,該進程會有一個標記來標記自己正在被調試,所以可以通過 sysctl 去查看當前進程的資訊,看有沒有這個標記位即可檢查當前調試狀態。
檢測到調試器就退出,或者製造崩潰,或者隱藏工程,當然也可以定時去查看有沒有這個標記。
syscall
為從實現從使用者態切換到核心態,系統提供了一個系統調用函數 syscall,上面講到的 ptrace 也是通過系統調用去實現的。
在Kernel Syscalls27這裡可以找到 ptrace 對應的編號。
26. ptrace 801e812c T
所以如下的調用等同於調用 ptrace:
syscall(26,31,0,0,0);
<b> arm </b>
syscall 是通過非強制中斷來實現從使用者態到核心態,也可以通過彙編 svc 調用來實現。
覺得不錯的話,歡迎關注我的公眾號哦!
教你如何動態調試 iOS App(反編譯App)