iOS小技能:iOS15崩潰排查技巧(symbolicatecrash符號化分析問題、導出和隱藏符號)

語言: CN / TW / HK

“我正在參加「掘金·啟航計劃」”

引言

預備知識:http://blog.csdn.net/z929118967/article/details/127726025

I 符號化的方法

  • 藉助第三方工具:bugly.qq.com 製作慢

    登錄http://bugly.qq.com/v2/crash-reporting 壓縮上傳符號表。 找到對應的記錄分析。

  • 利用Xcode自帶的symbolicatecrash 進行符號化

    1、export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer 2、symbolicatecrash appName.crash appName.app > appName.log ```objectivec devzkndeMacBook-Pro:LatestBuild devzkn$ /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash --dsym=/Users/devzkn/work/.git//LatestBuild/.dylib.dSYM /Users/devzkn/Desktop/SpringBoard-2018-03-12-162524.ips --output=/Users/devzkn/Desktop/kn.crash

```

1.1 通過命令行工具 symbolicatecrash 來手動符號化 crash log

Use Xcode'ssymbolicatecrash tool to symbolicate your crash report. This tool will search system symbols in the iOS DeviceSupportpath automatically.

objectivec export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer symbolicatecrash appName.crash appName.app > appName.log

具體的做法:

  • 查找symbolicatecrash 工具的目錄

```objectivec ➜ Debug-iphoneos cd /Applications/Xcode.app/Contents

➜ Contents find . -name 'symbolicatecrash'
./Developer/Platforms/MacOSX.platform/Developer/iOSSupport/Library/PrivateFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

./Developer/Platforms/WatchSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash

./Developer/Platforms/AppleTVSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash

./Developer/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash

./SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

```

  • 符號化: symbolicatecrash appName.crash appName.app > appName.log

/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash --dsym=/Users/mac/Desktop/aaa3ffdf-16ce-3065-bcba-293f7aee7c9b.dSYM /Users/mac/Desktop/crashlog-EEF95364-6768-44D3-B8DF-46EC13B0D245.txt --output=/Users/mac/Desktop/kn.crash

  • 符號化之前後的效果對比

在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述 在這裏插入圖片描述

1.2 通過 Xcode 進行符號化:

將 .crash 文件,.dSYM 和 .app 文件放到同一個目錄下,打開 Xcode 的 Window 菜單下的 organizer,再點擊 Device tab,最後選中左邊的 Device Logs。選擇 import 將 .crash 文件導入就可以看到 crash 的詳細 log 了。

1.3 遇到的常見問題

  • 手動解析iOS crash文件時候,會出現這個報錯

objectivec Error: "DEVELOPER_DIR" is not defined at /Applications/Xcode.app/Contents

解決方案 export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

1.4 iOS15崩潰排查技巧

symbolicatecrash符號化分析問題、導出和隱藏符號 http://blog.csdn.net/z929118967/article/details/104983425

iOS15符號化換新工具了, iOS 15 的crash 文件改了格式, 用 Xcode 13 的 symbolicatecrash 也無法解析了,可使用腳本將新格式轉換為之前的格式,再丟進去 symbolicate。

Mac OS 11.3+的系統用Console 打開也會自動轉換,或者用 Xcode 的 View Devide Logs 來先給開發這邊先查看

關注#公號:iOS逆向,回覆translation下載轉換腳本

python3 translation.py -i {input_sybolicated_json_file} -o {output_path}

II 、導出和隱藏符號

2.1 導出符號信息

  • 查看導出符號信息:nm -gm tmp_64.dylib

    (__DATA,__data) external (undefined) external CFDataCreate (from CoreFoundation) (undefined) external _CFNotificationCenterGetDarwinNotifyCenter (from CoreFoundation) (__TEXT,__text) external (undefined) external _IOObjectRelease (from IOKit) (undefined) external _IORegistryEntryCreateCFProperty (from IOKit) 000000010ffa3f97 (__DATA,__objc_data) external _OBJC_CLASS$BslyjNwZmPCJkVst 000000010ffa3f97 (__DATA,__objc_data) external _OBJC_CLASS$_ChiDDQmRSQpwQJgm

2.2 控制符號是否導出

static 參數修飾,不會導出符號信息

```objectivec static char _person_name[30] = {'\0'};

```

  • 在編譯參數中加入-exported_symbols_list export_list

  • 在編譯參數中指定-fvisibility=hidden,對指定符號增加visibility(“default”)來導出符號

```objectivec

define EXPORT attribute((visibility("default")))

```

III 根據 iOS 崩潰日誌獲取對應系統庫源碼

定位崩潰日誌對應的系統庫源碼找到CURRENT_PROJECT_VERSION

  • 根據系統版本號尋找
  • 根據系統編譯版本號尋找
    在這裏插入圖片描述

3.1 根據系統版本號 (OS Version)定位源碼

根據OS Version尋找CURRENT_PROJECT_VERSION

  • 崩潰日誌 ```bash Incident Identifier: 6156848E-344E-4D9E-84E0-87AFD0D0AE7B CrashReporter Key: 76f2fb60060d6a7f814973377cbdc866fffd521f Hardware Model: iPhone8,1 Process: TouchCanvas [1052] Path: /private/var/containers/Bundle/Application/51346174-37EF-4F60-B72D-8DE5F01035F5/TouchCanvas.app/TouchCanvas Identifier: com.example.apple-samplecode.TouchCanvas Version: 1 (3.0) Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.example.apple-samplecode.TouchCanvas [1806]

Date/Time: 2020-03-27 18:06:51.4969 -0700 Launch Time: 2020-03-27 18:06:31.7593 -0700 OS Version: iPhone OS 13.3.1 (17D50)

22 libdyld.dylib 0x00000001b6728360 start + 4

```

  • 依據 Xcode 發佈的歷史版本文案,推斷 iPhone OS V13.3.1 對應的 macOS 版本是10.15.2。因此去 http://opensource.apple.com/ 找到對應的版本 在這裏插入圖片描述

