@leejungkiin/awkit 1.0.2 → 1.0.4
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 +0 -10
- package/core/GEMINI.md +50 -25
- package/package.json +3 -3
- package/skills/beads-manager/SKILL.md +298 -181
- package/workflows/expert/codeExpert.md +25 -10
- package/workflows/expert/planExpert.md +37 -14
- package/workflows/lifecycle/plan.md +13 -9
- package/workflows/mobile/reverse-android-build.md +232 -0
- package/workflows/mobile/reverse-android-scan.md +158 -0
- package/workflows/mobile/reverse-android.md +26 -660
- package/workflows/mobile/reverse-ios-build.md +248 -0
- package/workflows/mobile/reverse-ios-scan.md +155 -0
- package/workflows/mobile/reverse-ios.md +28 -588
|
@@ -5,33 +5,26 @@ skill: smali-to-kotlin
|
|
|
5
5
|
|
|
6
6
|
# /reverse-android — Android APK Reverse Engineering Workflow
|
|
7
7
|
|
|
8
|
-
> **Skill
|
|
9
|
-
> **Tech Stack:** Kotlin + Jetpack Compose + Hilt + Retrofit + Room + Coroutines
|
|
8
|
+
> **Skill:** `smali-to-kotlin` | **Tech:** Kotlin + Compose + Hilt + Retrofit + Room
|
|
10
9
|
> **Philosophy:** "Read Smali to understand WHAT & WHY → Write Kotlin for HOW"
|
|
11
10
|
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
## ⚡ QUICK START
|
|
15
14
|
|
|
16
|
-
User cung cấp
|
|
17
|
-
|
|
18
|
-
- File `AndroidManifest.xml` (để bắt đầu từ Step 1)
|
|
19
|
-
- Nói: "Tôi muốn reverse engineer APK này"
|
|
20
|
-
|
|
21
|
-
Workflow sẽ dẫn dắt từng bước — **không bao giờ nhảy cóc**.
|
|
15
|
+
User cung cấp: Apktool output dir, `AndroidManifest.xml`, hoặc nói "reverse engineer APK này".
|
|
16
|
+
Workflow dẫn dắt từng bước — **không bao giờ nhảy cóc**.
|
|
22
17
|
|
|
23
18
|
---
|
|
24
19
|
|
|
25
|
-
## 🔵 Session Setup
|
|
20
|
+
## 🔵 Session Setup
|
|
26
21
|
|
|
27
22
|
### Bước 0.1: Khởi tạo session state
|
|
28
23
|
|
|
29
|
-
Tạo và track session state trong suốt quá trình:
|
|
30
|
-
|
|
31
24
|
```yaml
|
|
32
25
|
reverse_session:
|
|
33
|
-
project_name: "[TBD -
|
|
34
|
-
apktool_dir: "[path
|
|
26
|
+
project_name: "[TBD - từ manifest]"
|
|
27
|
+
apktool_dir: "[path]"
|
|
35
28
|
current_step: 0
|
|
36
29
|
library_report_done: false
|
|
37
30
|
manifest_analyzed: false
|
|
@@ -42,665 +35,37 @@ reverse_session:
|
|
|
42
35
|
|
|
43
36
|
### Bước 0.2: Xác nhận input
|
|
44
37
|
|
|
45
|
-
Hỏi user (nếu chưa cung cấp):
|
|
46
|
-
|
|
47
38
|
```
|
|
48
39
|
🔧 Android Reverse Engineering bắt đầu!
|
|
49
40
|
|
|
50
41
|
Em cần biết:
|
|
51
|
-
1. Thư mục Apktool output ở đâu?
|
|
52
|
-
2. Tên app gốc
|
|
53
|
-
3. Package name original? (vd: com.example.myapp)
|
|
54
|
-
|
|
55
|
-
Nếu chưa chạy Apktool, dùng lệnh:
|
|
56
|
-
apktool d your-app.apk -o ./decompiled/
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## 📦 Step 0: Library Scanner (BẮT BUỘC — Không được bỏ qua)
|
|
62
|
-
|
|
63
|
-
> **Mục tiêu:** Nhận diện toàn bộ thư viện trước khi code bất kỳ thứ gì.
|
|
64
|
-
> **Reference:** `skills/smali-to-kotlin/library-patterns.md`
|
|
65
|
-
|
|
66
|
-
### Bước 0.3: Quét Smali directories
|
|
67
|
-
|
|
68
|
-
User chạy lệnh sau hoặc AI đọc cấu trúc thư mục:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
# Liệt kê top-level packages trong smali/
|
|
72
|
-
find [apktool_dir]/smali -maxdepth 3 -type d | sed 's|[apktool_dir]/smali/||' | sort
|
|
73
|
-
|
|
74
|
-
# Multi-dex apps (smali_classes2, smali_classes3...)
|
|
75
|
-
find [apktool_dir] -name "smali*" -maxdepth 1 -type d
|
|
76
|
-
find [apktool_dir]/smali_classes2 -maxdepth 3 -type d 2>/dev/null | sort
|
|
77
|
-
|
|
78
|
-
# Native libraries
|
|
79
|
-
find [apktool_dir]/lib -name "*.so" 2>/dev/null
|
|
80
|
-
|
|
81
|
-
# Assets
|
|
82
|
-
ls [apktool_dir]/assets/ 2>/dev/null
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Bước 0.4: Phân tích và tạo Library Detection Report
|
|
86
|
-
|
|
87
|
-
Dùng patterns từ `library-patterns.md`, phân loại từng package:
|
|
88
|
-
|
|
89
|
-
```markdown
|
|
90
|
-
## 📦 Library Detection Report — [App Name]
|
|
91
|
-
|
|
92
|
-
### ✅ Reuse (Thêm vào build.gradle)
|
|
93
|
-
| Library | Package Detected | Recommended Version | Notes |
|
|
94
|
-
|---------|-----------------|--------------------|----|
|
|
95
|
-
| Retrofit | com/squareup/retrofit2 | 2.9.0 | Keep |
|
|
96
|
-
| OkHttp | com/squareup/okhttp3 | 4.12.0 | Keep |
|
|
97
|
-
| [...] | [...] | [...] | [...] |
|
|
98
|
-
|
|
99
|
-
### 🔄 Replace (Legacy — cần đổi)
|
|
100
|
-
| Old Library | Package Detected | Modern Replacement |
|
|
101
|
-
|-------------|-----------------|-------------------|
|
|
102
|
-
| Volley | com/android/volley | Retrofit + OkHttp |
|
|
103
|
-
| AsyncTask | android.os.AsyncTask | Coroutines |
|
|
104
|
-
| [...] | [...] | [...] |
|
|
105
|
-
|
|
106
|
-
### 🔵 Firebase/Google SDKs
|
|
107
|
-
| SDK | Package Detected | Action |
|
|
108
|
-
|-----|-----------------|--------|
|
|
109
|
-
| Firebase Analytics | com/google/firebase/analytics | Add latest |
|
|
110
|
-
| [...] | [...] | [...] |
|
|
111
|
-
|
|
112
|
-
### 📱 Native (.so) — Giữ nguyên
|
|
113
|
-
| File | Architecture | Notes |
|
|
114
|
-
|------|-------------|-------|
|
|
115
|
-
| lib*.so | arm64-v8a | JNI bridge needed |
|
|
116
|
-
|
|
117
|
-
### 🏷️ App Code (Rebuild in Kotlin)
|
|
118
|
-
| Package | Estimated Module |
|
|
119
|
-
|---------|-----------------|
|
|
120
|
-
| com/example/app/ui | Presentation layer |
|
|
121
|
-
| com/example/app/data | Data layer |
|
|
122
|
-
|
|
123
|
-
### ❓ Unknown Packages (Cần điều tra thêm)
|
|
124
|
-
| Package | Path | Possible Library |
|
|
125
|
-
|---------|------|-----------------|
|
|
126
|
-
| [...] | [...] | Custom? |
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Bước 0.5: User review và approve report
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
📦 Library Report đã sẵn sàng!
|
|
133
|
-
|
|
134
|
-
Anh review và xác nhận:
|
|
135
|
-
✅ Danh sách "Reuse" có đúng không?
|
|
136
|
-
🔄 Có thư viện nào trong "Replace" mà anh muốn giữ không?
|
|
137
|
-
|
|
138
|
-
Sau khi anh OK, em sẽ bắt đầu Step 1 (Manifest Analysis).
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
> **GATE:** Không tiếp tục Step 1 khi chưa có user approval report.
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## 📄 Step 1: AndroidManifest Analysis & Project Bootstrap
|
|
146
|
-
|
|
147
|
-
> **Input:** `[apktool_dir]/AndroidManifest.xml`
|
|
148
|
-
> **Reference:** `skills/smali-to-kotlin/SKILL.md` → Step 1
|
|
149
|
-
|
|
150
|
-
### Bước 1.1: Đọc và phân tích AndroidManifest.xml
|
|
151
|
-
|
|
152
|
-
User cung cấp nội dung file hoặc AI đọc từ path. Trích xuất:
|
|
153
|
-
|
|
154
|
-
```yaml
|
|
155
|
-
extract:
|
|
156
|
-
- application_id: "com.example.app"
|
|
157
|
-
- package_name: "com.example.app"
|
|
158
|
-
- min_sdk: 21
|
|
159
|
-
- target_sdk: 34
|
|
160
|
-
- permissions:
|
|
161
|
-
network: [INTERNET, ACCESS_NETWORK_STATE]
|
|
162
|
-
storage: [READ_EXTERNAL_STORAGE]
|
|
163
|
-
camera: [CAMERA]
|
|
164
|
-
location: []
|
|
165
|
-
other: []
|
|
166
|
-
- entry_points:
|
|
167
|
-
application_class: "com.example.app.MyApp"
|
|
168
|
-
splash_activity: "com.example.app.SplashActivity"
|
|
169
|
-
main_activity: "com.example.app.MainActivity"
|
|
170
|
-
- components:
|
|
171
|
-
activities: [list]
|
|
172
|
-
services: [list]
|
|
173
|
-
receivers: [list]
|
|
174
|
-
providers: [list]
|
|
175
|
-
- deep_links: [list of intent-filters with schemes]
|
|
176
|
-
- features: [uses-feature list]
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Bước 1.2: Đề xuất project structure
|
|
180
|
-
|
|
181
|
-
Xuất Clean Architecture structure dựa trên manifest analysis (xem template trong SKILL.md Step 1).
|
|
182
|
-
|
|
183
|
-
Mapping activities → Compose screens:
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
SplashActivity → presentation/screens/splash/SplashScreen.kt
|
|
187
|
-
MainActivity → presentation/screens/main/MainScreen.kt
|
|
188
|
-
LoginActivity → presentation/screens/auth/LoginScreen.kt
|
|
189
|
-
[...]
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Bước 1.3: Tạo `build.gradle.kts` skeleton
|
|
193
|
-
|
|
194
|
-
```kotlin
|
|
195
|
-
// app/build.gradle.kts
|
|
196
|
-
plugins {
|
|
197
|
-
alias(libs.plugins.android.application)
|
|
198
|
-
alias(libs.plugins.kotlin.android)
|
|
199
|
-
alias(libs.plugins.kotlin.compose)
|
|
200
|
-
alias(libs.plugins.hilt.android)
|
|
201
|
-
alias(libs.plugins.ksp)
|
|
202
|
-
alias(libs.plugins.kotlin.serialization)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
android {
|
|
206
|
-
namespace = "[package_name]"
|
|
207
|
-
compileSdk = [target_sdk]
|
|
208
|
-
|
|
209
|
-
defaultConfig {
|
|
210
|
-
applicationId = "[application_id]"
|
|
211
|
-
minSdk = [min_sdk]
|
|
212
|
-
targetSdk = [target_sdk]
|
|
213
|
-
versionCode = 1
|
|
214
|
-
versionName = "1.0.0"
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
buildFeatures {
|
|
218
|
-
compose = true
|
|
219
|
-
buildConfig = true
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
dependencies {
|
|
224
|
-
// Jetpack Compose BOM
|
|
225
|
-
val composeBom = platform(libs.androidx.compose.bom)
|
|
226
|
-
implementation(composeBom)
|
|
227
|
-
implementation(libs.androidx.compose.ui)
|
|
228
|
-
implementation(libs.androidx.compose.material3)
|
|
229
|
-
implementation(libs.androidx.activity.compose)
|
|
230
|
-
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
|
231
|
-
implementation(libs.androidx.navigation.compose)
|
|
232
|
-
|
|
233
|
-
// Coroutines
|
|
234
|
-
implementation(libs.kotlinx.coroutines.android)
|
|
235
|
-
|
|
236
|
-
// Hilt DI
|
|
237
|
-
implementation(libs.hilt.android)
|
|
238
|
-
ksp(libs.hilt.compiler)
|
|
239
|
-
implementation(libs.androidx.hilt.navigation.compose)
|
|
240
|
-
|
|
241
|
-
// Network (từ Library Report)
|
|
242
|
-
implementation(libs.retrofit)
|
|
243
|
-
implementation(libs.okhttp)
|
|
244
|
-
implementation(libs.okhttp.logging)
|
|
245
|
-
implementation(libs.kotlinx.serialization.json)
|
|
246
|
-
|
|
247
|
-
// Local Storage (từ Library Report)
|
|
248
|
-
implementation(libs.room.runtime)
|
|
249
|
-
implementation(libs.room.ktx)
|
|
250
|
-
ksp(libs.room.compiler)
|
|
251
|
-
implementation(libs.datastore.preferences)
|
|
252
|
-
|
|
253
|
-
// Image Loading
|
|
254
|
-
implementation(libs.coil.compose)
|
|
255
|
-
|
|
256
|
-
// Logging
|
|
257
|
-
implementation(libs.timber)
|
|
258
|
-
|
|
259
|
-
// [Thêm các libs từ Library Report "Reuse" section]
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### ✅ Checkpoint Step 1
|
|
264
|
-
|
|
265
|
-
```markdown
|
|
266
|
-
## ✅ Step 1 Complete: Manifest Analysis & Bootstrap
|
|
267
|
-
|
|
268
|
-
### Extracted:
|
|
269
|
-
- Package: [package_name]
|
|
270
|
-
- Entry points: [list]
|
|
271
|
-
- Permissions: [count] total
|
|
272
|
-
- Screens to rebuild: [list from activities]
|
|
273
|
-
|
|
274
|
-
### Created:
|
|
275
|
-
- Project structure proposal
|
|
276
|
-
- build.gradle.kts skeleton
|
|
277
|
-
|
|
278
|
-
### ⏭️ Next: Step 2 — Data Layer Reconstruction
|
|
279
|
-
- Hãy cung cấp Smali files cho: API calls, network models, database queries
|
|
280
|
-
- Folders thường có: smali/[package]/network/, smali/[package]/model/, smali/[package]/data/
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
## 💾 Step 2: Data Layer Reconstruction
|
|
286
|
-
|
|
287
|
-
> **Input:** Smali files cho network, models, database logic
|
|
288
|
-
> **Reference:** `skills/smali-to-kotlin/SKILL.md` → Step 2
|
|
289
|
-
> **Reading help:** `skills/smali-to-kotlin/smali-reading-guide.md`
|
|
290
|
-
|
|
291
|
-
### Bước 2.1: Network Layer
|
|
292
|
-
|
|
293
|
-
Từ Smali, trích xuất và tạo:
|
|
294
|
-
|
|
295
|
-
```kotlin
|
|
296
|
-
// data/remote/api/[Feature]Api.kt
|
|
297
|
-
interface UserApi {
|
|
298
|
-
@GET("users/{id}")
|
|
299
|
-
suspend fun getUser(@Path("id") id: String): UserDto
|
|
300
|
-
|
|
301
|
-
@POST("auth/login")
|
|
302
|
-
suspend fun login(@Body request: LoginRequest): TokenDto
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Bước 2.2: DTOs (Data Transfer Objects)
|
|
307
|
-
|
|
308
|
-
```kotlin
|
|
309
|
-
// data/remote/dto/UserDto.kt
|
|
310
|
-
@Serializable
|
|
311
|
-
data class UserDto(
|
|
312
|
-
@SerialName("user_id") val userId: String,
|
|
313
|
-
@SerialName("full_name") val fullName: String,
|
|
314
|
-
@SerialName("email") val email: String,
|
|
315
|
-
// map từ Smali fields
|
|
316
|
-
)
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Bước 2.3: Room Database (nếu app có local DB)
|
|
320
|
-
|
|
321
|
-
```kotlin
|
|
322
|
-
// data/local/entity/UserEntity.kt
|
|
323
|
-
@Entity(tableName = "users")
|
|
324
|
-
data class UserEntity(
|
|
325
|
-
@PrimaryKey val id: String,
|
|
326
|
-
val name: String,
|
|
327
|
-
val email: String
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
// data/local/dao/UserDao.kt
|
|
331
|
-
@Dao
|
|
332
|
-
interface UserDao {
|
|
333
|
-
@Query("SELECT * FROM users WHERE id = :id")
|
|
334
|
-
fun getUserById(id: String): Flow<UserEntity?>
|
|
335
|
-
|
|
336
|
-
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
337
|
-
suspend fun insert(user: UserEntity)
|
|
338
|
-
}
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### Bước 2.4: Repository
|
|
42
|
+
1. Thư mục Apktool output ở đâu?
|
|
43
|
+
2. Tên app gốc? Package name?
|
|
342
44
|
|
|
343
|
-
|
|
344
|
-
// domain/repository/UserRepository.kt (interface)
|
|
345
|
-
interface UserRepository {
|
|
346
|
-
fun getUser(id: String): Flow<Result<User>>
|
|
347
|
-
suspend fun login(email: String, password: String): Result<Token>
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// data/repository/UserRepositoryImpl.kt (implementation)
|
|
351
|
-
@Singleton
|
|
352
|
-
class UserRepositoryImpl @Inject constructor(
|
|
353
|
-
private val api: UserApi,
|
|
354
|
-
private val dao: UserDao
|
|
355
|
-
) : UserRepository {
|
|
356
|
-
override fun getUser(id: String): Flow<Result<User>> = flow {
|
|
357
|
-
// offline-first pattern
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### ✅ Checkpoint Step 2
|
|
363
|
-
|
|
364
|
-
```markdown
|
|
365
|
-
## ✅ Step 2 Complete: Data Layer
|
|
366
|
-
|
|
367
|
-
### Created:
|
|
368
|
-
- API interfaces: [list]
|
|
369
|
-
- DTOs: [list]
|
|
370
|
-
- Room entities + DAOs: [list if applicable]
|
|
371
|
-
- Repositories: [list]
|
|
372
|
-
|
|
373
|
-
### Decisions:
|
|
374
|
-
- [Key decisions documented]
|
|
375
|
-
|
|
376
|
-
### ⏭️ Next: Step 3 — Core Logic & Utils
|
|
377
|
-
- Cung cấp Smali cho: encryption, hashing, date formatting, custom algorithms
|
|
45
|
+
Chưa chạy Apktool? → apktool d your-app.apk -o ./decompiled/
|
|
378
46
|
```
|
|
379
47
|
|
|
380
48
|
---
|
|
381
49
|
|
|
382
|
-
##
|
|
383
|
-
|
|
384
|
-
> **Input:** Smali for encryption, hashing, utils
|
|
385
|
-
> **CRITICAL:** Output phải match 100% với app gốc
|
|
386
|
-
|
|
387
|
-
### Bước 3.1: Nhận diện utils cần rebuild
|
|
388
|
-
|
|
389
|
-
Tìm trong Smali:
|
|
390
|
-
```
|
|
391
|
-
- javax/crypto/Cipher → AES/DES encryption
|
|
392
|
-
- java/security/MessageDigest → MD5/SHA hashing
|
|
393
|
-
- android/util/Base64 → Base64 encoding
|
|
394
|
-
- Custom loops với XOR, shift → custom obfuscation
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### Bước 3.2: Tái tạo thành Kotlin objects
|
|
398
|
-
|
|
399
|
-
```kotlin
|
|
400
|
-
// util/CryptoUtils.kt
|
|
401
|
-
object CryptoUtils {
|
|
402
|
-
fun hashMd5(input: String): String {
|
|
403
|
-
val md = MessageDigest.getInstance("MD5")
|
|
404
|
-
val digest = md.digest(input.toByteArray())
|
|
405
|
-
return digest.joinToString("") { "%02x".format(it) }
|
|
406
|
-
}
|
|
50
|
+
## 📋 Pipeline Overview (7 Steps)
|
|
407
51
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
52
|
+
| Step | Phase | Sub-workflow | Gate |
|
|
53
|
+
|------|-------|-------------|------|
|
|
54
|
+
| 0 | 📦 Library Scanner | [`/re-android-scan`](reverse-android-scan.md) | User approve report |
|
|
55
|
+
| 1 | 📄 Manifest & Bootstrap | [`/re-android-scan`](reverse-android-scan.md) | Checkpoint |
|
|
56
|
+
| 2 | 💾 Data Layer | [`/re-android-build`](reverse-android-build.md) | Checkpoint |
|
|
57
|
+
| 3 | 🧮 Core Logic & Utils | [`/re-android-build`](reverse-android-build.md) | Checkpoint |
|
|
58
|
+
| 4 | 🎨 UI & ViewModel | [`/re-android-build`](reverse-android-build.md) | Per-screen loop |
|
|
59
|
+
| 5 | 📦 SDK Integration | [`/re-android-build`](reverse-android-build.md) | Checkpoint |
|
|
60
|
+
| 6 | ✅ Parity Check | [`/re-android-build`](reverse-android-build.md) | Final QA |
|
|
414
61
|
|
|
415
|
-
###
|
|
62
|
+
### Execution Flow
|
|
416
63
|
|
|
417
|
-
```kotlin
|
|
418
|
-
// Luôn tạo unit test cho crypto/hash functions!
|
|
419
|
-
class CryptoUtilsTest {
|
|
420
|
-
@Test
|
|
421
|
-
fun `md5 hash matches original`() {
|
|
422
|
-
// Test với known input/output từ app gốc
|
|
423
|
-
assertEquals("expected_hash", CryptoUtils.hashMd5("test_input"))
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
64
|
```
|
|
427
|
-
|
|
428
|
-
### ✅ Checkpoint Step 3
|
|
429
|
-
|
|
430
|
-
---
|
|
431
|
-
|
|
432
|
-
## 🎨 Step 4: UI & ViewModel Reconstruction (Per Screen — Lặp lại)
|
|
433
|
-
|
|
434
|
-
> **Input:** `res/layout/layout_xxx.xml` + Activity/Fragment Smali
|
|
435
|
-
> **Lặp lại** cho MỌI màn hình trong danh sách từ Step 1
|
|
436
|
-
> **Reference:** `skills/smali-to-kotlin/SKILL.md` → Step 4
|
|
437
|
-
|
|
438
|
-
### Bước 4.0: Chọn màn hình (theo thứ tự ưu tiên)
|
|
439
|
-
|
|
65
|
+
Session Setup → Step 0+1 (/re-android-scan) → Step 2-6 (/re-android-build)
|
|
440
66
|
```
|
|
441
|
-
Thứ tự rebuild đề nghị:
|
|
442
|
-
1. SplashScreen (đơn giản nhất)
|
|
443
|
-
2. Auth screens (Login, Register, Forgot Password)
|
|
444
|
-
3. Main/Home screen
|
|
445
|
-
4. Detail screens
|
|
446
|
-
5. Settings / Profile
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Bước 4.1: Resource Extraction (On-Demand)
|
|
450
|
-
|
|
451
|
-
Chỉ copy resources của màn hình này:
|
|
452
|
-
|
|
453
|
-
```markdown
|
|
454
|
-
### Resources cần thiết cho [ScreenName]:
|
|
455
|
-
- Drawables: [ic_logo.xml, bg_login.png, ...]
|
|
456
|
-
- Strings: [login_title, email_hint, password_hint, ...]
|
|
457
|
-
- Colors: [primary_color, background_color, ...]
|
|
458
|
-
- Dimens: [margin_standard, text_size_title, ...]
|
|
459
|
-
- Fonts: [inter_regular.ttf, ...]
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Bước 4.2: XML Layout → Compose Migration
|
|
463
|
-
|
|
464
|
-
Đọc layout XML, convert sang Compose composables:
|
|
465
|
-
|
|
466
|
-
```kotlin
|
|
467
|
-
// presentation/screens/[screen]/[Screen]Screen.kt
|
|
468
|
-
@Composable
|
|
469
|
-
fun LoginScreen(
|
|
470
|
-
viewModel: LoginViewModel = hiltViewModel(),
|
|
471
|
-
onNavigateToHome: () -> Unit
|
|
472
|
-
) {
|
|
473
|
-
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
474
|
-
val snackbarHostState = remember { SnackbarHostState() }
|
|
475
|
-
|
|
476
|
-
LaunchedEffect(Unit) {
|
|
477
|
-
viewModel.events.collectLatest { event ->
|
|
478
|
-
when (event) {
|
|
479
|
-
is LoginEvent.NavigateToHome -> onNavigateToHome()
|
|
480
|
-
is LoginEvent.ShowError -> snackbarHostState.showSnackbar(event.message)
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
Scaffold(snackbarHost = { SnackbarHost(snackbarHostState) }) { padding ->
|
|
486
|
-
LoginContent(
|
|
487
|
-
uiState = uiState,
|
|
488
|
-
onEmailChange = viewModel::onEmailChange,
|
|
489
|
-
onPasswordChange = viewModel::onPasswordChange,
|
|
490
|
-
onLoginClick = viewModel::login,
|
|
491
|
-
modifier = Modifier.padding(padding)
|
|
492
|
-
)
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### Bước 4.3: ViewModel
|
|
498
|
-
|
|
499
|
-
```kotlin
|
|
500
|
-
// presentation/screens/[screen]/[Screen]ViewModel.kt
|
|
501
|
-
@HiltViewModel
|
|
502
|
-
class LoginViewModel @Inject constructor(
|
|
503
|
-
private val loginUseCase: LoginUseCase
|
|
504
|
-
) : ViewModel() {
|
|
505
|
-
|
|
506
|
-
private val _uiState = MutableStateFlow(LoginUiState())
|
|
507
|
-
val uiState: StateFlow<LoginUiState> = _uiState.asStateFlow()
|
|
508
|
-
|
|
509
|
-
private val _events = MutableSharedFlow<LoginEvent>()
|
|
510
|
-
val events: SharedFlow<LoginEvent> = _events.asSharedFlow()
|
|
511
|
-
|
|
512
|
-
fun login() {
|
|
513
|
-
viewModelScope.launch {
|
|
514
|
-
_uiState.update { it.copy(isLoading = true) }
|
|
515
|
-
loginUseCase(uiState.value.email, uiState.value.password)
|
|
516
|
-
.onSuccess { _events.emit(LoginEvent.NavigateToHome) }
|
|
517
|
-
.onFailure { _uiState.update { s -> s.copy(error = it.message) } }
|
|
518
|
-
_uiState.update { it.copy(isLoading = false) }
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
data class LoginUiState(
|
|
524
|
-
val email: String = "",
|
|
525
|
-
val password: String = "",
|
|
526
|
-
val isLoading: Boolean = false,
|
|
527
|
-
val error: String? = null
|
|
528
|
-
)
|
|
529
|
-
|
|
530
|
-
sealed interface LoginEvent {
|
|
531
|
-
data object NavigateToHome : LoginEvent
|
|
532
|
-
data class ShowError(val message: String) : LoginEvent
|
|
533
|
-
}
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
### ✅ Checkpoint Step 4 (Per Screen)
|
|
537
|
-
|
|
538
|
-
```markdown
|
|
539
|
-
## ✅ Step 4 Complete: [ScreenName]
|
|
540
|
-
|
|
541
|
-
### Resources extracted: [list]
|
|
542
|
-
### Files created:
|
|
543
|
-
- [ScreenName]Screen.kt
|
|
544
|
-
- [ScreenName]ViewModel.kt
|
|
545
|
-
### Next screen: [ScreenName] or Step 5 if all screens done
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
> **Loop:** Quay lại Step 4.0 cho màn hình tiếp theo. Hoàn thành tất cả → Step 5.
|
|
549
67
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
## 📦 Step 5: Third-party SDK & Native Library Integration
|
|
553
|
-
|
|
554
|
-
> **Input:** Library Report từ Step 0 (Approved Libraries)
|
|
555
|
-
|
|
556
|
-
### Bước 5.1: Native Libraries (.so)
|
|
557
|
-
|
|
558
|
-
```kotlin
|
|
559
|
-
// Declare JNI bridge for each .so file
|
|
560
|
-
class NativeBridge {
|
|
561
|
-
companion object {
|
|
562
|
-
init {
|
|
563
|
-
System.loadLibrary("library_name")
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Match exact C/C++ function signatures from .so
|
|
568
|
-
external fun nativeMethod(param: String): ByteArray
|
|
569
|
-
external fun nativeVersion(): String
|
|
570
|
-
}
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
### Bước 5.2: Application class setup
|
|
574
|
-
|
|
575
|
-
```kotlin
|
|
576
|
-
// App.kt
|
|
577
|
-
@HiltAndroidApp
|
|
578
|
-
class App : Application() {
|
|
579
|
-
override fun onCreate() {
|
|
580
|
-
super.onCreate()
|
|
581
|
-
setupTimber()
|
|
582
|
-
setupFirebase()
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
private fun setupTimber() {
|
|
586
|
-
if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
|
|
587
|
-
else Timber.plant(CrashReportingTree())
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
private fun setupFirebase() {
|
|
591
|
-
// Firebase auto-initializes via manifest
|
|
592
|
-
// Manual config if needed:
|
|
593
|
-
// FirebaseApp.initializeApp(this)
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
### Bước 5.3: Hilt modules cho SDK dependencies
|
|
599
|
-
|
|
600
|
-
```kotlin
|
|
601
|
-
// di/NetworkModule.kt
|
|
602
|
-
@Module
|
|
603
|
-
@InstallIn(SingletonComponent::class)
|
|
604
|
-
object NetworkModule {
|
|
605
|
-
@Provides @Singleton
|
|
606
|
-
fun provideOkHttpClient(): OkHttpClient =
|
|
607
|
-
OkHttpClient.Builder()
|
|
608
|
-
.addInterceptor(AuthInterceptor())
|
|
609
|
-
.addInterceptor(HttpLoggingInterceptor().apply {
|
|
610
|
-
level = if (BuildConfig.DEBUG) BODY else NONE
|
|
611
|
-
})
|
|
612
|
-
.build()
|
|
613
|
-
|
|
614
|
-
@Provides @Singleton
|
|
615
|
-
fun provideRetrofit(okHttp: OkHttpClient): Retrofit =
|
|
616
|
-
Retrofit.Builder()
|
|
617
|
-
.baseUrl(BuildConfig.BASE_URL)
|
|
618
|
-
.client(okHttp)
|
|
619
|
-
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
|
620
|
-
.build()
|
|
621
|
-
}
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
### ✅ Checkpoint Step 5
|
|
625
|
-
|
|
626
|
-
---
|
|
627
|
-
|
|
628
|
-
## ✅ Step 6: Parity Check & Quality Gate
|
|
629
|
-
|
|
630
|
-
> **Mục tiêu:** Đảm bảo app mới hoạt động giống 100% app gốc
|
|
631
|
-
|
|
632
|
-
### Bước 6.1: Branch coverage từ Smali
|
|
633
|
-
|
|
634
|
-
Tạo test checklist từ các `if-else` / `when` tìm thấy trong Smali:
|
|
635
|
-
|
|
636
|
-
```markdown
|
|
637
|
-
### Edge Cases cần test (từ Smali analysis):
|
|
638
|
-
- [ ] Login với email trống
|
|
639
|
-
- [ ] Login với password sai > 3 lần
|
|
640
|
-
- [ ] Network timeout handling
|
|
641
|
-
- [ ] Empty list state
|
|
642
|
-
- [ ] Null response from server
|
|
643
|
-
- [ ] App lifecycle (background/foreground)
|
|
644
|
-
- [ ] [Custom cases từ specific Smali branches]
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
### Bước 6.2: API Parity verification
|
|
648
|
-
|
|
649
|
-
```
|
|
650
|
-
Checklist:
|
|
651
|
-
- [ ] Base URL matches original
|
|
652
|
-
- [ ] Request headers identical (User-Agent, auth tokens, etc.)
|
|
653
|
-
- [ ] Request body format matches (JSON field names, encoding)
|
|
654
|
-
- [ ] Response parsing correct (all fields mapped)
|
|
655
|
-
- [ ] Error responses handled
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
### Bước 6.3: Data parity
|
|
659
|
-
|
|
660
|
-
```
|
|
661
|
-
Checklist:
|
|
662
|
-
- [ ] Encryption output matches for same input
|
|
663
|
-
- [ ] Hash values match for same input
|
|
664
|
-
- [ ] Date/time formatting matches locale
|
|
665
|
-
- [ ] Local storage read/write works correctly
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
### Bước 6.4: Build và test
|
|
669
|
-
|
|
670
|
-
```bash
|
|
671
|
-
# Debug build
|
|
672
|
-
./gradlew assembleDebug
|
|
673
|
-
|
|
674
|
-
# Unit tests
|
|
675
|
-
./gradlew test
|
|
676
|
-
|
|
677
|
-
# Lint
|
|
678
|
-
./gradlew lint
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
### ✅ Final Checkpoint
|
|
682
|
-
|
|
683
|
-
```markdown
|
|
684
|
-
## 🎉 Reverse Engineering Complete!
|
|
685
|
-
|
|
686
|
-
### Summary:
|
|
687
|
-
- Screens rebuilt: [count]
|
|
688
|
-
- Libraries reused: [count]
|
|
689
|
-
- Libraries replaced: [count]
|
|
690
|
-
- Native libs integrated: [count]
|
|
691
|
-
|
|
692
|
-
### Test Results:
|
|
693
|
-
- Unit tests: [pass/fail]
|
|
694
|
-
- Lint: [pass/warnings]
|
|
695
|
-
|
|
696
|
-
### Known Differences from Original:
|
|
697
|
-
- [Any intentional or unavoidable differences]
|
|
698
|
-
|
|
699
|
-
### ⏭️ Recommended Next Steps:
|
|
700
|
-
1. `/test` — Chạy full test suite
|
|
701
|
-
2. `/deploy` — Khi sẵn sàng release
|
|
702
|
-
3. `/code-janitor` — Dọn dẹp code trước merge
|
|
703
|
-
```
|
|
68
|
+
**Chạy tuần tự:** Xong `/re-android-scan` → chuyển sang `/re-android-build`.
|
|
704
69
|
|
|
705
70
|
---
|
|
706
71
|
|
|
@@ -716,7 +81,7 @@ never_do:
|
|
|
716
81
|
- Mass-copy resources from APK (on-demand only)
|
|
717
82
|
- Use deprecated libraries without replacement plan
|
|
718
83
|
- Skip parity check for encryption utils
|
|
719
|
-
- Proceed to next step without user confirmation
|
|
84
|
+
- Proceed to next step without user confirmation
|
|
720
85
|
|
|
721
86
|
always_do:
|
|
722
87
|
- Document decisions in session state
|
|
@@ -729,12 +94,13 @@ always_do:
|
|
|
729
94
|
|
|
730
95
|
## 🔗 Related
|
|
731
96
|
|
|
97
|
+
- **Sub-workflows:** [`/re-android-scan`](reverse-android-scan.md) · [`/re-android-build`](reverse-android-build.md)
|
|
732
98
|
- **Skill:** `smali-to-kotlin` (core knowledge & rules)
|
|
733
99
|
- **Library DB:** `skills/smali-to-kotlin/library-patterns.md`
|
|
734
100
|
- **Smali Guide:** `skills/smali-to-kotlin/smali-reading-guide.md`
|
|
101
|
+
- **Sibling:** `/reverse-ios` (iOS counterpart)
|
|
735
102
|
- **After RE done:** `/test`, `/deploy`, `/code-janitor`
|
|
736
|
-
- **Future iOS version:** `smali-to-swift` skill + `/reverse-ios` workflow
|
|
737
103
|
|
|
738
104
|
---
|
|
739
105
|
|
|
740
|
-
*reverse-android workflow
|
|
106
|
+
*reverse-android workflow v2.0.0 — Modular RE Pipeline*
|