'iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制'

Android iOS Mac App Store Xcode iPhone 軟件 騰訊QQ 圖靈教育 2019-08-12
"
"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-2 使用Xcode 9 註冊設備

正是App Store 嚴格的審核以及應用安裝源的限制,比較有效地控制了惡意程序的傳播。

沙盒

沙盒(sandbox)是iOS 的一個防禦機制,每個應用都會有一個自己的沙盒。應用只能在自己的沙盒目錄下讀寫數據,應用A 不能訪問應用B 的沙盒,它們之間是互相隔離的。正因如此,攻擊者上傳惡意程序後,即使僥倖通過了App Store 的審核,被安裝到用戶的手機之後也不能獲取其他應用的數據。獲取沙盒目錄的方法如下:

-(void)getPath{
//獲取沙盒根目錄路徑
NSString*homeDir = NSHomeDirectory();
NSLog(@"homedir: %@",homeDir);
//獲取Documents 目錄路徑
NSString*docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"docDir: %@",docDir);
//獲取Library 目錄路徑
NSString*libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)
lastObject];
NSLog(@"libDir: %@",libDir);
//獲取cache 目錄路徑
NSString*cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"cachesDir: %@",cachesDir);
//獲取tmp 目錄路徑
NSString*tmpDir =NSTemporaryDirectory();
NSLog(@"tmpDir: %@",tmpDir);
//獲取應用的自身xx.app 目錄
NSBundle *bundle = [NSBundle mainBundle];
NSString *strAppPath = [bundle bundlePath];
NSLog(@"appDir: %@",strAppPath);
}

輸出的結果如下:

homedir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD
docDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Documents
libDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library
cachesDir:
/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library/Caches
tmpDir:
/private/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/tmp/
appDir:
/private/var/mobile/Containers/Bundle/Application/A5E6DC61-7AAA-467F-BC63-5BEDB8DDB113/
testSandbox.app

沙盒機制限制了應用只能讀寫沙盒之內的文件,而我們在有些情況下需要訪問一些公共資源(如通訊錄、短信、照片和位置等),這些是存在沙盒之外的。蘋果提供了公開的API 去訪問公共資源,不過都會彈出申請權限提示框,用戶必須允許才能操作成功,比如微信訪問照片提示需要用戶授權,如圖1-3 所示。

代碼簽名

代碼簽名(code signing)是iOS 一個重要的安全機制,所有的二進制文件都必須經過簽名才能被執行。在內存中,只有簽名來源為自己的頁才會被執行,這樣應用就不能自我升級或者動態改變行為。我們可以使用codesign 命令來驗證應用的簽名信息是否被破壞。輸入下面的命令後,如果沒有輸出信息,就表示簽名信息沒有被破壞:

codesign --verify testSandbox.app/

此外,使用下面的命令還可以查看簽名的相關信息:

$ codesign -vv -d testSandbox.app/
Executable=/Users/exchen/Library/Developer/Xcode/DerivedData/testSandbox-fzalslvcpprgiodycqxzblqeztql/
Build/Products/Debug-iphoneos/testSandbox.app/testSandbox
Identifier=net.exchen.testSandbox
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=694 flags=0x0(none) hashes=14+5 location=embedded
Signature size=4701
Authority=iPhone Developer: [email protected] (248BRN4CNL)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2018 年4 月8 日 01:27:40
Info.plist entries=26
TeamIdentifier=QQ4RE63T4U
Sealed Resources version=2 rules=13 files=7
Internal requirements count=1 size=188

用戶權限隔離

iOS 使用了用戶權限進行隔離。系統中的瀏覽器、電話、短信以及從App Store 上下載的應用,這些都以mobile 用戶權限運行,只有重要的系統進程才以root 用戶權限運行。這樣一來,即使惡意軟件安裝成功,也會由於存在權限限制,而使攻擊的可能性變小。我們打開“電話”應用(MobilePhone),通過ps 命令查看相關的進程信息,可以看到它是以mobile 的身份運行的:

iPhone:~ root# ps aux | grep MobilePhone
mobile 23754 0.0 0.9 661736 9152 ?? Ss 1:00AM 0:01.31 /Applications/MobilePhone.app/MobilePhone
root 23774 0.0 0.1 537356 572 s001 S+ 1:00AM 0:00.01 grep MobilePhone

再打開“短信”應用(MobileSMS),同樣通過ps 命令查看相關的進程信息,會發現它也是以mobile 用戶的身份運行的:

iPhone:~ root# ps aux | grep MobileSMS
mobile 23764 0.1 1.2 659024 12384 ?? Rs 1:00AM 0:01.82 /Applications/MobileSMS.app/MobileSMS
root 23776 0.0 0.1 537356 572 s001 S+ 1:01AM 0:00.01 grep MobileSMS

數據執行保護

iOS 中存在數據執行保護(Data Execution Prevention,DEP)機制,這一機制能夠區分內存中哪些是可執行的代碼,哪些是數據。該機制不允許執行數據,只允許執行代碼。在默認情況下,數據段的屬性是可讀、可寫、不可執行的,如果我們通過vm_protect 函數把數據段的屬性修改為可讀、可寫、可執行,就會打印錯誤信息。代碼如下:

unsigned int data = 0x12345678;
struct mach_header* image_addr = _dyld_get_image_header(0); //獲取鏡像地址
vm_address_t offset = image_addr + (int)0x8000; //數據段的偏移
kern_return_t err;
mach_port_t port = mach_task_self();
err = vm_protect(port, (vm_address_t) offset, sizeof(data), NO,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS) {
NSLog(@"prot error: %s \\n", mach_error_string(err));
return;
}
vm_write(port, (vm_address_t) offset, (vm_address_t) & data, sizeof(data));

運行之後打印的錯誤信息為:

2018-04-08 23:59:01.680009 vm_write[6222:265002] prot error: (os/kern) protection failure

地址隨機化

地址空間佈局隨機化(Address Space Layout Randomization,ASLR)能夠讓二進制文件、動態庫文件、代碼段以及數據段的內存地址在每次加載的時候都是隨機的。使用_dyld_get_image_vmaddr_slide 函數可以獲取模塊的ASLR 偏移地址,使用_dyld_get_image_header 函數可以獲取模塊的基址。我們編寫如下代碼:

//獲取第一個模塊的基址
intptr_t slide_addr = _dyld_get_image_vmaddr_slide(0);
struct mach_header *mh_addr = _dyld_get_image_header(0);
printf("slide_addr: 0x%x\\n", slide_addr);
printf("mh_addr: 0x%x\\n",mh_addr);

