@leejungkiin/awkit 1.0.5 → 1.0.7
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/VERSION +1 -1
- package/package.json +2 -2
- package/skills/smali-to-kotlin/SKILL.md +85 -331
- package/skills/smali-to-kotlin/phase-0-discovery.md +129 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +157 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-swift/SKILL.md +91 -532
- package/skills/smali-to-swift/phase-0-discovery.md +154 -0
- package/skills/smali-to-swift/phase-1-architecture.md +173 -0
- package/skills/smali-to-swift/phase-2-blueprint-ui.md +348 -0
- package/skills/smali-to-swift/phase-3-logic-build.md +312 -0
- package/workflows/mobile/reverse-android-build.md +119 -79
- package/workflows/mobile/reverse-android-design.md +10 -7
- package/workflows/mobile/reverse-android.md +52 -46
- package/workflows/mobile/reverse-ios-build.md +161 -50
- package/workflows/mobile/reverse-ios-design.md +10 -1
- package/workflows/mobile/reverse-ios.md +49 -37
|
@@ -4,9 +4,10 @@ description: >-
|
|
|
4
4
|
iOS Reverse Engineering specialist. Reads decrypted IPA output (class-dump headers,
|
|
5
5
|
Hopper/IDA disassembly, resources, Info.plist) and rebuilds the app from scratch using
|
|
6
6
|
modern Swift + SwiftUI + Clean Architecture (MVVM).
|
|
7
|
+
UI-First approach: design and approve UI visuals before coding logic.
|
|
7
8
|
Includes framework detection to reuse existing dependencies.
|
|
8
9
|
author: Antigravity Team
|
|
9
|
-
version:
|
|
10
|
+
version: 2.0.0
|
|
10
11
|
trigger: conditional
|
|
11
12
|
activation_keywords:
|
|
12
13
|
- "/reverse-ios"
|
|
@@ -24,10 +25,11 @@ platform: ios
|
|
|
24
25
|
sibling_skill: smali-to-kotlin (Android counterpart)
|
|
25
26
|
---
|
|
26
27
|
|
|
27
|
-
# 🍎 Smali-to-Swift Skill
|
|
28
|
+
# 🍎 Smali-to-Swift Skill v2 — UI-First
|
|
28
29
|
|
|
29
30
|
> **Purpose:** Transform decrypted iOS IPA (class-dump headers, disassembly, resources, plist) into a modern Swift app with SwiftUI, Clean Architecture, and MVVM.
|
|
30
|
-
> **Philosophy:** "
|
|
31
|
+
> **Philosophy:** "Map → Blueprint → UI First → Logic Behind"
|
|
32
|
+
> **Key Change (v2):** UI is designed and approved BEFORE coding any business logic.
|
|
31
33
|
|
|
32
34
|
---
|
|
33
35
|
|
|
@@ -40,7 +42,7 @@ sibling_skill: smali-to-kotlin (Android counterpart)
|
|
|
40
42
|
| Detect & reuse third-party frameworks | Crack/bypass DRM or jailbreak |
|
|
41
43
|
| Extract only needed resources (on-demand) | Mass-copy assets blindly |
|
|
42
44
|
| Set up Clean Architecture project structure | Handle Android reverse engineering |
|
|
43
|
-
|
|
|
45
|
+
| Code UI first, then wire logic behind | Submit to App Store |
|
|
44
46
|
|
|
45
47
|
→ For Android reverse engineering → sibling skill: `smali-to-kotlin`
|
|
46
48
|
→ After rebuild complete → use `/test` or `/deploy` workflows
|
|
@@ -55,7 +57,7 @@ When this skill is active, the agent becomes:
|
|
|
55
57
|
> - Master at reading ObjC/Swift class-dump headers and ARM disassembly
|
|
56
58
|
> - Fluent in Clean Architecture + MVVM + SwiftUI
|
|
57
59
|
> - Knows when to reuse vs rewrite third-party frameworks
|
|
58
|
-
> - Enforces resource-on-demand
|
|
60
|
+
> - Enforces UI-First and resource-on-demand principles
|
|
59
61
|
|
|
60
62
|
---
|
|
61
63
|
|
|
@@ -74,17 +76,12 @@ When this skill is active, the agent becomes:
|
|
|
74
76
|
### What we get from an IPA:
|
|
75
77
|
```
|
|
76
78
|
Payload/App.app/
|
|
77
|
-
├── App # Mach-O binary (
|
|
78
|
-
├── Info.plist # App metadata
|
|
79
|
-
├── Frameworks/ # Embedded frameworks
|
|
80
|
-
│ ├── SomeSDK.framework/
|
|
81
|
-
│ └── libswiftCore.dylib
|
|
79
|
+
├── App # Mach-O binary (need decrypt first)
|
|
80
|
+
├── Info.plist # App metadata
|
|
81
|
+
├── Frameworks/ # Embedded frameworks
|
|
82
82
|
├── Assets.car # Compiled asset catalog
|
|
83
83
|
├── Base.lproj/ # Storyboards / XIBs (compiled)
|
|
84
|
-
|
|
85
|
-
│ └── LaunchScreen.storyboardc/
|
|
86
|
-
├── *.nib # Compiled XIB files
|
|
87
|
-
├── *.momd # Core Data models (compiled)
|
|
84
|
+
├── *.nib / *.momd # Compiled UIKit / Core Data
|
|
88
85
|
├── embedded.mobileprovision # Provisioning profile
|
|
89
86
|
├── _CodeSignature/ # Code signing
|
|
90
87
|
└── [other resources: json, png, html, js, fonts...]
|
|
@@ -106,10 +103,10 @@ Payload/App.app/
|
|
|
106
103
|
| Purpose | Technology | Replaces |
|
|
107
104
|
|---------|-----------|----------|
|
|
108
105
|
| **Network** | URLSession + async/await | AFNetworking / Alamofire (evaluate) |
|
|
109
|
-
| **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle
|
|
106
|
+
| **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle |
|
|
110
107
|
| **Local DB** | SwiftData (iOS 17+) or Core Data | Raw SQLite / FMDB / Realm |
|
|
111
108
|
| **Preferences** | UserDefaults / @AppStorage | NSUserDefaults direct |
|
|
112
|
-
| **Keychain** | KeychainAccess (or custom
|
|
109
|
+
| **Keychain** | KeychainAccess (or custom) | Raw Security.framework |
|
|
113
110
|
| **Image Loading** | AsyncImage / Kingfisher / Nuke | SDWebImage (evaluate) |
|
|
114
111
|
| **Async** | Swift Concurrency (async/await, actors) | GCD / NSOperation / PromiseKit |
|
|
115
112
|
|
|
@@ -130,33 +127,22 @@ always_replace:
|
|
|
130
127
|
Mantle/ObjectMapper: "Codable"
|
|
131
128
|
GCD_dispatch_async: "Task { } / async-await"
|
|
132
129
|
NSOperation: "TaskGroup / async let"
|
|
133
|
-
NSTimer: "Timer.publish (Combine) or Task.sleep"
|
|
134
|
-
UIAlertView: "SwiftUI .alert modifier"
|
|
135
|
-
UIActionSheet: "SwiftUI .confirmationDialog"
|
|
136
130
|
UITableView: "List / LazyVStack"
|
|
137
131
|
UICollectionView: "LazyVGrid / LazyHGrid"
|
|
138
|
-
UIPageViewController: "TabView with .page style"
|
|
139
132
|
Storyboard_segues: "NavigationStack + NavigationLink"
|
|
140
|
-
NSNotificationCenter_addObserver: "NotificationCenter.notifications (AsyncSequence)"
|
|
141
133
|
KVO: "@Observable macro"
|
|
142
134
|
Delegate_patterns: "AsyncStream or closures"
|
|
143
135
|
Target_Action: "SwiftUI action closures"
|
|
144
136
|
|
|
145
137
|
evaluate_before_replacing:
|
|
146
|
-
Alamofire: "Keep if deeply used
|
|
147
|
-
SDWebImage: "
|
|
148
|
-
Realm: "
|
|
149
|
-
RxSwift: "
|
|
150
|
-
SnapKit: "
|
|
151
|
-
Masonry: "Replace with SwiftUI layout"
|
|
152
|
-
MBProgressHUD: "SwiftUI .overlay + ProgressView"
|
|
153
|
-
SVProgressHUD: "SwiftUI .overlay + ProgressView"
|
|
154
|
-
IQKeyboardManager: "SwiftUI handles keyboard automatically"
|
|
138
|
+
Alamofire: "Keep if deeply used, else → URLSession"
|
|
139
|
+
SDWebImage: "→ AsyncImage + Kingfisher"
|
|
140
|
+
Realm: "→ SwiftData (if iOS 17+)"
|
|
141
|
+
RxSwift: "→ async/await + AsyncSequence"
|
|
142
|
+
SnapKit: "→ SwiftUI layout"
|
|
155
143
|
|
|
156
144
|
keep_as_is:
|
|
157
145
|
- "Firebase SDKs (use latest via SPM)"
|
|
158
|
-
- "Google Sign-In"
|
|
159
|
-
- "Facebook SDK (latest)"
|
|
160
146
|
- "Apple frameworks (MapKit, CoreLocation, AVFoundation, etc.)"
|
|
161
147
|
- "Native C/C++ libraries (.dylib)"
|
|
162
148
|
- "CryptoKit (Apple native)"
|
|
@@ -164,492 +150,50 @@ keep_as_is:
|
|
|
164
150
|
|
|
165
151
|
---
|
|
166
152
|
|
|
167
|
-
## 📋 EXECUTION PIPELINE (
|
|
168
|
-
|
|
169
|
-
> **Rule:** Always complete one step fully before moving to the next.
|
|
170
|
-
> **Rule:** After each step, create a checkpoint summary for the user.
|
|
171
|
-
|
|
172
|
-
### Step 0: Framework Scanner (PRE-STEP — Always First) 🔍
|
|
173
|
-
|
|
174
|
-
**Purpose:** Scan the IPA structure to identify all third-party frameworks before any coding.
|
|
175
|
-
|
|
176
|
-
**Process:**
|
|
177
|
-
1. **Scan `Frameworks/` directory:**
|
|
178
|
-
```
|
|
179
|
-
Frameworks/Alamofire.framework → Alamofire (network)
|
|
180
|
-
Frameworks/SDWebImage.framework → SDWebImage (image loading)
|
|
181
|
-
Frameworks/Realm.framework → Realm (database)
|
|
182
|
-
Frameworks/FBSDKCoreKit.framework → Facebook SDK
|
|
183
|
-
Frameworks/GoogleSignIn.framework → Google Sign-In
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
2. **Scan class-dump headers for imports:**
|
|
187
|
-
```
|
|
188
|
-
#import <AFNetworking/...> → AFNetworking
|
|
189
|
-
#import <Masonry/...> → Masonry (auto-layout)
|
|
190
|
-
#import <MBProgressHUD/...> → MBProgressHUD
|
|
191
|
-
@import Firebase; → Firebase SDK
|
|
192
|
-
@import GoogleMobileAds; → AdMob
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
3. **Check Mach-O linked frameworks:**
|
|
196
|
-
```bash
|
|
197
|
-
otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
4. **Check embedded dylibs:**
|
|
201
|
-
```bash
|
|
202
|
-
find Payload/App.app -name "*.dylib" -o -name "*.framework" | sort
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
5. **Check for CocoaPods / SPM markers:**
|
|
206
|
-
```
|
|
207
|
-
Pods/ directory presence → was using CocoaPods
|
|
208
|
-
.package.resolved → was using SPM
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
6. **Output: Framework Detection Report**
|
|
212
|
-
```markdown
|
|
213
|
-
## 📦 Framework Detection Report
|
|
214
|
-
|
|
215
|
-
### ✅ Can Reuse (add to Package.swift / Podfile)
|
|
216
|
-
| Framework | Detected | Latest Version | Action |
|
|
217
|
-
|-----------|----------|----------------|--------|
|
|
218
|
-
| Alamofire | Frameworks/Alamofire.framework | 5.9.0 | Evaluate |
|
|
219
|
-
| Kingfisher | (header import) | 7.12.0 | Add via SPM |
|
|
220
|
-
|
|
221
|
-
### 🔄 Must Replace (legacy)
|
|
222
|
-
| Old Framework | Detected | Modern Replacement |
|
|
223
|
-
|---------------|----------|-------------------|
|
|
224
|
-
| AFNetworking | Frameworks/AFNetworking.framework | URLSession async/await |
|
|
225
|
-
| Masonry | header imports | SwiftUI layout |
|
|
226
|
-
|
|
227
|
-
### 🍏 Apple Frameworks Used
|
|
228
|
-
| Framework | Purpose |
|
|
229
|
-
|-----------|---------|
|
|
230
|
-
| MapKit | Maps |
|
|
231
|
-
| CoreLocation | GPS |
|
|
232
|
-
| AVFoundation | Camera/Audio |
|
|
233
|
-
|
|
234
|
-
### 📱 Native (.dylib) — Investigate
|
|
235
|
-
| File | Notes |
|
|
236
|
-
|------|-------|
|
|
237
|
-
| libcrypto.dylib | Custom crypto? |
|
|
238
|
-
|
|
239
|
-
### ❓ Unknown (investigate)
|
|
240
|
-
| Framework/Import | Notes |
|
|
241
|
-
|------------------|-------|
|
|
242
|
-
| CustomSDK.framework | Proprietary? |
|
|
243
|
-
```
|
|
153
|
+
## 📋 EXECUTION PIPELINE (v2 — UI-First)
|
|
244
154
|
|
|
245
|
-
|
|
155
|
+
> **Philosophy:** "Nhìn thấy trước, code logic sau"
|
|
156
|
+
> **Rule:** Always complete one phase fully before moving to the next.
|
|
157
|
+
> **Rule:** UI must be approved before coding logic.
|
|
246
158
|
|
|
247
|
-
### Step 1: Info.plist & Entitlements Analysis + Project Bootstrap 📄
|
|
248
|
-
|
|
249
|
-
**Input:** User provides `Info.plist` + entitlements from IPA.
|
|
250
|
-
|
|
251
|
-
**Tasks:**
|
|
252
|
-
1. Extract Bundle ID and display name
|
|
253
|
-
2. List required permissions (Privacy keys):
|
|
254
|
-
```
|
|
255
|
-
NSCameraUsageDescription → Camera
|
|
256
|
-
NSPhotoLibraryUsageDescription → Photo Library
|
|
257
|
-
NSLocationWhenInUseUsageDescription → Location
|
|
258
|
-
NSMicrophoneUsageDescription → Microphone
|
|
259
|
-
```
|
|
260
|
-
3. Identify URL Schemes (deep links)
|
|
261
|
-
4. Check app capabilities from entitlements:
|
|
262
|
-
```
|
|
263
|
-
com.apple.developer.associated-domains → Universal Links
|
|
264
|
-
aps-environment → Push Notifications
|
|
265
|
-
com.apple.developer.in-app-payments → Apple Pay
|
|
266
|
-
```
|
|
267
|
-
5. Analyze class-dump headers for entry points:
|
|
268
|
-
- `AppDelegate` → lifecycle logic
|
|
269
|
-
- Root ViewController → initial screen
|
|
270
|
-
- Tab bar / Navigation structure
|
|
271
|
-
6. **Output:** Propose Clean Architecture project structure
|
|
272
|
-
|
|
273
|
-
**Project Structure Template:**
|
|
274
159
|
```
|
|
275
|
-
App
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
│
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
│ │ ├── APIClient.swift # URLSession wrapper
|
|
285
|
-
│ │ ├── Endpoints/ # API endpoint definitions
|
|
286
|
-
│ │ └── DTOs/ # Codable response models
|
|
287
|
-
│ ├── Local/
|
|
288
|
-
│ │ ├── SwiftDataModels/ # @Model classes
|
|
289
|
-
│ │ ├── KeychainService.swift
|
|
290
|
-
│ │ └── UserDefaultsKeys.swift
|
|
291
|
-
│ └── Repositories/ # Repository implementations
|
|
292
|
-
├── Domain/ # Domain Layer
|
|
293
|
-
│ ├── Models/ # Business models
|
|
294
|
-
│ ├── Repositories/ # Repository protocols
|
|
295
|
-
│ └── UseCases/
|
|
296
|
-
├── Presentation/ # Presentation Layer
|
|
297
|
-
│ ├── Navigation/
|
|
298
|
-
│ │ ├── AppNavigation.swift # NavigationStack + routes
|
|
299
|
-
│ │ └── Route.swift # Deep link routes
|
|
300
|
-
│ ├── Theme/
|
|
301
|
-
│ │ ├── AppTheme.swift # Colors, fonts, spacing
|
|
302
|
-
│ │ └── Components/ # Reusable SwiftUI components
|
|
303
|
-
│ └── Screens/
|
|
304
|
-
│ ├── Launch/
|
|
305
|
-
│ │ └── LaunchScreen.swift
|
|
306
|
-
│ ├── Auth/
|
|
307
|
-
│ │ ├── LoginScreen.swift
|
|
308
|
-
│ │ └── LoginViewModel.swift
|
|
309
|
-
│ ├── Home/
|
|
310
|
-
│ │ ├── HomeScreen.swift
|
|
311
|
-
│ │ └── HomeViewModel.swift
|
|
312
|
-
│ └── ...
|
|
313
|
-
├── Utilities/
|
|
314
|
-
│ ├── Extensions/
|
|
315
|
-
│ ├── Crypto/ # Encryption/hashing utils
|
|
316
|
-
│ └── Helpers/
|
|
317
|
-
└── Resources/
|
|
318
|
-
├── Localizable.xcstrings
|
|
319
|
-
└── Fonts/
|
|
160
|
+
Phase 0: Discovery → App Map (satellite view)
|
|
161
|
+
Phase 1: Architecture → Layer design + UI-First build order (district view)
|
|
162
|
+
┌─── Loop per Feature ──────────────────────────────────────┐
|
|
163
|
+
│ Phase 2: Blueprint + UI → Contracts + Visual UI Shell │
|
|
164
|
+
│ 🚦 GATE: User approves UI + Contracts │
|
|
165
|
+
│ Phase 3: Logic Build → Domain → Data → Wire UI↔Logic │
|
|
166
|
+
│ 📊 CHECKPOINT: Feature complete │
|
|
167
|
+
└─── Repeat for next feature ───────────────────────────────┘
|
|
168
|
+
Phase 4: Final Parity Check
|
|
320
169
|
```
|
|
321
170
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
### Step 2: Data Layer Reconstruction 💾
|
|
325
|
-
|
|
326
|
-
**Input:** User provides class-dump headers + Hopper pseudo-code for network/data classes.
|
|
327
|
-
|
|
328
|
-
**Tasks:**
|
|
329
|
-
1. **Models:** Convert ObjC interfaces → Swift structs
|
|
330
|
-
```objc
|
|
331
|
-
// ObjC header (class-dump)
|
|
332
|
-
@interface UserModel : NSObject
|
|
333
|
-
@property (nonatomic, copy) NSString *userId;
|
|
334
|
-
@property (nonatomic, copy) NSString *fullName;
|
|
335
|
-
@property (nonatomic, assign) NSInteger age;
|
|
336
|
-
@end
|
|
337
|
-
```
|
|
338
|
-
```swift
|
|
339
|
-
// Swift
|
|
340
|
-
struct User: Codable, Identifiable {
|
|
341
|
-
let id: String
|
|
342
|
-
let fullName: String
|
|
343
|
-
let age: Int
|
|
344
|
-
|
|
345
|
-
enum CodingKeys: String, CodingKey {
|
|
346
|
-
case id = "user_id"
|
|
347
|
-
case fullName = "full_name"
|
|
348
|
-
case age
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
2. **API Layer:**
|
|
354
|
-
- Extract base URL, endpoints, headers from disassembly
|
|
355
|
-
- Create async URLSession-based API client:
|
|
356
|
-
```swift
|
|
357
|
-
actor APIClient {
|
|
358
|
-
private let session: URLSession
|
|
359
|
-
private let baseURL: URL
|
|
360
|
-
|
|
361
|
-
func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T {
|
|
362
|
-
let (data, response) = try await session.data(for: endpoint.urlRequest(baseURL: baseURL))
|
|
363
|
-
guard let httpResponse = response as? HTTPURLResponse,
|
|
364
|
-
(200...299).contains(httpResponse.statusCode) else {
|
|
365
|
-
throw APIError.invalidResponse
|
|
366
|
-
}
|
|
367
|
-
return try JSONDecoder().decode(T.self, from: data)
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
3. **Local Storage:**
|
|
373
|
-
- CoreData models → SwiftData `@Model` classes
|
|
374
|
-
- NSUserDefaults keys → `@AppStorage` or typed UserDefaults wrapper
|
|
375
|
-
- Keychain items → KeychainAccess wrapper
|
|
376
|
-
|
|
377
|
-
4. **Repository:**
|
|
378
|
-
```swift
|
|
379
|
-
// Domain layer - protocol
|
|
380
|
-
protocol UserRepository: Sendable {
|
|
381
|
-
func getUser(id: String) async throws -> User
|
|
382
|
-
func login(email: String, password: String) async throws -> AuthToken
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// Data layer - implementation
|
|
386
|
-
final class UserRepositoryImpl: UserRepository {
|
|
387
|
-
private let apiClient: APIClient
|
|
388
|
-
private let modelContext: ModelContext
|
|
389
|
-
|
|
390
|
-
func getUser(id: String) async throws -> User {
|
|
391
|
-
// offline-first: check local → fetch remote → cache
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
### Step 3: Core Logic & Utils Reconstruction 🧮
|
|
399
|
-
|
|
400
|
-
**Input:** Disassembly/pseudo-code for encryption, hashing, custom utils.
|
|
401
|
-
|
|
402
|
-
**Tasks:**
|
|
403
|
-
1. Translate ObjC/C crypto logic → Swift
|
|
404
|
-
- Use `CryptoKit` for modern crypto (SHA256, AES-GCM, HMAC)
|
|
405
|
-
- Use `CommonCrypto` for legacy-compatible (MD5, AES-CBC)
|
|
406
|
-
- Preserve exact input/output signatures
|
|
407
|
-
|
|
408
|
-
2. Common ObjC → Swift crypto patterns:
|
|
409
|
-
```objc
|
|
410
|
-
// ObjC (class-dump + disassembly)
|
|
411
|
-
+ (NSString *)md5Hash:(NSString *)input;
|
|
412
|
-
+ (NSData *)aesEncrypt:(NSData *)data withKey:(NSString *)key;
|
|
413
|
-
```
|
|
414
|
-
```swift
|
|
415
|
-
// Swift
|
|
416
|
-
import CryptoKit
|
|
417
|
-
import CommonCrypto
|
|
418
|
-
|
|
419
|
-
enum CryptoUtils {
|
|
420
|
-
static func md5Hash(_ input: String) -> String {
|
|
421
|
-
let data = Data(input.utf8)
|
|
422
|
-
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
|
|
423
|
-
data.withUnsafeBytes { CC_MD5($0.baseAddress, CC_LONG(data.count), &digest) }
|
|
424
|
-
return digest.map { String(format: "%02x", $0) }.joined()
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
static func aesEncrypt(data: Data, key: String) throws -> Data {
|
|
428
|
-
// Implement matching original algorithm exactly
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
3. **Verification:** XCTest unit tests with known input/output pairs
|
|
434
|
-
|
|
435
|
-
**Critical Rule:**
|
|
436
|
-
> ⚠️ Crypto/hash functions MUST produce identical output to the original app.
|
|
437
|
-
> Test with known pairs captured from the running original app.
|
|
171
|
+
### Reference Files
|
|
438
172
|
|
|
439
|
-
|
|
173
|
+
Each phase has a detailed instruction file:
|
|
174
|
+
- `phase-0-discovery.md` — Framework scan, plist analysis, app map
|
|
175
|
+
- `phase-1-architecture.md` — Layer design, feature mapping, build order
|
|
176
|
+
- `phase-2-blueprint-ui.md` — Contracts + UI visual shell + parity check
|
|
177
|
+
- `phase-3-logic-build.md` — Domain, data, DI, ViewModel, wire UI↔logic
|
|
440
178
|
|
|
441
|
-
###
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
**Tasks:**
|
|
446
|
-
1. **Resource Extraction (On-Demand):**
|
|
447
|
-
- Extract only images, colors, strings for current screen
|
|
448
|
-
- Use Asset Catalog for organized resources
|
|
449
|
-
- Map ObjC string tables to `Localizable.xcstrings`
|
|
450
|
-
|
|
451
|
-
2. **UIKit → SwiftUI Migration:**
|
|
452
|
-
```
|
|
453
|
-
UIViewController → SwiftUI View struct
|
|
454
|
-
UINavigationController → NavigationStack
|
|
455
|
-
UITabBarController → TabView
|
|
456
|
-
UITableView → List / LazyVStack
|
|
457
|
-
UICollectionView → LazyVGrid / LazyHGrid
|
|
458
|
-
UIScrollView → ScrollView
|
|
459
|
-
UIImageView → AsyncImage / Image
|
|
460
|
-
UILabel → Text
|
|
461
|
-
UITextField → TextField
|
|
462
|
-
UIButton → Button
|
|
463
|
-
UIActivityIndicatorView → ProgressView
|
|
464
|
-
UIAlertController → .alert / .confirmationDialog modifier
|
|
465
|
-
UIPageViewController → TabView(.page)
|
|
466
|
-
UIStackView → VStack / HStack
|
|
467
|
-
MKMapView → Map (MapKit SwiftUI)
|
|
468
|
-
WKWebView → WebView (custom wrapper)
|
|
469
|
-
UIRefreshControl → .refreshable modifier
|
|
470
|
-
UISearchController → .searchable modifier
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
3. **ViewModel Creation:**
|
|
474
|
-
```swift
|
|
475
|
-
@Observable
|
|
476
|
-
final class LoginViewModel {
|
|
477
|
-
var email = ""
|
|
478
|
-
var password = ""
|
|
479
|
-
var isLoading = false
|
|
480
|
-
var error: String?
|
|
481
|
-
|
|
482
|
-
private let loginUseCase: LoginUseCase
|
|
483
|
-
|
|
484
|
-
init(loginUseCase: LoginUseCase) {
|
|
485
|
-
self.loginUseCase = loginUseCase
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
func login() async {
|
|
489
|
-
isLoading = true
|
|
490
|
-
defer { isLoading = false }
|
|
491
|
-
do {
|
|
492
|
-
try await loginUseCase.execute(email: email, password: password)
|
|
493
|
-
} catch {
|
|
494
|
-
self.error = error.localizedDescription
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
4. **Screen Composable:**
|
|
501
|
-
```swift
|
|
502
|
-
struct LoginScreen: View {
|
|
503
|
-
@State private var viewModel: LoginViewModel
|
|
504
|
-
|
|
505
|
-
init(loginUseCase: LoginUseCase) {
|
|
506
|
-
_viewModel = State(initialValue: LoginViewModel(loginUseCase: loginUseCase))
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
var body: some View {
|
|
510
|
-
Form {
|
|
511
|
-
TextField("Email", text: $viewModel.email)
|
|
512
|
-
.textContentType(.emailAddress)
|
|
513
|
-
.keyboardType(.emailAddress)
|
|
514
|
-
|
|
515
|
-
SecureField("Password", text: $viewModel.password)
|
|
516
|
-
.textContentType(.password)
|
|
517
|
-
|
|
518
|
-
Button("Login") {
|
|
519
|
-
Task { await viewModel.login() }
|
|
520
|
-
}
|
|
521
|
-
.disabled(viewModel.isLoading)
|
|
522
|
-
}
|
|
523
|
-
.overlay { if viewModel.isLoading { ProgressView() } }
|
|
524
|
-
.alert("Error", isPresented: .constant(viewModel.error != nil)) {
|
|
525
|
-
Button("OK") { viewModel.error = nil }
|
|
526
|
-
} message: {
|
|
527
|
-
Text(viewModel.error ?? "")
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
```
|
|
179
|
+
### Supporting Files
|
|
180
|
+
- `objc-reading-guide.md` — How to read ObjC class-dump headers
|
|
181
|
+
- `framework-patterns.md` — Common iOS framework detection patterns
|
|
532
182
|
|
|
533
183
|
---
|
|
534
184
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
**Input:** Framework Report from Step 0.
|
|
538
|
-
|
|
539
|
-
**Tasks:**
|
|
540
|
-
1. **Swift Package Manager setup:**
|
|
541
|
-
```swift
|
|
542
|
-
// Package.swift dependencies (or Xcode SPM UI)
|
|
543
|
-
dependencies: [
|
|
544
|
-
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "11.0.0"),
|
|
545
|
-
.package(url: "https://github.com/onevcat/Kingfisher", from: "7.12.0"),
|
|
546
|
-
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
|
|
547
|
-
]
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
2. **Native C/C++ libraries:**
|
|
551
|
-
```swift
|
|
552
|
-
// Bridging header for C libraries
|
|
553
|
-
// App-Bridging-Header.h
|
|
554
|
-
#include "native_crypto.h"
|
|
555
|
-
|
|
556
|
-
// Swift usage
|
|
557
|
-
func callNativeFunction() -> String {
|
|
558
|
-
let result = native_function_name(param)
|
|
559
|
-
return String(cString: result)
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
3. **App lifecycle for SDK init:**
|
|
564
|
-
```swift
|
|
565
|
-
@main
|
|
566
|
-
struct MyApp: App {
|
|
567
|
-
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
|
|
568
|
-
|
|
569
|
-
var body: some Scene {
|
|
570
|
-
WindowGroup {
|
|
571
|
-
ContentView()
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
class AppDelegate: NSObject, UIApplicationDelegate {
|
|
577
|
-
func application(_ application: UIApplication,
|
|
578
|
-
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
579
|
-
FirebaseApp.configure()
|
|
580
|
-
// Other SDK initialization
|
|
581
|
-
return true
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
---
|
|
587
|
-
|
|
588
|
-
### Step 6: Parity Check & Quality Gate ✅
|
|
589
|
-
|
|
590
|
-
**Per-module checklist:**
|
|
591
|
-
1. **Branch Coverage:** Review all conditional paths from disassembly
|
|
592
|
-
2. **API Parity:** Same requests/responses as original
|
|
593
|
-
3. **Data Parity:** Crypto output matches, local storage compatible
|
|
594
|
-
4. **UI Parity:** Screen-by-screen comparison
|
|
595
|
-
5. **Performance:**
|
|
596
|
-
- Instruments profiling
|
|
597
|
-
- No unnecessary @State re-renders
|
|
598
|
-
- Proper actor isolation (no data races)
|
|
599
|
-
|
|
600
|
-
---
|
|
601
|
-
|
|
602
|
-
## 🔍 ObjC HEADER READING GUIDE
|
|
603
|
-
|
|
604
|
-
### Property Types → Swift
|
|
605
|
-
```objc
|
|
606
|
-
@property (nonatomic, copy) NSString *name; // → let name: String
|
|
607
|
-
@property (nonatomic, strong) NSArray *items; // → let items: [Any] (refine type)
|
|
608
|
-
@property (nonatomic, assign) BOOL isActive; // → let isActive: Bool
|
|
609
|
-
@property (nonatomic, assign) NSInteger count; // → let count: Int
|
|
610
|
-
@property (nonatomic, assign) CGFloat height; // → let height: CGFloat
|
|
611
|
-
@property (nonatomic, strong) NSDictionary *meta; // → let meta: [String: Any]
|
|
612
|
-
@property (nonatomic, strong) NSDate *createdAt; // → let createdAt: Date
|
|
613
|
-
@property (nonatomic, strong) NSURL *imageURL; // → let imageURL: URL?
|
|
614
|
-
@property (nonatomic, strong) NSData *data; // → let data: Data
|
|
615
|
-
@property (nullable, nonatomic, copy) NSString *bio; // → let bio: String?
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
### Method Signatures → Swift
|
|
619
|
-
```objc
|
|
620
|
-
- (void)fetchUserWithId:(NSString *)userId completion:(void (^)(UserModel *, NSError *))completion;
|
|
621
|
-
// → func fetchUser(id: String) async throws -> User
|
|
622
|
-
|
|
623
|
-
+ (instancetype)sharedInstance;
|
|
624
|
-
// → static let shared = ClassName()
|
|
625
|
-
|
|
626
|
-
- (BOOL)validateEmail:(NSString *)email;
|
|
627
|
-
// → func validateEmail(_ email: String) -> Bool
|
|
628
|
-
```
|
|
185
|
+
## 🔑 KEY DIFFERENCES FROM v1
|
|
629
186
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
// Or AsyncStream for multiple values:
|
|
641
|
-
func userUpdates() -> AsyncStream<User>
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
### Blocks → Closures / async
|
|
645
|
-
```objc
|
|
646
|
-
typedef void (^CompletionHandler)(NSData * _Nullable data, NSError * _Nullable error);
|
|
647
|
-
- (void)requestWithCompletion:(CompletionHandler)completion;
|
|
648
|
-
```
|
|
649
|
-
```swift
|
|
650
|
-
// Modern Swift: drop the callback, use async
|
|
651
|
-
func request() async throws -> Data
|
|
652
|
-
```
|
|
187
|
+
| Aspect | v1 (Old) | v2 (UI-First) |
|
|
188
|
+
|--------|----------|---------------|
|
|
189
|
+
| **Pipeline** | 6-step linear | 4-phase with feature loop |
|
|
190
|
+
| **UI coded when** | Last (Step 4) | Early (Phase 2, before logic) |
|
|
191
|
+
| **Resource extraction** | Last (Step 4.1) | Early (Phase 2.7, before UI code) |
|
|
192
|
+
| **Visual parity check** | End only (Step 6) | Mid-pipeline (Phase 2.9) + Final |
|
|
193
|
+
| **Gate between UI/Logic** | None | Mandatory — user approves UI first |
|
|
194
|
+
| **Preview** | None | Full #Preview for all states |
|
|
195
|
+
| **User feedback** | 1 time (end) | 2 times (UI gate + final check) |
|
|
196
|
+
| **Rework risk** | High | Low (UI locked before logic) |
|
|
653
197
|
|
|
654
198
|
---
|
|
655
199
|
|
|
@@ -658,12 +202,12 @@ func request() async throws -> Data
|
|
|
658
202
|
```yaml
|
|
659
203
|
triggers_from:
|
|
660
204
|
- "/reverse-ios" workflow command
|
|
661
|
-
- Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios"
|
|
205
|
+
- Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios"
|
|
662
206
|
|
|
663
207
|
delegates_to:
|
|
664
208
|
- "/test" — after parity check
|
|
665
209
|
- "/deploy" — when rebuild is complete
|
|
666
|
-
- beads-manager — auto-track progress per
|
|
210
|
+
- beads-manager — auto-track progress per phase
|
|
667
211
|
|
|
668
212
|
works_with:
|
|
669
213
|
- memory-sync — saves decisions, patterns, solutions
|
|
@@ -675,41 +219,58 @@ independent_from:
|
|
|
675
219
|
- smali-to-kotlin (sibling, same pattern, different platform)
|
|
676
220
|
```
|
|
677
221
|
|
|
222
|
+
### Session State Tracking
|
|
223
|
+
|
|
224
|
+
```yaml
|
|
225
|
+
session_state:
|
|
226
|
+
current_phase: 0-4
|
|
227
|
+
current_feature: "Auth"
|
|
228
|
+
phase_2_status:
|
|
229
|
+
contracts: approved | pending
|
|
230
|
+
ui_shell: approved | pending
|
|
231
|
+
resources: extracted | pending
|
|
232
|
+
completed_features: ["Launch", "Login"]
|
|
233
|
+
pending_features: ["Home", "Settings"]
|
|
234
|
+
```
|
|
235
|
+
|
|
678
236
|
---
|
|
679
237
|
|
|
680
238
|
## 🚫 ANTI-PATTERNS
|
|
681
239
|
|
|
682
240
|
```yaml
|
|
683
241
|
never_do:
|
|
684
|
-
- Copy all resources blindly from IPA → only on-demand
|
|
242
|
+
- Copy all resources blindly from IPA → only on-demand per screen
|
|
243
|
+
- Skip Phase 2 UI gate → jump to logic coding
|
|
244
|
+
- Code ViewModel before UI is approved → UI design might change
|
|
245
|
+
- Modify UI shell significantly in Phase 3 → only wire, don't redesign
|
|
685
246
|
- Use UIKit when SwiftUI equivalent exists → always prefer SwiftUI
|
|
686
|
-
- Use GCD
|
|
687
|
-
- Use NSJSONSerialization → use Codable
|
|
247
|
+
- Use GCD for new code → use async/await
|
|
688
248
|
- Modify encryption output → must match original exactly
|
|
689
|
-
- Create massive ViewController God objects → split into
|
|
249
|
+
- Create massive ViewController God objects → split into Views + ViewModels
|
|
690
250
|
- Skip framework scanner step → always detect reusable dependencies first
|
|
691
|
-
- Use ObjC in new code → Swift only (except bridging headers
|
|
251
|
+
- Use ObjC in new code → Swift only (except bridging headers)
|
|
692
252
|
- Force unwrap optionals → use guard let / if let / nil coalescing
|
|
693
253
|
|
|
694
254
|
always_do:
|
|
695
|
-
- Run Framework Scanner (
|
|
696
|
-
-
|
|
255
|
+
- Run Framework Scanner (Phase 0) before any coding
|
|
256
|
+
- Extract resources BEFORE coding UI (2.7 → 2.8)
|
|
257
|
+
- Create #Preview for ALL states (normal, loading, error, empty)
|
|
258
|
+
- Get user approval on UI before coding logic
|
|
259
|
+
- Keep stateless View for Preview even after wiring
|
|
697
260
|
- Use Swift Concurrency (async/await) for all async operations
|
|
698
261
|
- Use @Observable (iOS 17+) for ViewModels
|
|
699
|
-
- Use NavigationStack for navigation
|
|
700
|
-
- Unit test all encryption/hashing utils
|
|
701
|
-
- Follow Clean Architecture layer separation strictly
|
|
702
262
|
- Use SPM for dependency management (not CocoaPods)
|
|
263
|
+
- Unit test all encryption/hashing utils
|
|
703
264
|
```
|
|
704
265
|
|
|
705
266
|
---
|
|
706
267
|
|
|
707
268
|
## 📊 CHECKPOINT TEMPLATE
|
|
708
269
|
|
|
709
|
-
After each
|
|
270
|
+
After each phase/feature, output:
|
|
710
271
|
|
|
711
272
|
```markdown
|
|
712
|
-
## ✅
|
|
273
|
+
## ✅ [Phase/Feature] Complete: [Name]
|
|
713
274
|
|
|
714
275
|
### What was done:
|
|
715
276
|
- [Summary]
|
|
@@ -723,7 +284,7 @@ After each step, output:
|
|
|
723
284
|
### Decisions made:
|
|
724
285
|
- [Key decisions]
|
|
725
286
|
|
|
726
|
-
### ⏭️ Next:
|
|
287
|
+
### ⏭️ Next: [Phase/Feature] — [Name]
|
|
727
288
|
- [What user needs to provide]
|
|
728
289
|
```
|
|
729
290
|
|
|
@@ -731,19 +292,17 @@ After each step, output:
|
|
|
731
292
|
|
|
732
293
|
## 🧩 PLATFORM RE TEMPLATE PATTERN
|
|
733
294
|
|
|
734
|
-
This skill follows the same **
|
|
295
|
+
This skill follows the same **4-phase pipeline** as `smali-to-kotlin`:
|
|
735
296
|
|
|
736
|
-
|
|
|
737
|
-
|
|
297
|
+
| Phase | Android (smali-to-kotlin) | iOS (smali-to-swift) |
|
|
298
|
+
|-------|--------------------------|---------------------|
|
|
738
299
|
| 0 | Library Scanner (Smali packages) | Framework Scanner (Frameworks/ + headers) |
|
|
739
|
-
| 1 | AndroidManifest
|
|
740
|
-
| 2 |
|
|
741
|
-
| 3 |
|
|
742
|
-
| 4 |
|
|
743
|
-
| 5 | Hilt + JNI | SPM + Bridging Header |
|
|
744
|
-
| 6 | Parity Check | Parity Check |
|
|
300
|
+
| 1 | AndroidManifest → Architecture | Info.plist → Architecture |
|
|
301
|
+
| 2 | Contracts + Compose UI Shell | Contracts + SwiftUI Shell |
|
|
302
|
+
| 3 | Domain + Data + Wire Compose | Domain + Data + Wire SwiftUI |
|
|
303
|
+
| 4 | Parity Check | Parity Check |
|
|
745
304
|
|
|
746
305
|
---
|
|
747
306
|
|
|
748
|
-
*smali-to-swift
|
|
307
|
+
*smali-to-swift v2.0.0 — UI-First iOS Reverse Engineering Skill*
|
|
749
308
|
*Created by Antigravity Team*
|