1. 程式人生 > >教你如何動態調試 iOS App(反編譯App)

教你如何動態調試 iOS App(反編譯App)

逆向工程 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 root@IP ,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.debugapplications

get-task-allow

task_for_pid-allow

run-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 的搜狗輸入法項目名稱為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 root@IP:/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)