可以發現,第一次運行時,ASLR 偏移地址是0x94000,基址是0x100094000。這也可以通過LLDB(Low Level Debugger,詳見2.5 節)查看:

mh_addr: 0x100094000
(lldb) image list -o -f
[ 0] 0x0000000000094000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x0000000100094000)

我們退出程序再次運行,ASLR 偏移地址是0xe8000,基址是0x1000e8000。可以看出,程序每次運行,偏移地址和基址都是隨機的,一般都不會和上次一樣:

slide_addr: 0xe8000
mh_addr: 0x1000e8000
(lldb) image list -o -f
[ 0] 0x00000000000e8000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x00000001000e8000)

每次重啟手機之後,在內核中模塊的基地址也是隨機的。

後臺程序

Android 應用能夠在後臺創建執行代碼的服務,這些服務可能會偷偷下載文件消耗流量,造成扣費的情況。iOS 應用不能在後臺執行代碼,只要用戶點擊Home 鍵,前臺應用的所有線程都會被掛起,只有播放音樂、獲取實時位置等必須在後臺執行的操作才能執行。不過在iOS 中,也是有後臺程序的,被稱為daemon(守護程序)。比如在打開Safari(瀏覽器)上網時,突然有電話打進來,接聽電話的界面就會顯示在前臺,如果沒有後臺程序,怎麼處理來電呢?只是蘋果並沒有給開發者開放後臺程序,只有越獄之後,才能編寫後臺程序。

iOS 的系統進程launchd 會在系統啟動後檢測/System/Library/LaunchDaemons 和/Library/LaunchDaemons 這兩個目錄中的.plist 文件,而.plist 文件描述了daemon 程序的路徑。

下面我們寫一個daemon 程序進行測試,程序的名稱叫作daemonTest,其功能是每隔5 秒輸出一條信息,具體代碼如下:

#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}

編譯:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

簽名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

簽名需要用到的ent.plist 文件的內容請參考2.5.1 節。然後我們編寫用於描述daemonTest的.plist 文件,文件名稱為net.exchen.daemonTest.plist,具體內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>

將daemonTest 上傳到/usr/bin 目錄,再將net.exchen.daemonTest.plist 文件上傳到/Library/LaunchDaemons/目錄,接著設置相應的權限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用launchctl load 命令啟動daemon:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我們打開控制檯查看日誌,就可以看到每隔5 秒會輸出一條信息,並且在鎖屏狀態下代碼也能執行,是真正的後臺程序,如圖1-4 所示。

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-2 使用Xcode 9 註冊設備

正是App Store 嚴格的審核以及應用安裝源的限制,比較有效地控制了惡意程序的傳播。

沙盒

沙盒(sandbox)是iOS 的一個防禦機制,每個應用都會有一個自己的沙盒。應用只能在自己的沙盒目錄下讀寫數據,應用A 不能訪問應用B 的沙盒,它們之間是互相隔離的。正因如此,攻擊者上傳惡意程序後,即使僥倖通過了App Store 的審核,被安裝到用戶的手機之後也不能獲取其他應用的數據。獲取沙盒目錄的方法如下:

-(void)getPath{
//獲取沙盒根目錄路徑
NSString*homeDir = NSHomeDirectory();
NSLog(@"homedir: %@",homeDir);
//獲取Documents 目錄路徑
NSString*docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"docDir: %@",docDir);
//獲取Library 目錄路徑
NSString*libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)
lastObject];
NSLog(@"libDir: %@",libDir);
//獲取cache 目錄路徑
NSString*cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"cachesDir: %@",cachesDir);
//獲取tmp 目錄路徑
NSString*tmpDir =NSTemporaryDirectory();
NSLog(@"tmpDir: %@",tmpDir);
//獲取應用的自身xx.app 目錄
NSBundle *bundle = [NSBundle mainBundle];
NSString *strAppPath = [bundle bundlePath];
NSLog(@"appDir: %@",strAppPath);
}

輸出的結果如下:

homedir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD
docDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Documents
libDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library
cachesDir:
/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library/Caches
tmpDir:
/private/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/tmp/
appDir:
/private/var/mobile/Containers/Bundle/Application/A5E6DC61-7AAA-467F-BC63-5BEDB8DDB113/
testSandbox.app

沙盒機制限制了應用只能讀寫沙盒之內的文件,而我們在有些情況下需要訪問一些公共資源(如通訊錄、短信、照片和位置等),這些是存在沙盒之外的。蘋果提供了公開的API 去訪問公共資源,不過都會彈出申請權限提示框,用戶必須允許才能操作成功,比如微信訪問照片提示需要用戶授權,如圖1-3 所示。

代碼簽名

代碼簽名(code signing)是iOS 一個重要的安全機制,所有的二進制文件都必須經過簽名才能被執行。在內存中,只有簽名來源為自己的頁才會被執行,這樣應用就不能自我升級或者動態改變行為。我們可以使用codesign 命令來驗證應用的簽名信息是否被破壞。輸入下面的命令後,如果沒有輸出信息,就表示簽名信息沒有被破壞:

codesign --verify testSandbox.app/

此外,使用下面的命令還可以查看簽名的相關信息:

$ codesign -vv -d testSandbox.app/
Executable=/Users/exchen/Library/Developer/Xcode/DerivedData/testSandbox-fzalslvcpprgiodycqxzblqeztql/
Build/Products/Debug-iphoneos/testSandbox.app/testSandbox
Identifier=net.exchen.testSandbox
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=694 flags=0x0(none) hashes=14+5 location=embedded
Signature size=4701
Authority=iPhone Developer: [email protected] (248BRN4CNL)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2018 年4 月8 日 01:27:40
Info.plist entries=26
TeamIdentifier=QQ4RE63T4U
Sealed Resources version=2 rules=13 files=7
Internal requirements count=1 size=188

用戶權限隔離

iOS 使用了用戶權限進行隔離。系統中的瀏覽器、電話、短信以及從App Store 上下載的應用,這些都以mobile 用戶權限運行,只有重要的系統進程才以root 用戶權限運行。這樣一來,即使惡意軟件安裝成功,也會由於存在權限限制,而使攻擊的可能性變小。我們打開“電話”應用(MobilePhone),通過ps 命令查看相關的進程信息,可以看到它是以mobile 的身份運行的:

iPhone:~ root# ps aux | grep MobilePhone
mobile 23754 0.0 0.9 661736 9152 ?? Ss 1:00AM 0:01.31 /Applications/MobilePhone.app/MobilePhone
root 23774 0.0 0.1 537356 572 s001 S+ 1:00AM 0:00.01 grep MobilePhone

