@leejungkiin/awkit 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/VERSION +1 -1
- package/bin/awk.js +1 -1
- package/core/GEMINI.md +4 -0
- package/package.json +1 -1
- package/skills/smali-to-kotlin/SKILL.md +521 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-swift/SKILL.md +749 -0
- package/skills/smali-to-swift/framework-patterns.md +189 -0
- package/skills/smali-to-swift/objc-reading-guide.md +388 -0
- package/workflows/mobile/reverse-android.md +740 -0
- package/workflows/mobile/reverse-ios.md +674 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# 📦 iOS Framework Detection Patterns
|
|
2
|
+
|
|
3
|
+
> Reference database for Step 0 (Framework Scanner).
|
|
4
|
+
> Agent uses these patterns to identify third-party frameworks from IPA structure, class-dump headers, and Mach-O linked libraries.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 🟢 Network & API
|
|
9
|
+
|
|
10
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
11
|
+
|-------------------|-----------|-------------------|--------|
|
|
12
|
+
| `Alamofire.framework` / `import Alamofire` | Alamofire | URLSession async/await | Evaluate |
|
|
13
|
+
| `AFNetworking.framework` / `#import <AFNetworking/...>` | AFNetworking | URLSession async/await | Replace |
|
|
14
|
+
| `Moya.framework` | Moya | URLSession + Endpoint enum | Evaluate |
|
|
15
|
+
| `Apollo.framework` | Apollo (GraphQL) | Keep (current) | Add via SPM |
|
|
16
|
+
| `SocketRocket.framework` / `SRWebSocket` | SocketRocket | URLSessionWebSocketTask | Replace |
|
|
17
|
+
| `Starscream.framework` | Starscream | URLSessionWebSocketTask | Evaluate |
|
|
18
|
+
| `SwiftyJSON.framework` | SwiftyJSON | Codable (built-in) | Replace |
|
|
19
|
+
| `ObjectMapper.framework` | ObjectMapper | Codable | Replace |
|
|
20
|
+
| `Mantle.framework` | Mantle | Codable | Replace |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🟡 Image Loading
|
|
25
|
+
|
|
26
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
27
|
+
|-------------------|-----------|-------------------|--------|
|
|
28
|
+
| `SDWebImage.framework` / `#import <SDWebImage/...>` | SDWebImage | Kingfisher / AsyncImage | Replace |
|
|
29
|
+
| `Kingfisher.framework` | Kingfisher | Keep (current) | Add via SPM |
|
|
30
|
+
| `Nuke.framework` | Nuke | Keep (current) | Add via SPM |
|
|
31
|
+
| `PINRemoteImage.framework` | PINRemoteImage | Kingfisher | Replace |
|
|
32
|
+
| `FLAnimatedImage.framework` | FLAnimatedImage | Kingfisher (GIF support) | Replace |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🔵 Reactive Programming
|
|
37
|
+
|
|
38
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
39
|
+
|-------------------|-----------|-------------------|--------|
|
|
40
|
+
| `RxSwift.framework` / `import RxSwift` | RxSwift | async/await + AsyncSequence | Gradual migrate |
|
|
41
|
+
| `RxCocoa.framework` | RxCocoa | SwiftUI bindings | Replace |
|
|
42
|
+
| `ReactiveSwift.framework` | ReactiveSwift | async/await + AsyncSequence | Replace |
|
|
43
|
+
| `Combine` (Apple built-in) | Combine | Keep or migrate to AsyncSequence | Evaluate |
|
|
44
|
+
| `PromiseKit.framework` | PromiseKit | async/await | Replace |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🟠 UI & Layout
|
|
49
|
+
|
|
50
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
51
|
+
|-------------------|-----------|-------------------|--------|
|
|
52
|
+
| `SnapKit.framework` / `import SnapKit` | SnapKit | SwiftUI layout | Replace |
|
|
53
|
+
| `Masonry.framework` / `#import <Masonry/...>` | Masonry | SwiftUI layout | Replace |
|
|
54
|
+
| `Cartography.framework` | Cartography | SwiftUI layout | Replace |
|
|
55
|
+
| `Lottie.framework` / `import Lottie` | Lottie | Keep (has SwiftUI support) | Add via SPM |
|
|
56
|
+
| `SVProgressHUD.framework` | SVProgressHUD | SwiftUI ProgressView | Replace |
|
|
57
|
+
| `MBProgressHUD.framework` | MBProgressHUD | SwiftUI ProgressView | Replace |
|
|
58
|
+
| `JGProgressHUD.framework` | JGProgressHUD | SwiftUI ProgressView | Replace |
|
|
59
|
+
| `IQKeyboardManager.framework` | IQKeyboardManager | SwiftUI keyboard handling | Remove |
|
|
60
|
+
| `TTTAttributedLabel.framework` | TTTAttributedLabel | SwiftUI Text + AttributedString | Replace |
|
|
61
|
+
| `Hero.framework` | Hero | NavigationTransition / matchedGeometryEffect | Evaluate |
|
|
62
|
+
| `DZNEmptyDataSet.framework` | DZNEmptyDataSet | SwiftUI ContentUnavailableView | Replace |
|
|
63
|
+
| `SkeletonView.framework` | SkeletonView | SwiftUI .redacted(reason:) | Replace |
|
|
64
|
+
| `Charts.framework` (danielgindi) | Charts | Swift Charts (iOS 16+) | Replace |
|
|
65
|
+
| `FSCalendar.framework` | FSCalendar | Custom SwiftUI Calendar | Replace |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 🟣 Firebase & Google
|
|
70
|
+
|
|
71
|
+
| Detection Pattern | Framework | Action |
|
|
72
|
+
|-------------------|-----------|--------|
|
|
73
|
+
| `FirebaseAnalytics.framework` / `FirebaseCore` | Firebase Analytics | Add latest via SPM |
|
|
74
|
+
| `FirebaseCrashlytics.framework` | Crashlytics | Add latest via SPM |
|
|
75
|
+
| `FirebaseMessaging.framework` | FCM | Add latest via SPM |
|
|
76
|
+
| `FirebaseAuth.framework` | Firebase Auth | Add latest via SPM |
|
|
77
|
+
| `FirebaseFirestore.framework` | Firestore | Add latest via SPM |
|
|
78
|
+
| `FirebaseDatabase.framework` | Realtime DB | Add latest via SPM |
|
|
79
|
+
| `FirebaseStorage.framework` | Cloud Storage | Add latest via SPM |
|
|
80
|
+
| `FirebaseRemoteConfig.framework` | Remote Config | Add latest via SPM |
|
|
81
|
+
| `GoogleMobileAds.framework` | AdMob | Add latest via SPM |
|
|
82
|
+
| `GoogleSignIn.framework` | Google Sign-In | Add latest via SPM |
|
|
83
|
+
| `GoogleMaps.framework` | Google Maps | Add via SPM/CocoaPods |
|
|
84
|
+
| `GooglePlaces.framework` | Google Places | Add via SPM/CocoaPods |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 🔴 Social SDKs
|
|
89
|
+
|
|
90
|
+
| Detection Pattern | Framework | Action |
|
|
91
|
+
|-------------------|-----------|--------|
|
|
92
|
+
| `FBSDKCoreKit.framework` | Facebook Core | Add latest via SPM |
|
|
93
|
+
| `FBSDKLoginKit.framework` | Facebook Login | Add latest via SPM |
|
|
94
|
+
| `FBSDKShareKit.framework` | Facebook Share | Add latest via SPM |
|
|
95
|
+
| `LineSDK.framework` | LINE SDK | Add via SPM |
|
|
96
|
+
| `KakaoSDK*.framework` | Kakao SDK | Add via SPM |
|
|
97
|
+
| `TwitterKit.framework` | Twitter SDK | Evaluate (deprecated?) |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## ⚪ Database & Storage
|
|
102
|
+
|
|
103
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
104
|
+
|-------------------|-----------|-------------------|--------|
|
|
105
|
+
| `Realm.framework` / `RealmSwift.framework` | Realm | SwiftData (iOS 17+) | Evaluate |
|
|
106
|
+
| `FMDB.framework` | FMDB (SQLite wrapper) | SwiftData / GRDB | Replace |
|
|
107
|
+
| `GRDB.framework` | GRDB.swift | Keep (current) | Add via SPM |
|
|
108
|
+
| `MagicalRecord.framework` | MagicalRecord | SwiftData | Replace |
|
|
109
|
+
| `CoreData.framework` (Apple) | Core Data | SwiftData (iOS 17+) | Upgrade |
|
|
110
|
+
| `KeychainAccess.framework` | KeychainAccess | Keep (current) | Add via SPM |
|
|
111
|
+
| `SAMKeychain.framework` | SAMKeychain | KeychainAccess | Replace |
|
|
112
|
+
| `MMKV.framework` | MMKV (Tencent) | UserDefaults / @AppStorage | Evaluate |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## ⚫ Utility
|
|
117
|
+
|
|
118
|
+
| Detection Pattern | Framework | Latest Replacement | Action |
|
|
119
|
+
|-------------------|-----------|-------------------|--------|
|
|
120
|
+
| `CocoaLumberjack.framework` | CocoaLumberjack | OSLog / swift-log | Replace |
|
|
121
|
+
| `SwiftyUserDefaults.framework` | SwiftyUserDefaults | @AppStorage | Replace |
|
|
122
|
+
| `Then.framework` | Then | Swift closures | Remove (not needed) |
|
|
123
|
+
| `R.swift` / `Rswift.framework` | R.swift | Xcode asset symbols | Replace |
|
|
124
|
+
| `SwiftGen` | SwiftGen | Xcode asset symbols | Replace |
|
|
125
|
+
| `CryptoSwift.framework` | CryptoSwift | CryptoKit (Apple) | Replace |
|
|
126
|
+
| `SwiftDate.framework` | SwiftDate | Foundation Date APIs | Evaluate |
|
|
127
|
+
| `DeviceKit.framework` | DeviceKit | UIDevice extensions | Evaluate |
|
|
128
|
+
| `Reachability.framework` / `ReachabilitySwift` | Reachability | NWPathMonitor (Network) | Replace |
|
|
129
|
+
| `ZXingObjC.framework` | ZXing (QR) | AVFoundation / VisionKit (native) | Replace |
|
|
130
|
+
| `JWTDecode.framework` | JWTDecode | Keep | Add via SPM |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 🔐 Security
|
|
135
|
+
|
|
136
|
+
| Detection Pattern | Framework | Action |
|
|
137
|
+
|-------------------|-----------|--------|
|
|
138
|
+
| `CryptoKit` (Apple) | CryptoKit | Keep (native) |
|
|
139
|
+
| `CommonCrypto` (Apple) | CommonCrypto | Keep (for legacy algorithms) |
|
|
140
|
+
| `Security.framework` (Apple) | Security | Keep (native) |
|
|
141
|
+
| `SSLPinning` headers | Custom SSL pinning | Re-implement with URLSession delegate |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🔍 Detection Strategy
|
|
146
|
+
|
|
147
|
+
### Step 1: Embedded Frameworks
|
|
148
|
+
```bash
|
|
149
|
+
# List all embedded frameworks
|
|
150
|
+
ls Payload/App.app/Frameworks/
|
|
151
|
+
|
|
152
|
+
# Check Mach-O linked libraries
|
|
153
|
+
otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Step 2: Class-dump Header Imports
|
|
157
|
+
```bash
|
|
158
|
+
# Find all imports in dumped headers
|
|
159
|
+
grep -rh "#import <" headers/ | sort -u
|
|
160
|
+
grep -rh "@import " headers/ | sort -u
|
|
161
|
+
grep -rh "import " headers/ | grep -v Foundation | grep -v UIKit | sort -u
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Step 3: Binary String Search
|
|
165
|
+
```bash
|
|
166
|
+
# Find framework identifiers in binary
|
|
167
|
+
strings Payload/App.app/App | grep -i "cocoapods\|carthage\|SPM\|alamofire\|firebase"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 4: CocoaPods / SPM Markers
|
|
171
|
+
```bash
|
|
172
|
+
# Check for Pods metadata
|
|
173
|
+
find Payload/App.app -name "Pods-*" -o -name "cocoapods*"
|
|
174
|
+
# Check for SPM metadata
|
|
175
|
+
find Payload/App.app -name "*.package" -o -name "Package.resolved"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Step 5: Classify & Report
|
|
179
|
+
```
|
|
180
|
+
For each detected framework:
|
|
181
|
+
1. Match against patterns above
|
|
182
|
+
2. Categorize: Keep / Replace / Upgrade / Evaluate
|
|
183
|
+
3. Unknown → investigate purpose via class-dump headers
|
|
184
|
+
4. App's own code → mark for Swift rewrite
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
*framework-patterns v1.0.0 — Reference database for IPA framework detection*
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# 🔬 ObjC/ARM Reading Guide for AI
|
|
2
|
+
|
|
3
|
+
> Quick reference for interpreting Objective-C headers (class-dump) and ARM disassembly (Hopper/IDA) when reverse engineering iOS apps.
|
|
4
|
+
> Used by the `smali-to-swift` skill during Steps 1-6.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📝 Class-Dump Header Basics
|
|
9
|
+
|
|
10
|
+
### Interface Declaration
|
|
11
|
+
```objc
|
|
12
|
+
@interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
|
|
13
|
+
|
|
14
|
+
// Properties
|
|
15
|
+
@property (nonatomic, strong) UITableView *tableView;
|
|
16
|
+
@property (nonatomic, copy) NSString *titleText;
|
|
17
|
+
@property (nonatomic, assign) BOOL isLoading;
|
|
18
|
+
@property (nonatomic, assign) NSInteger currentPage;
|
|
19
|
+
@property (nullable, nonatomic, weak) id<MyDelegate> delegate;
|
|
20
|
+
|
|
21
|
+
// Instance methods
|
|
22
|
+
- (void)fetchDataWithCompletion:(void (^)(NSArray *, NSError *))completion;
|
|
23
|
+
- (BOOL)validateEmail:(NSString *)email;
|
|
24
|
+
|
|
25
|
+
// Class methods
|
|
26
|
+
+ (instancetype)sharedInstance;
|
|
27
|
+
+ (NSString *)formatDate:(NSDate *)date;
|
|
28
|
+
|
|
29
|
+
@end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### → Swift Translation
|
|
33
|
+
```swift
|
|
34
|
+
final class MyViewModel: Observable {
|
|
35
|
+
var items: [Item] = []
|
|
36
|
+
var titleText: String = ""
|
|
37
|
+
var isLoading: Bool = false
|
|
38
|
+
var currentPage: Int = 0
|
|
39
|
+
|
|
40
|
+
func fetchData() async throws -> [Item] { ... }
|
|
41
|
+
func validateEmail(_ email: String) -> Bool { ... }
|
|
42
|
+
|
|
43
|
+
static let shared = MyViewModel()
|
|
44
|
+
static func formatDate(_ date: Date) -> String { ... }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🔑 Type Mappings: ObjC → Swift
|
|
51
|
+
|
|
52
|
+
### Primitive Types
|
|
53
|
+
```
|
|
54
|
+
BOOL → Bool
|
|
55
|
+
NSInteger → Int
|
|
56
|
+
NSUInteger → UInt
|
|
57
|
+
CGFloat → CGFloat
|
|
58
|
+
double → Double
|
|
59
|
+
float → Float
|
|
60
|
+
void → Void
|
|
61
|
+
char * → UnsafePointer<CChar>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Object Types
|
|
65
|
+
```
|
|
66
|
+
NSString * → String
|
|
67
|
+
NSMutableString * → String (var)
|
|
68
|
+
NSArray * → [Any] (refine element type from context)
|
|
69
|
+
NSMutableArray * → [Any] (var)
|
|
70
|
+
NSDictionary * → [String: Any] (refine types)
|
|
71
|
+
NSMutableDictionary → [String: Any] (var)
|
|
72
|
+
NSSet * → Set<AnyHashable>
|
|
73
|
+
NSNumber * → Int / Double / Bool (depending on context)
|
|
74
|
+
NSData * → Data
|
|
75
|
+
NSDate * → Date
|
|
76
|
+
NSURL * → URL
|
|
77
|
+
NSError * → Error (use Swift error handling)
|
|
78
|
+
id → Any
|
|
79
|
+
id<Protocol> → some Protocol
|
|
80
|
+
instancetype → Self
|
|
81
|
+
NSNull → nil (optional)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### UIKit → SwiftUI
|
|
85
|
+
```
|
|
86
|
+
UIView → some View (custom)
|
|
87
|
+
UILabel → Text
|
|
88
|
+
UIImageView → Image / AsyncImage
|
|
89
|
+
UIButton → Button
|
|
90
|
+
UITextField → TextField
|
|
91
|
+
UITextView → TextEditor
|
|
92
|
+
UISwitch → Toggle
|
|
93
|
+
UISlider → Slider
|
|
94
|
+
UIProgressView → ProgressView(.linear)
|
|
95
|
+
UIActivityIndicator → ProgressView()
|
|
96
|
+
UIStackView → VStack / HStack
|
|
97
|
+
UIScrollView → ScrollView
|
|
98
|
+
UITableView → List / LazyVStack
|
|
99
|
+
UICollectionView → LazyVGrid / LazyHGrid
|
|
100
|
+
UINavigationBar → navigationTitle + toolbar
|
|
101
|
+
UITabBar → TabView
|
|
102
|
+
UISegmentedControl → Picker(.segmented)
|
|
103
|
+
UIPageControl → TabView(.page)
|
|
104
|
+
UIAlertController → .alert / .confirmationDialog
|
|
105
|
+
UISearchBar → .searchable modifier
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 📐 Property Attributes → Swift
|
|
111
|
+
|
|
112
|
+
```objc
|
|
113
|
+
// Memory management
|
|
114
|
+
(strong) → let/var (default in Swift, ARC handles)
|
|
115
|
+
(weak) → weak var
|
|
116
|
+
(copy) → let (for value types like String)
|
|
117
|
+
(assign) → var (for primitives)
|
|
118
|
+
(retain) → same as strong
|
|
119
|
+
|
|
120
|
+
// Atomicity
|
|
121
|
+
(nonatomic) → default in Swift (no action needed)
|
|
122
|
+
(atomic) → actor isolation or locks (if thread-safe needed)
|
|
123
|
+
|
|
124
|
+
// Nullability
|
|
125
|
+
(nullable) → Type? (Optional)
|
|
126
|
+
(nonnull) → Type (Non-optional)
|
|
127
|
+
(_Nullable) → Type?
|
|
128
|
+
(_Nonnull) → Type
|
|
129
|
+
(null_unspecified) → Type! (IUO — avoid, use ? instead)
|
|
130
|
+
|
|
131
|
+
// Readability
|
|
132
|
+
(readonly) → let / private(set) var
|
|
133
|
+
(readwrite) → var
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 🎯 Common ObjC Patterns → Swift
|
|
139
|
+
|
|
140
|
+
### 1. Singleton
|
|
141
|
+
```objc
|
|
142
|
+
+ (instancetype)sharedInstance {
|
|
143
|
+
static MyClass *instance = nil;
|
|
144
|
+
static dispatch_once_t onceToken;
|
|
145
|
+
dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; });
|
|
146
|
+
return instance;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
```swift
|
|
150
|
+
final class MyClass {
|
|
151
|
+
static let shared = MyClass()
|
|
152
|
+
private init() {}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2. Delegate Pattern
|
|
157
|
+
```objc
|
|
158
|
+
@protocol DataServiceDelegate <NSObject>
|
|
159
|
+
- (void)dataService:(DataService *)service didFetchItems:(NSArray<Item *> *)items;
|
|
160
|
+
- (void)dataService:(DataService *)service didFailWithError:(NSError *)error;
|
|
161
|
+
@optional
|
|
162
|
+
- (void)dataServiceDidStartLoading:(DataService *)service;
|
|
163
|
+
@end
|
|
164
|
+
```
|
|
165
|
+
```swift
|
|
166
|
+
// Modern Swift: Replace with async/await
|
|
167
|
+
func fetchItems() async throws -> [Item]
|
|
168
|
+
|
|
169
|
+
// Or if streaming updates needed:
|
|
170
|
+
func itemUpdates() -> AsyncStream<[Item]>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 3. Block/Closure Callbacks
|
|
174
|
+
```objc
|
|
175
|
+
typedef void (^CompletionBlock)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error);
|
|
176
|
+
|
|
177
|
+
- (void)requestURL:(NSURL *)url completion:(CompletionBlock)completion;
|
|
178
|
+
```
|
|
179
|
+
```swift
|
|
180
|
+
// Modern: async/await
|
|
181
|
+
func request(url: URL) async throws -> (Data, URLResponse)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 4. Notification Observer
|
|
185
|
+
```objc
|
|
186
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
187
|
+
selector:@selector(handleNotification:)
|
|
188
|
+
name:@"UserDidLogin"
|
|
189
|
+
object:nil];
|
|
190
|
+
```
|
|
191
|
+
```swift
|
|
192
|
+
// Modern: AsyncSequence
|
|
193
|
+
for await _ in NotificationCenter.default.notifications(named: .userDidLogin) {
|
|
194
|
+
// handle
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 5. GCD Dispatch
|
|
199
|
+
```objc
|
|
200
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
201
|
+
NSData *data = [self fetchData];
|
|
202
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
203
|
+
[self updateUI:data];
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
```swift
|
|
208
|
+
Task {
|
|
209
|
+
let data = await fetchData()
|
|
210
|
+
// SwiftUI automatically updates on MainActor via @Observable
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 6. NSUserDefaults
|
|
215
|
+
```objc
|
|
216
|
+
[[NSUserDefaults standardUserDefaults] setObject:@"value" forKey:@"key"];
|
|
217
|
+
NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:@"key"];
|
|
218
|
+
```
|
|
219
|
+
```swift
|
|
220
|
+
// SwiftUI
|
|
221
|
+
@AppStorage("key") var value: String = ""
|
|
222
|
+
|
|
223
|
+
// Or typed wrapper
|
|
224
|
+
enum UserDefaultsKeys {
|
|
225
|
+
@UserDefaultsBacked(key: "key", defaultValue: "")
|
|
226
|
+
static var value: String
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 7. KVO (Key-Value Observing)
|
|
231
|
+
```objc
|
|
232
|
+
[self addObserver:self forKeyPath:@"model.name" options:NSKeyValueObservingOptionNew context:nil];
|
|
233
|
+
|
|
234
|
+
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
|
235
|
+
// update UI
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
```swift
|
|
239
|
+
// Modern: @Observable handles this automatically
|
|
240
|
+
@Observable
|
|
241
|
+
class ViewModel {
|
|
242
|
+
var name: String = "" // SwiftUI auto-observes changes
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### 8. Error Handling
|
|
247
|
+
```objc
|
|
248
|
+
NSError *error = nil;
|
|
249
|
+
NSData *data = [self processDataWithError:&error];
|
|
250
|
+
if (error) {
|
|
251
|
+
NSLog(@"Error: %@", error.localizedDescription);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
```swift
|
|
255
|
+
do {
|
|
256
|
+
let data = try processData()
|
|
257
|
+
} catch {
|
|
258
|
+
print("Error: \(error.localizedDescription)")
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 🔍 ARM Disassembly (Hopper/IDA) Quick Reference
|
|
265
|
+
|
|
266
|
+
### Function Prologue
|
|
267
|
+
```arm
|
|
268
|
+
; Hopper pseudo-code is usually readable C-like code
|
|
269
|
+
; Focus on understanding the LOGIC, not the assembly
|
|
270
|
+
|
|
271
|
+
int -[MyClass fetchData](void * self, void * _cmd) {
|
|
272
|
+
r0 = [self apiClient]; // Access property
|
|
273
|
+
r1 = @selector(getData:); // Method selector
|
|
274
|
+
r0 = [r0 getData:r1]; // Call method
|
|
275
|
+
return r0;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### String Constants (Finding API URLs)
|
|
280
|
+
```arm
|
|
281
|
+
; Look for CFSTR or @"..." patterns
|
|
282
|
+
adr x0, aHttpsApiExamp ; "https://api.example.com"
|
|
283
|
+
adr x1, aApiV1Users ; "/api/v1/users"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Conditional Branches
|
|
287
|
+
```arm
|
|
288
|
+
; Compare and branch
|
|
289
|
+
cmp w0, #0 ; if (result == 0)
|
|
290
|
+
b.eq label_true ; goto true branch
|
|
291
|
+
b.ne label_false ; goto false branch
|
|
292
|
+
|
|
293
|
+
; In Hopper pseudo-code:
|
|
294
|
+
if (r0 == 0x0) {
|
|
295
|
+
// true branch
|
|
296
|
+
} else {
|
|
297
|
+
// false branch
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Method Calls (ObjC Runtime)
|
|
302
|
+
```arm
|
|
303
|
+
; objc_msgSend = calling an ObjC method
|
|
304
|
+
bl _objc_msgSend ; [obj method]
|
|
305
|
+
bl _objc_msgSend$stret ; [obj methodReturningStruct]
|
|
306
|
+
|
|
307
|
+
; In Hopper pseudo-code:
|
|
308
|
+
r0 = [r0 stringByAppendingString:r1];
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 🎯 High-Value Patterns to Look For
|
|
314
|
+
|
|
315
|
+
### API Base URL
|
|
316
|
+
```objc
|
|
317
|
+
// In class-dump headers or disassembly
|
|
318
|
+
#define kBaseURL @"https://api.example.com/v1"
|
|
319
|
+
// or
|
|
320
|
+
static NSString *const BaseURL = @"https://api.example.com";
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Keychain Keys
|
|
324
|
+
```objc
|
|
325
|
+
[SSKeychain setPassword:token forService:@"MyApp" account:@"auth_token"];
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Encryption
|
|
329
|
+
```objc
|
|
330
|
+
#import <CommonCrypto/CommonCryptor.h>
|
|
331
|
+
CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, ...);
|
|
332
|
+
|
|
333
|
+
// or
|
|
334
|
+
#import <CommonCrypto/CommonDigest.h>
|
|
335
|
+
CC_MD5(data.bytes, (CC_LONG)data.length, result);
|
|
336
|
+
CC_SHA256(data.bytes, (CC_LONG)data.length, result);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### URL Schemes (Deep Links)
|
|
340
|
+
```xml
|
|
341
|
+
<!-- In Info.plist -->
|
|
342
|
+
<key>CFBundleURLTypes</key>
|
|
343
|
+
<array>
|
|
344
|
+
<dict>
|
|
345
|
+
<key>CFBundleURLSchemes</key>
|
|
346
|
+
<array>
|
|
347
|
+
<string>myapp</string>
|
|
348
|
+
</array>
|
|
349
|
+
</dict>
|
|
350
|
+
</array>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Push Notification Token
|
|
354
|
+
```objc
|
|
355
|
+
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## 🔐 Obfuscation in iOS
|
|
361
|
+
|
|
362
|
+
iOS apps are **less commonly obfuscated** than Android, but look for:
|
|
363
|
+
|
|
364
|
+
### Symbol Stripping
|
|
365
|
+
- Release builds strip debug symbols
|
|
366
|
+
- class-dump still extracts ObjC class/method names
|
|
367
|
+
- Swift symbols may be mangled: `_$s7MyClass10fetchDataSSyF`
|
|
368
|
+
- Use `swift-demangle` to decode: `xcrun swift-demangle <mangled_name>`
|
|
369
|
+
|
|
370
|
+
### String Encryption
|
|
371
|
+
```objc
|
|
372
|
+
// Encrypted strings decoded at runtime
|
|
373
|
+
+ (NSString *)decryptString:(NSString *)encrypted;
|
|
374
|
+
```
|
|
375
|
+
**Strategy:** Find the decryption method, understand algorithm, then decrypt.
|
|
376
|
+
|
|
377
|
+
### Anti-Debug / Jailbreak Detection
|
|
378
|
+
```objc
|
|
379
|
+
// Common patterns to look for (and note for re-implementation or removal)
|
|
380
|
+
+ (BOOL)isJailbroken;
|
|
381
|
+
+ (BOOL)isDebugged;
|
|
382
|
+
sysctl(CTL_KERN, KERN_PROC, ...); // debug check
|
|
383
|
+
access("/Applications/Cydia.app", F_OK); // jailbreak check
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
*objc-reading-guide v1.0.0 — AI reference for ObjC header & ARM disassembly interpretation*
|