在這裏插入圖片描述

如果沒有找到對應的源碼文件,則嘗試查找上一個版本 - 根據二進制文件名:libdyld.dylib 推斷對應的PROJECT_NAME是dyld - 對照 macOS 10.15.2 ,可以推斷dyld的項目版本號CURRENT_PROJECT_VERSION是 733.8

在這裏插入圖片描述

  • 點擊右側下載按鈕,即下載源碼

在這裏插入圖片描述

缺點

1、 部分情況無法準確得知對應的macOS 系統版本號,CURRENT_PROJECT_VERSION 不夠精確。 2、 部分情況無法根據二進制文件反推出對應的 PROJECT_NAME 無法根據libsystem_asl.dylib找到與 system_asl 相關的源碼

3.2 根據系統編譯版本號定位源碼

根據OS Build Version 獲取 PROJECT_VERSION

  • 1、在 ~/Library/Developer/Xcode/iOS\ DeviceSupport目錄下查找到對應的二進制文件。

```bash ➜ ~ cd ~/Library/Developer/Xcode/iOS\ DeviceSupport ➜ iOS DeviceSupport find . -name libdyld.dylib

./14.0 (18A373)/Symbols/usr/lib/system/libdyld.dylib ./12.4.8 (16G201)/Symbols/usr/lib/system/libdyld.dylib

``` 如果本地沒有找到,可以去網絡搜索collected iOS-System-Symbols/blob

  • 2、接下來你可以使用 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool、file、及llvm-objdump -m 查看macho的對應的CURRENT_PROJECT_VERSION

例如使用 otool -l ./Symbols/usr/lib/system/libdyld.dylib,發現 14.0 (18A373)對應的libdyld.dylib的CURRENT_PROJECT_VERSION是828.4.0

```bash Load command 5 cmd LC_ID_DYLIB cmdsize 56 name /usr/lib/system/libdyld.dylib (offset 24) time stamp 2 Thu Jan 1 08:00:02 1970 current version 828.4.0 compatibility version 1.0.0

```

在這裏插入圖片描述

當然如果你習慣使用llvm-objdump ,也可以使用-m和-s 進行獲取CURRENT_PROJECT_VERSION信息

```bash llvm-objdump -s ./Symbols/usr/lib/system/libdyld.dylib | grep "Contents of section __const" -A 3 llvm-objdump -m --dylibs-used ./Symbols/usr/lib/system/libdyld.dylib

```

-m, -macho 使用Mach-O特定的目標文件解析器。使用-macho時,命令和其他選項的行為可能會有所不同。 -s 顯示文件中每個段的內容 - llvm-objdump.cpp

3.3 小結

| | 優點 | 缺點 | | :------------: | :----------------------: | :----------------------------------------------------------: | | 系統版本號 | 簡單,無需對應的符號文件 | 部分情況無法準確得知對應的macOS 系統版本號,部分情況無法根據二進制文件反推出對應的 PROJECT_NAME | | 系統編譯版本號 | | 需要下載對應的符號文件(通常在1G以上) |

IV dSYM的其他應用場景

場景:用户在機器1上用 Xcode 將 App 工程(存放於本機文件路徑1)佈署到 iPhone 上,然後在機器2上用 Xcode 打開文件路徑2的工程,然後 Attach 到 iPhone 上的 App 進程,這時 Xcode 因為找不到文件路徑1所以無法顯示源代碼,這時 Xcode 只能展示彙編代碼

4.1 Xcode調試非本機構建的程序

  • 在 lldb 中增加符號文件路徑: (lldb) target symbols add /Users/mac/Downloads/testApp.dSYM

  • 在 lldb 中設置機器1上的文件路徑1與機器2上的文件路徑2的映射關係:

```objectivec / 設置源機器與當前機器上源文件路徑的映射關係 / (lldb) settings set target.source-map "機器1上的文件路徑1" "機器2上的文件路徑2"

/ 添加映射關係 / (lldb) settings append target.source-map "機器1上的文件路徑1" "機器2上的文件路徑2"

/ 顯示已配置的映射關係 / (lldb) settings show target.source-map

```

機器1上的文件路徑1和機器2上的文件路徑2應該包含相同版本的源文件,否則調試時會顯示異常

see also

查看模塊偏移後的基地址 ```bash (lldb) image list -o -f

[ 0] 0x0000000000eb8000 /Users/mac/Library/Developer/Xcode/DerivedData/Housekeeper-fzqstvcmffmiksaunlmbvfhyqpei/Build/Products/Debug-iphoneos/Housekeeper.app/Housekeeper

```

ASLR偏移 ---- 虛擬內存起始地址與模塊基地址的偏移量

| 選項 | 説明 | | :----------------------------------- | :----------------------------------------------------------- | | -arch= | 指定體系架構給反彙編器,使用-version命令查看可用的體系架構 | | -cfg | 為目標文件中的每個符號創建一個CFG,並將其寫入graphviz文件(僅限Mach-O)。 | | -dsym= | 使用.dSYM文件獲取調試信息。 | | -g | 如果可用,從調試信息中打印行信息。 | | -m, -macho | 使用Mach-O特定的目標文件解析器。使用-macho時,命令和其他選項的行為可能會有所不同。 | | -mattr= | 定位特定屬性。 | | -mc-x86-disable-arith-relaxation | 禁用X86的算術指令放寬 | | -stats | 啟用程序的統計輸出 | | -triple= | 目標三重拆解,使用-version命令查看可用目標。 | | -x86-asm-syntax=