再打開“短信”應用(MobileSMS),同樣通過ps 命令查看相關的進程信息,會發現它也是以mobile 用戶的身份運行的:

iPhone:~ root# ps aux | grep MobileSMS
mobile 23764 0.1 1.2 659024 12384 ?? Rs 1:00AM 0:01.82 /Applications/MobileSMS.app/MobileSMS
root 23776 0.0 0.1 537356 572 s001 S+ 1:01AM 0:00.01 grep MobileSMS

數據執行保護

iOS 中存在數據執行保護(Data Execution Prevention,DEP)機制,這一機制能夠區分內存中哪些是可執行的代碼,哪些是數據。該機制不允許執行數據,只允許執行代碼。在默認情況下,數據段的屬性是可讀、可寫、不可執行的,如果我們通過vm_protect 函數把數據段的屬性修改為可讀、可寫、可執行,就會打印錯誤信息。代碼如下:

unsigned int data = 0x12345678;
struct mach_header* image_addr = _dyld_get_image_header(0); //獲取鏡像地址
vm_address_t offset = image_addr + (int)0x8000; //數據段的偏移
kern_return_t err;
mach_port_t port = mach_task_self();
err = vm_protect(port, (vm_address_t) offset, sizeof(data), NO,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS) {
NSLog(@"prot error: %s \\n", mach_error_string(err));
return;
}
vm_write(port, (vm_address_t) offset, (vm_address_t) & data, sizeof(data));

運行之後打印的錯誤信息為:

2018-04-08 23:59:01.680009 vm_write[6222:265002] prot error: (os/kern) protection failure

地址隨機化

地址空間佈局隨機化(Address Space Layout Randomization,ASLR)能夠讓二進制文件、動態庫文件、代碼段以及數據段的內存地址在每次加載的時候都是隨機的。使用_dyld_get_image_vmaddr_slide 函數可以獲取模塊的ASLR 偏移地址,使用_dyld_get_image_header 函數可以獲取模塊的基址。我們編寫如下代碼:

//獲取第一個模塊的基址
intptr_t slide_addr = _dyld_get_image_vmaddr_slide(0);
struct mach_header *mh_addr = _dyld_get_image_header(0);
printf("slide_addr: 0x%x\\n", slide_addr);
printf("mh_addr: 0x%x\\n",mh_addr);

可以發現,第一次運行時,ASLR 偏移地址是0x94000,基址是0x100094000。這也可以通過LLDB(Low Level Debugger,詳見2.5 節)查看:

mh_addr: 0x100094000
(lldb) image list -o -f
[ 0] 0x0000000000094000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x0000000100094000)

我們退出程序再次運行,ASLR 偏移地址是0xe8000,基址是0x1000e8000。可以看出,程序每次運行,偏移地址和基址都是隨機的,一般都不會和上次一樣:

slide_addr: 0xe8000
mh_addr: 0x1000e8000
(lldb) image list -o -f
[ 0] 0x00000000000e8000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x00000001000e8000)

每次重啟手機之後,在內核中模塊的基地址也是隨機的。

後臺程序

Android 應用能夠在後臺創建執行代碼的服務,這些服務可能會偷偷下載文件消耗流量,造成扣費的情況。iOS 應用不能在後臺執行代碼,只要用戶點擊Home 鍵,前臺應用的所有線程都會被掛起,只有播放音樂、獲取實時位置等必須在後臺執行的操作才能執行。不過在iOS 中,也是有後臺程序的,被稱為daemon(守護程序)。比如在打開Safari(瀏覽器)上網時,突然有電話打進來,接聽電話的界面就會顯示在前臺,如果沒有後臺程序,怎麼處理來電呢?只是蘋果並沒有給開發者開放後臺程序,只有越獄之後,才能編寫後臺程序。

iOS 的系統進程launchd 會在系統啟動後檢測/System/Library/LaunchDaemons 和/Library/LaunchDaemons 這兩個目錄中的.plist 文件,而.plist 文件描述了daemon 程序的路徑。

下面我們寫一個daemon 程序進行測試,程序的名稱叫作daemonTest,其功能是每隔5 秒輸出一條信息,具體代碼如下:

#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}

編譯:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

簽名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

簽名需要用到的ent.plist 文件的內容請參考2.5.1 節。然後我們編寫用於描述daemonTest的.plist 文件,文件名稱為net.exchen.daemonTest.plist,具體內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>

將daemonTest 上傳到/usr/bin 目錄,再將net.exchen.daemonTest.plist 文件上傳到/Library/LaunchDaemons/目錄,接著設置相應的權限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用launchctl load 命令啟動daemon:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我們打開控制檯查看日誌,就可以看到每隔5 秒會輸出一條信息,並且在鎖屏狀態下代碼也能執行,是真正的後臺程序,如圖1-4 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-4 每隔5 秒輸出信息

使用launchctl unload 命令可以停止daemon:

launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist

——

如果你也對iOS安全感興趣,下面這本“祕籍”一定會幫到你,《黑客防線》技術月刊原總編輯孫彬評價說,這是一本“拿到就能上手找飯吃”的iOS安全技術書。

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-2 使用Xcode 9 註冊設備

正是App Store 嚴格的審核以及應用安裝源的限制,比較有效地控制了惡意程序的傳播。

沙盒

沙盒(sandbox)是iOS 的一個防禦機制,每個應用都會有一個自己的沙盒。應用只能在自己的沙盒目錄下讀寫數據,應用A 不能訪問應用B 的沙盒,它們之間是互相隔離的。正因如此,攻擊者上傳惡意程序後,即使僥倖通過了App Store 的審核,被安裝到用戶的手機之後也不能獲取其他應用的數據。獲取沙盒目錄的方法如下:

-(void)getPath{
//獲取沙盒根目錄路徑
NSString*homeDir = NSHomeDirectory();
NSLog(@"homedir: %@",homeDir);
//獲取Documents 目錄路徑
NSString*docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"docDir: %@",docDir);
//獲取Library 目錄路徑
NSString*libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)
lastObject];
NSLog(@"libDir: %@",libDir);
//獲取cache 目錄路徑
NSString*cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"cachesDir: %@",cachesDir);
//獲取tmp 目錄路徑
NSString*tmpDir =NSTemporaryDirectory();
NSLog(@"tmpDir: %@",tmpDir);
//獲取應用的自身xx.app 目錄
NSBundle *bundle = [NSBundle mainBundle];
NSString *strAppPath = [bundle bundlePath];
NSLog(@"appDir: %@",strAppPath);
}

