需求
做一個自定命令行, 能夠打印Mach-O文件的架構
1. main 函數處理
1.1 通過Xcode創建一個Single View App 項目
int main(int argc, char * argv[]) {
@autoreleasepool {
// printf("%s\n", argv[0]);
// 查看參數個數
if (argc == 1) {
printf("-l 查看 Mach-O 信息\n");
return 0;
}
// 比較參數的值
if (strcmp(argv[1], "-l") != 0) {
printf("-l 查看 Mach-O 信息\n");
return 0;
}
// Mach-O路徑
NSString *machOPath = @"/private/var/containers/Bundle/Application/2036E1A7-46E6-4205-BD0A-9A305598315A/Fission.app/Fission";
// 1. 創建文件句柄
// 文件句柄是一個字節一個字節地讀取, 不需要把整個文件都加載到內存中, 節省內存
NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:machOPath];
NSLog(@"%@", handle);
// 2. 處理文件內容
// ...
// 3. 關閉文件
[handle closeFile];
return 0;
}
}
1.2 編譯命令行
- 選擇真機設備編譯
- 運行環境選擇release
1.3 編譯, 找到命令行
1.4 測試命令行
- 將可執行文件
TestCL
導入手機路徑/usr/bin/
下 注意
: 如果存在TestCL
文件, 1. 先刪除 2. 再導入, 不要直接拖進去替換
- 直接使用會報權限問題
- 給文件添加執行權限
chmod +x /usr/bin/TestCL
- 測試成功
2. 讀取魔數(magic number)
2.1 magic number
: 魔數, 用來標識架構類型
2.2 查看可執行文件的魔數
- 通過MachOView查看
3. 通過內核源碼比對魔數的值
-
下載最新的就可以了
-
文件路徑: xnu-xxx -> EXTERNAL_HEADERS -> mach-o -> fat.h 和 loader.h
-
爲啥有兩個值? 大小端問題
-
魔數對應代碼
// 字節長度
/**
按照posix標準,一般整形對應的*_t類型爲:
1字節 uint8_t
2字節 uint16_t
4字節 uint32_t
8字節 uint64_t
*/
int length = sizeof(uint32_t);
// 讀出最前面的4個字節(magic number)
NSData *magicData = [handle readDataOfLength:length];
// magic number : 魔數, 用來標識架構類型
uint32_t magicNumber;
[magicData getBytes:&magicNumber length:length];
// 輸出架構類型
if (magicNumber == FAT_CIGAM || magicNumber == FAT_MAGIC) {
printf("FAT文件\n");
} else if (magicNumber == MH_CIGAM_64 || magicNumber == MH_MAGIC_64) {
printf("arm_64文件\n");
} else if (magicNumber == MH_MAGIC || magicNumber == MH_CIGAM) {
printf("非arm_64文件\n");
} else {
printf("讀取失敗\n");
}
4. 給TestCL文件添加SpringBoard權限
4.1 權限相關的問題
- 爲啥添加SpringBoard的權限,因爲它的權限非常高, 可以任意訪問其他App的文檔路徑
- SpringBoard的路徑:
- 蘋果的權限文件大多以
.entitlements
結尾
.entitlements == .xml == .plist文件
4.2 導出Mach-O文件的權限
// -e : export 導出
// > : 覆蓋
// >> : 追加
ldid -e 可執行文件 > 可執行文件.entitlements
4.3 給可執行文件重新簽上權限
// 注意: -S和可執行文件的權限文件要緊跟着,沒有空格
ldid -S可執行文件權限文件 可執行文件
5. 報錯總結
5.1 Bad CPU type in executable
- 沒有選擇真機編譯
5.2 Killed: 9
- 原因1 : 沒有選擇發佈版本(release), 而選擇了測試版本(debug)
- 原因2 : 將TestCL文件導入手機時, 直接拖進去替換了原來的TestCL文件
5.3 -sh: /usr/bin/ TestCL: Permission denied
- 沒有執行權限, 添加即可
chmod +x /usr/bin/TestCL