ในฐานะที่เป็นระบบ UNIX ที่สอดคล้องกัน OS X ทำงานร่วมกับไดเรกทอรีที่รู้จักกันดีซึ่งเป็นมาตรฐานในรสชาติ UNIX ทั้งหมด:
OS X เพิ่มไดเรกทอรีพิเศษของตัวเองลงในทรี Unix ภายใต้รากของระบบ:
จากมุมมองของระบบไฟล์ iOS คล้ายกับ OS X มากโดยมีความแตกต่างดังต่อไปนี้:
ไฟล์ที่มีส่วนขยาย. IPA สามารถไม่บีบอัดได้โดยการเปลี่ยนส่วนขยายเป็น. ZIP และคลายซิป
/iTunesArtwork
/iTunesArtwork@2x
/iTunesMetadata.plist
/WatchKitSupport/WK
/META-INF
/Payload/
/Payload/<Application>.app/
/Payload/<Application>.app/<Application> ← Apple FairPlay DRM Encrypted Executable
/Payload/<Application>.app/Info.plist A file that contains some of the application specific configurations
/Payload/<Application>.app/_CodeSignature/ Contains a plist file with a signature over all files in the bundle
/Payload/<Application>.app/Assets.car Another zipped archive that contains assets (icons)
/Payload/<Application>.app/Frameworks/ Contains the app native libraries as .dylib or .framework files
/Payload/<Application>.app/PlugIns/ May contain app extensions as .appex files
/Payload/<Application>.app/Core Data It is used to save permanent data for offline use and sync across iCloud devices
/Payload/<Application>.app/PkgInfo An alternate way to specify the type and creator codes of your application or bundle
/Payload/<Application>.app/en.lproj, etc Language packs that contains resources for those specific languages
/var/containers/Bundle/Application/<UUID> Bundle directory; tampering invalidates signature
/var/mobile/Containers/Data/<UUID> Application runtime data
/var/mobile/Containers/Data/<UUID>/Documents/ Contains all the user-generated data
/var/mobile/Containers/Data/<UUID>/Library/ Contains all files that aren't user-specific – caches, preferences, cookies, plist files
/var/mobile/Containers/Data/<UUID>/Library/Caches/
Contains semi-persistent cached files
/var/mobile/Containers/Data/<UUID>/Library/Application Support/
Contains persistent files necessary for running the app
/var/mobile/Containers/Data/<UUID>/Library/Preferences/<bundle id>.plist
Properties that can persist after an application is restarted. Contains NSUserDefaults
/var/mobile/Containers/Data/<UUID>/tmp/ Temporary files that do not need to persist between app launches
ไฟล์ PLIST เป็นไฟล์ XML ที่มีโครงสร้างที่มี คู่คีย์-ค่า ที่รองรับประเภทวัตถุพื้นฐานเช่นพจนานุกรมรายการตัวเลขและสตริง โดยปกติแล้ววัตถุระดับบนสุดเป็นพจนานุกรม PLIST สามารถเป็นไฟล์ ไบนารี หรือ XML หรือ JSON
| ประเภทนามธรรม | องค์ประกอบ XML | ชั้นโกโก้ | ประเภทรากฐานหลัก |
|---|---|---|---|
| อาร์เรย์ | <array> | NSArray | CFArray ( CFArrayRef ) |
| พจนานุกรม | <dict> | NSDictionary | CFDictionary ( CFDictionaryRef ) |
| สาย | <string> | NSString | CFString ( CFStringRef ) |
| ข้อมูล | <data> | NSData | CFData ( CFDataRef ) |
| วันที่ | <date> | NSDate | CFDate ( CFDateRef ) |
| หมายเลข - จำนวนเต็ม | <integer> | NSNumber ( intValue ) | CFNumber ( CFNumberRef , ค่าจำนวนเต็ม) |
| หมายเลข - จุดลอยตัว | <real> | NSNumber ( floatValue ) | CFNumber ( CFNumberRef , ค่าจุดลอยตัว) |
| บูลีน | <true/> หรือ <false/> | NSNumber ( boolValue == YES หรือ boolValue == NO ) | CFBoolean ( CFBooleanRef ; kCFBooleanTrue หรือ kCFBooleanFalse ) |
Info.plist มาตรฐานมีรายการต่อไปนี้:
plutil -convert xml1 binary_file.plist
plutil -convert xml1 data_file.json -o data_file.plist
https://docs.python.org/3/library/plistlib.html
แอปพลิเคชันผู้ใช้สามารถเข้าถึงการทำงานเป็นผู้ใช้ มือถือ ในขณะที่กระบวนการที่สำคัญของระบบทำงานเป็น รูท อย่างไรก็ตาม Sandbox ช่วยให้สามารถควบคุมการกระทำที่ประมวลผลและแอปพลิเคชันได้ดีขึ้น
ตัวอย่างเช่นแม้ว่าสองกระบวนการทำงานเป็นผู้ใช้ (มือถือ) พวกเขาจะ ไม่ได้รับอนุญาตให้เข้าถึงหรือแก้ไขข้อมูลของกันและกัน
แต่ละแอปพลิเคชันได้รับการติดตั้งภายใต้ /var/mobile/Applications/<UUID> UUID เป็นแบบสุ่ม เมื่อติดตั้งแล้วแอปพลิเคชันจะมีการอ่าน จำกัด การเข้าถึงพื้นที่และฟังก์ชั่นบางอย่าง (SMS โทรศัพท์ ... ) หากแอปพลิเคชันต้องการเข้าถึง พื้นที่ที่ได้รับการป้องกัน จะมีการขออนุญาตจากป๊อปอัพ
นักพัฒนาแอพสามารถใช้ประโยชน์จาก API การป้องกันข้อมูล iOS เพื่อใช้ การควบคุมการเข้าถึงที่ละเอียด สำหรับข้อมูลผู้ใช้ที่เก็บไว้ในหน่วยความจำแฟลช APIs ถูกสร้างขึ้นบน ตัวประมวลผล Enclave ที่ปลอดภัย (SEP) SEP เป็นตัวประมวลผลร่วมที่ให้ บริการการเข้ารหัสลับสำหรับการปกป้องข้อมูลและการจัดการคีย์ คีย์ฮาร์ดแวร์เฉพาะอุปกรณ์- อุปกรณ์ UID (ID ที่ไม่ซ้ำกัน)- ฝังอยู่ในวงล้อมที่ปลอดภัย เพื่อให้มั่นใจถึงความสมบูรณ์ของการปกป้องข้อมูลแม้ว่าเคอร์เนลระบบปฏิบัติการจะถูกบุกรุก
เมื่อไฟล์ถูกสร้างขึ้นบนดิสก์คีย์ AES 256 บิตใหม่จะถูกสร้างขึ้นด้วยความช่วยเหลือของเครื่องกำเนิดหมายเลขสุ่มที่ใช้ฮาร์ดแวร์ของ Secure Enclave เนื้อหาของไฟล์จะถูกเข้ารหัสด้วยคีย์ที่สร้างขึ้น จากนั้นคีย์นี้จะถูกบันทึกเข้ารหัสด้วยคีย์คลาสพร้อมกับ ID คลาสโดยมีข้อมูลทั้งสองที่เข้ารหัสโดยคีย์ของระบบภายในข้อมูลเมตาของไฟล์
สำหรับการถอดรหัสไฟล์ข้อมูลเมตาถูกถอดรหัสโดยใช้คีย์ของระบบ จากนั้นใช้ ID คลาสคีย์คลาสจะถูกเรียกคืนเพื่อถอดรหัสคีย์ต่อไฟล์และถอดรหัสไฟล์
ไฟล์สามารถกำหนดให้กับหนึ่งในสี่คลาสการป้องกันที่แตกต่างกันซึ่งอธิบายรายละเอียดเพิ่มเติมในคู่มือความปลอดภัย iOS
แต่ละแอพมีไดเรกทอรีโฮมที่ไม่ซ้ำกันและเป็น Sandbox เพื่อให้พวกเขาไม่สามารถเข้าถึงทรัพยากรระบบที่ได้รับการป้องกันหรือไฟล์ที่จัดเก็บโดยระบบหรือโดยแอพอื่น ๆ ข้อ จำกัด เหล่านี้ดำเนินการผ่านนโยบาย Sandbox (AKA. โปรไฟล์ ) ซึ่งบังคับใช้โดยกรอบการควบคุมการเข้าถึง BSD (MAC) ที่เชื่อถือได้ผ่านการขยายเคอร์เนล
ความสามารถ/การอนุญาต บางอย่างสามารถกำหนดค่าได้โดยนักพัฒนาของแอป (เช่นการป้องกันข้อมูลหรือการแบ่งปันพวงกุญแจ) และจะมีผลโดยตรงหลังจากการติดตั้ง อย่างไรก็ตามสำหรับผู้อื่น ผู้ใช้จะถูกถามอย่างชัดเจนในครั้งแรกที่แอปพยายามเข้าถึงทรัพยากรที่ได้รับการป้องกัน
สตริงวัตถุประสงค์ หรือ คำอธิบายการใช้งานสตริง เป็นข้อความที่กำหนดเองที่เสนอให้กับผู้ใช้ในการแจ้งเตือนคำขออนุญาตของระบบเมื่อขออนุญาตเข้าถึงข้อมูลที่ได้รับการป้องกันหรือทรัพยากร
หากมีซอร์สโค้ดดั้งเดิมคุณสามารถตรวจสอบสิทธิ์ที่รวมอยู่ในไฟล์ Info.plist :
Info.plist ในตัวแก้ไขเริ่มต้นและค้นหาคีย์ที่เริ่มต้นด้วย "Privacy -" คุณสามารถสลับมุมมองเพื่อแสดงค่าดิบโดยคลิกขวาและเลือก "แสดงคีย์/ค่าดิบ" (วิธีนี้เช่น "Privacy - Location When In Use Usage Description" จะเปลี่ยนเป็น NSLocationWhenInUseUsageDescription มีการบันทึก
ถ้ามี IPA เท่านั้น:
Info.plist อยู่ใน Payload/<appname>.app/Info.plistplutil -convert xml1 Info.plist ) ตามที่อธิบายไว้ในบทที่ "การทดสอบความปลอดภัยขั้นพื้นฐาน iOS", ส่วน "ไฟล์ info.plist"UsageDescription : <plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is used to provide turn-by-turn directions to your destination.</string>
App Store ใช้ความสามารถของอุปกรณ์เพื่อให้แน่ใจว่ามีเฉพาะอุปกรณ์ที่เข้ากันได้เท่านั้นและได้รับอนุญาตให้ดาวน์โหลดแอพ พวกเขาจะระบุไว้ในไฟล์ Info.plist ของแอพภายใต้ [UIRequiredDeviceCapabilities](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/plist/info/UIRequiredDeviceCapabilities) สำคัญ.
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
โดยทั่วไปแล้วคุณจะพบความสามารถของ ARMV7 ซึ่งหมายความว่าแอพนั้นรวบรวมไว้สำหรับชุดคำสั่ง ARMV7 เท่านั้นหรือหากเป็นแอพสากล 32/64 บิต
ตัวอย่างเช่นแอปอาจขึ้นอยู่กับ NFC อย่างสมบูรณ์ในการทำงาน (เช่นแอป "แท็กแท็ก NFC") จากการอ้างอิงความเข้ากันได้ของอุปกรณ์ iOS ที่เก็บถาวร NFC มีให้เฉพาะใน iPhone 7 (และ iOS 11) นักพัฒนาอาจต้องการยกเว้นอุปกรณ์ที่เข้ากันไม่ได้ทั้งหมดโดยการตั้งค่าความสามารถของอุปกรณ์ nfc
การให้สิทธิ์เป็นคู่ค่าคีย์ที่ลงชื่อเข้าใช้แอพและอนุญาตให้มีการรับรองความถูกต้องเกินกว่าปัจจัยรันไทม์เช่นรหัสผู้ใช้ UNIX เนื่องจากการลงนามในการลงนามแบบดิจิทัลจึงไม่สามารถเปลี่ยนแปลงได้ การให้สิทธิ์ถูกใช้อย่างกว้างขวางโดยแอพระบบและ Daemons เพื่อดำเนินการเฉพาะที่มีสิทธิพิเศษซึ่งจะต้องใช้กระบวนการในการทำงานเป็นรูท สิ่งนี้จะช่วยลดศักยภาพในการเพิ่มสิทธิพิเศษโดยแอพระบบหรือ Daemon ที่ถูกบุกรุก
ตัวอย่างเช่นหากคุณต้องการตั้งค่าความสามารถ "การปกป้องข้อมูลเริ่มต้น" คุณจะต้องไปที่แท็บ ความสามารถ ใน XCode และเปิดใช้งาน การป้องกันข้อมูล สิ่งนี้เขียนโดยตรงโดย XCode ไปยังไฟล์ <appname>.entitlements เป็น com.apple.developer.default-data-protection การให้สิทธิ์ด้วยค่าเริ่มต้น NSFileProtectionComplete ใน IPA เราอาจพบสิ่งนี้ใน embedded.mobileprovision เป็น:
<key>Entitlements</key>
<dict>
...
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
</dict>
สำหรับความสามารถอื่น ๆ เช่น HealthKit ผู้ใช้จะต้องได้รับอนุญาตดังนั้นจึงไม่เพียงพอที่จะเพิ่มสิทธิ์การใช้งานคีย์พิเศษและสตริงจะต้องเพิ่มลงในไฟล์ Info.plist ของแอพ
Enclave ที่ปลอดภัย เป็นส่วนหนึ่งของ A7 และ SOC ใหม่ที่ใช้สำหรับการปกป้องข้อมูล, Touch ID และ ID ใบหน้า วัตถุประสงค์ของวงล้อมที่ปลอดภัยคือการจัดการคีย์และข้อมูลอื่น ๆ เช่นชีวภาพที่มีความอ่อนไหวพอที่จะไม่ได้รับการจัดการโดยโปรเซสเซอร์แอปพลิเคชัน มันถูกแยกด้วยตัวกรองฮาร์ดแวร์เพื่อให้ AP ไม่สามารถเข้าถึงได้ มันแบ่งปัน RAM กับ AP แต่ส่วนของ RAM - TZ0 ถูกเข้ารหัส Enclave ที่ปลอดภัยนั้นเป็นแกนโปรเซสเซอร์ 4MB AKF ที่ฉับพลันเรียกว่า Secure Enclave Processor (SEP) เทคโนโลยีที่ใช้นั้นคล้ายกับ Trustzone/Securcore ของ ARM แต่มีรหัสที่เป็นกรรมสิทธิ์สำหรับแกน Apple KF โดยทั่วไปและ SEP โดยเฉพาะ
SOC ในแต่ละอุปกรณ์มีตัวประมวลผลร่วม AES พร้อม คีย์ GID และ คีย์ UID ในตัว
ID ที่ไม่ซ้ำกันของอุปกรณ์ (UID) และ ID กลุ่มอุปกรณ์ (GID) เป็นปุ่ม AES 256 บิตที่หลอมรวม (UID) หรือคอมไพล์ (GID) ลงในโปรเซสเซอร์แอปพลิเคชันระหว่างการผลิต ไม่มีซอฟต์แวร์หรือเฟิร์มแวร์สามารถอ่านได้โดยตรง พวกเขาสามารถเห็นได้เฉพาะผลลัพธ์ของการเข้ารหัสหรือการถอดรหัสที่ดำเนินการโดยใช้พวกเขา UID นั้นไม่ซ้ำกันสำหรับอุปกรณ์แต่ละตัวและไม่ได้บันทึกโดย Apple หรือซัพพลายเออร์ใด ๆ GID เป็นเรื่องธรรมดาสำหรับโปรเซสเซอร์ทั้งหมดในคลาสของอุปกรณ์และใช้เป็นระดับการป้องกันเพิ่มเติมเมื่อส่งมอบซอฟต์แวร์ระบบในระหว่างการติดตั้งและกู้คืน การรวมปุ่มเหล่านี้เข้ากับซิลิคอนช่วยป้องกันไม่ให้พวกเขาถูกดัดแปลงหรือบายพาสหรือเข้าถึงนอกเครื่องยนต์ AES
คีย์ GID ( คีย์ ID กลุ่ม ) เป็นคีย์ AES 256 บิตที่ใช้ร่วมกันโดยอุปกรณ์ทั้งหมดที่มีตัวประมวลผลแอปพลิเคชันเดียวกัน คีย์ GID เป็นส่วนหนึ่งของวิธีการที่ iOS เข้ารหัสซอฟต์แวร์บนอุปกรณ์ นี่คือองค์ประกอบหนึ่งของระบบรักษาความปลอดภัย iOS ซึ่งรวมถึงลายเซ็น SHSH คีย์นี้แตกต่างกันไปในแต่ละรุ่น Apple SoC
คีย์ GID นั้นยังไม่ได้รับการสกัดจากอุปกรณ์ใด ๆ ดังนั้นวิธีเดียวที่จะใช้มันคือการผ่านเครื่องยนต์ AES เอง
แต่
GID สามารถรับได้ ผ่านขั้นตอนการโจมตีบูตเย็นราคาแพง (https://en.m.wikipedia.org/wiki/cold_boot_attack) และขั้นตอนต่อไปของการสแกน SociTHEN-BEAM/THEMMETHER การทดลองดังกล่าวมีราคาแพงและซับซ้อนอย่างไม่ยุติธรรมดังนั้นจึงไม่เคยเกิดขึ้นกับทุกคนที่จะพยายามนำไปใช้ยกเว้นห้องปฏิบัติการส่วนตัว Cellebrite Cellebrite ไม่แบ่งปันงานวิจัย
คีย์ UID ( คีย์ ID ที่ไม่ซ้ำกันของอุปกรณ์ ) เป็นคีย์ฮาร์ดแวร์ AES 256 บิตซึ่งไม่ซ้ำกันสำหรับแต่ละ iPhone
คีย์ที่ได้รับบางส่วนถูกคำนวณโดยบริการเคอร์เนล IOAESACCELERATOR ที่ BOOT คีย์เหล่านี้ถูกสร้างขึ้นโดยการเข้ารหัสค่าคงที่ทั้งด้วยคีย์ UID (0x7d0 ตัวระบุ) หรือคีย์ GID (ตัวระบุ 0x3e8)
คีย์ 0x835- สร้างขึ้นโดยการเข้ารหัส 0x01010101010101010101010101010101 ด้วย UID-key ใช้สำหรับการปกป้องข้อมูล
คีย์ 0x836- สร้างโดยการเข้ารหัส 0x00E5A0E6526FAE66C5C1C6D4F16D6180 ด้วย UID-KEY นี่คือการคำนวณโดยเคอร์เนลในระหว่างการกู้คืน แต่เป็นศูนย์ในระหว่างการบูตปกติ นอกจากนี้ยังคำนวณโดย bootloader ที่ปลอดภัยและการใช้งานที่รู้จักเพียงอย่างเดียวคือการถอดรหัส LLB ใน NOR เช่น 0x835 มันแตกต่างกันสำหรับแต่ละอุปกรณ์
คีย์ 0x837 - สร้างโดยการเข้ารหัส 0x345A2D6C5050D058780DA431F0710E15 ด้วยคีย์ S5L8900 GID ส่งผลให้ 0x188458A6D15034DFE386F23B61D43774 มันถูกใช้เป็นคีย์การเข้ารหัสสำหรับไฟล์ IMG2 ด้วยการแนะนำ IMG3 ใน iPhone OS 2.0 ตอนนี้ KBAG จะถูกใช้แทนคีย์ 0x837 เนื่องจาก iPhone OS เวอร์ชัน 1.x ใช้เฉพาะบน iPhone และ iPod touch (ทั้งสองใช้ S5L8900) ค่าที่เข้ารหัสสำหรับโปรเซสเซอร์อื่น ๆ จึงไม่สำคัญ
คีย์ 0x838- สร้างขึ้นโดยการเข้ารหัส 0x8C8318A27D7F030717D2B8FC5514F8E1 กับ UID-key อีกคีย์ที่ใช้ UID-AES-Key ใช้ในการเข้ารหัสทุกอย่างยกเว้น LLB ใน NOR (iboot, Devicetree, รูปภาพ)
คีย์ 0x899- สร้างโดยการเข้ารหัส 0xD1E8FCB53937BF8DEFC74CD1D0F1D4B0 ด้วย UID-Key ไม่ทราบการใช้งาน
คีย์ 0x89a- สร้างขึ้นโดยการเข้ารหัส 0xDB1F5B33606C5F1C1934AA66589C0661 ด้วย UID-key รับคีย์เฉพาะอุปกรณ์ ใช้กับอุปกรณ์ A4 มันถูกใช้เพื่อเข้ารหัส shsh blobs บนอุปกรณ์
คีย์ 0x89b- สร้างโดยการเข้ารหัส 0x183E99676BB03C546FA468F51C0CBD49 ด้วย UID-KEY มันถูกใช้เพื่อเข้ารหัสคีย์พาร์ติชันข้อมูล
คีย์ 0x8a3- สร้างโดยการเข้ารหัส 0x568241656551e0cdf56ff84cc11a79ef กับ UID-KEY (ใช้ AES-256-CBC) มันถูกใช้ในระหว่างการอัพเกรดซอฟต์แวร์ใน A12 และต่อมาเพื่อเข้ารหัสค่า "เครื่องกำเนิดไฟฟ้า" (โดยใช้ AES-128-CBC) ก่อนที่จะ hashing มันจะกลายเป็น nonce
ข้อมูลเพิ่มเติม: https://css.csail.mit.edu/6.858/2020/readings/ios-security-may19.pdf
https://www.securitylab.ru/contest/428454.php
https://www.securitylab.ru/contest/429973.php
ไฟล์โมดูล Objective-C มีส่วนขยาย“ .m” (ถ้าใช้การผสมผสานของ C ++ และ Objective-C ส่วนขยาย“ .mm” ส่วนขยาย) ไฟล์ส่วนหัว -“ .h” วัตถุทั้งหมดของคลาสที่สร้างขึ้นใน Objective-C ต้องจัดสรรในกอง ดังนั้นประเภท ID ซึ่งเป็นตัวชี้ไปยังวัตถุของคลาสใด ๆ (อันที่จริงแล้วโมฆะ *) ได้รับความสำคัญเป็นพิเศษ ตัวชี้โมฆะเรียกว่าไม่มีค่าคงที่ ดังนั้นตัวชี้ไปยังชั้นเรียนใด ๆ สามารถส่งไปยังประเภท ID ปัญหาเกิดขึ้น: วิธีการค้นหาว่าวัตถุที่ซ่อนอยู่ภายใต้ ID เป็นของคลาสใด สิ่งนี้ทำได้ด้วย ISA Invariant ซึ่งมีอยู่ในวัตถุใด ๆ ของคลาสที่สืบทอด NSObject คลาสพื้นฐานพิเศษ (คำนำหน้า NS ย่อมาจากขั้นตอนต่อไป) ISA Invariant เป็นคลาสประเภทที่สงวนไว้ วัตถุประเภทนี้ช่วยให้คุณสามารถค้นหาชื่อของตัวเองและคลาสพื้นฐานชุดของค่าคงที่คลาสรวมถึงต้นแบบของวิธีการทั้งหมดที่วัตถุนี้นำไปใช้และที่อยู่ของพวกเขา (ผ่านรายการตัวเลือกท้องถิ่น) คำที่สงวนไว้โดยวัตถุประสงค์ทั้งหมดนอกเหนือจากคำที่สงวนไว้ C เริ่มต้นด้วยสัญลักษณ์ @(เช่น @protocol, @Selector, @Interface) โดยทั่วไปชื่อของค่าคงที่คลาสที่กำหนดไว้ (@private, @protected) เริ่มต้นด้วยขีดเส้นใต้ สำหรับสตริงโกโก้มีคลาส NSSTRING ที่มีประโยชน์มาก ค่าคงที่สตริงของคลาสนี้เขียนเป็น @"Hello World" และไม่เป็นค่าคงที่ C ปกติของสตริง "Hello World" ประเภทบูล (ถ่านที่ไม่ได้ลงนามเป็นหลัก) สามารถใช้ค่าคงที่ใช่และไม่ใช่ คำที่สงวนไว้เฉพาะวัตถุประสงค์ C-specific (ซึ่งแตกต่างจากภาษา C และพบได้ในไฟล์ส่วนหัว OBJC/OBJC.H) แสดงอยู่ด้านล่าง:
@interface เริ่มประกาศคลาสหรือหมวดหมู่ (หมวดหมู่คือการขยายคลาสโดยไม่มีการสืบทอด)
@end เสร็จสิ้นการประกาศ นิยามของคลาสหมวดหมู่หรือโปรโตคอลใด ๆ
@private จำกัด ขอบเขตของค่าคงที่คลาสกับวิธีการเรียน (คล้ายกับ C ++)
@protected ยืนโดยค่าเริ่มต้น จำกัด ขอบเขตของค่าคงที่คลาสกับวิธีการเรียนและวิธีการเรียนที่ได้รับ (คล้ายกับ C ++)
@public ลบข้อ จำกัด การกำหนดขอบเขต (คล้ายกับ C ++)
@try กำหนดบล็อกที่มีข้อยกเว้นที่เป็นไปได้ (คล้ายกับ C ++)
@throw พ่นวัตถุข้อยกเว้น (คล้ายกับ C ++)
@catch() จัดการข้อยกเว้นที่โยนในบล็อก @Try ก่อนหน้า (คล้ายกับ C ++)
@finally กำหนดบล็อกหลังจากบล็อก @Try ซึ่งการควบคุมผ่านไม่ว่าจะมีข้อยกเว้นหรือไม่ก็ตาม
@class ตัวย่อรูปแบบของการประกาศคลาส (ชื่อเท่านั้น (คล้ายกับ C ++))
@selector(method_name) ส่งคืนตัวเลือกที่คอมไพล์สำหรับชื่อเมธอด method_name
@protocol(protocol_name) ส่งคืนอินสแตนซ์ของคลาสโปรโตคอลชื่อ protocol_name
@encode(type_spec) เริ่มต้นสตริงอักขระที่จะใช้ในการเข้ารหัสข้อมูลประเภท type_spec
@synchronized() กำหนดบล็อกของรหัสที่ดำเนินการโดยเธรดเดียว ณ เวลาใดก็ตาม
@implementation เริ่มกำหนดคลาสหรือหมวดหมู่
@protocol เริ่มการประกาศโปรโตคอล (คล้ายกับคลาส C ++ ที่ประกอบด้วยฟังก์ชั่นเสมือนจริง)
ในการบังคับให้วัตถุดำเนินการวิธีการคุณต้องส่งข้อความที่มีชื่อเหมือนกับวิธีการที่ต้องการ ข้อความนี้เรียกว่าตัวเลือกวิธีการ ไวยากรณ์สำหรับการส่งมีดังนี้:
[receiver method];
- (void) addObject: (id) otherObject;
หากคุณใส่เครื่องหมายบวก + ที่จุดเริ่มต้นของต้นแบบวิธีการแล้ววิธีการดังกล่าวจะได้รับการพิจารณาเป็นวิธีการเรียนและโดยธรรมชาติจะไม่ยอมรับพารามิเตอร์ตนเองโดยนัย (ซึ่งคล้ายกับการประกาศวิธีการคงที่ใน C ++) และหากไม่มี ISA คงที่ของวัตถุที่ชี้ไปด้วยตัวเองตัวชี้ซูเปอร์แน่นอนก็จะไม่ทำงานเช่นกัน ดังนั้นต้นแบบของวิธีการใด ๆ จึงถูกประกาศเช่นนี้:
- | + (<return type>) mainMethodNamePart
[: (<type of first parameter>) nameOfFirstFormalParameter
[[optionalMethodNamePart]: (<type of second parameter>) secondFormalParameterName] ...
]
ตัวอย่างเช่น:
+ (Class)class;
+ (id)alloc;
- (id)init;
- (void)addObject: (id)anObject;
+ (NSString *)stringWithCString: (const char*)aCString usingUncoding: (enum NSStringEncoding)encoding;
- (NSString *)initStringWithFormat: (NSString *)format, ...;
เอกสารการพัฒนาของ Apple
https://developer.apple.com/library/archive/documentation/macosx/conceptual/osx_technology_overview/systemframeworks/systemframeworks.html
https://www.theiphonewiki.com/wiki//system/library/frameworks
เฟรมเวิร์กจะถูกเก็บไว้ในหลาย ๆ ตำแหน่งในระบบไฟล์:
นอกจากนี้แอปพลิเคชันอาจรวมถึงกรอบของตนเอง
เอกสารการพัฒนาของ Apple - เครือข่าย
เอกสารประกอบการพัฒนาของ Apple - NetWorkextension
เอกสารการพัฒนาของ Apple - NetworkingDriverkit
แอพส่วนใหญ่ที่คุณอาจพบเชื่อมต่อกับปลายทางระยะไกล แม้กระทั่งก่อนที่คุณจะทำการวิเคราะห์แบบไดนามิกใด ๆ (เช่นการจับภาพและการวิเคราะห์การจราจร) คุณสามารถรับอินพุตเริ่มต้นหรือจุดเริ่มต้นได้โดยการระบุโดเมนที่แอปพลิเคชันควรสื่อสาร
โดยทั่วไปโดเมนเหล่านี้จะปรากฏเป็นสตริงภายในไบนารีของแอปพลิเคชัน หนึ่งสามารถแยกโดเมนโดยการดึงสตริงด้วย rabin2 -zz <path_to_binary> หรือใน IDA Pro ตัวเลือกหลังมีข้อได้เปรียบที่ชัดเจน: มันสามารถให้บริบทแก่คุณได้เนื่องจากคุณจะสามารถดูได้ว่าบริบทแต่ละโดเมนจะถูกใช้โดยการตรวจสอบการอ้างอิงข้าม
จากที่นี่คุณสามารถใช้ข้อมูลนี้เพื่อรับข้อมูลเชิงลึกมากขึ้นซึ่งอาจใช้ในภายหลังในระหว่างการวิเคราะห์ของคุณเช่นคุณสามารถจับคู่โดเมนกับใบรับรองที่ตรึงหรือดำเนินการลาดตระเวนเพิ่มเติมในชื่อโดเมนเพื่อทราบข้อมูลเพิ่มเติมเกี่ยวกับสภาพแวดล้อมเป้าหมาย
การใช้งานและการตรวจสอบการเชื่อมต่อที่ปลอดภัยอาจเป็นกระบวนการที่ซับซ้อนและมีหลายแง่มุมที่ต้องพิจารณา ตัวอย่างเช่นแอปพลิเคชันจำนวนมากใช้โปรโตคอลอื่น ๆ นอกเหนือจาก HTTP เช่น XMPP หรือแพ็กเก็ต TCP ธรรมดาหรือดำเนินการปักหมุดใบรับรองในความพยายามที่จะยับยั้งการโจมตี MITM
เฟรมเวิร์กเครือข่ายได้รับการแนะนำในการประชุม Apple Worldwide Developers Conference (WWDC) ในปี 2561 และเป็นการแทนที่ Sockets API เฟรมเวิร์กเครือข่ายระดับต่ำนี้ให้คลาสเพื่อส่งและรับข้อมูลด้วยการสนับสนุนเครือข่ายแบบไดนามิกการรักษาความปลอดภัยและประสิทธิภาพในตัว
TLS 1.3 ถูกเปิดใช้งานโดยค่าเริ่มต้นในเฟรมเวิร์กเครือข่ายหากอาร์กิวเมนต์ using: .tls ถูกใช้ มันเป็นตัวเลือกที่ต้องการมากกว่ากรอบการขนส่งที่ปลอดภัยมรดก
URLSession ถูกสร้างขึ้นบนเฟรมเวิร์กเครือข่ายและใช้บริการขนส่งเดียวกัน คลาสยังใช้ TLS 1.3 โดยค่าเริ่มต้นหากจุดสิ้นสุดคือ HTTPS
URLSession ควรใช้สำหรับการเชื่อมต่อ HTTP และ HTTPS แทนที่จะใช้เฟรมเวิร์กเครือข่ายโดยตรง ชั้นเรียนสนับสนุนทั้งสองโครงการ URL และได้รับการปรับให้เหมาะสมสำหรับการเชื่อมต่อดังกล่าว ต้องใช้รหัสหม้อไอน้ำน้อยลงลดความชอบสำหรับข้อผิดพลาดและสร้างความมั่นใจในการเชื่อมต่อที่ปลอดภัยโดยค่าเริ่มต้น ควรใช้เฟรมเวิร์กเครือข่ายเมื่อมีข้อกำหนดเครือข่ายระดับต่ำและ/หรือขั้นสูง
เอกสารอย่างเป็นทางการของ Apple รวมถึงตัวอย่างของการใช้เฟรมเวิร์กเครือข่ายเพื่อใช้งาน NetCat และ URLSession เพื่อดึงข้อมูลเว็บไซต์ลงในหน่วยความจำ
https://developer.limneos.net/
https://www.theiphonewiki.com/wiki//system/library/privateframeworks
เครื่องมือล่าสุดสำหรับอุปกรณ์ของคุณสามารถพบได้ที่นี่ https://canijailbreak.com
งานวิจัยนี้เขียนขึ้นโดยทั่วไปสำหรับ checkra1ned iPhones 5S ถึง X พร้อม iOS 10–15 และสามารถอัปเดตในระยะยาวหากเครื่องมือ bootrom pwnage ใหม่จะถูกปล่อยออกมา ตรวจสอบ https://www.theiphonewiki.com/wiki/bootrom#bootrom_exploits
https://repo.chariz.com )killall SpringBoardเปิดไฟล์. deb/.ipa พร้อมตัวจัดการไฟล์ filza และกดติดตั้งหากคุณเห็นข้อผิดพลาดด้วย. deb การติดตั้งลองค้นหาและติดตั้งการอ้างอิงทั้งหมด
ติดตั้ง AppSync Unified จาก https://cydia.akemi.ai/ repo
https://apt.bingner.com/
https://apt.thebigboss.org/repofiles/cydia/
https://cydia.saurik.com
https://repo.dynastic.co/
https://getdelta.co/
https://cokepokes.github.io/
https://cydia.akemi.ai/
https://nscake.github.io/
https://repo.chariz.com/
https://mrepo.org/
https://rejail.ru/
https://repo.hackyouriphone.org/
https://build.frida.re/ - Frida
https://cydia.radare.org/ - radare2
ติดตั้งบนเดสก์ท็อป
brew install libimobiledevice ideviceinstaller libirecovery
sudo port install idevicerestore
idevice_id รายการอุปกรณ์ที่แนบมาหรือชื่ออุปกรณ์พิมพ์ของอุปกรณ์ที่กำหนด idevicebackup สร้างหรือกู้คืนการสำรองข้อมูลสำหรับอุปกรณ์ idevicedebug มรดก idevicecrashreport idevicebackup2 สร้างหรือกู้คืนการสำรองข้อมูลสำหรับ idevicedebugserverproxy ที่ใช้งาน iOS 4 หรือใหม่ การดีบักระยะ idevicescreenshot idevicediagnostics โต้ตอบกับส่วนต่อประสานการวินิจฉัยของอุปกรณ์ ideviceenterrecovery ทำให้อุปกรณ์เข้าสู่โหมดการกู้คืน ideviceimagemounter ภาพเมา idevicename บนดิสก์บนอุปกรณ์ ideviceinfo แสดงข้อมูลเกี่ยวกับอุปกรณ์ที่เชื่อมต่ออุปกรณ์ idevicepair idevicesetlocation จำลองตำแหน่งบนอุปกรณ์ idevicesyslog รีเลย์ syslog ของอุปกรณ์ที่เชื่อมต่อ
ideviceinstaller --list-apps
ideviceinstaller --install <Application.ipa>
ideviceinstaller --uninstall <bundle id>
idevicedebug -d run <bundle id>
irecovery --shell อนุญาตให้สื่อสารกับ iBoot/IBSS ของอุปกรณ์ iOS
idevicerestore --latest การคืนค่าเฟิร์มแวร์ใหม่ให้กับอุปกรณ์ idevicerestore --erase --latest
บังคับให้กู้คืนด้วยการลบข้อมูลทั้งหมด
Utility inetcat เพื่อเปิดเผยการเชื่อมต่อแบบดิบกับอุปกรณ์ iproxy 2222:22 ผูกพอร์ตท้องถิ่น 2222 และส่งต่อไปยัง 22 ของอุปกรณ์ USB ตัวแรก
ติดตั้งบนอุปกรณ์ถ่ายเอกสารไฟล์ Apple "2"
ใช้ iMazing หรือ ifunbox เพื่อเข้าถึงระบบไฟล์
ติดตั้ง Filza File Manager
ติดตั้ง openssh บนอุปกรณ์และทำงานบนเดสก์ท็อป:
iproxy 2222:22
ssh -p 2222 root@localhost
รหัสผ่าน iOS เริ่มต้นสำหรับ root คือ alpine อย่าเปลี่ยนถ้าคุณมีหน่วยความจำที่ไม่ดี
ติดตั้งบนอุปกรณ์ newterm 2 จาก https://repo.chariz.com เพื่อใช้เทอร์มินัลท้องถิ่น
cd /private/var/containers/Bundle/Application/<guid>/myapp.app
// Contains compiled code, statically linked files, compressed NIB files.
cd /private/var/mobile/Containers/Data/Application/
ls -lrt // Your freshly installed IPA is at the bottom of list
cd [app guid]/Documents/
cd [app guid]/Library/
/private/var/Keychains
TrustStore.sqlite3
keychain-2.db
pinningrules.sqlite3
// Extract IPA (whether App Store encrypted or not)
scp -r -P 2222 root@localhost:/var/containers/Bundle/Application/<app GUID>/hitme.app ~/hitme.app
// Different to SSH, the uppercase P for Port with SCP. Order important.
scp -P 2222 root@localhost:/var/root/overflow.c localfilename.c
// from Jailbroken device to local machine
// Caution:no space after the root@localhost: Otherwise you copy the entire filesystem!
scp -P 2222 root@localhost:/private/var/mobile/Containers/Data/Application/<App GUID>/Library/Caches/Snapshots/com.my.app
// from local machine to remote Jailbroken device
scp -P 2222 hello.txt root@localhost:/var/root/
ติดตั้ง libflex และ flexing จาก https://nscake.github.io/
เปิด Newterm และเรียกใช้ killall SpringBoard
ตอนนี้คุณสามารถโหลด Flex ภายในแอปพลิเคชันใด ๆ โดย LongPress บนแถบสถานะ
Frida เป็นชุดเครื่องมือเครื่องมือไบนารีแบบไดนามิกที่ช่วยให้เราสามารถเรียกใช้สคริปต์ในซอฟต์แวร์ที่ล็อคไว้ก่อนหน้านี้ โดยสรุป Frida ช่วยให้คุณฉีดตัวอย่าง JavaScript ลงในแอพดั้งเดิมบน Windows, Mac, Linux, iOS และ Android
เพิ่ม frida repo ไปยัง Cydia - https://build.frida.re/
ถ้าคุณไม่มี Python 3:
brew install pyenv
pyenv install 3.9.0 (หรือล่าสุด)
จากนั้นติดตั้ง
pip3 install frida-tools
frida-ls-devices LIST
frida-ps -U แสดงรายการชื่อกระบวนการและ PID ทั้งหมดบนอุปกรณ์ USB
frida-ps -Uai รายการแอพที่ติดตั้งทั้งหมดบนอุปกรณ์ USB
frida-ps -Ua รายการแอพที่กำลังทำงานอยู่ทั้งหมดบนอุปกรณ์ USB
frida-ls-devices รายการอุปกรณ์ที่แนบมาทั้งหมด
frida-ps -D 0216027d1d6d3a03 เชื่อมต่อ Frida กับอุปกรณ์เฉพาะ
เครื่องมือ frida-discover สำหรับการค้นหาฟังก์ชั่นภายในในกระบวนการ
frida-trace -U Twitter -i "*URL*" ติดตาม API พื้นเมือง
frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"
เรียกใช้แอพและการโทร Crypto API
frida-trace -U Twitter -m "-[NSURL* *HTTP*]" การติดตาม Objective-C apis
frida -U -n Twitter -l inject.js ฉีด สคริปต์ เข้าสู่กระบวนการบนอุปกรณ์ USB ผ่าน REPL
frida -n cat เชื่อมต่อกับ Cat ตามชื่อ
frida -f foobar Force Open Foobar
frida -U -f foobar --no-pause เปิด foobar ผ่าน USB และ Force Start เริ่มใช้แอพที่กำลังทำงานอยู่
frida-ps -U | grep -i myapp รับรหัสกระบวนการของแอพเป้าหมายจากอุปกรณ์ที่เชื่อมต่อ USB
frida -U -f foobar --no-pause -q --eval 'console.log("Hi Frida");'
เรียกใช้สคริปต์และออกจาก Frida
ณ จุดนี้เรามี NativeFunction ของเราที่เก็บไว้ในตัวแปร play_sound เรียกมันเหมือนฟังก์ชั่นปกติ play_sound() และจำไว้ว่าให้พารามิเตอร์อินพุต ( int ): play_sound(1007)
รวมเข้าด้วยกัน:
var address = Module.findExportByName('AudioToolbox', 'AudioServicesPlaySystemSound')
var play_sound = new NativeFunction(address, 'void', ['int'])
play_sound(1007)
คุณต้องได้รับอินสแตนซ์ของวัตถุก่อนเช่นกัน:
var instance = ObjC.classes.ClassName.alloc().init();ObjC.choose , like - if you know there's only one instance already created somewhere on the heap - you can to something like var instance = ObjC.chooseSync(ObjC.classes.ClassName)[0];var instance = ObjC.classes.MySingleton.getInstance().myInterestingInstance();and then call the method on the instance:
instance.setSomething();
or, if the method signature takes an argument, like - setSomething: , you can also pass the argument (just remember to put a _ instead of ObjC's : ):
instance.setSomething_(argument);
frida -U "My App" // Attach Frida to app over USB
Process.id
419
Process.getCurrentThreadId()
3843
var b = "hello frida"
console.log(b)
"hello frida"
c = Memory.allocUtf8String(b)
"0x1067ec510"
Memory.readUtf8String(c)
"hello frida"
console.log(c)
0x1067ec510
console.log(c.readUtf8String(5))
hello
console.log(c.readUtf8String(11))
hello frida
ptrToC = new NativePointer(c);
"0x1067ec510"
console.log(ptrToC)
0x1067ec510
console.log(ptrToC.readCString(8))
hello fr
Memory.readUtf8String(ptrToC)
"hello frida"
Objective-C's syntax includes the : and @ characters. These characters were not used in the Frida Javascript API .
// Attach to playground process ID
frida -p $(ps -ax | grep -i -m1 playground |awk '{print $1}')
ObjC.available
true
ObjC.classes.UIDevice.currentDevice().systemVersion().toString()
"11.1"
ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String()
ObjC.classes.UIWindow.keyWindow().toString()
RET: <WKNavigation: 0x106e165c0>
// shows Static Methods and Instance Methods
ObjC.classes.NSString.$ownMethods
ObjC.classes.NSString.$ivars
var myDate = ObjC.classes.NSDate.alloc().init()
console.log(myDate)
2019-04-19 19:03:46 +0000
myDate.timeIntervalSince1970()
1555700626.021566
myDate.description().toString()
"2019-04-19 19:03:46 +0000"
var a = ObjC.classes.NSUUID.alloc().init()
console.log(a)
4645BFD2-94EE-413D-9CE5-8982D41ED6AE
a.UUIDString()
{
"handle": "0x7ff3b2403b20"
}
a.UUIDString().toString()
"4645BFD2-94EE-413D-9CE5-8982D41ED6AE"
var b = ObjC.classes.NSString.stringWithString_("foo");
b.isKindOfClass_(ObjC.classes.NSString)
true
b.isKindOfClass_(ObjC.classes.NSUUID)
false
b.isEqualToString_("foo")
true
b.description().toString()
"foo"
var c = ObjC.classes.NSString.stringWithFormat_('foo ' + 'bar ' + 'lives');
console.log(c)
foo bar lives
var url = ObjC.classes.NSURL.URLWithString_('www.foobar.com')
console.log(url)
www.foobar.com
url.isKindOfClass_(ObjC.classes.NSURL)
true
console.log(url.$class)
NSURL
var b = ObjC.classes.NSString.stringWithString_("foo");
var d = ObjC.classes.NSData
d = b.dataUsingEncoding_(1) // NSASCIIStringEncoding = 1, NSUTF8StringEncoding = 4,
console.log(d)
<666f6f> // This prints the Hex value "666f6f = foo"
d.$className
"NSConcreteMutableData"
var x = d.CKHexString() // Get you the Byte array as a Hex string
console.log(x)
666f6f
x.$className
"NSTaggedPointerString"
var newStr = ObjC.classes.NSString.stringWithUTF8String_[d.bytes]
// demoapp is the iOS app name
myapp=$(ps x | grep -i -m1 demoapp | awk '{print $1}')
frida-trace -i "getfsent*" -p $myapp
// Connect to process with Frida script
frida --codeshare mrmacete/objc-method-observer -p 85974
Process.enumerateModules()
// this will print all loaded Modules
Process.findModuleByName("libboringssl.dylib")
{
"base": "0x1861e2000",
"name": "libboringssl.dylib",
"path": "/usr/lib/libboringssl.dylib",
"size": 712704
}
Process.findModuleByAddress("0x1c1c4645c")
{
"base": "0x1c1c2a000",
"name": "libsystem_kernel.dylib",
"path": "/usr/lib/system/libsystem_kernel.dylib",
"size": 200704
}
DebugSymbol.fromAddress(Module.findExportByName(null, 'strstr'))
{
"address": "0x183cb81e8",
"fileName": "",
"lineNumber": 0,
"moduleName": "libsystem_c.dylib",
"name": "strstr"
}
Module.findExportByName(null, 'strstr')
"0x183cb81e8"
Module.getExportByName(null,'strstr')
"0x183cb81e8"
Process.findModuleByAddress("0x183cb81e8")
{
"base": "0x183cb6000",
"name": "libsystem_c.dylib",
"path": "/usr/lib/system/libsystem_c.dylib",
"size": 516096
}
a = Process.findModuleByName("Reachability")
a.enumerateExports()
....
{
"address": "0x102fab020",
"name": "ReachabilityVersionString",
"type": "variable"
},
{
"address": "0x102fab058",
"name": "ReachabilityVersionNumber",
"type": "variable"
}
....
...
..
frida -U -f funky-chicken.debugger-challenge --no-pause -q --eval 'var x={};Process.enumerateModulesSync().forEach(function(m){x[m.name] = Module.enumerateExportsSync(m.name)});' | grep -B 1 -A 1 task_threads
"address": "0x1c1c4645c",
"name": "task_threads",
"type": "function"
frida -U -f funky-chicken.debugger-challenge --no-pause -q --eval 'var x={};Process.findModuleByAddress("0x1c1c4645c");'
{
"base": "0x1c1c2a000",
"name": "libsystem_kernel.dylib",
"path": "/usr/lib/system/libsystem_kernel.dylib",
"size": 200704
}
[objc_playground]-> var a = ObjC.classes.NSString.stringWithString_("foo");
[objc_playground]-> a.superclass().toString()
"NSString"
[objc_playground]-> a.class().toString()
"NSTaggedPointerString"
// PASTE THIS CODE INTO THE FRIDA INTERFACE...
Interceptor.attach(ObjC.classes.NSTaggedPointerString['- isEqualToString:'].implementation, {
onEnter: function (args) {
var str = new ObjC.Object(ptr(args[2])).toString()
console.log('[+] Hooked NSTaggedPointerString[- isEqualToString:] ->' , str);
}
});
// TRIGGER YOUR INTERCEPTOR
[objc_playground_2]-> a.isEqualToString_("foo")
[+] Hooked NSTaggedPointerString[- isEqualToString:] -> foo
1 // TRUE
[objc_playground_2]-> a.isEqualToString_("bar")
[+] Hooked NSTaggedPointerString[- isEqualToString:] -> bar
0 // FALSE
// frida -U -l open.js --no-pause -f com.yd.demoapp
// the below javascript code is the contents of open.js
var targetFunction = Module.findExportByName("libsystem_kernel.dylib", "open");
Interceptor.attach(targetFunction, {
onEnter: function (args) {
const path = Memory.readUtf8String(this.context.x0);
console.log("[+] " + path)
}
});
frida-trace --v Check it works frida-trace --help Excellent place to read about Flags frida-trace -f objc_playground Spawn and NO trace frida-trace -m "+[NSUUID UUID]" -U "Debug CrackMe" Trace ObjC UUID static Class Method frida-trace -m "*[ComVendorDebugger* *]" -U -f com.robot.demo.app ObjC wildcard trace on Classes frida-trace -m "*[YDDummyApp.UserProfileMngr *]" -U -f com.robot.demo.app Trace mangled Swift functions frida-trace -i "getaddrinfo" -i "SSLSetSessionOption" -U -f com.robot.demo Trace C function on iOS frida-trace -m "*[*URLProtection* *]" -U -f com.robot.demo For https challenge information frida-trace -m "*[NSURLSession* *didReceiveChallenge*]" -U -f com.robot.demo Check whether https check delegate used frida-trace -U -f com.robot.demo.app -I libsystem_c.dylib Trace entire Module. frida-trace -p $myapp -I UIKit Trace UIKit Module. frida-trace -f objc_playground -I CoreFoundation Trace CoreFoundation Module. frida-trace -I YDRustyKit -U -f com.yd.mobile Trace my own module. frida-trace -m "-[NSURLRequest initWithURL:]" -U -f com.robot.demo Get app files and APIs frida-trace -m "-[NSURL initWithString:]" -U -f com.robot.demo Find the API endpoints frida-trace -m "*[NSURL absoluteString]" -U -f com.robot.demo My favorite of these
frida-trace -i "*strcpy" -f hitme aaaa bbbb
Instrumenting functions...
_platform_strcpy: Loaded handler at "/.../__handlers__/libSystem.B.dylib/_platform_strcpy.js"
Started tracing 1 function. Press Ctrl+C to stop.
Edit the auto-generated, template Javascript file.
-----------
onEnter: function (log, args, state) {
// strcpy() arg1 is the Source. arg0 is the Destination.
console.log('n[+] _platform_strcpy()');
var src_ptr = args[1].toString()
var src_string = Memory.readCString(args[1]);
var src_byte_array = Memory.readByteArray(args[1],4);
var textDecoder = new TextDecoder("utf-8");
var decoded = textDecoder.decode(src_byte_array);
console.log('[+] src_ptrt-> ' , src_ptr);
console.log('[+] src_stringt-> ' + src_string);
console.log('[+] src_byte_arrayt-> ' + src_byte_array);
console.log('[+] src_byte_array sizet-> ' + src_byte_array.byteLength);
console.log('[+] src_byte_array decodedt-> ' + decoded);
},
ผลลัพธ์:
[+] _platform_strcpy()
[+] src_ptr -> 0x7ffeefbffaa6
[+] src_string -> aaaa
[+] src_byte_array -> [object ArrayBuffer]
[+] src_byte_array size -> 4
[+] decoded -> aaaa
[+] _platform_strcpy()
[+] src_ptr -> 0x7ffeefbffaab
[+] src_string -> bbbb
[+] src_byte_array -> [object ArrayBuffer]
[+] src_byte_array size -> 4
[+] decoded -> bbbb
frida-ps -Uai // get your bundle ID
frida --codeshare mrmacete/objc-method-observer -U -f funky-chicken.push-demo
[+] At the Frida prompt...
observeSomething('*[ABC* *]'); // any Class beginning with ABC, regardless of instance or static class
observeSomething('-[WKWebsiteDataStore httpCookieStore]');
observeSomething('-[WKWebAllowDenyPolicyListener *]');
observeSomething('-[WKWebView loadRequest:]'); // dump the URL to hit
observeSomething('-[WKWebView load*]'); // you get all HTML, js, css, etc
observeSomething('-[WKWebView loadHTMLString:baseURL:]') // really effective; see the entire request
observeSomething('-[WKWebView *Agent]'); // try to see if somebody set a custom UserAgent
observeSomething('*[* isEqualToString*]'); // watch string compares
bash -c "exec -a YDFooBar ./frida-server &"
frida-server -l 0.0.0.0:19999 &
frida-ps -ai -H 192.168.0.38:19999
frida-trace -m "*[NSURLSession* *didReceiveChallenge*]" -H 192.168.0.38:19999 -f com.youdog.rusty.tinyDormant
Objection is a runtime mobile exploration toolkit powered by Frida to assess the security posture of mobile applications without needing to write scripts .
pip3 install objection
objection device_type Get information about an attached device
objection explore Start the objection exploration REPL
objection explore --startup-command 'ios jailbreak simulate'
objection explore --startup-command 'ios jailbreak disable'
Early Instrumentation
ls
env This will print out the locations of the applications Library, Caches and Documents directories
!<shell command> Run OS command
file download <remote path> [<local path>]
file upload <local path> [<remote path>]
Upload/Download
file cat <file> View file
memory dump all <local destination> memory dump from_base <base_address> <size_to_dump> <local_destination>
Dump all memory/Dump part
memory list modules List loaded modules in memory
memory list exports <module_name> Exports of a loaded module
memory search "<pattern eg: 41 41 41 ?? 41>" (--string) (--offsets-only)
memory write "<address>" "<pattern eg: 41 41 41 41>" (--string)
Search/Write
sqlite connect pewpew.sqlite Query the sqlite database
sqlite execute schema Have a look at the table structure
sqlite execute query select * from data;
Execute any query
import <local path frida-script> Import frida script
jobs list List running scripts/jobs
jobs kill <job id> Kill script/job
ios plist cat credentials.plist Read plist file
ios info binary Inspect binary info
ios sslpinning disable --quiet Disable SSL pinning
ios jailbreak simulate Simulate a jailbroken environment to understand how an application behaves
ios jailbreak disable Jailbreak detection bypass
ios nsuserdefaults get Dump NSUserDefaults
ios nsurlcredentialstorage dump Dump NSURLCredentialStorage
ios keychain dump Dump app keychain
ios cookies get Get secure flags and sensitive data stored in cookies
ios monitor crypto monitor Hooks CommonCrypto to output information about cryptographic operation
ios ui dump Dump UI hierarchy
ios ui alert "<message>" Show alert
env Local app paths
ios bundles list_bundles List bundles of the application
ios bundles list_frameworks List external frameworks used by the application
ios hooking list classes List classes of the app
ios hooking search classes <str> Search a class that contains a string
ios hooking list class_methods List methods of a specific class
ios hooking search methods <str> Search a method that contains a string
ios hooking watch class <class_name>
Hook all the methods of a class, dump all the initial parameters and returns
ios hooking watch method "-[<class_name> <method_name>]" --dump-args --dump-return --dump-backtrace
Hook an specific method of a class dumping the parameters, backtraces and returns
ios hooking set return_value "-[<class_name> <method_name>]" false
This will make the selected method return the indicated boolean
ios hooking generate simple <class_name>
Generate hooking template.
r2 frida://device-id/Snapchat Attach to a running app using the display name.
r2 frida://attach/usb//Gadget Attach to the Frida Gadget
r2 frida://device-id//com.snapchat.android Spawn an app using two // and the package name.
r2 frida://spawn/usb/device-id/com.android.app Or explicitly using the word spawn
r2 frida://spawn/usb//com.android.app Or without entering the device-id
=!? Get the list of commands
=!?~^i :
i Show target information
ii[*] List imports
il List libraries
is[*] <lib> List symbols of lib (local and global ones)
iE[*] <lib> Same as is, but only for the export global ones
iEa[*] (<lib>) <sym> Show address of export symbol
isa[*] (<lib>) <sym> Show address of symbol
ic <class> List Objective-C classes or methods of <class>
ip <protocol> List Objective-C protocols or methods of <protocol>
=!i Shows target information
=!i* Shows target information in r2 form
.=!i* Radare2 imports all the dynamic binary data from Frida. Eg: which architecture, endianness, pointer size, etc...
.=!iE* Radare2 imports all the dynamic export data from Frida for all the dynamic libraries.
.=!iE* <lib> Radare2 imports all the dynamic export data from Frida for only one specific library.
.=!ii* Radare2 imports all the dynamic import data from Frida.
=!ii <lib> List imports. Commonly used with the symbol ~ , which is the internal grep of r2 .
=!ii* <lib> List imports in r2 form.
=!il List libraries. Commonly used with the symbol ~ , which is the internal grep of r2.
=!iE <lib> List exports of library(ies)
=!iEa (<lib>) <sym> Show address of export symbol
=!iEa* (<lib>) <sym> Show address of export symbol in r2 format
=!isa[*] (<lib>) <sym> Show address of symbol
=!ic List classes
=!/ keyword Search hex/string pattern in memory ranges (see search.in=?)
> =!?~^/ :
/[x][j] <string|hexpairs> Search hex/string pattern in memory ranges (see search.in=?)
/w[j] string Search wide string
/v[1248][j] value Search for a value honoring e cfg.bigendian of given width
> =!?~^d :
db (<addr>|<sym>) List or place breakpoint
db- (<addr>|<sym>)|* Remove breakpoint(s)
dc Continue breakpoints or resume a spawned process
dd[-][fd] ([newfd]) List, dup2 or close filedescriptors
dm[.|j|*] Show memory regions
dma <size> Allocate bytes on the heap, address is returned
dmas <string> Allocate a string inited with on the heap
dmad <addr> <size> Allocate bytes on the heap, copy contents from
dmal List live heap allocations created with dma[s]
dma- (<addr>...) Kill the allocations at (or all of them without param)
dmp <addr> <size> <perms> Change page at
dmm List all named squashed mapsdmh List all heap allocated chunksdmhj List all heap allocated chunks in JSONdmh* Export heap chunks and regions as r2 flagsdmhm Show which maps are used to allocate heap chunksdp Show current piddpt Show threadsdr Show thread registers (see dpt)dl libname Dlopen a librarydl2 libname [main] Inject library using Frida's >= 8.2 new APIdt (<addr>|<sym>) ... Trace list of addresses or symbolsdth (<addr>|<sym>) (x y..) Define function header (z=str,i=int,v=hex barray,s=barray)dt- Clear all tracingdtr <addr> (<regs>...) Trace register valuesdtf <addr> [fmt] Trace address with format (^ixzO) (see dtf?)dtSf[*j] [sym|addr] Trace address or symbol using the stalker (Frida >= 10.3.13)dtS[*j] seconds Trace all threads for given seconds using the stalkerdi[0,1,-1] [addr] Intercept and replace return value of addressdx [hexpairs] Inject code and execute it (TODO)dxc [sym|addr] [args..] Call the target symbol with given args e[?] [a[=b]] List/get/set config evaluable vars
[0x00000000] > = ! e
e patch.code=true
e search.in=perm:r--
e search.quiet=false
e stalker.event=compile
e stalker.timeout=300
e stalker.in=raw =!. script.js
=!ic List iOS classes
More info: https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06c-reverse-engineering-and-tampering#tampering-and-runtime-instrumentation
Frida GUI.
Frida GUI.
Frida GUI. https://github.com/FuzzySecurity/Fermion
More info:
https://frida.re/docs/examples/ios/
https://frida.re/docs/frida-trace/
https://frida.re/docs/examples/ios/
https://github.com/sensepost/objection/wiki/Using-objection
Apple's Entitlements Troubleshooting – https://developer.apple.com/library/content/technotes/tn2415/_index.html
Apple's Code Signing – https://developer.apple.com/support/code-signing/
Cycript Manual – http://www.cycript.org/manual/
Frida iOS Tutorial – https://www.frida.re/docs/ios/
Frida iOS Examples – https://www.frida.re/docs/examples/ios/
r2frida Wiki – https://github.com/enovella/r2frida-wiki/blob/master/README.md
Charlie Miller, Dino Dai Zovi. The iOS Hacker's Handbook. Wiley, 2012 – https://www.wiley.com/en-us/iOS+Hacker's+Handbook-p-9781118204122
Jonathan Levin. Mac OS X and iOS Internals: To the Apple's Core. Wiley, 2013 – http://newosxbook.com/MOXiI.pdf
Install SSL Kill Switch 2 from https://github.com/nabla-c0d3/ssl-kill-switch2/releases/
Open your settings and enable SSL Kill Switch 2
Run Charles on PC.
Install Charles Root Certificate on iOS device:
Help → SSL Proxing → Install Charles Root Certificate on Mobile Device or Remote Browser.
The following window will appear:
Depending on your network architecture the IP address Charles is running on may differ.
Proxy → SSL Proxying Settings... → Add (Include) → Host: * ; ท่าเรือ: *
Since all binary files inside an .ipa are encrypted with AES and being decrypted with a private key by Secure Enclave Processor at the runtime there is a few ways to decrypt it:
If you don't have Node.js:
brew install nvm
nvm install node
To dump decrypted ipa using bagbak utility install it on desktop:
sudo npm install -g bagbak
Then download your application from the App Store and dump:
bagbak <bundle id or name> --uuid <uuid> --output <output>
There are several ways to run the hardware AES engine:
Patch iBoot to jump to aes_crypto_cmd
Use OpenIBoot
Use XPwn with a kernel patch
Use Greenpois0n console:
ideviceenterrecovery
irecovery --shell
go aes dec <file>
Use ipwndfu
Use checkra1n
Run checkra1n with -p to run into pongoOS (https://github.com/checkra1n/pongoOS) and use the aes command over USB
If you want to disassemble an application from the App Store, remove the FairPlay DRM first.
After decrypting .ipa file open app binary in disassembler like IDA Pro .
In this section the term "app binary" refers to the Macho-O file in the application bundle which contains the compiled code, and should not be confused with the application bundle - the IPA file.
If you have a license for IDA Pro, you can analyze the app binary using IDA Pro as well.
To get started, simply open the app binary in IDA Pro.
Upon opening the file, IDA Pro will perform auto-analysis, which can take a while depending on the size of the binary. Once the auto-analysis is completed you can browse the disassembly in the IDA View (Disassembly) window and explore functions in the Functions window, both shown in the screenshot below.
https://github.com/ChiChou/IDA-ObjCExplorer/blob/master/ObjCExplore.py – Obj-C Classes Explorer for IDA Pro. Just press Ctrl + Shift + E .
https://github.com/avast/retdec-idaplugin – RetDec decompiler for IDA Pro. Just press Ctrl + D .
https://github.com/zynamics/objc-helper-plugin-ida – zynamics Objective-C helper script.
https://github.com/techbliss/Frida_For_Ida_Pro – Connect frida.
https://github.com/vadimszzz/idapython/blob/master/cortex_m_firmware.py – IDA Python module for loading ARM Cortex M firmware.
https://github.com/saelo/ida_scripts/blob/master/kernelcache.py – Identify and rename function stubs in an iOS kernelcache.
https://github.com/luismiras/IDA-iOS-scripts/blob/master/find_iOS_syscalls.py – Find iOS syscalls.
https://github.com/stefanesser/IDA-IOS-Toolkit/blob/master/listAllKEXT.py – List all Kexts.
https://github.com/stefanesser/IDA-IOS-Toolkit/blob/master/findSyscallTable.py – This script searches the iOS syscall table within the iOS kernelcache.
https://github.com/stefanesser/IDA-IOS-Toolkit/blob/master/fixupSysctlSet.py – This script ensures that all sysctl_oid structures referenced by the sysctl_set segment are marked correctly.
https://github.com/bazad/ida_kernelcache – An IDA Toolkit for analyzing iOS kernelcaches.
You can use class-dump to get information about methods in the application's source code.
Note the architectures: armv7 (which is 32-bit) and arm64 . This design of a fat binary allows an application to be deployed on all devices. To analyze the application with class-dump, we must create a so-called thin binary, which contains one architecture only:
iOS8-jailbreak:~ root# lipo -thin armv7 DamnVulnerableIOSApp -output DVIA32
And then we can proceed to performing class-dump:
iOS8-jailbreak: ~ root# class-dump DVIA32
@interface FlurryUtil : ./DVIA/DVIA/DamnVulnerableIOSApp/DamnVulnerableIOSApp/YapDatabase/Extensions/Views/Internal/
{
}
+ (BOOL)appIsCracked ;
+ (BOOL)deviceIsJailbroken ; Note the plus sign, which means that this is a class method that returns a BOOL type. A minus sign would mean that this is an instance method. Refer to later sections to understand the practical difference between these.
Strings are always a good starting point while analyzing a binary, as they provide context to the associated code. For instance, an error log string such as "Cryptogram generation failed" gives us a hint that the adjoining code might be responsible for the generation of a cryptogram.
In order to extract strings from an iOS binary, you can use GUI tools such as Ghidra or Cutter or rely on CLI-based tools such as the strings Unix utility strings <path_to_binary> or radare2's rabin2 rabin2 -zz <path_to_binary> . When using the CLI-based ones you can take advantage of other tools such as grep (eg in conjunction with regular expressions) to further filter and analyze the results.
NM
nm libprogressbar.a | less
rabin2
rabin2 -s file
radare2
is~FUNC
Check URLs:
strings <binary inside app bundle> | grep -E 'session|https'
strings <binary inside app bundle> | grep -E 'pinning'
rabin2 -qz <binary inside app bundle> // in Data Section
rabin2 -qzz <binary inside app bundle> // ALL strings in binary
jtool -dA __TEXT.__cstring c_playground
Dumping C-Strings from address 0x100000f7c (Segment: __TEXT.__cstring)..
Address : 0x100000f7c = Offset 0xf7c
0x100000f7c: and we have a winner @ %ldr
0x100000f98: and that's a wrap folks!r
IDA Pro can be used for obtaining cross references by right clicking the desired function and selecting Show xrefs .
w0 = 32-bitx0 = 64-bitwzr or xzr . Write to = discard, read from = 0 .sp - unlike other instruction sets, never modified implicitly (eg no push / pop ).pc , not modifiable directly.str ).mov to copy one register to another, eg mov x0, x1 -> x0 = x1 .0 loaded from wzr / xzr .orr x0, xzr, 5 .movz + movk , eg: movz x0 , 0x1234 , lsl 32
movk x0 , 0x5678 , lsl 16
movk x0 , 0x9abcx0 = 0x123456789abc .movn for negative values, eg movn x0, 1 -> x0 = -1 .lsl and lsr instructions = logic-shift-left and logic-shift-right, eg lsl x0, x0, 8 -> x0 <<= 8 .lsl and lsr not only used as instructions, but also as operands to other instructions (see movz above).asl for arithmetic shift also exists, but less frequently used.ldr and str with multiple variations and addressing modes:ldr x0, [x1] -> x0 = *x1str x0, [x1] -> *x1 = x0ldr x0, [x1, 0x10] -> x0 = *(x1 + 0x10)ldp / stp to load/store two registers at once behind each other, eg:stp x0, x1, [x2] -> *x2 = x0; *(x2 + 8) = x1;xN for 64-bit, wN for 32-bitldrh / srth for 16-bitldrb / strb for 8-bitldrsw x0, [x1] -> load 32-bit int, sign extend to 64-bitldrsh x0, [x1] -> load 16-bit int, sign extend to 64-bitldrsb x0, [x1] -> load 8-bit int, sign extend to 64-bitstr instructions)ldr x0, [x1, 0x10]ldr x0, [x1, 0x10]! (notice the ! ) -> x1 += 0x10; x0 = *x1;ldr x0, [x1], 0x10 -> x0 = *x1; x1 += 0x10;adr x0, 0x12345 (only works for small offset from PC)adrp + add : adrp x0 , 0xffffff8012345000 ; "address of page", last 12 bits are always zero
add x0 , x0 , 0x678ldr .Note: Only dealing with integral types here. The rules change when floating-point is involved.
x0 - x7 first 8 arguments, rest on the stack (low address to high) with natural alignment (as if they were members of a struct)x8 pointer to where to write the return value if >128 bits, otherwise scratch registerx9 - x17 scratch registersx18 platform register (reserved, periodically zeroed by XNU)x19 - x28 callee-savedx29 frame pointer (basically also just callee-saved)x30 return addressx19 - x28 usually start like this: stp x24 , x23 , [ sp , - 0x40 ] !
stp x22 , x21 , [ sp , 0x10 ]
stp x20 , x19 , [ sp , 0x20 ]
stp x29 , x30 , [ sp , 0x30 ]
add x29 , sp , 0x30 ldp x29 , x30 , [ sp , 0x30 ]
ldp x20 , x19 , [ sp , 0x20 ]
ldp x22 , x21 , [ sp , 0x10 ]
ldp x24 , x23 , [ sp ], 0x40
retadd sp, sp, 0x... and sub sp, sp, 0x... .x0 - x7 come before variadic arguments on the stack, naturally aligned.x0 .x0 , the second/upper half in x1 .x8 to where the result is written.nzcv holds condition flags (Negative, Zero, Carry, oVerflow).instr.cond ), others as source operands ( instr ..., cond ). List of condition codes:eq / ne = equal/not equallt / le / gt / ge = less than/less or equal/greater than/greater or equal (signed)lo / ls / hi / hs = lower/lower or same/higher/higher or same (unsigned)cs / cc = carry set/carry clear are aliases of hs / lo .cmp = most common/basic compare instruction, sets condition flags. ตัวอย่าง: cmp x0 , x1
cmp x0 , 3cmn = compare negativetst = bitwise testadds / adcs = add/add with carrysubs / sbcs = subtract/subtract with carrynegs / ngcs = negate/negate with carrycset = conditional set, eg: cmp x0 , 3
cset x0 , lox0 = (x0 < 3)csel = conditional select, eg: cmp x0 , 3
csel x0 , x1 , x2 , lox0 = (x0 < 3) ? x1 : x2ccmp = conditional compare, eg: cmp x0 , 3
ccmp x0 , 7 , 2 , hs
b.hi 0xffffff8012345678hi condition will be true if x0 < 3 || x0 > 7 (third ccmp operand is raw nzcv data).b = simple branch, jump to PC-relative address. b 0xffffff8012345678 cmp x0 , 3
b.lo 0xffffff8012345678 ; jump to 0xffffff8012345678 if x < 3cbz / cbnz = compare-branch-zero and compare-branch-non-zero. cmp xN , 0
b.eq 0x... cmp xN , 0
b.ne 0x...if(x) or if(!x) .)tbz / tbnz = test single bit and branch if zero/non-zero.tbz x0, 3, ... translates to if((x0 & (1 << 3)) == 0) goto ... .bl = branch-and-link (eg bl 0xffffff8012345678 )x30 and jump to PC-relative address. Used for static function calls.blr = branch-and-link to register (eg blr x8 )x30 and jump to address in x8 . Used for calls with function pointers or C++ virtual methods.br = branch to register (eg br x8 )x8 . Used for tail calls.ret = return to address in register, default: x30x30 (eg ret x8 ), but compiler doesn't usually generate that.nop = do nothingsvc = make a system call using an immediate value (eg svc 0x80 ). Note that the immediate value is separate from the syscall number. XNU ignores the immediate and expects the syscall number in x16 .. = special symbol that refers to the address of the instruction it is used in (eg adr x0, . )Install the following prerequisites:
brew install ldid xz
Set up the THEOS environment variable:
echo "export THEOS=~/theos" >> ~/.zshrc
source ~/.zshrc
Clone Theos:
git clone --recursive https://github.com/theos/theos.git $THEOS
Get the toolchain:
Xcode contains the toolchain.
Get an iOS SDK:
Xcode always provides the latest iOS SDK, but as of Xcode 7.3, it no longer includes private frameworks you can link against. This may be an issue when developing tweaks. You can get patched SDKs from our SDKs repo.
curl -LO https://github.com/theos/sdks/archive/master.zip
TMP=$(mktemp -d)
unzip master.zip -d $TMP
mv $TMP/sdks-master/*.sdk $THEOS/sdks
rm -r master.zip $TMP
Logos is a Perl regex-based preprocessor that simplifies the boilerplate code needed to create hooks for Objective-C methods and C functions with an elegant Objective-C-like syntax. It's most commonly used along with the Theos build system, which was originally developed to create jailbreak tweaks. Logos was once integrated in the same Git repo as Theos, but now has been decoupled from Theos to its own repo.
Logos aims to provide an interface for Cydia Substrate by default, but can be configured to directly use the Objective-C runtime.
Logos is a component of the Theos development suite.
%hookf(return type, functionName, arguments list...) {
/* body */
}
Generate a function hook for the function named functionName . Set functionName in %init to an expression if the symbol should be dynamically looked up.
ตัวอย่าง:
// Given the function prototype (only add it yourself if it's not declared in an included/imported header)
FILE *fopen(const char *path, const char *mode);
// The hook is thus made
%hookf(FILE *, fopen, const char *path, const char *mode) {
puts("Hey, we're hooking fopen to deny relative paths!");
if (path[0] != '/') {
return NULL;
}
return %orig; // Call the original implementation of this function
}
// functions can also be looked up at runtime, if, for example, the function is in a private framework
%hookf(BOOL, MGGetBoolAnswer, CFStringRef string) {
if (CFEqual(string, CFSTR("StarkCapability"))) {
return YES;
}
return %orig;
}
%ctor() {
%init(MGGetBoolAnswer = MSFindSymbol(NULL, "_MGGetBoolAnswer"));
}
%ctor {
/* body */
}
Generate an anonymous constructor (of default priority). This function is executed after the binary is loaded into memory. argc , argv , and envp are implicit arguments so they can be used as they would be in a main function.
%dtor {
/* body */
}
Generate an anonymous deconstructor (of default priority). This function is executed before the binary is unloaded from memory. argc , argv , and envp are implicit arguments so they can be used as they would be in a main function.
The directives in this category open a block of code which must be closed by an %end directive (shown below). These should not exist within functions or methods.
%group GroupName
/* %hooks */
%end
Generate a hook group with the name GroupName . Groups can be used for conditional initialization or code organization. All ungrouped hooks are in the default group, initializable via %init without arguments.
Cannot be inside another %group block.
Grouping can be used to manage backwards compatibility with older code.
ตัวอย่าง:
%group iOS8
%hook IOS8_SPECIFIC_CLASS
// your code here
%end // end hook
%end // end group ios8
%group iOS9
%hook IOS9_SPECIFIC_CLASS
// your code here
%end // end hook
%end // end group ios9
%ctor {
if (kCFCoreFoundationVersionNumber > 1200) {
%init(iOS9);
} else {
%init(iOS8);
}
}
%hook ClassName
/* objc methods */
%end
Open a hook block for the class named ClassName .
Can be inside a %group block.
ตัวอย่าง:
%hook SBApplicationController
- (void)uninstallApplication:(SBApplication *)application {
NSLog(@"Hey, we're hooking uninstallApplication:!");
%orig; // Call the original implementation of this method
}
%end
%new
/* objc method */
%new(signature)
/* objc method */
Add a new method to a hooked class or subclass by adding this directive above the method definition. signature is the Objective-C type encoding for the new method; if it is omitted, one will be generated.
Must be inside a %hook or %subclass block.
ตัวอย่าง:
%new
- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer {
NSLog(@"Recieved tap: %@", gestureRecognizer);
}
%subclass ClassName: Superclass <Protocol list>
/* %properties and methods */
%end
Generate a subclass at runtime. Like @property in normal Objective-C classes, you can use %property to add properties to the subclass. The %new specifier is needed for a method that doesn't exist in the superclass. To instantiate an object of the new class, you can use the %c operator.
Can be inside a %group block.
ตัวอย่าง:
// An interface is required to be able to call methods of the runtime subclass using block syntax.
@interface MyObject : NSObject
@property (nonatomic, retain) NSString * someValue;
@end
%subclass MyObject : NSObject
%property (nonatomic, retain) NSString * someValue;
- (instancetype)init {
if ((self = %orig)) {
[self setSomeValue:@"value"];
}
return self;
}
%end
%ctor {
// The runtime subclass cannot be linked at compile time so you have to use %c().
MyObject *myObject = [[%c(MyObject) alloc] init];
NSLog(@"myObject: %@", [myObject someValue]);
}
%property (nonatomic|assign|retain|copy|weak|strong|getter=...|setter=...) Type name;
Add a property to a %subclass just like you would with @property to a normal Objective-C subclass as well as adding new properties to existing classes within %hook.
Must be inside a %hook or %subclass block.
%end
Close a %group, %hook or %subclass block.
The directives in this category should only exist within a function or method body.
%init;
%init([<ClassName>=<expr>, …]);
%init(GroupName[, [+|-]<ClassName>=<expr>, …]);
Initialize a group's method and function hooks. Passing no group name will initialize the default group. Passing ClassName=expr arguments will substitute the given expressions for those classes at initialization time. The + sigil (as in class methods in Objective-C) can be prepended to the classname to substitute an expression for the metaclass. If not specified, the sigil defaults to - , to substitute the class itself. If not specified, the metaclass is derived from the class.
The class name replacement is specially useful for classes that contain characters that can't be used as the class name token for the %hook directive, such as spaces and dots.
ตัวอย่าง:
%hook ClassName
- (id)init {
return %orig;
}
%end
%ctor {
%init(ClassName=objc_getClass("SwiftApp.ClassName"));
}
%c([+|-]ClassName)
Evaluates to ClassName at runtime. If the + sigil is specified, it evaluates to MetaClass instead of Class. If not specified, the sigil defaults to - , evaluating to Class.
%orig
%orig(args, …)
Call the original hooked function or method. Doesn't work in a %new'd method. Works in subclasses, strangely enough, because MobileSubstrate will generate a super-call closure at hook time. (If the hooked method doesn't exist in the class we're hooking, it creates a stub that just calls the superclass implementation.) args is passed to the original function - don't include self and _cmd , Logos does this for you.
ตัวอย่าง:
%hook ClassName
- (int)add:(int)a to:(int)b {
if (a != 0) {
// Return original result if `a` is not 0
return %orig;
}
// Otherwise, use 1 as `a`
return %orig(1, b);
}
%end
&%orig
Get a pointer to the original function or method. Return type is void (*)(id, SEL[, arg types])
ตัวอย่าง:
// Call from outside hooked method:
void (*orig_ClassName_start)(id, SEL) = nil;
void doStuff(id self, SEL _cmd) {
if (self && orig_ClassName_start) {
orig_ClassName_start(self, _cmd);
}
}
%hook ClassName
- (void)start {
%orig;
orig_ClassName_start = &%orig;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
doStuff(self, _cmd);
});
}
%end
// Call with another object:
%hook ClassName
- (int)add:(int)a to:(int)b {
int (*_orig)(id, SEL, int, int) = &%orig;
ClassName * myObject = [ClassName new];
int r = _orig(myObject, _cmd, 1, 2);
[myObject release];
return r;
}
%end
Real world example at PreferenceLoader
%log;
%log([(<type>)<expr>, …]);
Dump the method arguments to syslog. Typed arguments included in %log will be logged as well.
You can use logify.pl to create a Logos source file from a header file that will log all of the functions of that header file. Here is an example of a very simple Logos tweak generated by logify.pl.
Given a header file named SSDownloadAsset.h :
@interface SSDownloadAsset : NSObject
- (NSString *)finalizedPath;
- (NSString *)downloadPath;
- (NSString *)downloadFileName;
+ (id)assetWithURL:(id)url type:(int)type;
- (id)initWithURLRequest:(id)urlrequest type:(int)type;
- (id)initWithURLRequest:(id)urlrequest;
- (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type;
@end
You can find logify.pl at $THEOS/bin/logify.pl and you would use it as so:
$THEOS/bin/logify.pl ./SSDownloadAsset.h
The resulting output should be:
%hook SSDownloadAsset
- (NSString *)finalizedPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
- (NSString *)downloadPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
- (NSString *)downloadFileName { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
+ (id)assetWithURL:(id)url type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
- (id)initWithURLRequest:(id)urlrequest type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
- (id)initWithURLRequest:(id)urlrequest { %log; id r = %orig; NSLog(@" = %@", r); return r; }
- (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
%end
| ส่วนขยาย | Process order |
|---|---|
| x | will be processed by Logos, then preprocessed and compiled as Objective-C. |
| xm | will be processed by Logos, then preprocessed and compiled as Objective-C++. |
| xi | will be preprocessed first, then Logos will process the result, and then it will be compiled as Objective-C. |
| xmi | will be preprocessed first, then Logos will process the result, and then it will be compiled as Objective-C++. |
xi or xmi files enable Logos directives to be used in preprocessor macros, such as #define . You can also import other Logos source files with the #include statement. However, this is discouraged, since this leads to longer build times recompiling code that hasn't changed. Separating into x and xm files, sharing variables and functions via extern declarations, is recommended.
These file extensions control how a build system such as Theos should build a Logos file. Logos itself does not take the file extension into account and works regardless of whether a file is Objective-C or Objective-C++.
https://theos.dev/docs/
https://cydia.saurik.com/faq/developing.html
http://www.cydiasubstrate.com/id/7cee77bc-c4a5-4b8b-b6ef-36e7dd039692/
http://www.cydiasubstrate.com/inject/
https://iphonedev.wiki/index.php/Cydia_Substrate
https://cwcaude.github.io/project/tutorial/2020/07/02/iOS-tweak-dev-1.html
https://cwcaude.github.io/project/tutorial/2020/07/04/iOS-tweak-dev-2.html
https://cwcaude.github.io/project/tutorial/2020/07/12/iOS-tweak-dev-3.html
https://cwcaude.github.io/project/tutorial/2020/07/16/iOS-tweak-dev-4.html