輸出的結果如下:

homedir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD
docDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Documents
libDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library
cachesDir:
/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library/Caches
tmpDir:
/private/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/tmp/
appDir:
/private/var/mobile/Containers/Bundle/Application/A5E6DC61-7AAA-467F-BC63-5BEDB8DDB113/
testSandbox.app

沙盒機制限制了應用只能讀寫沙盒之內的文件,而我們在有些情況下需要訪問一些公共資源(如通訊錄、短信、照片和位置等),這些是存在沙盒之外的。蘋果提供了公開的API 去訪問公共資源,不過都會彈出申請權限提示框,用戶必須允許才能操作成功,比如微信訪問照片提示需要用戶授權,如圖1-3 所示。

代碼簽名

代碼簽名(code signing)是iOS 一個重要的安全機制,所有的二進制文件都必須經過簽名才能被執行。在內存中,只有簽名來源為自己的頁才會被執行,這樣應用就不能自我升級或者動態改變行為。我們可以使用codesign 命令來驗證應用的簽名信息是否被破壞。輸入下面的命令後,如果沒有輸出信息,就表示簽名信息沒有被破壞:

codesign --verify testSandbox.app/

此外,使用下面的命令還可以查看簽名的相關信息:

$ codesign -vv -d testSandbox.app/
Executable=/Users/exchen/Library/Developer/Xcode/DerivedData/testSandbox-fzalslvcpprgiodycqxzblqeztql/
Build/Products/Debug-iphoneos/testSandbox.app/testSandbox
Identifier=net.exchen.testSandbox
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=694 flags=0x0(none) hashes=14+5 location=embedded
Signature size=4701
Authority=iPhone Developer: [email protected] (248BRN4CNL)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2018 年4 月8 日 01:27:40
Info.plist entries=26
TeamIdentifier=QQ4RE63T4U
Sealed Resources version=2 rules=13 files=7
Internal requirements count=1 size=188

用戶權限隔離

iOS 使用了用戶權限進行隔離。系統中的瀏覽器、電話、短信以及從App Store 上下載的應用,這些都以mobile 用戶權限運行,只有重要的系統進程才以root 用戶權限運行。這樣一來,即使惡意軟件安裝成功,也會由於存在權限限制,而使攻擊的可能性變小。我們打開“電話”應用(MobilePhone),通過ps 命令查看相關的進程信息,可以看到它是以mobile 的身份運行的:

iPhone:~ root# ps aux | grep MobilePhone
mobile 23754 0.0 0.9 661736 9152 ?? Ss 1:00AM 0:01.31 /Applications/MobilePhone.app/MobilePhone
root 23774 0.0 0.1 537356 572 s001 S+ 1:00AM 0:00.01 grep MobilePhone

再打開“短信”應用(MobileSMS),同樣通過ps 命令查看相關的進程信息,會發現它也是以mobile 用戶的身份運行的:

iPhone:~ root# ps aux | grep MobileSMS
mobile 23764 0.1 1.2 659024 12384 ?? Rs 1:00AM 0:01.82 /Applications/MobileSMS.app/MobileSMS
root 23776 0.0 0.1 537356 572 s001 S+ 1:01AM 0:00.01 grep MobileSMS

數據執行保護

iOS 中存在數據執行保護(Data Execution Prevention,DEP)機制,這一機制能夠區分內存中哪些是可執行的代碼,哪些是數據。該機制不允許執行數據,只允許執行代碼。在默認情況下,數據段的屬性是可讀、可寫、不可執行的,如果我們通過vm_protect 函數把數據段的屬性修改為可讀、可寫、可執行,就會打印錯誤信息。代碼如下:

unsigned int data = 0x12345678;
struct mach_header* image_addr = _dyld_get_image_header(0); //獲取鏡像地址
vm_address_t offset = image_addr + (int)0x8000; //數據段的偏移
kern_return_t err;
mach_port_t port = mach_task_self();
err = vm_protect(port, (vm_address_t) offset, sizeof(data), NO,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS) {
NSLog(@"prot error: %s \\n", mach_error_string(err));
return;
}
vm_write(port, (vm_address_t) offset, (vm_address_t) & data, sizeof(data));

運行之後打印的錯誤信息為:

2018-04-08 23:59:01.680009 vm_write[6222:265002] prot error: (os/kern) protection failure

地址隨機化

地址空間佈局隨機化(Address Space Layout Randomization,ASLR)能夠讓二進制文件、動態庫文件、代碼段以及數據段的內存地址在每次加載的時候都是隨機的。使用_dyld_get_image_vmaddr_slide 函數可以獲取模塊的ASLR 偏移地址,使用_dyld_get_image_header 函數可以獲取模塊的基址。我們編寫如下代碼:

//獲取第一個模塊的基址
intptr_t slide_addr = _dyld_get_image_vmaddr_slide(0);
struct mach_header *mh_addr = _dyld_get_image_header(0);
printf("slide_addr: 0x%x\\n", slide_addr);
printf("mh_addr: 0x%x\\n",mh_addr);

可以發現,第一次運行時,ASLR 偏移地址是0x94000,基址是0x100094000。這也可以通過LLDB(Low Level Debugger,詳見2.5 節)查看:

mh_addr: 0x100094000
(lldb) image list -o -f
[ 0] 0x0000000000094000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x0000000100094000)

我們退出程序再次運行,ASLR 偏移地址是0xe8000,基址是0x1000e8000。可以看出,程序每次運行,偏移地址和基址都是隨機的,一般都不會和上次一樣:

slide_addr: 0xe8000
mh_addr: 0x1000e8000
(lldb) image list -o -f
[ 0] 0x00000000000e8000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x00000001000e8000)

每次重啟手機之後,在內核中模塊的基地址也是隨機的。

後臺程序

Android 應用能夠在後臺創建執行代碼的服務,這些服務可能會偷偷下載文件消耗流量,造成扣費的情況。iOS 應用不能在後臺執行代碼,只要用戶點擊Home 鍵,前臺應用的所有線程都會被掛起,只有播放音樂、獲取實時位置等必須在後臺執行的操作才能執行。不過在iOS 中,也是有後臺程序的,被稱為daemon(守護程序)。比如在打開Safari(瀏覽器)上網時,突然有電話打進來,接聽電話的界面就會顯示在前臺,如果沒有後臺程序,怎麼處理來電呢?只是蘋果並沒有給開發者開放後臺程序,只有越獄之後,才能編寫後臺程序。

