تنزيل ملف PDF: 2022_C00C00R00CON_jailbreak.pdf
بدون جيلبريك
باستخدام ptrace (lldb / frida) → يحتاج التطبيق إلى استحقاق الحصول على المهمة
عن طريق حقن رمز فريدا → يحتاج التطبيق إلى إعادة تجميعه
وفي كلتا الحالتين، يجب عليك الاستقالة من الطلب
ولكن له الكثير من الآثار الجانبية:
معرف فريق مختلف
يتم تعديل الملفات
مع الهروب من السجن
تتم إضافة آليات اكتشاف كسر الحماية إلى الدفاع الهندسي العكسي لجعل تشغيل التطبيق على جهاز مكسور الحماية أكثر صعوبة. يؤدي هذا إلى حظر بعض الأدوات والتقنيات التي يرغب المهندسون العكسيون في استخدامها. كما هو الحال مع معظم أنواع الدفاع الأخرى، فإن اكتشاف كسر الحماية ليس فعالًا جدًا في حد ذاته، ولكن عمليات التحقق المتناثرة عبر الكود المصدري للتطبيق يمكن أن تؤدي إلى تحسين فعالية مخطط مكافحة التلاعب الشامل.
المخاطر الأمنية للمؤسسات التي يفرضها كسر الحماية في مواجهة الأدوات التي يمكن أن تساعد المستخدمين على تجنب طرق اكتشاف كسر الحماية الشائعة بسهولة. يمكن للمستخدم تنزيل أي تعديل للتطبيق مثل Spotify ++ مباشرة من متجر التطبيقات Cydia التابع لجهة خارجية. توفر الكثير من التطبيقات اكتشاف كسر الحماية، كما هو الحال مع العديد من تطبيقات الوسائط والخدمات المالية التي ترغب في الحد من قرصنة المحتوى وتسوية الحساب، على التوالي. لسوء الحظ، تعتمد اكتشافات كسر الحماية هذه على مجموعة من الاختبارات المباشرة والقابلة للتهرب نسبيًا، مثل:
يتمثل القيد الأساسي في اختبارات الكشف هذه واختبارات الكشف المماثلة في أنه يمكن للمهاجمين الوصول إليها، باعتبارها اختبارات من جانب العميل، وإجراء هندستها العكسية والتهرب منها. بالإضافة إلى ذلك، يجب أن تخضع التطبيقات التي تجري اختبارات الكشف عن كسر الحماية (مثل تطبيق 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 وC مثل statfs().
سويفت:
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
}
الهدف-ج:
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().
يمكنك التحقق من معالجات البروتوكول من خلال محاولة فتح عنوان URL لـ Cydia. يقوم متجر تطبيقات Cydia، والذي يتم تثبيته افتراضيًا بواسطة كل أدوات كسر الحماية، بتثبيت معالج بروتوكول cydia://.
سويفت:
if let url = URL ( string : " cydia://package/com.example.package " ) , UIApplication . shared . canOpenURL ( url ) {
// Device is jailbroken
}
الهدف-ج:
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 );
}
وفقًا لصفحة دليل القتل ( man 2 kill
)، يتم استخدام الإشارة 0
للتحقق من وجود الرقم التعريفي pid
الموجود في المعلمة الأولى بالفعل.
[…] ومع ذلك، فإن القيمة 0 ستؤدي إلى إجراء فحص الأخطاء (بدون إرسال أي إشارة). يمكن استخدام هذا للتحقق من صحة معرف المنتج.
عملية القتل هذه يتبعها فحص 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
، وقراءة الاستحقاقات وحساب المجموع الاختباري.
يحتوي مقطع توقيع التعليمات البرمجية على بنية superblob، والتي تحتوي في حد ذاتها على كائنات نقطية أخرى من أنواع مختلفة. يتم تعريف هيكل كليهما في بعض أكواد 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 المختلفة في هذا الملف:
/*
* 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
الثنائي على أربع نقاط من المحتوى تتبع النقطة الفائقة الأولية:
وهي على التوالي:
0xfade0c02
)، والذي يمكنك اكتشافه لأنه يحتوي على الاسم الثنائي المؤهل com.apple.ps
فيه.0xfade0c01
).0xfade7171
).0xfade0b01
).حاول إيقاف التطبيق بعد مهلة طويلة ولا تخرج مباشرة من مكان اكتشاف كسر الحماية.
fork()
عملية شوكة. لا يمنع Sandboxd التطبيقات من القدرة على استخدام fork() أو popen() أو أي وظائف C أخرى لإنشاء عمليات فرعية على أجهزة مكسورة الحماية. ومع ذلك، فإن sandboxd ينفي صراحة عملية التفرع على الأجهزة التي لم يتم كسر الحماية فيها. لذلك، من خلال التحقق من pid الذي تم إرجاعه على fork()، يمكن للتطبيق معرفة ما إذا كان الجهاز قد تم اختراقه. إذا نجحت عملية الشوكة، فيمكن للتطبيق استنتاج أنه يعمل على جهاز مكسور الحماية.
system()
سيؤدي استدعاء وظيفة system() باستخدام وسيطة NULL على جهاز غير مكسور الحماية إلى إرجاع 0. سيؤدي القيام بنفس الشيء على جهاز مكسور الحماية إلى إرجاع 1. وذلك لأن الوظيفة ستتحقق مما إذا كان /bin/sh موجودًا، وهو موجود فقط على أجهزة كسر الحماية.
اتصالات الاسترجاع SSH. نظرًا للجزء الكبير جدًا من الأجهزة التي تم كسر حمايتها والتي تم تثبيت OpenSSH عليها، تحاول بعض التطبيقات إجراء اتصال بـ 127.0.0.1 على المنفذ 22. إذا نجح الاتصال، فهذا يعني أنه تم تثبيت OpenSSH وتشغيله، مما يثبت أن الجهاز مكسور الحماية.
تحقق من الاسترجاع لـ 22 منفذًا مفتوحًا (OpenSSH) و44 منفذًا (checkra1n).
تبدأ طريقة الكشف هذه باستدعاء وظائف مثل _dyld_image_count()
و _dyld_get_image_name()
لمعرفة ما هو dylibs الذي تم تحميله حاليًا. من الصعب جدًا تصحيح هذه الطريقة ديناميكيًا نظرًا لأن التصحيحات نفسها جزء من dylibs.
/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
}
بشكل عام، كلما كان اكتشاف كسر الحماية أكثر تعقيدًا، زادت صعوبة اكتشافه وتجاوزه. الخطأ الأكثر شيوعًا عند تنفيذ اكتشاف كسر الحماية غالبًا ما يكمن في التنفيذ نفسه.
غالبًا ما نواجه تطبيقات تتميز باكتشاف رائع لكسر الحماية، ولكن يتم التنفيذ في وظيفة واحدة تُرجع صحيحًا أو خطأ اعتمادًا على ما إذا كان الجهاز مكسور الحماية. في هذه الحالات، نتجاوز اكتشاف كسر الحماية باستخدام 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/