下載PDF:2022_C00C00R00CON_jailbreak.pdf
沒有越獄
使用 ptrace (lldb / frida) → 應用程式需要 get-task-allow 權利
透過注入frida程式碼→app需要重新打包
在這兩種情況下,您都需要放棄申請
但它有很多副作用:
不同的團隊ID
文件被修改
越獄
逆向工程防禦中添加了越獄檢測機制,使在越獄設備上運行應用程式變得更加困難。這阻礙了逆向工程師喜歡使用的一些工具和技術。與大多數其他類型的防禦一樣,越獄檢測本身並不是非常有效,但在整個應用程式原始碼中分散檢查可以提高整體防篡改方案的有效性。
面對能夠幫助使用者輕鬆規避常見越獄偵測方法的工具,越獄複合帶來的企業安全風險。用戶可以直接從第三方應用程式商店 Cydia 下載任何應用程式調整,例如 Spotify++。許多應用程式都提供越獄檢測,許多想要限制內容盜版和帳戶洩露的媒體和金融服務應用程式也是如此。不幸的是,這些越獄檢測依賴於相對簡單且可規避的測試的組合,例如:
這些和類似的檢測測試的基本限制是,作為客戶端測試,攻擊者可以存取、逆向工程和規避它們。此外,執行這些越獄偵測測試的應用程式(例如MDM應用程式)必須經過Apple的應用程式審查流程,這限制了它們可以收集以分析裝置越獄狀態的資料範圍。讓我們快速瀏覽一下它們:
檢查通常與越獄相關的文件和目錄,例如:
//suspicious system and app paths to check
private static var suspicousAppandSystemPaths : [ String ] {
return [
" /usr/sbin/frida-server " ,
" /etc/apt/sources.list.d/electra.list " ,
" /etc/apt/sources.list.d/sileo.sources " ,
" /.bootstrapped_electra " ,
" /usr/lib/libjailbreak.dylib " ,
" /jb/lzma " ,
" /.cydia_no_stash " ,
" /.installed_unc0ver " ,
" /jb/offsets.plist " ,
" /usr/share/jailbreak/injectme.plist " ,
" /etc/apt/undecimus/undecimus.list " ,
" /var/lib/dpkg/info/mobilesubstrate.md5sums " ,
" /Library/MobileSubstrate/MobileSubstrate.dylib " ,
" /jb/jailbreakd.plist " ,
" /jb/amfid_payload.dylib " ,
" /jb/libjailbreak.dylib " ,
" /usr/libexec/cydia/firmware.sh " ,
" /var/lib/cydia " ,
" /etc/apt " ,
" /private/var/lib/apt " ,
" /private/var/Users/ " ,
" /var/log/apt " ,
" /Applications/Cydia.app " ,
" /private/var/stash " ,
" /private/var/lib/apt/ " ,
" /private/var/lib/cydia " ,
" /private/var/cache/apt/ " ,
" /private/var/log/syslog " ,
" /private/var/tmp/cydia.log " ,
" /Applications/Icy.app " ,
" /Applications/MxTube.app " ,
" /Applications/RockApp.app " ,
" /Applications/blackra1n.app " ,
" /Applications/SBSettings.app " ,
" /Applications/FakeCarrier.app " ,
" /Applications/WinterBoard.app " ,
" /Applications/IntelliScreen.app " ,
" /private/var/mobile/Library/SBSettings/Themes " ,
" /Library/MobileSubstrate/CydiaSubstrate.dylib " ,
" /System/Library/LaunchDaemons/com.ikey.bbot.plist " ,
" /Library/MobileSubstrate/DynamicLibraries/Veency.plist " ,
" /Library/MobileSubstrate/DynamicLibraries/LiveClock.plist " ,
" /System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist " ,
" /Applications/Cydia.app " ,
" /Applications/blackra1n.app " ,
" /Applications/FakeCarrier.app " ,
" /Applications/Icy.app " ,
" /Applications/IntelliScreen.app " ,
" /Applications/MxTube.app " ,
" /Applications/RockApp.app " ,
" /Applications/SBSettings.app " ,
" /Applications/WinterBoard.app "
]
}
大多數情況下,這些是使用
-(BOOL)fileExistsAtPath:(NSString*)
NSFileManager 或FileManager.default.fileExists(atPath: path)
中的路徑方法。然而,也有一些應用程式使用較低層級的 C 函數,例如 fopen()、stat() 或 access()。
檢查越獄機制的另一種方法是嘗試寫入應用程式沙箱之外的位置。您可以透過讓應用程式嘗試在/private
目錄中建立檔案來完成此操作。如果檔案建立成功,則裝置已越獄。
此方法包括檢查系統上特定檔案和目錄的權限。與未受感染的設備相比,越獄設備上具有寫入權限的目錄更多。根分割區就是一個例子,它原本只有讀取權限。如果發現有讀寫權限,則表示設備已越獄。執行這些檢查的方法有多種,例如使用 NSFileManager 和 statfs() 等 C 函數。
迅速:
do {
let pathToFileInRestrictedDirectory = " /private/jailbreak.txt "
try " This is a test. " . write ( toFile : pathToFileInRestrictedDirectory , atomically : true , encoding : String . Encoding . utf8 )
try FileManager . default . removeItem ( atPath : pathToFileInRestrictedDirectory )
// Device is jailbroken
} catch {
// Device is not jailbroken
}
Objective-C:
NSError *error;
NSString *stringToBeWritten = @" This is a test. " ;
[stringToBeWritten writeToFile: @" /private/jailbreak.txt " atomically: YES
encoding: NSUTF8StringEncoding error: &error];
if (error == nil ) {
// Device is jailbroken
return YES ;
} else {
// Device is not jailbroken
[[ NSFileManager defaultManager ] removeItemAtPath: @" /private/jailbreak.txt " error: nil ];
}
執行這些檢查的方法有多種,例如使用 NSFileManager 和 C 函數,如 statfs()、open()、utimes()、stat()、pathconf()、stat64()、fopen()。
您可以透過嘗試開啟 Cydia URL 來檢查協議處理程序。幾乎所有越獄工具都會預設安裝 Cydia 應用程式商店,它會安裝 cydia:// 協定處理程序。
迅速:
if let url = URL ( string : " cydia://package/com.example.package " ) , UIApplication . shared . canOpenURL ( url ) {
// Device is jailbroken
}
Objective-C:
if ([[UIApplication sharedApplication ] canOpenURL: [ NSURL URLWithString: @" cydia://package/com.example.package " ]]){
// Device is jailbroken
}
攻擊者可以存取、逆向工程和規避這種簡單的檢查。
ptrace ( PT_DENY_ATTACH );
void try_kill () {
const int pid = getpid ();
int ret = kill (pid, 0 );
}
根據kill( man 2 kill
)的手冊頁,訊號0
用於檢查第一個參數中給出的pid
是否確實存在。
[…] 然而,值為 0 將導致執行錯誤檢查(不發送訊號)。這可以用來檢查pid的有效性。
此終止操作之後是PTRACE
檢查:
inline bool ptrace_detect () {
int32_t opt[ 4 ] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PID,
getpid (),
};
kinfo_proc info;
sysctl (opt, 4 , &info, sizeof (kinfo_proc), nullptr , 0 );
return info. kp_proc . p_flag & P_TRACED;
}
getppid() == 1
getfsstat64(), statvfs()
fcntl(F_ADDSIGS)
csops(CS_OPS_MARKKILL)
我們可以檢查二進位檔案簽章的完整性。此檢查首先從磁碟開啟主應用程式二進位文件,尋找 kSecCodeMagicEmbeddedSignature 序列0xfade0cc0
,讀取權利併計算校驗和。
程式碼簽章段包含一個 superlob 結構,該結構本身包含其他不同類型的 blob。兩者的結構都在一些更開源的 Apple 程式碼中定義:
/*
* Structure of an embedded-signature SuperBlob
*/
typedef struct __BlobIndex {
uint32_t type; /* type of entry */
uint32_t offset; /* offset of entry */
} CS_BlobIndex;
typedef struct __SuperBlob {
uint32_t magic; /* magic number */
uint32_t length; /* total length of SuperBlob */
uint32_t count; /* number of index entries following */
CS_BlobIndex index[]; /* (count) entries */
/* followed by Blobs in no particular order as indicated by offsets in index */
} CS_SuperBlob;
超級 blob 僅包含一些魔法,即整個程式碼簽名部分的長度、blob 的計數以及這些 blob 的索引數組。不同的識別 blob 魔法在此文件中定義:
/*
* Magic numbers used by Code Signing
*/
enum {
kSecCodeMagicRequirement = 0xfade0c00 , /* single requirement */
kSecCodeMagicRequirementSet = 0xfade0c01 , /* requirement set */
kSecCodeMagicCodeDirectory = 0xfade0c02 , /* CodeDirectory */
kSecCodeMagicEmbeddedSignature = 0xfade0cc0 , /* single-architecture embedded signature */
kSecCodeMagicDetachedSignature = 0xfade0cc1 , /* detached multi-architecture signature */
kSecCodeMagicEntitlement = 0xfade7171 , /* entitlement blob */
};
例如,iOS ps
二進位檔案在最初的 superlob 之後有四個內容 blob:
這些分別是:
0xfade0c02
),您可以發現它,因為它包含限定的二進位名稱com.apple.ps
。0xfade0c01
)。0xfade7171
)。0xfade0b01
)。嘗試在長時間超時後停止應用程序,並且不要直接從越獄檢測位置退出。
fork()
進程分叉。 Sandboxd 不會拒絕應用程式使用 fork()、popen() 或任何其他 C 函數在越獄裝置上建立子程序的能力。然而,sandboxd 明確拒絕在非越獄設備上進行進程分叉。因此,透過檢查 fork() 傳回的 pid,應用程式可以判斷裝置是否受到威脅。如果分叉成功,應用程式可以推斷它正在越獄設備上運行。
system()
在非越獄設備上使用 NULL 參數呼叫 system() 函數將傳回 0。
SSH 環回連線。由於大部分越獄設備安裝了OpenSSH,因此一些應用程式會嘗試在連接埠22上連接127.0.0.1。
檢查 22 (OpenSSH) 和 44 (checkra1n) 開啟連接埠的環回。
此檢測方法首先呼叫_dyld_image_count()
和_dyld_get_image_name()
等函數來查看目前載入了哪些 dylib。由於補丁本身是 dylib 的一部分,因此這種方法很難動態修補。
例如/usr/lib/substitute-inserter.dylib
可以使用dlopen/記憶體掃描/dyld內部結構等
private static func checkDYLD ( ) -> Bool {
let suspiciousLibraries = [
" FridaGadget " ,
" frida " ,
" cynject " ,
" libcycript "
]
for libraryIndex in 0 ..< _dyld_image_count ( ) {
guard let loadedLibrary = String ( validatingUTF8 : _dyld_get_image_name ( libraryIndex ) ) else { continue }
for suspiciousLibrary in suspiciousLibraries {
if loadedLibrary . lowercased ( ) . contains ( suspiciousLibrary . lowercased ( ) ) {
return true
}
}
}
return false
}
檢查程式碼完整性
嘗試檢測弗里達
private static func isFridaRunning ( ) -> Bool {
func swapBytesIfNeeded ( port : in_port_t ) -> in_port_t {
let littleEndian = Int ( OSHostByteOrder ( ) ) == OSLittleEndian
return littleEndian ? _OSSwapInt16 ( port ) : port
}
var serverAddress = sockaddr_in ( )
serverAddress . sin_family = sa_family_t ( AF_INET )
serverAddress . sin_addr . s_addr = inet_addr ( " 127.0.0.1 " )
serverAddress . sin_port = swapBytesIfNeeded ( port : in_port_t ( 27042 ) )
let sock = socket ( AF_INET , SOCK_STREAM , 0 )
let result = withUnsafePointer ( to : & serverAddress ) {
$0 . withMemoryRebound ( to : sockaddr . self , capacity : 1 ) {
connect ( sock , $0 , socklen_t ( MemoryLayout < sockaddr_in > . stride ) )
}
}
if result != - 1 {
return true
}
return false
}
一般來說,越獄偵測越複雜,偵測和繞過就越困難。實施越獄檢測時最常見的錯誤往往在於實作本身。
我們經常遇到具有出色越獄檢測功能的應用程序,但其實現是在一個函數中,該函數根據設備是否越獄返回 true 或 false。在這些情況下,我們透過使用 Cycript 或類似工具來反轉檢測函數的返回值來繞過越獄檢測。
在實踐中,最好的越獄檢測結合多種技術並將它們整合到其他功能中,這樣它們就不會輕易被繞過。
https://github.com/mehrankmlf/SecurityKit
https://www.synacktiv.com/sites/default/files/2021-10/2021_sthack_jailbreak.pdf
https://www.romainthomas.fr/post/21-07-pokemongo-anti-frida-jailbreak-bypass/
https://aeonlucid.com/Snapchat-detection-on-iOS/
https://github.com/AeonLucid/SnapHide
https://redmaple.tech/blogs/macho-files/