iOS 的系統進程launchd 會在系統啟動後檢測/System/Library/LaunchDaemons 和/Library/LaunchDaemons 這兩個目錄中的.plist 文件,而.plist 文件描述了daemon 程序的路徑。

下面我們寫一個daemon 程序進行測試,程序的名稱叫作daemonTest,其功能是每隔5 秒輸出一條信息,具體代碼如下:

#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}

編譯:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

簽名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

簽名需要用到的ent.plist 文件的內容請參考2.5.1 節。然後我們編寫用於描述daemonTest的.plist 文件,文件名稱為net.exchen.daemonTest.plist,具體內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>

將daemonTest 上傳到/usr/bin 目錄,再將net.exchen.daemonTest.plist 文件上傳到/Library/LaunchDaemons/目錄,接著設置相應的權限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用launchctl load 命令啟動daemon:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我們打開控制檯查看日誌,就可以看到每隔5 秒會輸出一條信息,並且在鎖屏狀態下代碼也能執行,是真正的後臺程序,如圖1-4 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-4 每隔5 秒輸出信息

使用launchctl unload 命令可以停止daemon:

launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist

——

如果你也對iOS安全感興趣,下面這本“祕籍”一定會幫到你,《黑客防線》技術月刊原總編輯孫彬評價說,這是一本“拿到就能上手找飯吃”的iOS安全技術書。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

本書主要講了什麼?

本書是一套完整的iOS安全知識體系。跟著本書能循序漸進、系統性地學習iOS 安全技術。

作者立足系統,著眼安全,涉及的內容不僅有iOS系統的安全機制解析、越獄及後期的開發、代碼的注入與關鍵點攔截、隱私信息的類別及獲取方法、應用的破解與保護,還揭密了刷單及刷量會用到的一些伎倆,同時包括一些基礎知識的簡明教程。

——

小編已試過水,整本書內容整理下來,邏輯主線清晰,語言通俗,感覺要是有點相關的開發經驗,現在能立馬轉iOS安全工程師了。

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-2 使用Xcode 9 註冊設備

正是App Store 嚴格的審核以及應用安裝源的限制,比較有效地控制了惡意程序的傳播。

沙盒

沙盒(sandbox)是iOS 的一個防禦機制,每個應用都會有一個自己的沙盒。應用只能在自己的沙盒目錄下讀寫數據,應用A 不能訪問應用B 的沙盒,它們之間是互相隔離的。正因如此,攻擊者上傳惡意程序後,即使僥倖通過了App Store 的審核,被安裝到用戶的手機之後也不能獲取其他應用的數據。獲取沙盒目錄的方法如下:

-(void)getPath{
//獲取沙盒根目錄路徑
NSString*homeDir = NSHomeDirectory();
NSLog(@"homedir: %@",homeDir);
//獲取Documents 目錄路徑
NSString*docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"docDir: %@",docDir);
//獲取Library 目錄路徑
NSString*libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)
lastObject];
NSLog(@"libDir: %@",libDir);
//獲取cache 目錄路徑
NSString*cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"cachesDir: %@",cachesDir);
//獲取tmp 目錄路徑
NSString*tmpDir =NSTemporaryDirectory();
NSLog(@"tmpDir: %@",tmpDir);
//獲取應用的自身xx.app 目錄
NSBundle *bundle = [NSBundle mainBundle];
NSString *strAppPath = [bundle bundlePath];
NSLog(@"appDir: %@",strAppPath);
}

輸出的結果如下:

homedir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD
docDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Documents
libDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library
cachesDir:
/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library/Caches
tmpDir:
/private/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/tmp/
appDir:
/private/var/mobile/Containers/Bundle/Application/A5E6DC61-7AAA-467F-BC63-5BEDB8DDB113/
testSandbox.app

沙盒機制限制了應用只能讀寫沙盒之內的文件,而我們在有些情況下需要訪問一些公共資源(如通訊錄、短信、照片和位置等),這些是存在沙盒之外的。蘋果提供了公開的API 去訪問公共資源,不過都會彈出申請權限提示框,用戶必須允許才能操作成功,比如微信訪問照片提示需要用戶授權,如圖1-3 所示。

代碼簽名

代碼簽名(code signing)是iOS 一個重要的安全機制,所有的二進制文件都必須經過簽名才能被執行。在內存中,只有簽名來源為自己的頁才會被執行,這樣應用就不能自我升級或者動態改變行為。我們可以使用codesign 命令來驗證應用的簽名信息是否被破壞。輸入下面的命令後,如果沒有輸出信息,就表示簽名信息沒有被破壞:

codesign --verify testSandbox.app/

此外,使用下面的命令還可以查看簽名的相關信息:

$ codesign -vv -d testSandbox.app/
Executable=/Users/exchen/Library/Developer/Xcode/DerivedData/testSandbox-fzalslvcpprgiodycqxzblqeztql/
Build/Products/Debug-iphoneos/testSandbox.app/testSandbox
Identifier=net.exchen.testSandbox
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=694 flags=0x0(none) hashes=14+5 location=embedded
Signature size=4701
Authority=iPhone Developer: [email protected] (248BRN4CNL)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2018 年4 月8 日 01:27:40
Info.plist entries=26
TeamIdentifier=QQ4RE63T4U
Sealed Resources version=2 rules=13 files=7
Internal requirements count=1 size=188

用戶權限隔離

iOS 使用了用戶權限進行隔離。系統中的瀏覽器、電話、短信以及從App Store 上下載的應用,這些都以mobile 用戶權限運行,只有重要的系統進程才以root 用戶權限運行。這樣一來,即使惡意軟件安裝成功,也會由於存在權限限制,而使攻擊的可能性變小。我們打開“電話”應用(MobilePhone),通過ps 命令查看相關的進程信息,可以看到它是以mobile 的身份運行的:

iPhone:~ root# ps aux | grep MobilePhone
mobile 23754 0.0 0.9 661736 9152 ?? Ss 1:00AM 0:01.31 /Applications/MobilePhone.app/MobilePhone
root 23774 0.0 0.1 537356 572 s001 S+ 1:00AM 0:00.01 grep MobilePhone

再打開“短信”應用(MobileSMS),同樣通過ps 命令查看相關的進程信息,會發現它也是以mobile 用戶的身份運行的:

