下载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。在越狱设备上执行相同操作将返回 1。这是因为该函数将检查 /bin/sh 是否存在,并且仅存在于越狱设备。
SSH 环回连接。由于大部分越狱设备安装了OpenSSH,因此一些应用程序会尝试在端口22上连接127.0.0.1。如果连接成功,则表明OpenSSH已安装并正在运行,这证明设备已越狱。
检查 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/