@leejungkiin/awkit 1.0.1 → 1.0.3
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 +54 -25
- package/package.json +2 -2
- package/skills/beads-manager/SKILL.md +298 -181
- 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/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 +106 -0
- package/workflows/mobile/reverse-ios-build.md +248 -0
- package/workflows/mobile/reverse-ios-scan.md +155 -0
- package/workflows/mobile/reverse-ios.md +114 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# 🔬 Smali Reading Guide for AI
|
|
2
|
+
|
|
3
|
+
> Quick reference for interpreting Smali bytecode when reverse engineering Android apps.
|
|
4
|
+
> Used by the `smali-to-kotlin` skill during Steps 1-6.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📝 Smali Basics
|
|
9
|
+
|
|
10
|
+
### File Structure
|
|
11
|
+
```smali
|
|
12
|
+
.class public Lcom/example/app/MyClass;
|
|
13
|
+
.super Ljava/lang/Object;
|
|
14
|
+
.source "MyClass.java"
|
|
15
|
+
|
|
16
|
+
# interfaces
|
|
17
|
+
.implements Ljava/io/Serializable;
|
|
18
|
+
|
|
19
|
+
# static fields
|
|
20
|
+
.field private static final TAG:Ljava/lang/String; = "MyClass"
|
|
21
|
+
|
|
22
|
+
# instance fields
|
|
23
|
+
.field private name:Ljava/lang/String;
|
|
24
|
+
.field private age:I
|
|
25
|
+
|
|
26
|
+
# direct methods (constructors, static, private)
|
|
27
|
+
.method public constructor <init>()V
|
|
28
|
+
...
|
|
29
|
+
.end method
|
|
30
|
+
|
|
31
|
+
# virtual methods (public, protected, package-private)
|
|
32
|
+
.method public getName()Ljava/lang/String;
|
|
33
|
+
...
|
|
34
|
+
.end method
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Type Descriptors
|
|
38
|
+
```
|
|
39
|
+
V → void
|
|
40
|
+
Z → boolean
|
|
41
|
+
B → byte
|
|
42
|
+
S → short
|
|
43
|
+
C → char
|
|
44
|
+
I → int
|
|
45
|
+
J → long (2 registers)
|
|
46
|
+
F → float
|
|
47
|
+
D → double (2 registers)
|
|
48
|
+
L___; → object (e.g., Ljava/lang/String;)
|
|
49
|
+
[ → array (e.g., [I = int[], [Ljava/lang/String; = String[])
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Register Naming
|
|
53
|
+
```
|
|
54
|
+
p0, p1, p2... → parameter registers (p0 = 'this' for instance methods)
|
|
55
|
+
v0, v1, v2... → local variable registers
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🔑 Common Patterns → Kotlin Translation
|
|
61
|
+
|
|
62
|
+
### 1. String Constants & Field Access
|
|
63
|
+
```smali
|
|
64
|
+
# Smali
|
|
65
|
+
const-string v0, "https://api.example.com"
|
|
66
|
+
sput-object v0, Lcom/example/Config;->BASE_URL:Ljava/lang/String;
|
|
67
|
+
```
|
|
68
|
+
```kotlin
|
|
69
|
+
// Kotlin
|
|
70
|
+
object Config {
|
|
71
|
+
const val BASE_URL = "https://api.example.com"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. Method Calls
|
|
76
|
+
```smali
|
|
77
|
+
# Static method call
|
|
78
|
+
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
|
|
79
|
+
|
|
80
|
+
# Virtual method call (on instance)
|
|
81
|
+
invoke-virtual {p0, v0}, Lcom/example/MyClass;->setName(Ljava/lang/String;)V
|
|
82
|
+
|
|
83
|
+
# Interface method call
|
|
84
|
+
invoke-interface {v0}, Ljava/util/List;->size()I
|
|
85
|
+
|
|
86
|
+
# Direct method call (private/constructor)
|
|
87
|
+
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
|
88
|
+
```
|
|
89
|
+
```kotlin
|
|
90
|
+
// Kotlin equivalents
|
|
91
|
+
Log.d(tag, message)
|
|
92
|
+
myObject.setName(name) // or myObject.name = name
|
|
93
|
+
list.size
|
|
94
|
+
super()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. Conditionals (if-else)
|
|
98
|
+
```smali
|
|
99
|
+
# if (v0 == 0) goto :label
|
|
100
|
+
if-eqz v0, :cond_0
|
|
101
|
+
|
|
102
|
+
# if (v0 != v1) goto :label
|
|
103
|
+
if-ne v0, v1, :cond_1
|
|
104
|
+
|
|
105
|
+
# if (v0 >= v1) goto :label
|
|
106
|
+
if-ge v0, v1, :cond_2
|
|
107
|
+
```
|
|
108
|
+
```
|
|
109
|
+
Conditional opcodes:
|
|
110
|
+
if-eqz → == 0 if-eq → ==
|
|
111
|
+
if-nez → != 0 if-ne → !=
|
|
112
|
+
if-ltz → < 0 if-lt → <
|
|
113
|
+
if-gez → >= 0 if-ge → >=
|
|
114
|
+
if-gtz → > 0 if-gt → >
|
|
115
|
+
if-lez → <= 0 if-le → <=
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 4. Try-Catch
|
|
119
|
+
```smali
|
|
120
|
+
.method public doNetwork()V
|
|
121
|
+
.registers 4
|
|
122
|
+
|
|
123
|
+
:try_start_0
|
|
124
|
+
# ... risky code ...
|
|
125
|
+
:try_end_0
|
|
126
|
+
.catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_0
|
|
127
|
+
|
|
128
|
+
goto :goto_0
|
|
129
|
+
|
|
130
|
+
:catch_0
|
|
131
|
+
move-exception v0
|
|
132
|
+
# ... handle error ...
|
|
133
|
+
|
|
134
|
+
:goto_0
|
|
135
|
+
return-void
|
|
136
|
+
.end method
|
|
137
|
+
```
|
|
138
|
+
```kotlin
|
|
139
|
+
fun doNetwork() {
|
|
140
|
+
try {
|
|
141
|
+
// ... risky code ...
|
|
142
|
+
} catch (e: IOException) {
|
|
143
|
+
// ... handle error ...
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 5. Loops
|
|
149
|
+
```smali
|
|
150
|
+
# for loop pattern
|
|
151
|
+
const/4 v0, 0x0 # i = 0
|
|
152
|
+
|
|
153
|
+
:goto_0
|
|
154
|
+
array-length v1, v2 # v1 = array.length
|
|
155
|
+
if-ge v0, v1, :cond_0 # if (i >= length) break
|
|
156
|
+
|
|
157
|
+
# ... loop body using v0 as index ...
|
|
158
|
+
|
|
159
|
+
add-int/lit8 v0, v0, 0x1 # i++
|
|
160
|
+
goto :goto_0
|
|
161
|
+
|
|
162
|
+
:cond_0
|
|
163
|
+
# ... after loop ...
|
|
164
|
+
```
|
|
165
|
+
```kotlin
|
|
166
|
+
for (i in array.indices) {
|
|
167
|
+
// loop body
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 6. Switch/When
|
|
172
|
+
```smali
|
|
173
|
+
packed-switch v0, :pswitch_data_0
|
|
174
|
+
|
|
175
|
+
# ... default case ...
|
|
176
|
+
goto :goto_0
|
|
177
|
+
|
|
178
|
+
:pswitch_0 # case 0
|
|
179
|
+
...
|
|
180
|
+
:pswitch_1 # case 1
|
|
181
|
+
...
|
|
182
|
+
|
|
183
|
+
:pswitch_data_0
|
|
184
|
+
.packed-switch 0x0
|
|
185
|
+
:pswitch_0
|
|
186
|
+
:pswitch_1
|
|
187
|
+
.end packed-switch
|
|
188
|
+
```
|
|
189
|
+
```kotlin
|
|
190
|
+
when (value) {
|
|
191
|
+
0 -> { /* case 0 */ }
|
|
192
|
+
1 -> { /* case 1 */ }
|
|
193
|
+
else -> { /* default */ }
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 7. Object Creation
|
|
198
|
+
```smali
|
|
199
|
+
new-instance v0, Ljava/util/ArrayList;
|
|
200
|
+
invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V
|
|
201
|
+
```
|
|
202
|
+
```kotlin
|
|
203
|
+
val list = ArrayList<Any>()
|
|
204
|
+
// or better: val list = mutableListOf<Any>()
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 8. Casting & instanceof
|
|
208
|
+
```smali
|
|
209
|
+
# instanceof
|
|
210
|
+
instance-of v1, v0, Ljava/lang/String;
|
|
211
|
+
|
|
212
|
+
# cast
|
|
213
|
+
check-cast v0, Ljava/lang/String;
|
|
214
|
+
```
|
|
215
|
+
```kotlin
|
|
216
|
+
if (obj is String) { ... } // instanceof
|
|
217
|
+
val str = obj as String // cast
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 🎯 High-Value Patterns to Look For
|
|
223
|
+
|
|
224
|
+
### API Endpoints
|
|
225
|
+
```smali
|
|
226
|
+
# Look for URL string concatenation
|
|
227
|
+
const-string v0, "/api/v1/users"
|
|
228
|
+
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### SharedPreferences Keys
|
|
232
|
+
```smali
|
|
233
|
+
const-string v0, "user_token"
|
|
234
|
+
invoke-interface {v1, v0}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Intent Actions & Extras
|
|
238
|
+
```smali
|
|
239
|
+
const-string v0, "com.example.ACTION_REFRESH"
|
|
240
|
+
const-string v1, "extra_user_id"
|
|
241
|
+
invoke-virtual {v2, v1, v3}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Database Queries
|
|
245
|
+
```smali
|
|
246
|
+
const-string v0, "SELECT * FROM users WHERE id = ?"
|
|
247
|
+
invoke-virtual {v1, v0, v2}, Landroid/database/sqlite/SQLiteDatabase;->rawQuery(Ljava/lang/String;[Ljava/lang/String;)Landroid/database/Cursor;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Encryption Patterns
|
|
251
|
+
```smali
|
|
252
|
+
const-string v0, "AES/CBC/PKCS5Padding"
|
|
253
|
+
invoke-static {v0}, Ljavax/crypto/Cipher;->getInstance(Ljava/lang/String;)Ljavax/crypto/Cipher;
|
|
254
|
+
|
|
255
|
+
const-string v0, "SHA-256"
|
|
256
|
+
invoke-static {v0}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 🔍 Obfuscation Patterns (ProGuard/R8)
|
|
262
|
+
|
|
263
|
+
### Renamed Classes
|
|
264
|
+
```
|
|
265
|
+
Original: Lcom/example/UserRepository;
|
|
266
|
+
Obfuscated: La/b/c;
|
|
267
|
+
```
|
|
268
|
+
**Strategy:** Follow method calls and string constants to understand purpose.
|
|
269
|
+
|
|
270
|
+
### Renamed Methods
|
|
271
|
+
```
|
|
272
|
+
Original: ->getUserProfile
|
|
273
|
+
Obfuscated: ->a(Ljava/lang/String;)V
|
|
274
|
+
```
|
|
275
|
+
**Strategy:** Look at parameters, return types, and what the method does internally.
|
|
276
|
+
|
|
277
|
+
### String Encryption
|
|
278
|
+
```smali
|
|
279
|
+
# Common pattern: encrypted strings decoded at runtime
|
|
280
|
+
invoke-static {v0}, Lcom/example/StringDecryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
|
|
281
|
+
```
|
|
282
|
+
**Strategy:** Find the decryptor class, understand the algorithm, then decrypt all strings.
|
|
283
|
+
|
|
284
|
+
### Tips for Obfuscated Code
|
|
285
|
+
1. **Start from entry points** (Activities in Manifest) — these are rarely obfuscated
|
|
286
|
+
2. **Follow string constants** — strings reveal purpose
|
|
287
|
+
3. **Check annotation classes** — Retrofit/Room annotations may survive obfuscation
|
|
288
|
+
4. **mapping.txt** — if available in APK, use it to deobfuscate
|
|
289
|
+
5. **Look for SDK packages** — third-party SDKs are usually not obfuscated
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 📊 Register Width Rules
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
Single-width (1 register): boolean, byte, char, short, int, float, Object reference
|
|
297
|
+
Double-width (2 registers): long, double
|
|
298
|
+
|
|
299
|
+
Example:
|
|
300
|
+
.method public calc(IJLjava/lang/String;)V
|
|
301
|
+
.registers 6
|
|
302
|
+
# p0 = this
|
|
303
|
+
# p1 = int param (I)
|
|
304
|
+
# p2-p3 = long param (J) — takes 2 registers!
|
|
305
|
+
# p4 = String param
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
*smali-reading-guide v1.0.0 — AI reference for Smali bytecode interpretation*
|