iPhone:~ root# ps aux | grep MobileSMS
mobile 23764 0.1 1.2 659024 12384 ?? Rs 1:00AM 0:01.82 /Applications/MobileSMS.app/MobileSMS
root 23776 0.0 0.1 537356 572 s001 S+ 1:01AM 0:00.01 grep MobileSMS

數據執行保護

iOS 中存在數據執行保護(Data Execution Prevention,DEP)機制,這一機制能夠區分內存中哪些是可執行的代碼,哪些是數據。該機制不允許執行數據,只允許執行代碼。在默認情況下,數據段的屬性是可讀、可寫、不可執行的,如果我們通過vm_protect 函數把數據段的屬性修改為可讀、可寫、可執行,就會打印錯誤信息。代碼如下:

unsigned int data = 0x12345678;
struct mach_header* image_addr = _dyld_get_image_header(0); //獲取鏡像地址
vm_address_t offset = image_addr + (int)0x8000; //數據段的偏移
kern_return_t err;
mach_port_t port = mach_task_self();
err = vm_protect(port, (vm_address_t) offset, sizeof(data), NO,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS) {
NSLog(@"prot error: %s \\n", mach_error_string(err));
return;
}
vm_write(port, (vm_address_t) offset, (vm_address_t) & data, sizeof(data));

運行之後打印的錯誤信息為:

2018-04-08 23:59:01.680009 vm_write[6222:265002] prot error: (os/kern) protection failure

地址隨機化

地址空間佈局隨機化(Address Space Layout Randomization,ASLR)能夠讓二進制文件、動態庫文件、代碼段以及數據段的內存地址在每次加載的時候都是隨機的。使用_dyld_get_image_vmaddr_slide 函數可以獲取模塊的ASLR 偏移地址,使用_dyld_get_image_header 函數可以獲取模塊的基址。我們編寫如下代碼:

//獲取第一個模塊的基址
intptr_t slide_addr = _dyld_get_image_vmaddr_slide(0);
struct mach_header *mh_addr = _dyld_get_image_header(0);
printf("slide_addr: 0x%x\\n", slide_addr);
printf("mh_addr: 0x%x\\n",mh_addr);

可以發現,第一次運行時,ASLR 偏移地址是0x94000,基址是0x100094000。這也可以通過LLDB(Low Level Debugger,詳見2.5 節)查看:

mh_addr: 0x100094000
(lldb) image list -o -f
[ 0] 0x0000000000094000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x0000000100094000)

我們退出程序再次運行,ASLR 偏移地址是0xe8000,基址是0x1000e8000。可以看出,程序每次運行,偏移地址和基址都是隨機的,一般都不會和上次一樣:

slide_addr: 0xe8000
mh_addr: 0x1000e8000
(lldb) image list -o -f
[ 0] 0x00000000000e8000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x00000001000e8000)

每次重啟手機之後,在內核中模塊的基地址也是隨機的。

後臺程序

Android 應用能夠在後臺創建執行代碼的服務,這些服務可能會偷偷下載文件消耗流量,造成扣費的情況。iOS 應用不能在後臺執行代碼,只要用戶點擊Home 鍵,前臺應用的所有線程都會被掛起,只有播放音樂、獲取實時位置等必須在後臺執行的操作才能執行。不過在iOS 中,也是有後臺程序的,被稱為daemon(守護程序)。比如在打開Safari(瀏覽器)上網時,突然有電話打進來,接聽電話的界面就會顯示在前臺,如果沒有後臺程序,怎麼處理來電呢?只是蘋果並沒有給開發者開放後臺程序,只有越獄之後,才能編寫後臺程序。

iOS 的系統進程launchd 會在系統啟動後檢測/System/Library/LaunchDaemons 和/Library/LaunchDaemons 這兩個目錄中的.plist 文件,而.plist 文件描述了daemon 程序的路徑。

下面我們寫一個daemon 程序進行測試,程序的名稱叫作daemonTest,其功能是每隔5 秒輸出一條信息,具體代碼如下:

#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}

編譯:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

簽名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

簽名需要用到的ent.plist 文件的內容請參考2.5.1 節。然後我們編寫用於描述daemonTest的.plist 文件,文件名稱為net.exchen.daemonTest.plist,具體內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>

將daemonTest 上傳到/usr/bin 目錄,再將net.exchen.daemonTest.plist 文件上傳到/Library/LaunchDaemons/目錄,接著設置相應的權限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用launchctl load 命令啟動daemon:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我們打開控制檯查看日誌,就可以看到每隔5 秒會輸出一條信息,並且在鎖屏狀態下代碼也能執行,是真正的後臺程序,如圖1-4 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-4 每隔5 秒輸出信息

使用launchctl unload 命令可以停止daemon:

launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist

——

如果你也對iOS安全感興趣,下面這本“祕籍”一定會幫到你,《黑客防線》技術月刊原總編輯孫彬評價說,這是一本“拿到就能上手找飯吃”的iOS安全技術書。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

本書主要講了什麼?

本書是一套完整的iOS安全知識體系。跟著本書能循序漸進、系統性地學習iOS 安全技術。

作者立足系統,著眼安全,涉及的內容不僅有iOS系統的安全機制解析、越獄及後期的開發、代碼的注入與關鍵點攔截、隱私信息的類別及獲取方法、應用的破解與保護,還揭密了刷單及刷量會用到的一些伎倆,同時包括一些基礎知識的簡明教程。

——

小編已試過水,整本書內容整理下來,邏輯主線清晰,語言通俗,感覺要是有點相關的開發經驗,現在能立馬轉iOS安全工程師了。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

截取自拉勾網

我能不能讀這本書?

本書整體的深度和廣度都相對適中,可以幫助對iOS系統安全有興趣的廣大研究人員從入門到進階。

潛讀其中,會讓讀者對業內一些常見的安全相關的技術手段有清晰、直觀的瞭解,心領神會後暗道一聲原來如此!

"
iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

來自Unsplash

iOS 的系統安全性比Android 系統要高,其中有幾個主要的原因。

一是對應用安裝源的限制,iOS 設備必須從App Store 上下載應用或者使用企業證書做分發,而Android 系統的設備可以安裝任何安裝包(Android Package,APK),這樣會導致惡意應用可以很輕易地被安裝到手機上。

二是iOS 上的應用有著嚴格的“沙盒”機制,每個應用都只能訪問自己沙盒目錄下的數據,沒有公共的讀寫區域,而Android 系統存在公共讀寫區域,容易造成信息洩露。

三是iOS 應用被限制只能在前臺運行,只要點擊Home 鍵,應用的所有線程都會被掛起,只有一些必須運行在後臺的服務才能被執行(如實時位置、播放音樂等),而Android 應用可以創建後臺服務,即使應用被切換到後臺,代碼還是可以執行的,用戶很難覺察到。

