OS X는 적합한 유닉스 시스템으로서 모든 UNIX 풍미에 표준 인 잘 알려진 디렉토리와 함께 작동합니다.
OS X는 시스템 루트 아래에서 유닉스 트리에 자체 특수 디렉토리를 추가합니다.
파일 시스템 관점에서 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
응용 프로그램 사용자는 모바일 사용자로 실행할 수 있고 중요한 시스템 프로세스는 루트 로 실행됩니다. 그러나 샌드 박스를 사용하면 프로세스 및 응용 프로그램이 수행 할 수있는 작업을보다 잘 제어 할 수 있습니다.
예를 들어, 두 프로세스가 동일한 사용자 (모바일)로 실행 되더라도 서로의 데이터에 액세스하거나 수정할 수 없습니다 .
각 응용 프로그램은 /var/mobile/Applications/<UUID> 아래에 설치됩니다. uuid는 무작위입니다. 일단 설치되면 응용 프로그램은 일부 시스템 영역 및 기능 (SMS, 전화 통화 ...)에 대한 읽기 액세스가 제한되어 있습니다. 응용 프로그램이 보호 구역 에 액세스하려는 경우 팝업 요청 허가가 나타납니다.
앱 개발자는 iOS 데이터 보호 API를 활용하여 플래시 메모리에 저장된 사용자 데이터에 대한 세밀한 액세스 제어를 구현할 수 있습니다. API는 Sep ( Secure Enclave 프로세서 ) 위에 구축됩니다. SEP는 데이터 보호 및 키 관리를위한 암호화 작업을 제공하는 공동 프로세서입니다. 장치 별 하드웨어 키- 장치 UID (고유 ID)- 보안 엔 클레이브에 내장되어 운영 체제 커널이 손상된 경우에도 데이터 보호의 무결성을 보장합니다.
디스크에서 파일이 생성되면 Secure Enclave의 하드웨어 기반 랜덤 번호 생성기를 사용하여 새로운 256 비트 AES 키가 생성됩니다. 그런 다음 파일의 내용이 생성 된 키로 암호화됩니다. 그런 다음이 키는 클래스 ID와 함께 클래스 키로 암호화되며 파일의 메타 데이터 내부에서 시스템 키에 의해 암호화되어 있습니다.
파일을 해독하기 위해 메타 데이터는 시스템 키를 사용하여 해독됩니다. 그런 다음 클래스 ID를 사용하여 클래스 키를 검색하여 파일당 키를 해독하고 파일을 해독합니다.
파일은 4 가지 다른 보호 클래스 중 하나에 할당 할 수 있으며 iOS 보안 안내서에 자세히 설명되어 있습니다.
각 앱에는 고유 한 홈 디렉토리가 있으며 샌드 박스가 있으므로 시스템이나 다른 앱에서 저장된 보호 시스템 리소스 또는 파일에 액세스 할 수 없습니다. 이러한 제한은 샌드 박스 정책 (일명 프로파일 )을 통해 구현되며, 이는 커널 확장을 통해 신뢰할 수있는 BSD (MAC) 필수 액세스 제어 프레임 워크에 의해 시행됩니다.
일부 기능/권한은 앱 개발자 (예 : 데이터 보호 또는 키 체인 공유)에서 구성 할 수 있으며 설치 후 직접 발효됩니다. 그러나 다른 사람들의 경우 앱이 보호 된 리소스에 처음 액세스하려고 시도 할 때 사용자에게 명시 적으로 요청 받게됩니다 .
목적 문자열 또는 사용법 설명 문자열은 보호 된 데이터 또는 리소스에 액세스 할 수있는 권한을 요청할 때 시스템의 권한 요청 경고에 대해 사용자에게 제공되는 사용자 정의 텍스트입니다.
원래 소스 코드가있는 경우 Info.plist 파일에 포함 된 권한을 확인할 수 있습니다.
Info.plist 파일을 찾아서 "Privacy -" 로 시작하는 키를 검색하십시오. "원시 키/값 표시"(예 : "Privacy - Location When In Use Usage Description" NSlocationScription에서 NSLocationWhenInUseUsageDescription 으로 전환)를 마우스 오른쪽 버튼으로 클릭하고 선택하여 원시 값을 표시하도록보기를 전환 할 수 있습니다.
IPA 만있는 경우 :
Info.plist 는 Payload/<appname>.app/Info.plist 에 있습니다.plutil -convert xml1 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 사용자 ID와 같은 런타임 요소 이상의 인증을 허용합니다. 자격이 디지털로 서명되므로 변경할 수 없습니다. 자격은 시스템 앱과 데몬에 의해 광범위하게 사용되어 프로세스가 루트로 실행되도록 요구하는 특정 권한있는 작업을 수행합니다. 이는 타협 된 시스템 앱 또는 데몬으로 특권 에스컬레이션의 잠재력을 크게 줄입니다.
예를 들어 "기본 데이터 보호"기능을 설정하려면 Xcode의 기능 탭으로 이동하여 데이터 보호를 활성화해야합니다. 이것은 xcode에 의해 <appname>.entitlements 파일에 직접 작성하여 기본값 NSFileProtectionComplete 를 사용한 com.apple.developer.default-data-protection 자격으로 직접 작성됩니다. IPA에서 우리는 이것을 embedded.mobileprovision 에서 찾을 수 있습니다.
<key>Entitlements</key>
<dict>
...
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
</dict>
HealthKit과 같은 다른 기능의 경우 사용자에게 권한을 요청해야하므로 앱의 Info.plist 파일에 자격, 특수 키 및 문자열을 추가하는 것만으로는 충분하지 않습니다.
Secure Enclave는 데이터 보호, 터치 ID 및 얼굴 ID에 사용되는 A7 및 최신 SOC의 일부입니다. 보안 엔 클레이브의 목적은 응용 프로그램 프로세서가 처리하지 않을 정도로 민감한 생체 인식과 같은 키 및 기타 정보를 처리하는 것입니다. 하드웨어 필터로 분리되어 AP가 액세스 할 수 없습니다. AP와 RAM을 공유하지만 RAM의 일부 - TZ0은 암호화됩니다. Secure Enclave 자체는 Sep (Secure Enclave Processor)라고하는 Flashable 4MB AKF 프로세서 코어입니다. 사용 된 기술은 ARM의 Trustzone/Securcore와 유사하지만 일반적으로 Apple KF 코어 및 SEP에 대한 독점 코드가 포함되어 있습니다.
각 장치의 SOC에는 GID 키 및 UID 키가 내장 된 AES 공동 프로세서가 있습니다.
장치의 고유 한 ID (UID) 및 장치 그룹 ID (GID)는 제조 중에 AES 256 비트 키 (UID) 또는 컴파일 된 (GID)입니다. 소프트웨어 나 펌웨어는 직접 읽을 수 없습니다. 그들은 암호화 또는 암호 해독 작업 결과를 사용하여 수행 한 결과 만 볼 수 있습니다. UID는 각 장치마다 고유하며 Apple 또는 해당 공급 업체가 기록하지 않습니다. GID는 장치 클래스의 모든 프로세서에 공통적이며 설치 및 복원 중에 시스템 소프트웨어를 제공 할 때 추가적인 보호 수준으로 사용됩니다. 이러한 키를 실리콘에 통합하면 AES 엔진 외부에서 변조하거나 우회하거나 우회하거나 접근하는 것을 방지 할 수 있습니다.
GID 키 ( Group ID 키 )는 동일한 응용 프로그램 프로세서가있는 모든 장치에서 공유하는 256 비트 AES 키입니다. GID 키는 iOS가 장치의 소프트웨어를 암호화하는 방법의 일부입니다. 이것은 iOS 보안 시스템의 하나이며 SHSH 서명도 포함됩니다. 이 키는 각 Apple SoC 모델마다 다릅니다.
GID 키는 지금까지 어떤 장치에서도 추출되지 않았으므로이를 사용하는 유일한 방법은 AES 엔진 자체를 통과하는 것입니다.
하지만
GID는 값 비싼 콜드 부트 공격 절차 (https://en.m.wikipedia.org/wiki/cold_boot_attack)를 통해 얻을 수 있으며 , 전자-빔 석판 학자 Raith chipscanner (https://minateh.ru.equipment/eeaknological/eeam-lithipment/eeam-lithipment/eeam-lithipment/eeam-lithipment/eeam-lithophipment/eeam-lithipment/eeam-lithnerography)로 SOC를 스캔하는 다음은 비싼 절차를 통해 얻을 수 있습니다. 이러한 실험은 불분명하게 비싸고 복잡하므로 개인 실험실 Cellebrite를 제외하고는 아무도 구현하려고 시도하지 않았습니다. Cellebrite는 연구를 공유하지 않습니다.
UID 키 ( Device의 고유 ID 키 )는 각 iPhone마다 고유 한 AES 256 비트 하드웨어 키입니다.
일부 파생 된 키는 부팅시 IOAESACCELERATOR 커널 서비스에 의해 계산됩니다. 이 키는 UID 키 (0x7d0 식별자) 또는 GID 키 (0x3E8 식별자)와 함께 정적 값을 암호화하여 생성됩니다.
키 0x835 -UID-Key와 함께 0x01010101010101010101010101010101 암호화하여 생성. 데이터 보호에 사용됩니다.
키 0x836 -UID-Key와 함께 0x00E5A0E6526FAE66C5C1C6D4F16D6180 암호화하여 생성됩니다. 이것은 복원 중에 커널에 의해 계산되지만 일반적인 부팅 중에는 제로화됩니다. 또한 Secure Bootloader에 의해 계산되며 LLB를 NOR로 해독하는 것이 알려진 유일한 용도입니다. 0x835 와 마찬가지로 각 장치마다 다릅니다.
키 0x837 - S5L8900 GID 키를 사용하여 0x345A2D6C5050D058780DA431F0710E15 암호화하여 생성하여 0x188458A6D15034DFE386F23B61D43774 를 초래합니다. IMG2 파일의 암호화 키로 사용됩니다. iPhone OS 2.0에 IMG3가 도입되면 이제 0x837 키 대신 KBag가 사용됩니다. iPhone OS 버전 1.x는 iPhone 및 iPod Touch (S5L8900 사용)에서만 사용 되었기 때문에 다른 프로세서의 암호화 된 값은 중요하지 않습니다.
키 0x838 -UID-Key와 함께 0x8C8318A27D7F030717D2B8FC5514F8E1 암호화하여 생성됩니다. 또 다른 UID-AES-KEY 기반 키는 NOR (iboot, Devicetree, Pictures)에서 LLB를 제외한 모든 것을 암호화하는 데 사용됩니다.
키 0x899 -UID-Key와 함께 0xD1E8FCB53937BF8DEFC74CD1D0F1D4B0 암호화하여 생성됩니다. 사용되지 않은 사용.
키 0x89a -UID-Key를 사용하여 0xDB1F5B33606C5F1C1934AA66589C0661 암호화하여 생성하여 장치 별 키를 얻습니다. A4 장치에서 사용됩니다. 장치의 SHSH Blobs를 암호화하는 데 사용됩니다.
키 0x89B -UID-Key와 함께 0x183E99676BB03C546FA468F51C0CBD49 암호화하여 생성됩니다. 데이터 파티션 키를 암호화하는 데 사용됩니다.
키 0x8A3 -UID-KEY (AES-256-CBC 사용)를 사용하여 0x568241656551e0cdf56ff84cc11a79ef 암호화하여 생성됩니다. A12의 소프트웨어 업그레이드 중에 사용하여 "Generator"값 (AES-128-CBC 사용)을 암호화하기 전에 NOCE가되기 위해 사용됩니다.
추가 정보 : 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로 생성 된 클래스의 모든 객체는 힙에 할당되어야합니다. 따라서 모든 클래스 (실제로 void *)의 객체에 대한 포인터 인 ID 유형은 특별한 의미를 얻습니다. 널 포인터를 상수 NIL이라고합니다. 따라서 모든 클래스에 대한 포인터는 ID 유형으로 시전 할 수 있습니다. 문제가 발생합니다 : ID 아래에 숨어있는 객체가 어떤 클래스에 속하는지 알아내는 방법은 무엇입니까? 이는 ISA 불변 덕분에 이루어집니다. 이는 특수 기본 클래스 NSObject를 물려받는 클래스의 모든 객체에 존재합니다 (NS 접두사는 다음 단계를 나타냅니다). ISA 불변은 예약 된 유형 클래스입니다. 이 유형의 객체를 사용하면 자체 및 기본 클래스의 이름, 클래스 불일치 세트,이 객체가 구현 한 모든 메소드의 프로토 타입과 주소 (로컬 선택기 목록을 통해)를 찾을 수 있습니다. C 예약 된 단어 이외의 모든 대상 C 예약 단어는 @symbol (예 : @protocol, @selector, @interface)으로 시작합니다. 일반적으로 스코프 클래스 불일한 (@private, @protected)의 이름은 밑줄로 시작합니다. 문자열의 경우 Cocoa에는 매우 편리한 NSString 클래스가 있습니다. 이 클래스의 문자열 상수는 일반적인 C 문자열 상수 "Hello World"가 아닌 @"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) 메소드 이름에 대한 컴파일 된 선택기를 반환합니다.
@protocol(protocol_name) protocol_name 이라는 프로토콜 클래스의 인스턴스를 반환합니다.
@encode(type_spec) 유형 type_spec 의 데이터를 암호화하는 데 사용될 문자열을 초기화합니다.
@synchronized() 주어진 시점에서 하나의 스레드만으로 실행되는 코드 블록을 정의합니다.
@implementation 클래스 또는 카테고리를 정의하기 시작합니다
@protocol 프로토콜 선언을 시작합니다 (순수한 가상 함수로 구성된 C ++ 클래스와 유사)
객체를 강제로하려면 메소드를 실행하려면 필요한 메소드와 동일한 메시지를 보내야합니다. 이 메시지를 메소드 선택기라고합니다. 전송을위한 구문은 다음과 같습니다.
[receiver method];
- (void) addObject: (id) otherObject;
메소드 프로토 타입의 시작 부분에 플러스 부호 + 넣으면 그러한 방법은 클래스 메소드로 간주되며 자연스럽게 암시 적자 매개 변수를 허용하지 않습니다 (이는 C ++에서 정적 메소드를 선언하는 것과 유사합니다). 그리고 자아를 가리키는 대상의 불변이 없다면, 슈퍼 포인터는 물론 작동하지 않을 것입니다. 따라서 모든 방법의 프로토 타입은 다음과 같이 선언됩니다.
- | + (<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에서 현을 검색하여 도메인을 추출 할 수 있습니다. 후자의 옵션은 명확한 이점이 있습니다. 교차 참조를 확인하여 각 도메인이 어떤 컨텍스트를 사용하는지 확인할 수 있으므로 컨텍스트를 제공 할 수 있습니다.
여기 에서이 정보를 사용하여 분석 중에 나중에 사용할 수있는 더 많은 통찰력을 도출 할 수 있습니다. 예를 들어 도메인을 고정 인증서와 일치 시키거나 도메인 이름에 대한 추가 정찰을 수행하여 대상 환경에 대해 더 많이 알 수 있습니다.
보안 연결의 구현 및 검증은 복잡한 프로세스가 될 수 있으며 고려해야 할 수많은 측면이 있습니다. 예를 들어, 많은 응용 프로그램은 XMPP 또는 일반 TCP 패킷과 같은 HTTP 외에 다른 프로토콜을 사용하거나 MITM 공격을 막기 위해 고정 된 인증서를 수행합니다.
네트워크 프레임 워크는 2018 년 Apple Worldwide Developers Conference (WWDC)에서 소개되었으며 Sockets API를 대체했습니다. 이 저수준 네트워킹 프레임 워크는 내장 된 동적 네트워킹, 보안 및 성능 지원으로 데이터를 보내고받을 수있는 클래스를 제공합니다.
TLS 1.3은 using: .tls 인수가 사용되는 경우 네트워크 프레임 워크에서 기본적으로 활성화됩니다. 레거시 보안 전송 프레임 워크보다 선호되는 옵션입니다.
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
이 연구는 기본적으로 iOS 10–15를 사용하여 CheckRa1ned iPhone 5s ~ X에 대해 작성되었으며 새로운 BootRom Pwnage 도구가 출시되면 장기적으로 업데이트 할 수 있습니다. https://www.theiphonewiki.com/wiki/bootrom#bootrom_exploits를 확인하십시오
https://repo.chariz.com )에 추가하십시오.killall SpringBoardfilza 파일 관리자가있는 .deb/.ipa 파일을 열고 설치를 누르십시오.
https://cydia.akemi.ai/ repo에서 appsync Unified를 설치하십시오
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 장치를위한 백업을 생성 또는 복원 (레거시) idevicebackup2 IOS 4 이상 idevicecrashreport Retrieve Retrieve Retrieve Retrieve Retrieve Retrieve Reports idevicedebug 의 디버그 서버 서비스와 DEBICEGUG idevicedebugserverproxy FRODEGUS STY의 디버그 서버 서비스와 상호 작용합니다. 원격 디버깅 이데 idevicediagnostics 의 연결 장치의 진단 인터페이스와 상호 작용하는 장치 ideviceenterrecovery 장치의 복구 모드 ideviceimagemounter MOUNT DISK IMAGE ideviceinfo 연결된 장치의 연결된 정보 idevicename 디스플레이에 대한 정보를 표시하거나 장치 이름 idevicepair 쌍에 대한 idevicescreenshot 표시합니다. 연결된 장치의 스크린 샷 idevicesetlocation DEATION idevicesyslog 릴레이 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 로컬 포트 22222222222의 22 개로 바인딩하고 첫 번째 USB 장치의 22 개
장치 애플 파일 도관 "2"에 설치
파일 시스템에 액세스하려면 imazing 또는 ifunbox를 사용하십시오
Filza 파일 관리자를 설치하십시오
장치에 OpenSsh를 설치하고 데스크탑에서 실행하십시오.
iproxy 2222:22
ssh -p 2222 root@localhost
root 의 기본 iOS 비밀번호는 alpine 입니다. 기억이 나쁘면 변경하지 마십시오
로컬 터미널을 사용하려면 https://repo.chariz.com 에서 Device 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 실행하십시오
이제 Statusbar의 Longpress로 모든 응용 프로그램 내부에서 Flex를로드 할 수 있습니다.
Frida는 이전에 잠긴 소프트웨어에서 스크립트를 실행할 수있는 동적 이진 계측 툴킷입니다. 간단히 말해 Frida를 사용하면 Windows, Mac, Linux, iOS 및 Android의 기본 앱에 JavaScript 스 니펫을 주입 할 수 있습니다.
cydia에 frida repo를 추가 - https://build.frida.re/
파이썬 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*" 기본 API를 추적합니다
frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"
앱을 시작하고 Crypto API 호출을 추적하십시오
frida-trace -U Twitter -m "-[NSURL* *HTTP*]" 추적 대상 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를 통해 열린 foobar 및 힘을 시작합니다. 앱 실행을 시작합니다
frida-ps -U | grep -i myapp USB 연결 장치에서 대상 앱의 프로세스 ID를 가져옵니다.
frida -U -f foobar --no-pause -q --eval 'console.log("Hi Frida");'
스크립트를 실행하고 Frida를 종료하십시오
이 시점에서 우리는 play_sound 변수에 NativeFunction 저장했습니다. 정기적 인 함수 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);
},
The results:
[+] _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: * ; Port: *
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 |
|---|---|
| 엑스 | 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