作為一個一致的Unix系統,OS X與所有Unix口味的眾所周知的目錄合作:
OS X將自己的特殊目錄添加到系統根下的Unix樹中:
從文件系統的角度來看,iOS與OS X非常相似,並具有以下差異:
通過將擴展名更改為.zip和Unipping,可以將帶有.IPA擴展名的文件不壓縮。
/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
應用程序可以在關鍵系統進程作為root運行時作為移動用戶訪問運行。但是,沙箱可以更好地控製過程和應用程序可以執行的操作。
例如,即使兩個進程作為同一用戶(移動)運行,也不允許它們訪問或修改彼此的數據。
每個應用程序都安裝在/var/mobile/Applications/<UUID>下。 UUID是隨機的。安裝後,應用程序對某些系統區域和功能的閱讀訪問有限(SMS,電話...)。如果應用程序要訪問受保護區域,則會出現彈出式請求權限。
應用開發人員可以利用iOS數據保護API實現存儲在閃存中的用戶數據的細粒訪問控制。 API建立在安全飛地處理器(SEP)的頂部。 SEP是一個協助程序,可為數據保護和密鑰管理提供加密操作。設備特定的硬件鍵 -設備UID (唯一ID) -嵌入了安全的飛地中,即使操作系統內核被損害,也確保了數據保護的完整性。
當在磁盤上創建文件時,將在Secure Enclave的基於硬件的隨機數生成器的幫助下生成新的256位AES密鑰。然後,用生成的密鑰對文件的內容進行加密。然後,該密鑰與類ID一起保存使用類鍵,並在文件的元數據內加密兩個數據。
為了解密文件,使用系統鍵解密元數據。然後使用類ID檢索類鍵以解密每個文件密鑰並解密文件。
可以將文件分配給四個不同的保護類之一,這些類別在iOS安全指南中更詳細地進行了解釋。
每個應用程序都有一個唯一的主目錄並具有沙盒,因此它們無法訪問系統或其他應用程序存儲的受保護的系統資源或文件。這些限制是通過Sandbox策略(又稱配置文件)實現的,該策略由信任的BSD(MAC)強制性訪問控制框架通過內核擴展實施。
某些功能/權限可以由應用程序的開發人員(例如數據保護或鑰匙扣共享)配置,並在安裝後直接生效。但是,對於其他人來說,將在應用程序第一次嘗試訪問受保護資源時明確詢問用戶。
目的字符串或用法說明字符串是自定義文本,當請求訪問受保護的數據或資源的權限時,在系統許可請求警報中提供的用戶提供了自定義文本。
如果具有原始源代碼,則可以驗證Info.plist文件中包含的權限:
Info.plist文件,並蒐索以"Privacy -"開頭的密鑰。您可以通過右鍵單擊和選擇“顯示RAW KEYS/VALUES”(例如"Privacy - Location When In Use Usage Description" NSLocationWhenInUseUsageDescription來切換視圖以顯示原始值。
如果只有IPA:
Info.plist位於Payload/<appname>.app/Info.plist中。plutil -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使用設備功能,以確保僅列出兼容設備,因此允許下載應用程序。 They are specified in the Info.plist file of the app under the [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用戶ID)的身份驗證。由於權利是數字簽名的,因此無法更改。系統應用程序和守護程序將權利廣泛使用,以執行特定的特權操作,否則該操作將需要該過程作為root運行。這大大降低了通過折衷的系統應用程序或守護程序的特權升級潛力。
例如,如果要設置“默認數據保護”功能,則需要轉到XCode中的“功能”選項卡並啟用數據保護。這是由Xcode直接編寫的<appname>.entitlements文件,為com.apple.developer.default-data-protection witterlemt, NSFileProtectionComplete 。在IPA中,我們可能會在embedded.mobileprovision中找到它。 MobileProvisionas:
<key>Entitlements</key>
<dict>
...
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
</dict>
對於其他功能,例如HealthKit,必須要求用戶獲得許可,因此不足以添加權利,必須將特殊鍵和字符串添加到應用程序的Info.plist文件中。
安全飛地是用於數據保護,觸摸ID和麵部ID的A7和更新的SOC的一部分。安全飛地的目的是處理密鑰和其他信息,例如生物識別技術,這些信息足夠敏感,無法由應用程序處理器處理。它是用硬件過濾器隔離的,因此AP無法訪問它。它與AP共享RAM,但其部分RAM -TZ0已加密。安全飛地本身是一個閃爍的4MB AKF處理器核心,稱為安全飛地處理器(SEP)。所使用的技術類似於ARM的Trustzone/Securecore,但通常包含針對Apple KF核心的專有代碼,通常是專門的。
每個設備中的SOC都有一個具有GID鍵和UID鍵的AES協處理器。
設備的唯一ID(UID)和設備組ID(GID)為AES 256位鍵(UID)或在製造過程中匯集(GID)中的應用程序處理器。沒有任何軟件或固件可以直接讀取它們;他們只能看到使用它們執行的加密或解密操作的結果。 UID是每個設備獨有的,並且沒有由Apple或其任何供應商記錄。 GID對於一類設備中的所有處理器都是常見的,在安裝和還原過程中交付系統軟件時,用作額外的保護。將這些鑰匙集成到矽中有助於防止它們被篡改或繞過或在AES發動機外訪問。
GID密鑰(組ID密鑰)是所有設備與同一應用程序處理器共享的256位AES密鑰。 GID密鑰是iOS在設備上加密軟件的一部分。這是iOS安全系統的組成部分,其中還包括SHSH簽名。每個Apple SOC模型都有不同的鍵。
到目前為止,GID密鑰尚未從任何設備中提取,因此使用它的唯一方法是通過AES引擎本身。
但
GID可以通過昂貴的冷啟動攻擊程序(https://en.m.wikipedia.org/wiki/wiki/cold_boot_attack)和下一個不那麼昂貴的程序,該程序可以使用電子束石板石器儀芯片搜索者(https://minateh.ru/equipmenty canser)掃描SOC的過程。這樣的實驗是不合理的昂貴且複雜的,因此除了私人實驗室Cellebrite以外,任何人都從未想過嘗試實施它。 Cellebrite不分享其研究。
UID密鑰(設備的唯一ID密鑰)是AES 256位硬件密鑰,每個iPhone是獨特的。
一些派生的鍵由boot的ioaesaccelerator內核計算。這些鍵是通過使用UID鍵(0x7D0標識符)或GID鍵(0x3E8標識符)加密靜態值來生成的。
密鑰0x835 - 由UID鍵加密生成0x01010101010101010101010101010101 。用於數據保護。
密鑰0x836 - 由UID鍵加密生成0x00E5A0E6526FAE66C5C1C6D4F16D6180 。這是由內核在還原過程中計算出的,但在正常引導過程中被歸零。它也由安全的引導加載程序計算,其唯一已知的用途是在NOR中解密LLB。像0x835一樣,每個設備都不同。
密鑰0x837 - 由加密生成0x345A2D6C5050D058780DA431F0710E15帶有S5L8900 GID鍵,導致0x188458A6D15034DFE386F23B61D43774 。它用作IMG2文件的加密密鑰。隨著iPhone OS 2.0中IMG3的引入,現在使用KBAGS代替0x837密鑰。因為iPhone OS版本1.X僅在iPhone和iPod觸摸(都使用S5L8900)上使用,因此其他處理器的加密值無關緊要。
密鑰0x838 - 由加密為0x8C8318A27D7F030717D2B8FC5514F8E1與UID鍵生成。另一個基於UID-AES鍵的密鑰,用於加密除llb(iboot,devicetree,圖片)中的LLB以外的所有內容。
密鑰0x899 - 通過加密與UID-KEY生成0xD1E8FCB53937BF8DEFC74CD1D0F1D4B0 。用法未知。
鍵0x89a - 由加密0xDB1F5B33606C5F1C1934AA66589C0661與UID鍵一起生成,獲得了特定於設備的鍵。在A4設備上使用。它用於加密設備上的SHSH斑點。
密鑰0x89b - 由加密為0x183E99676BB03C546FA468F51C0CBD49與UID鍵生成。它用於加密數據分區密鑰。
密鑰0x8A3 - 通過加密0x568241656551e0cdf56ff84cc11a79ef與UID鍵(使用AES-256-CBC)生成。它在A12的軟件升級期間使用,然後在Hashing成為NONCE之前對“生成器”值(使用AES-128-CBC)進行加密。
更多信息: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類型是指向任何類的對象的指針(實際上,void *),都具有特殊的意義。空指針稱為常數零。因此,可以將任何類的指針投入到ID類型上。出現問題:如何找出隱藏在ID下的對象屬於哪個類?這要歸功於ISA不變性,該類別的任何對像都存在於繼承特殊基類NsObject的類的任何對像中(NS前綴代表下一步)。 ISA不變性是保留類型類的。這種類型的對象使您可以找到自己的名稱和基類的名稱,一組類別不變的,以及該對像已實現的所有方法的原型及其地址(通過選擇器的本地列表)。除C保留單詞以外的所有Objective-C保留單詞以 @符號開頭(例如@protocol,@selector,@interface)。通常,範圍範圍的類別不變性(@private, @protected)的名稱始於下劃線。對於字符串,可可具有非常方便的NSString課程。該類的字符串常數寫為 @“ Hello World”,而不是通常的C字符串常數“ Hello World”。 Bool類型(基本上是未簽名的Char)可以將常量值為“是”和“否”。下面列出了所有客觀-C特異性的保留單詞(與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)返回方法名稱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, ...;
蘋果開發人員文檔
https://developer.apple.com/library/archive/documentation/macosx/conceptual/osx_technology_overview/systemworks/systemworks/systemworks/systemprameworks.html
https://www.theiphonewiki.com/wiki//system/library/frameworks
框架存儲在文件系統上的多個位置:
此外,應用程序可能包括其自己的框架。
蘋果開發人員文檔 - 網絡
Apple開發人員文檔 - NetWorkextension
Apple開發人員文檔 - NetworkingDriverKit
您可能遇到的大多數應用程序連接到遠程端點。甚至在執行任何動態分析(例如流量捕獲和分析)之前,您也可以通過列舉應與該應用程序通信的域獲得一些初始輸入或輸入點。
通常,這些域將作為應用程序二進制中的字符串存在。可以通過使用rabin2 -zz <path_to_binary>或IDA Pro中檢索字符串來提取域。後一個選項具有明顯的優勢:它可以為您提供上下文,因為您可以通過檢查跨引用來查看每個域使用的上下文。
從這裡,您可以使用此信息來獲取更多的見解,這些見解可能在分析過程中可能會在以後使用,例如,您可以將域與固定證書匹配,或對域名進行進一步的偵察,以了解有關目標環境的更多信息。
安全連接的實施和驗證可能是一個複雜的過程,需要考慮許多方面。例如,許多應用程序都使用除HTTP(例如XMPP或普通TCP數據包)外的其他協議,或者執行證書固定以試圖阻止MITM攻擊。
網絡框架是在2018年在Apple Worldwide開發人員會議(WWDC)上引入的,是替代插座API的。這個低級網絡框架提供了與內置的動態網絡,安全性和性能支持一起發送和接收數據的類。
如果using: .tls使用:默認情況下,TLS 1.3將在網絡框架中啟用。這是與舊式安全運輸框架相比的首選選項。
URLSession建立在網絡框架上,並利用相同的運輸服務。如果端點為HTTPS,則該類還使用TLS 1.3。
URLSession應用於HTTP和HTTPS連接,而不是直接利用網絡框架。該類本質地支持兩個URL方案,並針對此類連接進行了優化。它需要更少的樣板代碼,從而減少錯誤的傾向並默認確保安全連接。僅當有低級和/或高級網絡要求時,才應使用網絡框架。
Apple官方文檔包括使用網絡框架實現NetCat和URLSession將網站數據獲取內存的示例。
https://developer.limneos.net/
https://www.theiphonewiki.com/wiki//system/library/privateframeworks
可以在此處找到設備的最新工具https://canijailbreak.com
這項研究基本上是為CheckRa1Ned Iphone 5s至X編寫的,X帶iOS 10-15,如果將發布新的Bootrom PWNage工具,則可以長期更新。檢查一下https://www.theiphonewiki.com/wiki/bootrom#bootrom_exploits
https://repo.chariz.com )killall SpringBoard使用Filza文件管理器打開.deb/.ipa文件,然後按Install,如果您看到.deb安裝的錯誤,請嘗試查找和安裝所有依賴關係
從https://cydia.akemi.ai/ repo安裝AppSync
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/ - 弗里達https://cydia.radare.org/ - radare2
在桌面上安裝
brew install libimobiledevice ideviceinstaller libirecovery
sudo port install idevicerestore
idevicediagnostics idevicebackup或恢復設備idevicedebug遺產idevicecrashreport ideviceenterrecovery創建或恢復運行iOS 4或更高版本的設備idevicedebugserverproxy備份 connection from a device for remote debugging idevicebackup2 Interact with the diagnostics interface of a device idevice_id Make a device enter recovery mode ideviceimagemounter Mount disk images on the device ideviceinfo Show information about a connected device idevicesetlocation Display or set the device name idevicepair Manage host pairings with devices and usbmuxd idevicesyslog Gets a screenshot from連接的設備idevicename模擬了連接設備的設備idevicescreenshot RELAY SYSLOG上的位置
ideviceinstaller --list-apps
ideviceinstaller --install <Application.ipa>
ideviceinstaller --uninstall <bundle id>
idevicedebug -d run <bundle id>
irecovery --shell允許與iOS設備的iboot/ibss進行通信
idevicerestore --latest將新的固件還原到設備idevicerestore --erase --latest
擦除所有數據的力量恢復
inetcat實用程序可暴露與設備iproxy 2222:22綁定本地端口2222並將22的RAW連接到第一個USB設備的22
在設備Apple文件導管“ 2”上安裝
使用iMazing或ifunbox訪問文件系統
安裝FILZA文件管理器
在設備上安裝OpenSSH並在桌面上運行:
iproxy 2222:22
ssh -p 2222 root@localhost
root的默認iOS密碼是alpine 。如果您的記憶不好,請不要更改它
從https://repo.chariz.com上安裝在設備newterm 2上使用本地終端
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/
從https://nscake.github.io/安裝libflex和flexing
開放新月並運行killall SpringBoard
現在,您可以通過longpress在狀態欄上加載任何應用程序中的flex
弗里達(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列出可用設備frida-ps -U列出了USB設備上所有運行的流程名稱和PID
frida-ps -Uai列出了USB設備上所有已安裝的應用程序frida-ps -Ua列出了USB設備上的所有運行應用程序frida-ls-devices列出了所有附加設備frida-ps -D 0216027d1d6d3a03將Frida連接到特定設備frida-discover工具,用於在過程中發現內部功能frida-trace -U Twitter -i "*URL*"跟踪本機Apis
frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"
啟動應用程序並跟踪加密API調用frida-trace -U Twitter -m "-[NSURL* *HTTP*]"跟踪Objective-C API
frida -U -n Twitter -l inject.js通過repl在USB設備上註入腳本frida -n cat用名字連接到貓frida -f foobar Force Open Foobar
frida -U -f foobar --no-pause USB和力量開始。開始運行應用程序frida-ps -U | grep -i myapp從USB連接的設備獲取目標應用程序的流程ID
frida -U -f foobar --no-pause -q --eval 'console.log("Hi 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獲得現有實例,例如 - 如果您知道只有一個實例已經在堆上創建了一個實例 - 您可以使用var instance = ObjC.chooseSync(ObjC.classes.ClassName)[0];var instance = ObjC.classes.MySingleton.getInstance().myInterestingInstance();然後在實例上調用該方法:
instance.setSomething();
或者,如果方法簽名採用一個參數,例如- setSomething:您也可以傳遞參數(只需記住將_而不是objc's :)放置一個_而不是objc : :):
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的語法包括:和@字符。這些字符未在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場所,可以閱讀有關旗幟的好地方frida-trace -f objc_playground產卵,無跟踪frida-trace -m "+[NSUUID UUID]" -U "Debug CrackMe" trace objc objc objc trace objc uuid static類方法frida-trace -m "*[ComVendorDebugger* *]" -U -f com.robot.demo.app objc objc prace on class類frida-trace -i "getaddrinfo" -i "SSLSetSessionOption" -U -f com.robot.demo frida-trace -m "*[YDDummyApp.UserProfileMngr *]" -U -f com.robot.demo.app frida-trace -m "*[*URLProtection* *]" -U -f com.robot.demo for HTTPS挑戰信息frida-trace -m "*[NSURLSession* *didReceiveChallenge*]" -U -f com.robot.demo frida-trace -U -f com.robot.demo.app -I libsystem_c.dylib跟踪整個模塊。 frida-trace -p $myapp -I UIKit跟踪Uikit模塊。 frida-trace -f objc_playground -I CoreFoundation夢想核心夢想模塊。 frida-trace -I YDRustyKit -U -f com.yd.mobile追踪我自己的模塊。 frida-trace -m "-[NSURLRequest initWithURL:]" -U -f com.robot.demo獲取應用程序文件和APIS frida-trace -m "-[NSURL initWithString:]" -U -f com.robot.demo -U -F frida-trace -m "*[NSURL absoluteString]" -U -f com.robot.demo我最喜歡的
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.
編輯自動生成的模板JavaScript文件。
-----------
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
異議是由Frida提供動力的運行時移動探索工具包,用於評估移動應用程序的安全姿勢,而無需編寫腳本。
pip3 install objection
objection device_type獲取有關附加設備的信息objection explore開始異議探索objection explore --startup-command 'ios jailbreak simulate'
objection explore --startup-command 'ios jailbreak disable'
早期儀器
ls
env這將打印出應用程序庫,緩存和文檔目錄的位置!<shell command>運行OS命令file download <remote path> [<local path>]
file upload <local path> [<remote path>]
上傳/下載file cat <file>查看文件memory dump all <local destination> memory dump from_base <base_address> <size_to_dump> <local_destination>
轉儲所有內存/轉儲零件memory list modules列表已加載的模塊中的模塊memory list exports <module_name>已加載模塊的導出memory search "<pattern eg: 41 41 41 ?? 41>" (--string) (--offsets-only)
memory write "<address>" "<pattern eg: 41 41 41 41>" (--string)
搜索/寫sqlite connect pewpew.sqlite查詢sqlite數據庫sqlite execute schema查看表結構sqlite execute query select * from data;
執行任何查詢import <local path frida-script>導入frida腳本jobs list運行腳本/作業jobs kill <job id>殺死腳本/工作ios plist cat credentials.plist讀取PLIST文件ios info binary檢查二進制信息ios sslpinning disable --quiet disable ssl固定ios jailbreak simulate模擬越獄環境,以了解應用程序的行為ios jailbreak disable越獄檢測旁路ios nsuserdefaults get dump nsuserdefaults
ios nsurlcredentialstorage dump nsurlcredentialStorage
ios keychain dump應用程序鑰匙扣ios cookies get獲得安全的標誌和存儲在cookie中的敏感數據ios monitor crypto monitor掛鉤CommonCrypto以輸出有關加密操作的信息ios ui dump UI層次結構ios ui alert "<message>"顯示警報
env本地應用程序路徑ios bundles list_bundles list列表捆綁ios bundles list_frameworks列表應用程序使用的外部框架ios hooking list classes的應用程序類ios hooking search classes <str>搜索一個包含字符串的類ios hooking list class_methods列表特定類的方法ios hooking search methods <str>搜索一種包含字符串的方法ios hooking watch class <class_name>
連接類的所有方法,轉儲所有初始參數並返回ios hooking watch method "-[<class_name> <method_name>]" --dump-args --dump-return --dump-backtrace
連接類的特定方法,將參數,回溯和返回的參數傾倒ios hooking set return_value "-[<class_name> <method_name>]" false
這將使選定的方法返回指示的布爾值ios hooking generate simple <class_name>
生成鉤模板。
r2 frida://device-id/Snapchat連接到運行的應用程序。
r2 frida://attach/usb//Gadget
r2 frida://device-id//com.snapchat.android使用兩個//和軟件包名稱產生應用程序。
r2 frida://spawn/usb/device-id/com.android.app或明確使用spawn一詞r2 frida://spawn/usb//com.android.app或不輸入device-id
=!?獲取命令列表
=!?~^i :
i顯示目標信息ii[*]列表導入il列表庫is[*] <lib>列表lib的符號(本地和全局)
iE[*] <lib>與IS相同,但僅適用於全局iEa[*] (<lib>) <sym>顯示導出符號的地址isa[*] (<lib>) <sym>顯示符號的地址ic <class>列出<class>的Objective-C類或方法ip <protocol>列出<solocation>的Objective-C協議或方法=!i顯示目標信息=!i*以R2形式顯示目標信息.=!i* Radare2從Frida導入所有動態二進制數據。例如:哪些體系結構,末端性,指針尺寸等...
.=!iE* Radare2為所有動態庫導入Frida的所有動態export數據。
.=!iE* <lib> Radare2僅為一個特定庫導入Frida的所有動態export數據。
.=!ii* Radare2從Frida導入所有動態import數據。
=!ii <lib>列表導入。通常與符號~一起使用,即r2的內部GREP。
=!ii* <lib>列表以R2表單導入。
=!il列表庫。通常與符號~一起使用,即R2的內部GREP。
=!iE <lib>庫的列表出口(IES)
=!iEa (<lib>) <sym>顯示導出符號的地址=!iEa* (<lib>) <sym>顯示出導出符號的地址R2格式=!isa[*] (<lib>) <sym>顯示符號的地址=!ic列表類=!/ keyword搜索十六進制/字符串模式在內存範圍內(請參閱search.in =?)
> =!?~^/ :
/[x][j] <string|hexpairs>搜索記憶範圍中的十六進制/字符串模式(請參閱search.in =?)
/w[j] string搜索寬字符串/v[1248][j] value搜索尊敬e cfg.bigendian的價值的價值。
> =!?~^d :
db (<addr>|<sym>)列表或放置斷點db- (<addr>|<sym>)|*刪除斷點(s)
dc繼續斷點或恢復產生的過程dd[-][fd] ([newfd])列表,DUP2或關閉歸檔的列表dm[.|j|*]顯示內存區域dma <size>在堆上分配字節,返回地址dmas <string>分配堆上的字符串dmad <addr> <size>在堆上分配字節,從dmal列表使用DMA創建的Live Heatp分配dma- (<addr>...)殺死(或無參數的所有分配)
dmp <addr> <size> <perms>更改頁面
dmm列表全部命名為壁球地圖dmh列出了所有分配的塊dmhj列出了JSON中所有分配的塊dmh*作為R2標誌導出堆和區域dmhm顯示哪些地圖用於分配堆塊dp顯示當前PIDdpt顯示線程dr顯示線程寄存器(請參閱DPT)dl libname dlopen a庫dl2 libname [main]使用frida> = 8.2新API注入庫dt (<addr>|<sym>) ...地址或符號的跟踪列表dth (<addr>|<sym>) (x y..)定義功能標頭(z = str,i = int,v = hex barray,s = barray)dt-清除所有跟踪dtr <addr> (<regs>...)跟踪寄存器值dtf <addr> [fmt]帶格式(^ixzo)的跟踪地址(請參閱DTF?)dtSf[*j] [sym|addr]使用纏擾者(frida> = 10.3.13)的跟踪地址或符號dtS[*j] seconds使用纏擾器跟踪給定秒的所有線程di[0,1,-1] [addr]截距並替換地址的返回值dx [hexpairs]注入代碼並執行(todo)dxc [sym|addr] [args..]用給定的args調用目標符號e[?] [a[=b]] list/get/set config可評估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列表iOS類
更多信息:https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06c-reverse-wearkineering-engineering-and-tampering-and-tampering#tampering-andpering-and-luntime-runtime-mentrumentation
Frida Gui。
Frida Gui。
Frida Gui。 https://github.com/fuzzysecurity/fermion
更多信息:
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-obpoction
Apple的權利故障排除 - https://developer.apple.com/library/content/content/technotes/tn2415/_index.html
蘋果的代碼簽名 - https://developer.apple.com/support/code-signing/
concript手冊 - http://www.cycript.org/manual/
Frida IOS教程 - https://www.frida.re/docs/ios/
Frida IOS示例 - https://www.frida.re/docs/examples/ios/
R2Frida Wiki - https://github.com/enovella/r2frida-wiki/blob/master/master/readme.md
查理·米勒(Charlie Miller),Dino Dai Zovi。 iOS黑客手冊。 Wiley,2012 - https://www.wiley.com/en-us/ios+hacker's+Handbook-p-9781118204122
喬納森·萊文(Jonathan Levin)。 Mac OS X和iOS內部:蘋果的核心。 Wiley,2013 - http://newosxbook.com/moxii.pdf
從https://github.com/nabla-c0d3/ssl-kill-kill-switch2/releases/安裝SSL殺死開關2
打開您的設置並啟用SSL Kill Switch 2
在PC上運行Charles。
在iOS設備上安裝查爾斯根證書:
幫助→SSL代理→在移動設備或遠程瀏覽器上安裝Charles Root證書。
以下窗口將顯示:
根據您的網絡體系結構,Charles運行的IP地址可能會有所不同。
代理→SSL代理設置...→添加(include)→主機: * ;港口: *
由於AN .IPA中的所有二進製文件都用AE進行加密,並在運行時通過安全飛地處理器對私鑰進行解密,因此有幾種方法可以解密它:
如果您沒有node.js:
brew install nvm
nvm install node
要使用Bagbak實用程序將IPA解密,將其安裝在桌面上:
sudo npm install -g bagbak
然後從App Store下載您的應用程序並轉儲:
bagbak <bundle id or name> --uuid <uuid> --output <output>
有幾種運行硬件AES引擎的方法:
補丁IBOOT跳到aes_crypto_cmd
使用openiboot
使用XPWN與內核補丁
使用GreenPois0n控制台:
ideviceenterrecovery
irecovery --shell
go aes dec <file>
使用IPWNDFU
使用checkra1n
使用-p運行checkra1n,以遇到pongoos(https://github.com/checkra1n/pongoos),並在USB上使用aes命令
如果要從App Store拆卸應用程序,請先刪除Fairplay DRM。
解密.IPA文件後,以IDA Pro這樣的拆卸器打開應用二進製文件。
在本節中,“應用程序二進制”一詞是指包含編譯代碼的應用程序包中的Macho -O文件,不應與應用程序捆綁包 - IPA文件混淆。
如果您有IDA Pro的許可證,則可以使用IDA Pro分析應用二進製文件。
首先,只需在IDA Pro中打開應用二進製文件即可。
打開文件後,IDA Pro將執行自動分析,這可能需要一段時間,具體取決於二進制的大小。自動分析完成後,您可以在IDA視圖(拆卸)窗口中瀏覽拆卸,並在功能窗口中探索功能,這兩者都在下面的屏幕截圖中顯示。
https://github.com/chichou/ida-objcexplorer/blob/master/objcexplore.py - obj-c class Explorer for Ida pro。只需按Ctrl + Shift + E即可。
https://github.com/avast/retdec-idaplugin - IDA Pro的RetDec分解器。只需按CTRL + D。
https://github.com/zynamics/objc-helper-plugin-ida - Zynamics Objective-C-C Helper腳本。
https://github.com/techbliss/frida_for_ida_pro - Connect Frida。
https://github.com/vadimszzz/idapython/blob/master/cortex_m_firmware.py - 用於加載ARM Cortex Cortex M固件的IDA Python模塊。
https://github.com/saelo/ida_scripts/blob/master/kernelcache.py - 在iOS kernelcache中識別和重命名函數存根。
https://github.com/luismiras/ida-ios-scripts/blob/master/find_ios_syscalls.py - 查找iOS syscalls。
https://github.com/stefanesser/ida-ios-toolkit/blob/master/listallkext.py - 列出所有kexts。
https://github.com/stefanesser/ida-ios-toolkit/blob/master/findsyscalltable.py - 此腳本搜索iOS kernelcache中的iOS syscall表。
https://github.com/stefanesser/ida-ios-toolkit/blob/master/fixupsysctlset.py-此腳本確保正確標記了SYSCTL_SET段引用的所有SYSCTL_OID結構。
https://github.com/bazad/ida_kernelcache - 用於分析iOS kernelcaches的IDA工具包。
您可以使用class-dump獲取有關應用程序源代碼中方法的信息。
注意架構: armv7 (32位)和arm64 。脂肪二進制的這種設計允許將應用程序部署在所有設備上。要用類dump分析應用程序,我們必須創建一個所謂的薄二進製文件,該二進制僅包含一個體系結構:
iOS8-jailbreak:~ root# lipo -thin armv7 DamnVulnerableIOSApp -output DVIA32
然後,我們可以繼續執行班級 - dump:
iOS8-jailbreak: ~ root# class-dump DVIA32
@interface FlurryUtil : ./DVIA/DVIA/DamnVulnerableIOSApp/DamnVulnerableIOSApp/YapDatabase/Extensions/Views/Internal/
{
}
+ (BOOL)appIsCracked ;
+ (BOOL)deviceIsJailbroken ; 注意加號,這意味著這是返回Bool類型的類方法。負符號將意味著這是一種實例方法。請參閱以後的部分,以了解它們之間的實際差異。
分析二進製文件時,字符串始終是一個很好的起點,因為它們為相關代碼提供了上下文。例如,諸如“加密圖生成失敗”之類的錯誤日誌字符串使我們暗示相鄰的代碼可能負責生成加密圖。
為了從iOS二進制中提取字符串,您可以使用GUI工具(例如Ghidra或Cutter),也可以依靠基於CLI的工具,例如字符串Unix Unix Utility strings <path_to_binary>或Radare2的Rabin2 Rabin2 rabin2 -zz <path_to_binary> 。當使用基於CLI的工具時,您可以利用其他工具(例如,與正則表達式結合使用)來進一步過濾和分析結果。
NM
nm libprogressbar.a | less
Rabin2
rabin2 -s file
RADARE2
is~FUNC
檢查URL:
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可用於通過右鍵單擊所需功能並選擇Show Xrefs來獲取交叉引用。
w0 = 32位x0 = 64位wzr或xzr 。寫入=丟棄,從= 0讀取。sp與其他指令集不同,從未隱式修改(例如沒有push / pop )。pc ,不直接修改。str除外)。mov將一個寄存器複製到另一寄存器,例如mov x0, x1 > x0 = x1 。0從wzr / xzr加載。orr x0, xzr, 5 。movz + movk ,例如: movz x0 , 0x1234 , lsl 32
movk x0 , 0x5678 , lsl 16
movk x0 , 0x9abcx0 = 0x123456789abc 。movn負值,例如movn x0, 1 > x0 = -1 。lsl和lsr指令= Logic-Shift-Left和Logic-Shift-Right,例如lsl x0, x0, 8 > x0 <<= 8 。lsl和lsr不僅用作說明,而且用作其他說明的操作數(請參見上面的movz )。asl也存在,但使用頻率較低。ldr和str具有多種變化和解決模式:ldr x0, [x1] - > x0 = *x1str x0, [x1] - > *x1 = x0ldr x0, [x1, 0x10] - > x0 = *(x1 + 0x10)ldp / stp一次加載 /存儲兩個寄存器,例如:stp x0, x1, [x2] - > *x2 = x0; *(x2 + 8) = x1;xN位, wN ,32位ldrh / srth 16位ldrb / strb用於8位ldrsw x0, [x1] - >加載32位INT,符號延伸至64位ldrsh x0, [x1] - >加載16位int,符號延伸至64位ldrsb x0, [x1] - >加載8位int,符號延伸至64位str指令)ldr x0, [x1, 0x10]ldr x0, [x1, 0x10]! (注意! ) - > x1 += 0x10; x0 = *x1;ldr x0, [x1], 0x10 > x0 = *x1; x1 += 0x10;adr x0, 0x12345 (僅適用於PC的小偏移)adrp + add : adrp x0 , 0xffffff8012345000 ; "address of page", last 12 bits are always zero
add x0 , x0 , 0x678ldr 。注意:僅在此處處理積分類型。涉及浮點時,規則會改變。
x0 x7前8個參數,以自然對齊(好像它們是結構的成員)放在堆棧上(低地址)x8指針指向在何處寫入返回值(如果> 128位),否則刮擦寄存器x9 x17刮擦寄存器x18平台寄存器(保留,定期由XNU歸零)x19 x28 callee savedx29框架指針(基本上也只是Callee Save)x30返回地址x19 x28中保存任何內容的函數通常以這樣的方式開始: 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...和sub sp, sp, 0x...x0 x7的參數,在堆棧上的variadic參數自然對齊之前。x0中。x0中的第一/下半部分,第二/下半部分為x1 。x8指針傳遞到了結果編寫的位置。nzcv保存條件標誌(負,零,隨身攜帶,溢出)。instr.cond ),而另一些說明則作為源操作數( instr ..., cond )。條件代碼列表:eq / ne =等於 /不相等lt / le / gt / ge =小於 /少或相等 /大於 /大或相等(簽名)lo / ls / hi / hs =較低 /較低或相同 /更高 /更高或相同(未簽名)cs / cc =隨身攜帶 /隨身攜帶是hs / lo的別名。cmp =最常見/基本比較指令,設置條件標誌。示例: cmp x0 , x1
cmp x0 , 3cmn =比較負面tst =位測試adds / adcs =添加 /添加隨身攜帶subs / sbcs =隨身攜帶 /減法 /減法negs / ngcs =否定 /否定cset =條件集,例如: cmp x0 , 3
cset x0 , lox0 = (x0 < 3)csel =條件選擇,例如: cmp x0 , 3
csel x0 , x1 , x2 , lox0 = (x0 < 3) ? x1 : x2ccmp =條件比較,例如: cmp x0 , 3
ccmp x0 , 7 , 2 , hs
b.hi 0xffffff8012345678hi條件將為x0 < 3 || x0 > 7 (第三ccmp操作數是RAW nzcv數據)。b =簡單的分支,跳到PC相關地址。 b 0xffffff8012345678 cmp x0 , 3
b.lo 0xffffff8012345678 ; jump to 0xffffff8012345678 if x < 3cbz / cbnz =比較零和分支 - 零-non-Zero。 cmp xN , 0
b.eq 0x... cmp xN , 0
b.ne 0x...if(x)或if(!x)很好地轉換為C。)。tbz / tbnz =測試單位和分支如果零 /非零。tbz x0, 3, ...轉化為if((x0 & (1 << 3)) == 0) goto ...bl =分支鏈接(例如bl 0xffffff8012345678 )x30 ,然後跳到PC相關地址。用於靜態功能調用。blr =分支鏈接要註冊(例如blr x8 )x30 ,然後跳到x8中的地址。用於帶有功能指針或C ++虛擬方法的調用。br =註冊分支(例如br x8 )x8中的地址。用於尾聲。ret =返回寄存器中的地址,默認值: x30x30以外的其他寄存器(例如ret x8 ),但編譯器通常不會產生。nop =什麼都不做svc =使用即時值(例如svc 0x80 )進行系統調用。請注意,即時值與SYSCALL編號分開。 XNU忽略了即時的,並期望x16中的SYSCALL編號。. =指指令地址的特殊符號在(例如adr x0, . )中使用。安裝以下先決條件:
brew install ldid xz
設置THEOS環境變量:
echo "export THEOS=~/theos" >> ~/.zshrc
source ~/.zshrc
克隆人Theos:
git clone --recursive https://github.com/theos/theos.git $THEOS
獲取工具鏈:
Xcode包含工具鏈。
獲取iOS SDK:
Xcode始終提供最新的iOS SDK,但是從Xcode 7.3開始,它不再包括您可以鏈接的私人框架。在開發調整時,這可能是一個問題。您可以從我們的SDKS Repo中獲得修補的SDK。
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
徽標是一個基於Perl Regex的預處理器,簡化了使用優雅的Objective-C樣語法為Objective-C方法和C函數創建掛鉤所需的樣板代碼。它最常用於Theos Build System,最初是為了創建越獄調整而開發的。徽標曾經與Theos集成在一起,但現在已從Theos脫鉤到其自己的存儲庫。
徽標的目的是默認情況下為Cydia基板提供一個接口,但可以配置為直接使用Objective-C運行時。
徽標是Theos開發套件的組成部分。
%hookf(return type, functionName, arguments list...) {
/* body */
}
為名為functionName的函數生成函數鉤。如果應動態查找符號,則在%init中set functionName in %init 。
例子:
// 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 */
}
生成一個匿名構造函數(默認優先級)。將二進制裝入內存後執行此功能。 argc , argv和envp是隱式參數,因此可以像在main功能中一樣使用它們。
%dtor {
/* body */
}
生成匿名解構器(默認優先級)。此功能在從內存中卸載二進制之前執行。 argc , argv和envp是隱式參數,因此可以像在main功能中一樣使用它們。
此類別中的指令打開了一個代碼塊,該代碼必須由%端指令關閉(如下所示)。這些不應在功能或方法中存在。
%group GroupName
/* %hooks */
%end
生成一個帶有名稱GroupName名稱的鉤組。組可用於有條件的初始化或代碼組織。所有未分組的鉤子都在默認組中,可通過%init初始化而無需參數。
不能在另一個%組塊中。
分組可用於管理與較舊代碼的向後兼容性。
例子:
%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
為名為ClassName的類打開鉤塊。
可以在一個%的組塊中。
例子:
%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 */
通過在方法定義上方添加此指令,將新方法添加到鉤類或子類中。簽名是針對新方法的Objective-C類型編碼;如果省略了,將生成一個。
必須在%掛鉤或%子類塊中。
例子:
%new
- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer {
NSLog(@"Recieved tap: %@", gestureRecognizer);
}
%subclass ClassName: Superclass <Protocol list>
/* %properties and methods */
%end
在運行時生成子類。像普通Objective-C類中的@property一樣,您可以使用%屬性將屬性添加到子類中。對於超類中不存在的方法,需要%新規範符。要實例化新類的對象,您可以使用%c運算符。
可以在一個%的組塊中。
例子:
// 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;
就像使用@property一樣,將屬性添加到%子類中,並將新屬性添加到%掛鉤中的現有類中。
必須在%掛鉤或%子類塊中。
%end
關閉%組,%掛鉤或%子類塊。
此類別中的指令僅在函數或方法主體內存在。
%init;
%init([<ClassName>=<expr>, …]);
%init(GroupName[, [+|-]<ClassName>=<expr>, …]);
初始化組的方法和功能鉤。傳遞沒有組名將初始化默認組。通過ClassName=expr參數將在初始化時替代給定的表達式。 + sigil(如“目標-C中的類方法”中)可以擬合到className以替換元表的表達式。如果未指定,Sigil默認為-代替類本身。如果未指定,則元素是從類得出的。
類名稱更換對於包含無法用作百分比指令的類名稱的字符(例如空格和點)的類也很有用。
例子:
%hook ClassName
- (id)init {
return %orig;
}
%end
%ctor {
%init(ClassName=objc_getClass("SwiftApp.ClassName"));
}
%c([+|-]ClassName)
在運行時評估ClassName 。如果指定了+ sigil,則將其評估為元類,而不是類。如果未指定,Sigil默認為- ,評估為類。
%orig
%orig(args, …)
調用原始掛鉤功能或方法。不適用於%新方法。奇怪的是,在子類中工作,因為Mobilesubstrate會在掛鉤時產生超級呼叫的關閉。 (如果我們正在掛接的類中的鉤方法不存在,它會創建一個剛剛稱為超類實現的存根。) args將傳遞給原始函數 - 不包括self和_cmd ,徽標為您來做。
例子:
%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
獲取指向原始功能或方法的指針。返回類型為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
peferenceloader的現實世界示例
%log;
%log([(<type>)<expr>, …]);
將方法參數轉移到Syslog。 %log中包含的鍵入參數也將記錄。
您可以使用logify.pl來從標頭文件創建徽標源文件,該文件將記錄該標頭文件的所有功能。這是Logify.pl生成的非常簡單的徽標調整的示例。
給定一個名為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
您可以在$ theos/bin/logify.pl上找到logify.pl,然後將其使用:
$THEOS/bin/logify.pl ./SSDownloadAsset.h
最終的輸出應為:
%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
| 擴大 | 過程順序 |
|---|---|
| x | 將通過徽標處理,然後進行預處理並作為Objective-C進行編譯。 |
| XM | 將通過徽標處理,然後進行預處理並作為Objective-C ++編譯。 |
| xi | 將首先進行預處理,然後徽標將處理結果,然後將其編譯為Objective-C。 |
| XMI | 將首先進行預處理,然後徽標將處理結果,然後將其編譯為Objective-C ++。 |
XI或XMI文件使徽標指令可用於預處理器宏(例如#define )中。您還可以使用#include語句導入其他徽標源文件。但是,這是不鼓勵的,因為這會導致較長的構建時間重新編譯代碼,但沒有改變。建議分為X和XM文件,通過extern聲明共享變量和功能。
這些文件擴展可以控制構建系統(例如Theos)的構建方式。徽標本身不會考慮文件擴展名,並且無論文件是Objective-C還是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