下面我們來詳細瞭解一下iOS 的安全機制。

應用的安裝源

App Store 是蘋果的應用市場,蘋果手機上使用的微信、QQ和支付寶等應用都是從App Store 上下載的。同樣,如果你想開發一款應用並上架App Store,必須提交蘋果公司進行審核,審核通過之後,應用才能在App Store 上被搜索、下載。除了從App Store 上下載應用外,還有其他安裝應用的方法,其中一種方法是使用企業證書做分發,價格為每年299 美元。這種方法不限制安裝設備的數量,但是安裝完成後想要打開軟件時,會出現“未受信任的企業級開發者”提示,如圖1-1 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-1 未信任的企業開發者

這時我們就需要點擊“設置”→“通用”→“設備管理①”,信任安裝的應用。還有一種方法是使用個人/公司證書進行開發及測試,價格為每年99 美元。這種方法首先需要將設備的UDID(Unique Device Identifier,設備唯一標識符,在8.1 節有更詳細的介紹)添加到開發者賬號中,最多可以添加100 臺設備,然後下載配置文件,在Xcode 上添加配置文件並編譯相應的程序,最後就能安裝在這臺設備上了。Xcode 9 有自動註冊設備的功能,當我們使用Xcode 進行真機調試,連接一個新設備的時候會進行自動註冊,如圖1-2 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-2 使用Xcode 9 註冊設備

正是App Store 嚴格的審核以及應用安裝源的限制,比較有效地控制了惡意程序的傳播。

沙盒

沙盒(sandbox)是iOS 的一個防禦機制,每個應用都會有一個自己的沙盒。應用只能在自己的沙盒目錄下讀寫數據,應用A 不能訪問應用B 的沙盒,它們之間是互相隔離的。正因如此,攻擊者上傳惡意程序後,即使僥倖通過了App Store 的審核,被安裝到用戶的手機之後也不能獲取其他應用的數據。獲取沙盒目錄的方法如下:

-(void)getPath{
//獲取沙盒根目錄路徑
NSString*homeDir = NSHomeDirectory();
NSLog(@"homedir: %@",homeDir);
//獲取Documents 目錄路徑
NSString*docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"docDir: %@",docDir);
//獲取Library 目錄路徑
NSString*libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES)
lastObject];
NSLog(@"libDir: %@",libDir);
//獲取cache 目錄路徑
NSString*cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)
firstObject];
NSLog(@"cachesDir: %@",cachesDir);
//獲取tmp 目錄路徑
NSString*tmpDir =NSTemporaryDirectory();
NSLog(@"tmpDir: %@",tmpDir);
//獲取應用的自身xx.app 目錄
NSBundle *bundle = [NSBundle mainBundle];
NSString *strAppPath = [bundle bundlePath];
NSLog(@"appDir: %@",strAppPath);
}

輸出的結果如下:

homedir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD
docDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Documents
libDir: /var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library
cachesDir:
/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/Library/Caches
tmpDir:
/private/var/mobile/Containers/Data/Application/E24754D2-22F8-4E8E-8A6C-2B18561DB5AD/tmp/
appDir:
/private/var/mobile/Containers/Bundle/Application/A5E6DC61-7AAA-467F-BC63-5BEDB8DDB113/
testSandbox.app

沙盒機制限制了應用只能讀寫沙盒之內的文件,而我們在有些情況下需要訪問一些公共資源(如通訊錄、短信、照片和位置等),這些是存在沙盒之外的。蘋果提供了公開的API 去訪問公共資源,不過都會彈出申請權限提示框,用戶必須允許才能操作成功,比如微信訪問照片提示需要用戶授權,如圖1-3 所示。

代碼簽名

代碼簽名(code signing)是iOS 一個重要的安全機制,所有的二進制文件都必須經過簽名才能被執行。在內存中,只有簽名來源為自己的頁才會被執行,這樣應用就不能自我升級或者動態改變行為。我們可以使用codesign 命令來驗證應用的簽名信息是否被破壞。輸入下面的命令後,如果沒有輸出信息,就表示簽名信息沒有被破壞:

codesign --verify testSandbox.app/

此外,使用下面的命令還可以查看簽名的相關信息:

$ codesign -vv -d testSandbox.app/
Executable=/Users/exchen/Library/Developer/Xcode/DerivedData/testSandbox-fzalslvcpprgiodycqxzblqeztql/
Build/Products/Debug-iphoneos/testSandbox.app/testSandbox
Identifier=net.exchen.testSandbox
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=694 flags=0x0(none) hashes=14+5 location=embedded
Signature size=4701
Authority=iPhone Developer: [email protected] (248BRN4CNL)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2018 年4 月8 日 01:27:40
Info.plist entries=26
TeamIdentifier=QQ4RE63T4U
Sealed Resources version=2 rules=13 files=7
Internal requirements count=1 size=188

用戶權限隔離

iOS 使用了用戶權限進行隔離。系統中的瀏覽器、電話、短信以及從App Store 上下載的應用,這些都以mobile 用戶權限運行,只有重要的系統進程才以root 用戶權限運行。這樣一來,即使惡意軟件安裝成功,也會由於存在權限限制,而使攻擊的可能性變小。我們打開“電話”應用(MobilePhone),通過ps 命令查看相關的進程信息,可以看到它是以mobile 的身份運行的:

iPhone:~ root# ps aux | grep MobilePhone
mobile 23754 0.0 0.9 661736 9152 ?? Ss 1:00AM 0:01.31 /Applications/MobilePhone.app/MobilePhone
root 23774 0.0 0.1 537356 572 s001 S+ 1:00AM 0:00.01 grep MobilePhone

再打開“短信”應用(MobileSMS),同樣通過ps 命令查看相關的進程信息,會發現它也是以mobile 用戶的身份運行的:

iPhone:~ root# ps aux | grep MobileSMS
mobile 23764 0.1 1.2 659024 12384 ?? Rs 1:00AM 0:01.82 /Applications/MobileSMS.app/MobileSMS
root 23776 0.0 0.1 537356 572 s001 S+ 1:01AM 0:00.01 grep MobileSMS

數據執行保護

iOS 中存在數據執行保護(Data Execution Prevention,DEP)機制,這一機制能夠區分內存中哪些是可執行的代碼,哪些是數據。該機制不允許執行數據,只允許執行代碼。在默認情況下,數據段的屬性是可讀、可寫、不可執行的,如果我們通過vm_protect 函數把數據段的屬性修改為可讀、可寫、可執行,就會打印錯誤信息。代碼如下:

unsigned int data = 0x12345678;
struct mach_header* image_addr = _dyld_get_image_header(0); //獲取鏡像地址
vm_address_t offset = image_addr + (int)0x8000; //數據段的偏移
kern_return_t err;
mach_port_t port = mach_task_self();
err = vm_protect(port, (vm_address_t) offset, sizeof(data), NO,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
if (err != KERN_SUCCESS) {
NSLog(@"prot error: %s \\n", mach_error_string(err));
return;
}
vm_write(port, (vm_address_t) offset, (vm_address_t) & data, sizeof(data));

運行之後打印的錯誤信息為:

2018-04-08 23:59:01.680009 vm_write[6222:265002] prot error: (os/kern) protection failure

地址隨機化

地址空間佈局隨機化(Address Space Layout Randomization,ASLR)能夠讓二進制文件、動態庫文件、代碼段以及數據段的內存地址在每次加載的時候都是隨機的。使用_dyld_get_image_vmaddr_slide 函數可以獲取模塊的ASLR 偏移地址,使用_dyld_get_image_header 函數可以獲取模塊的基址。我們編寫如下代碼:

//獲取第一個模塊的基址
intptr_t slide_addr = _dyld_get_image_vmaddr_slide(0);
struct mach_header *mh_addr = _dyld_get_image_header(0);
printf("slide_addr: 0x%x\\n", slide_addr);
printf("mh_addr: 0x%x\\n",mh_addr);

可以發現,第一次運行時,ASLR 偏移地址是0x94000,基址是0x100094000。這也可以通過LLDB(Low Level Debugger,詳見2.5 節)查看:

mh_addr: 0x100094000
(lldb) image list -o -f
[ 0] 0x0000000000094000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x0000000100094000)

我們退出程序再次運行,ASLR 偏移地址是0xe8000,基址是0x1000e8000。可以看出,程序每次運行,偏移地址和基址都是隨機的,一般都不會和上次一樣:

slide_addr: 0xe8000
mh_addr: 0x1000e8000
(lldb) image list -o -f
[ 0] 0x00000000000e8000 /var/containers/Bundle/Application/9B2F1512-812E-4C3A-BBA7-A15DB63FFB1F/
getBaseAddress.app/getBaseAddress(0x00000001000e8000)

每次重啟手機之後,在內核中模塊的基地址也是隨機的。

後臺程序

Android 應用能夠在後臺創建執行代碼的服務,這些服務可能會偷偷下載文件消耗流量,造成扣費的情況。iOS 應用不能在後臺執行代碼,只要用戶點擊Home 鍵,前臺應用的所有線程都會被掛起,只有播放音樂、獲取實時位置等必須在後臺執行的操作才能執行。不過在iOS 中,也是有後臺程序的,被稱為daemon(守護程序)。比如在打開Safari(瀏覽器)上網時,突然有電話打進來,接聽電話的界面就會顯示在前臺,如果沒有後臺程序,怎麼處理來電呢?只是蘋果並沒有給開發者開放後臺程序,只有越獄之後,才能編寫後臺程序。

iOS 的系統進程launchd 會在系統啟動後檢測/System/Library/LaunchDaemons 和/Library/LaunchDaemons 這兩個目錄中的.plist 文件,而.plist 文件描述了daemon 程序的路徑。

下面我們寫一個daemon 程序進行測試,程序的名稱叫作daemonTest,其功能是每隔5 秒輸出一條信息,具體代碼如下:

#include <stdio.h>
#include <UIKit/UIKit.h>
int main(){
int i=0;
while(1){
NSLog(@"Daemon test %d", i);
i++;
sleep(5);
}
return 0;
}

編譯:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

簽名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

簽名需要用到的ent.plist 文件的內容請參考2.5.1 節。然後我們編寫用於描述daemonTest的.plist 文件,文件名稱為net.exchen.daemonTest.plist,具體內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>net.exchen.daemonTest</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/daemonTest</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>

將daemonTest 上傳到/usr/bin 目錄,再將net.exchen.daemonTest.plist 文件上傳到/Library/LaunchDaemons/目錄,接著設置相應的權限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用launchctl load 命令啟動daemon:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我們打開控制檯查看日誌,就可以看到每隔5 秒會輸出一條信息,並且在鎖屏狀態下代碼也能執行,是真正的後臺程序,如圖1-4 所示。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

圖1-4 每隔5 秒輸出信息

使用launchctl unload 命令可以停止daemon:

launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist

——

如果你也對iOS安全感興趣,下面這本“祕籍”一定會幫到你,《黑客防線》技術月刊原總編輯孫彬評價說,這是一本“拿到就能上手找飯吃”的iOS安全技術書。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

本書主要講了什麼?

本書是一套完整的iOS安全知識體系。跟著本書能循序漸進、系統性地學習iOS 安全技術。

作者立足系統,著眼安全,涉及的內容不僅有iOS系統的安全機制解析、越獄及後期的開發、代碼的注入與關鍵點攔截、隱私信息的類別及獲取方法、應用的破解與保護,還揭密了刷單及刷量會用到的一些伎倆,同時包括一些基礎知識的簡明教程。

——

小編已試過水,整本書內容整理下來,邏輯主線清晰,語言通俗,感覺要是有點相關的開發經驗,現在能立馬轉iOS安全工程師了。

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

截取自拉勾網

我能不能讀這本書?

本書整體的深度和廣度都相對適中,可以幫助對iOS系統安全有興趣的廣大研究人員從入門到進階。

潛讀其中,會讓讀者對業內一些常見的安全相關的技術手段有清晰、直觀的瞭解,心領神會後暗道一聲原來如此!

iOS 的系統安全性比Android 系統要高!// 解讀iOS安全機制

試讀:刷量與作弊

封面新聞中報道:【全國累計有900多萬人從事刷流量產業】近日有專家指出,各類刷量平臺在我國已超過1000家,刷量產業的人員規模累計達到900多萬。從地下某個刷量平臺訂單信息來看,在整個行業中,被刷最多的數據依次是:文章閱讀量、電商評價和其他。刷量需求者的地域性比較明顯,主要分佈在互聯網經濟發達的沿海地區。其中,廣東、北京、山東三地的刷量人員規模遙遙領先。

那App市場是怎麼刷量和作弊的呢?點擊閱讀原文跳轉到圖靈社區閱讀。

"

相關推薦

推薦中...