@leejungkiin/awkit 1.1.0 → 1.1.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/awf.js +1 -1
- package/bin/awk.js +237 -26
- package/core/AGENTS.md +8 -9
- package/core/GEMINI.md +74 -199
- package/package.json +3 -2
- package/skill-packs/neural-memory/skills/nm-memory-sync/SKILL.md +2 -2
- package/skills/CATALOG.md +3 -2
- package/skills/README.md +109 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/awf-session-restore/SKILL.md +108 -184
- package/skills/beads-manager/SKILL.md +2 -2
- package/skills/brainstorm-agent/SKILL.md +47 -2
- package/skills/gemini-conductor/SKILL.md +234 -0
- package/skills/memory-sync/SKILL.md +29 -1
- package/skills/nm-memory-sync/SKILL.md +2 -2
- package/skills/orchestrator/SKILL.md +29 -155
- package/skills/skills/nm-memory-sync/SKILL.md +2 -2
- package/skills/smali-to-kotlin/SKILL.md +1 -1
- package/skills/smali-to-swift/SKILL.md +1 -1
- package/skills/swiftui-pro/SKILL.md +108 -0
- package/skills/swiftui-pro/agents/openai.yaml +10 -0
- package/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/skills/swiftui-pro/references/accessibility.md +13 -0
- package/skills/swiftui-pro/references/api.md +39 -0
- package/skills/swiftui-pro/references/data.md +43 -0
- package/skills/swiftui-pro/references/design.md +31 -0
- package/skills/swiftui-pro/references/hygiene.md +9 -0
- package/skills/swiftui-pro/references/navigation.md +14 -0
- package/skills/swiftui-pro/references/performance.md +46 -0
- package/skills/swiftui-pro/references/swift.md +56 -0
- package/skills/swiftui-pro/references/views.md +35 -0
- package/skills/symphony-enforcer/SKILL.md +362 -0
- package/skills/symphony-orchestrator/SKILL.md +301 -0
- package/skills/telegram-notify/SKILL.md +57 -0
- package/symphony/LICENSE +21 -0
- package/symphony/README.md +178 -0
- package/symphony/app/api/agents/route.js +152 -0
- package/symphony/app/api/events/route.js +22 -0
- package/symphony/app/api/knowledge/route.js +253 -0
- package/symphony/app/api/locks/route.js +29 -0
- package/symphony/app/api/notes/route.js +125 -0
- package/symphony/app/api/preflight/route.js +23 -0
- package/symphony/app/api/projects/route.js +116 -0
- package/symphony/app/api/roles/route.js +134 -0
- package/symphony/app/api/skills/route.js +82 -0
- package/symphony/app/api/status/route.js +18 -0
- package/symphony/app/api/tasks/route.js +157 -0
- package/symphony/app/api/workflows/route.js +61 -0
- package/symphony/app/api/workspaces/route.js +15 -0
- package/symphony/app/globals.css +2605 -0
- package/symphony/app/layout.js +20 -0
- package/symphony/app/page.js +2122 -0
- package/symphony/cli/index.js +1060 -0
- package/symphony/core/agent-manager.js +357 -0
- package/symphony/core/context-bus.js +100 -0
- package/symphony/core/db.js +223 -0
- package/symphony/core/file-lock-manager.js +154 -0
- package/symphony/core/merge-pipeline.js +234 -0
- package/symphony/core/orchestrator.js +236 -0
- package/symphony/core/task-manager.js +335 -0
- package/symphony/core/workspace-manager.js +168 -0
- package/symphony/jsconfig.json +7 -0
- package/symphony/lib/core.mjs +1034 -0
- package/symphony/mcp/index.js +29 -0
- package/symphony/mcp/server.js +110 -0
- package/symphony/mcp/tools/context.js +80 -0
- package/symphony/mcp/tools/locks.js +99 -0
- package/symphony/mcp/tools/status.js +82 -0
- package/symphony/mcp/tools/tasks.js +216 -0
- package/symphony/mcp/tools/workspace.js +143 -0
- package/symphony/next.config.mjs +7 -0
- package/symphony/package.json +53 -0
- package/symphony/scripts/postinstall.js +49 -0
- package/symphony/symphony.config.js +41 -0
- package/templates/conductor-tracks.md +38 -0
- package/templates/specs/PROJECT.md +50 -0
- package/templates/specs/ROADMAP.md +79 -0
- package/templates/specs/TECH-SPEC.md +81 -0
- package/templates/specs/task-spec-template.xml +65 -0
- package/templates/workflow_dual_mode_template.md +5 -5
- package/workflows/_uncategorized/AGENTS.md +38 -0
- package/workflows/_uncategorized/decompile.md +67 -0
- package/workflows/_uncategorized/skill-health.md +7 -7
- package/workflows/ads/ads-audit.md +5 -5
- package/workflows/ads/ads-optimize.md +10 -10
- package/workflows/ads/adsExpert.md +7 -7
- package/workflows/conductor.md +97 -0
- package/workflows/context/auto-implement.md +4 -4
- package/workflows/context/codebase-sync.md +19 -8
- package/workflows/context/next.md +27 -27
- package/workflows/context/user-intent-analysis-workflow.md +4 -4
- package/workflows/expert/codeExpert.md +28 -31
- package/workflows/expert/debugExpert.md +11 -11
- package/workflows/expert/planExpert.md +21 -36
- package/workflows/git/smart-git-ops.md +49 -6
- package/workflows/lifecycle/debug.md +7 -7
- package/workflows/lifecycle/deploy.md +10 -10
- package/workflows/lifecycle/init.md +103 -91
- package/workflows/lifecycle/master-code-workflow.md +3 -3
- package/workflows/lifecycle/plan.md +19 -21
- package/workflows/quality/audit.md +1 -1
- package/workflows/quality/project-audit.md +1 -1
- package/workflows/roles/vibe-coding-master-workflow.md +2 -2
- package/workflows/smart-git-ops.md +146 -0
- package/workflows/ui/app-screen-analyzer.md +4 -4
- package/workflows/ui/create-feature.md +8 -8
- package/workflows/ui/create-spec-architect.md +11 -11
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# decompile.sh — Decompile APK/JAR/AAR using jadx, fernflower, or both
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
usage() {
|
|
6
|
+
cat <<EOF
|
|
7
|
+
Usage: decompile.sh [OPTIONS] <file>
|
|
8
|
+
|
|
9
|
+
Decompile an Android APK, XAPK, JAR, or AAR file.
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
<file> Path to the .apk, .xapk, .jar, or .aar file
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-o, --output DIR Output directory (default: <filename>-decompiled)
|
|
16
|
+
--deobf Enable deobfuscation of names
|
|
17
|
+
--no-res Skip resource decoding (faster, code-only)
|
|
18
|
+
--engine ENGINE Decompiler engine: jadx, fernflower, or both (default: jadx)
|
|
19
|
+
-h, --help Show this help message
|
|
20
|
+
|
|
21
|
+
Engines:
|
|
22
|
+
jadx Use jadx (default). Handles APK/JAR/AAR natively, decodes resources.
|
|
23
|
+
fernflower Use Fernflower/Vineflower. Better on complex Java, lambdas, generics.
|
|
24
|
+
For APK files, requires dex2jar as intermediate step.
|
|
25
|
+
both Run both decompilers side by side for comparison.
|
|
26
|
+
jadx output → <output>/jadx/
|
|
27
|
+
fernflower → <output>/fernflower/
|
|
28
|
+
|
|
29
|
+
Environment:
|
|
30
|
+
FERNFLOWER_JAR_PATH Path to fernflower.jar or vineflower.jar
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
decompile.sh app-release.apk
|
|
34
|
+
decompile.sh app-bundle.xapk
|
|
35
|
+
decompile.sh --engine both --deobf app-release.apk
|
|
36
|
+
decompile.sh --engine fernflower library.jar
|
|
37
|
+
EOF
|
|
38
|
+
exit 0
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# --- Parse arguments ---
|
|
42
|
+
OUTPUT_DIR=""
|
|
43
|
+
DEOBF=false
|
|
44
|
+
NO_RES=false
|
|
45
|
+
ENGINE="jadx"
|
|
46
|
+
INPUT_FILE=""
|
|
47
|
+
|
|
48
|
+
while [[ $# -gt 0 ]]; do
|
|
49
|
+
case "$1" in
|
|
50
|
+
-o|--output) OUTPUT_DIR="$2"; shift 2 ;;
|
|
51
|
+
--deobf) DEOBF=true; shift ;;
|
|
52
|
+
--no-res) NO_RES=true; shift ;;
|
|
53
|
+
--engine) ENGINE="$2"; shift 2 ;;
|
|
54
|
+
-h|--help) usage ;;
|
|
55
|
+
-*) echo "Error: Unknown option $1" >&2; usage ;;
|
|
56
|
+
*) INPUT_FILE="$1"; shift ;;
|
|
57
|
+
esac
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
# --- Validate input ---
|
|
61
|
+
if [[ -z "$INPUT_FILE" ]]; then
|
|
62
|
+
echo "Error: No input file specified." >&2
|
|
63
|
+
usage
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [[ ! -f "$INPUT_FILE" ]]; then
|
|
67
|
+
echo "Error: File not found: $INPUT_FILE" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
ext="${INPUT_FILE##*.}"
|
|
72
|
+
ext_lower=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
|
|
73
|
+
case "$ext_lower" in
|
|
74
|
+
apk|xapk|jar|aar) ;;
|
|
75
|
+
*)
|
|
76
|
+
echo "Error: Unsupported file type '.$ext'. Expected .apk, .xapk, .jar, or .aar" >&2
|
|
77
|
+
exit 1
|
|
78
|
+
;;
|
|
79
|
+
esac
|
|
80
|
+
|
|
81
|
+
case "$ENGINE" in
|
|
82
|
+
jadx|fernflower|both) ;;
|
|
83
|
+
*)
|
|
84
|
+
echo "Error: Unknown engine '$ENGINE'. Use jadx, fernflower, or both." >&2
|
|
85
|
+
exit 1
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
|
|
89
|
+
BASENAME=$(basename "$INPUT_FILE" ".$ext_lower")
|
|
90
|
+
INPUT_FILE_ABS=$(realpath "$INPUT_FILE")
|
|
91
|
+
|
|
92
|
+
if [[ -z "$OUTPUT_DIR" ]]; then
|
|
93
|
+
OUTPUT_DIR="${BASENAME}-decompiled"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# --- XAPK handling ---
|
|
97
|
+
# XAPK is a ZIP containing one or more APKs, optional OBB files, and a manifest.json.
|
|
98
|
+
# We extract it, find all APKs inside, and decompile each one.
|
|
99
|
+
XAPK_EXTRACTED_DIR=""
|
|
100
|
+
XAPK_APK_FILES=()
|
|
101
|
+
|
|
102
|
+
if [[ "$ext_lower" == "xapk" ]]; then
|
|
103
|
+
XAPK_EXTRACTED_DIR=$(mktemp -d "${TMPDIR:-/tmp}/xapk-extract-XXXXXX")
|
|
104
|
+
echo "=== Extracting XAPK archive ==="
|
|
105
|
+
unzip -qo "$INPUT_FILE_ABS" -d "$XAPK_EXTRACTED_DIR"
|
|
106
|
+
|
|
107
|
+
# Show manifest.json if present
|
|
108
|
+
if [[ -f "$XAPK_EXTRACTED_DIR/manifest.json" ]]; then
|
|
109
|
+
echo "XAPK manifest found:"
|
|
110
|
+
cat "$XAPK_EXTRACTED_DIR/manifest.json"
|
|
111
|
+
echo
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Find all APK files inside
|
|
115
|
+
while IFS= read -r -d '' apk_file; do
|
|
116
|
+
XAPK_APK_FILES+=("$apk_file")
|
|
117
|
+
done < <(find "$XAPK_EXTRACTED_DIR" -name "*.apk" -print0 | sort -z)
|
|
118
|
+
|
|
119
|
+
if [[ ${#XAPK_APK_FILES[@]} -eq 0 ]]; then
|
|
120
|
+
echo "Error: No APK files found inside XAPK archive." >&2
|
|
121
|
+
rm -rf "$XAPK_EXTRACTED_DIR"
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
echo "Found ${#XAPK_APK_FILES[@]} APK(s) inside XAPK:"
|
|
126
|
+
for f in "${XAPK_APK_FILES[@]}"; do
|
|
127
|
+
echo " - $(basename "$f")"
|
|
128
|
+
done
|
|
129
|
+
echo
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# --- Locate fernflower JAR ---
|
|
133
|
+
find_fernflower_jar() {
|
|
134
|
+
if [[ -n "${FERNFLOWER_JAR_PATH:-}" ]] && [[ -f "$FERNFLOWER_JAR_PATH" ]]; then
|
|
135
|
+
echo "$FERNFLOWER_JAR_PATH"
|
|
136
|
+
return
|
|
137
|
+
fi
|
|
138
|
+
# Check common locations
|
|
139
|
+
for candidate in \
|
|
140
|
+
"$HOME/fernflower/build/libs/fernflower.jar" \
|
|
141
|
+
"$HOME/vineflower/build/libs/vineflower.jar" \
|
|
142
|
+
"$HOME/fernflower/fernflower.jar" \
|
|
143
|
+
"$HOME/vineflower/vineflower.jar"; do
|
|
144
|
+
if [[ -f "$candidate" ]]; then
|
|
145
|
+
echo "$candidate"
|
|
146
|
+
return
|
|
147
|
+
fi
|
|
148
|
+
done
|
|
149
|
+
return 1
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# --- Locate dex2jar ---
|
|
153
|
+
find_dex2jar() {
|
|
154
|
+
if command -v d2j-dex2jar &>/dev/null; then
|
|
155
|
+
echo "d2j-dex2jar"
|
|
156
|
+
elif command -v d2j-dex2jar.sh &>/dev/null; then
|
|
157
|
+
echo "d2j-dex2jar.sh"
|
|
158
|
+
else
|
|
159
|
+
return 1
|
|
160
|
+
fi
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# --- jadx decompilation ---
|
|
164
|
+
run_jadx() {
|
|
165
|
+
local out_dir="$1"
|
|
166
|
+
|
|
167
|
+
if ! command -v jadx &>/dev/null; then
|
|
168
|
+
echo "Error: jadx is not installed or not in PATH." >&2
|
|
169
|
+
return 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
local args=()
|
|
173
|
+
args+=("-d" "$out_dir")
|
|
174
|
+
[[ "$DEOBF" == true ]] && args+=("--deobf")
|
|
175
|
+
[[ "$NO_RES" == true ]] && args+=("--no-res")
|
|
176
|
+
args+=("--show-bad-code")
|
|
177
|
+
args+=("$INPUT_FILE_ABS")
|
|
178
|
+
|
|
179
|
+
echo "Running: jadx ${args[*]}"
|
|
180
|
+
jadx "${args[@]}"
|
|
181
|
+
|
|
182
|
+
echo "jadx output: $out_dir/sources/"
|
|
183
|
+
if [[ -d "$out_dir/sources" ]]; then
|
|
184
|
+
local count
|
|
185
|
+
count=$(find "$out_dir/sources" -name "*.java" | wc -l)
|
|
186
|
+
echo "Java files decompiled by jadx: $count"
|
|
187
|
+
fi
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# --- Fernflower decompilation ---
|
|
191
|
+
run_fernflower() {
|
|
192
|
+
local out_dir="$1"
|
|
193
|
+
local jar_to_decompile=""
|
|
194
|
+
|
|
195
|
+
local ff_jar
|
|
196
|
+
if ! ff_jar=$(find_fernflower_jar); then
|
|
197
|
+
echo "Error: Fernflower/Vineflower JAR not found." >&2
|
|
198
|
+
echo "Set FERNFLOWER_JAR_PATH or see references/setup-guide.md" >&2
|
|
199
|
+
return 1
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
mkdir -p "$out_dir"
|
|
203
|
+
|
|
204
|
+
# For APK/AAR, we need dex2jar first to convert DEX→JAR
|
|
205
|
+
if [[ "$ext_lower" == "apk" || "$ext_lower" == "aar" ]]; then
|
|
206
|
+
local d2j
|
|
207
|
+
if ! d2j=$(find_dex2jar); then
|
|
208
|
+
echo "Error: dex2jar is required to use Fernflower on .$ext_lower files." >&2
|
|
209
|
+
echo "Install dex2jar — see references/setup-guide.md" >&2
|
|
210
|
+
return 1
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
echo "Converting $ext_lower to JAR with dex2jar..."
|
|
214
|
+
local converted_jar="$out_dir/${BASENAME}-dex2jar.jar"
|
|
215
|
+
"$d2j" -f -o "$converted_jar" "$INPUT_FILE_ABS" 2>&1 || true
|
|
216
|
+
if [[ ! -f "$converted_jar" ]]; then
|
|
217
|
+
echo "Error: dex2jar conversion failed." >&2
|
|
218
|
+
return 1
|
|
219
|
+
fi
|
|
220
|
+
jar_to_decompile="$converted_jar"
|
|
221
|
+
else
|
|
222
|
+
jar_to_decompile="$INPUT_FILE_ABS"
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Build fernflower args
|
|
226
|
+
local ff_args=()
|
|
227
|
+
ff_args+=("-dgs=1") # decompile generic signatures
|
|
228
|
+
ff_args+=("-mpm=60") # 60s max per method to avoid hangs
|
|
229
|
+
if [[ "$DEOBF" == true ]]; then
|
|
230
|
+
ff_args+=("-ren=1") # rename obfuscated identifiers
|
|
231
|
+
fi
|
|
232
|
+
ff_args+=("$jar_to_decompile")
|
|
233
|
+
ff_args+=("$out_dir")
|
|
234
|
+
|
|
235
|
+
echo "Running: java -jar $ff_jar ${ff_args[*]}"
|
|
236
|
+
java -jar "$ff_jar" "${ff_args[@]}"
|
|
237
|
+
|
|
238
|
+
# Fernflower outputs a JAR containing .java files — extract it
|
|
239
|
+
local result_jar="$out_dir/$(basename "$jar_to_decompile")"
|
|
240
|
+
if [[ -f "$result_jar" ]]; then
|
|
241
|
+
local sources_dir="$out_dir/sources"
|
|
242
|
+
mkdir -p "$sources_dir"
|
|
243
|
+
unzip -qo "$result_jar" -d "$sources_dir"
|
|
244
|
+
rm -f "$result_jar"
|
|
245
|
+
echo "Fernflower output: $sources_dir/"
|
|
246
|
+
local count
|
|
247
|
+
count=$(find "$sources_dir" -name "*.java" | wc -l)
|
|
248
|
+
echo "Java files decompiled by Fernflower: $count"
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
# Clean up intermediate dex2jar output
|
|
252
|
+
if [[ -n "${converted_jar:-}" ]] && [[ -f "${converted_jar:-}" ]]; then
|
|
253
|
+
rm -f "$converted_jar"
|
|
254
|
+
fi
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# --- Summary helper ---
|
|
258
|
+
print_structure() {
|
|
259
|
+
local src_dir="$1"
|
|
260
|
+
local label="$2"
|
|
261
|
+
if [[ -d "$src_dir" ]]; then
|
|
262
|
+
echo
|
|
263
|
+
echo "Top-level packages ($label):"
|
|
264
|
+
find "$src_dir" -mindepth 1 -maxdepth 3 -type d | head -20 | sed "s|$src_dir/||" | grep -v '^$' | sort
|
|
265
|
+
fi
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# --- Decompile a single file with the selected engine ---
|
|
269
|
+
decompile_single() {
|
|
270
|
+
local file_abs="$1"
|
|
271
|
+
local out_dir="$2"
|
|
272
|
+
local label="$3"
|
|
273
|
+
|
|
274
|
+
# Temporarily override INPUT_FILE_ABS for run_jadx/run_fernflower
|
|
275
|
+
local saved_input="$INPUT_FILE_ABS"
|
|
276
|
+
local saved_ext="$ext_lower"
|
|
277
|
+
INPUT_FILE_ABS="$file_abs"
|
|
278
|
+
ext_lower="${file_abs##*.}"
|
|
279
|
+
ext_lower=$(echo "$ext_lower" | tr '[:upper:]' '[:lower:]')
|
|
280
|
+
|
|
281
|
+
if [[ -n "$label" ]]; then
|
|
282
|
+
echo "=== Decompiling $label (engine: $ENGINE) ==="
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
case "$ENGINE" in
|
|
286
|
+
jadx)
|
|
287
|
+
run_jadx "$out_dir"
|
|
288
|
+
print_structure "$out_dir/sources" "jadx"
|
|
289
|
+
;;
|
|
290
|
+
fernflower)
|
|
291
|
+
run_fernflower "$out_dir"
|
|
292
|
+
print_structure "$out_dir/sources" "fernflower"
|
|
293
|
+
;;
|
|
294
|
+
both)
|
|
295
|
+
echo "--- Pass 1: jadx ---"
|
|
296
|
+
run_jadx "$out_dir/jadx"
|
|
297
|
+
echo
|
|
298
|
+
echo "--- Pass 2: Fernflower ---"
|
|
299
|
+
run_fernflower "$out_dir/fernflower"
|
|
300
|
+
|
|
301
|
+
print_structure "$out_dir/jadx/sources" "jadx"
|
|
302
|
+
print_structure "$out_dir/fernflower/sources" "fernflower"
|
|
303
|
+
|
|
304
|
+
echo
|
|
305
|
+
echo "=== Comparison ==="
|
|
306
|
+
local jadx_count=0 ff_count=0
|
|
307
|
+
if [[ -d "$out_dir/jadx/sources" ]]; then
|
|
308
|
+
jadx_count=$(find "$out_dir/jadx/sources" -name "*.java" | wc -l)
|
|
309
|
+
fi
|
|
310
|
+
if [[ -d "$out_dir/fernflower/sources" ]]; then
|
|
311
|
+
ff_count=$(find "$out_dir/fernflower/sources" -name "*.java" | wc -l)
|
|
312
|
+
fi
|
|
313
|
+
echo "jadx: $jadx_count Java files"
|
|
314
|
+
echo "Fernflower: $ff_count Java files"
|
|
315
|
+
|
|
316
|
+
if [[ -d "$out_dir/jadx/sources" ]]; then
|
|
317
|
+
local jadx_errors
|
|
318
|
+
jadx_errors=$(grep -rl 'JADX WARNING\|JADX WARN\|JADX ERROR\|Code decompiled incorrectly' "$out_dir/jadx/sources" 2>/dev/null | wc -l || echo 0)
|
|
319
|
+
echo "jadx files with warnings/errors: $jadx_errors"
|
|
320
|
+
fi
|
|
321
|
+
echo
|
|
322
|
+
echo "Tip: compare specific classes between jadx/ and fernflower/ to pick the better output."
|
|
323
|
+
;;
|
|
324
|
+
esac
|
|
325
|
+
|
|
326
|
+
INPUT_FILE_ABS="$saved_input"
|
|
327
|
+
ext_lower="$saved_ext"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# --- Run ---
|
|
331
|
+
echo "=== Decompiling $INPUT_FILE (engine: $ENGINE) ==="
|
|
332
|
+
echo "Output directory: $OUTPUT_DIR"
|
|
333
|
+
echo
|
|
334
|
+
|
|
335
|
+
if [[ "$ext_lower" == "xapk" ]]; then
|
|
336
|
+
# Decompile each APK found inside the XAPK
|
|
337
|
+
mkdir -p "$OUTPUT_DIR"
|
|
338
|
+
|
|
339
|
+
# Copy XAPK manifest for reference
|
|
340
|
+
if [[ -f "$XAPK_EXTRACTED_DIR/manifest.json" ]]; then
|
|
341
|
+
cp "$XAPK_EXTRACTED_DIR/manifest.json" "$OUTPUT_DIR/xapk-manifest.json"
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
# Copy OBB file list for reference
|
|
345
|
+
obb_files=()
|
|
346
|
+
while IFS= read -r -d '' obb; do
|
|
347
|
+
obb_files+=("$obb")
|
|
348
|
+
done < <(find "$XAPK_EXTRACTED_DIR" -name "*.obb" -print0 2>/dev/null)
|
|
349
|
+
if [[ ${#obb_files[@]} -gt 0 ]]; then
|
|
350
|
+
echo "OBB files found (not decompiled, data-only):"
|
|
351
|
+
for obb in "${obb_files[@]}"; do
|
|
352
|
+
echo " - $(basename "$obb") ($(du -h "$obb" | cut -f1))"
|
|
353
|
+
done
|
|
354
|
+
echo
|
|
355
|
+
fi
|
|
356
|
+
|
|
357
|
+
for apk_file in "${XAPK_APK_FILES[@]}"; do
|
|
358
|
+
apk_name=$(basename "$apk_file" .apk)
|
|
359
|
+
echo
|
|
360
|
+
echo "======================================================"
|
|
361
|
+
decompile_single "$apk_file" "$OUTPUT_DIR/$apk_name" "$apk_name.apk"
|
|
362
|
+
done
|
|
363
|
+
|
|
364
|
+
# Cleanup extracted XAPK
|
|
365
|
+
rm -rf "$XAPK_EXTRACTED_DIR"
|
|
366
|
+
|
|
367
|
+
echo
|
|
368
|
+
echo "=== XAPK decompilation complete ==="
|
|
369
|
+
echo "Subdirectories in $OUTPUT_DIR/:"
|
|
370
|
+
ls -1 "$OUTPUT_DIR/"
|
|
371
|
+
else
|
|
372
|
+
decompile_single "$INPUT_FILE_ABS" "$OUTPUT_DIR" ""
|
|
373
|
+
echo
|
|
374
|
+
echo "=== Decompilation complete ==="
|
|
375
|
+
fi
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# find-api-calls.sh — Search decompiled source for API calls and HTTP endpoints
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
usage() {
|
|
6
|
+
cat <<EOF
|
|
7
|
+
Usage: find-api-calls.sh <source-dir> [OPTIONS]
|
|
8
|
+
|
|
9
|
+
Search decompiled Java/Kotlin source for HTTP API calls and endpoints.
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
<source-dir> Path to the decompiled sources directory
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--retrofit Search only for Retrofit annotations
|
|
16
|
+
--okhttp Search only for OkHttp patterns
|
|
17
|
+
--volley Search only for Volley patterns
|
|
18
|
+
--urls Search only for hardcoded URLs
|
|
19
|
+
--auth Search only for auth-related patterns
|
|
20
|
+
--all Search all patterns (default)
|
|
21
|
+
-h, --help Show this help message
|
|
22
|
+
|
|
23
|
+
Output:
|
|
24
|
+
Results are printed as file:line:match for easy navigation.
|
|
25
|
+
EOF
|
|
26
|
+
exit 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
SOURCE_DIR=""
|
|
30
|
+
SEARCH_RETROFIT=false
|
|
31
|
+
SEARCH_OKHTTP=false
|
|
32
|
+
SEARCH_VOLLEY=false
|
|
33
|
+
SEARCH_URLS=false
|
|
34
|
+
SEARCH_AUTH=false
|
|
35
|
+
SEARCH_ALL=true
|
|
36
|
+
|
|
37
|
+
while [[ $# -gt 0 ]]; do
|
|
38
|
+
case "$1" in
|
|
39
|
+
--retrofit) SEARCH_RETROFIT=true; SEARCH_ALL=false; shift ;;
|
|
40
|
+
--okhttp) SEARCH_OKHTTP=true; SEARCH_ALL=false; shift ;;
|
|
41
|
+
--volley) SEARCH_VOLLEY=true; SEARCH_ALL=false; shift ;;
|
|
42
|
+
--urls) SEARCH_URLS=true; SEARCH_ALL=false; shift ;;
|
|
43
|
+
--auth) SEARCH_AUTH=true; SEARCH_ALL=false; shift ;;
|
|
44
|
+
--all) SEARCH_ALL=true; shift ;;
|
|
45
|
+
-h|--help) usage ;;
|
|
46
|
+
-*) echo "Error: Unknown option $1" >&2; usage ;;
|
|
47
|
+
*) SOURCE_DIR="$1"; shift ;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
if [[ -z "$SOURCE_DIR" ]]; then
|
|
52
|
+
echo "Error: No source directory specified." >&2
|
|
53
|
+
usage
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if [[ ! -d "$SOURCE_DIR" ]]; then
|
|
57
|
+
echo "Error: Directory not found: $SOURCE_DIR" >&2
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
GREP_OPTS="-rn --include=*.java --include=*.kt"
|
|
62
|
+
|
|
63
|
+
section() {
|
|
64
|
+
echo
|
|
65
|
+
echo "==== $1 ===="
|
|
66
|
+
echo
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
run_grep() {
|
|
70
|
+
local pattern="$1"
|
|
71
|
+
# shellcheck disable=SC2086
|
|
72
|
+
grep $GREP_OPTS -E "$pattern" "$SOURCE_DIR" 2>/dev/null || true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# --- Retrofit ---
|
|
76
|
+
if [[ "$SEARCH_ALL" == true || "$SEARCH_RETROFIT" == true ]]; then
|
|
77
|
+
section "Retrofit Annotations"
|
|
78
|
+
run_grep '@(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|HTTP)\s*\('
|
|
79
|
+
section "Retrofit Headers & Parameters"
|
|
80
|
+
run_grep '@(Headers|Header|Query|QueryMap|Path|Body|Field|FieldMap|Part|PartMap|Url)\s*\('
|
|
81
|
+
section "Retrofit Base URL"
|
|
82
|
+
run_grep '(baseUrl|base_url)\s*\('
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# --- OkHttp ---
|
|
86
|
+
if [[ "$SEARCH_ALL" == true || "$SEARCH_OKHTTP" == true ]]; then
|
|
87
|
+
section "OkHttp Request Building"
|
|
88
|
+
run_grep '(Request\.Builder|HttpUrl|\.newCall|\.enqueue|addInterceptor|addNetworkInterceptor)'
|
|
89
|
+
section "OkHttp URL Construction"
|
|
90
|
+
run_grep '(\.url\s*\(|\.addQueryParameter|\.addPathSegment|\.scheme\s*\(|\.host\s*\()'
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# --- Volley ---
|
|
94
|
+
if [[ "$SEARCH_ALL" == true || "$SEARCH_VOLLEY" == true ]]; then
|
|
95
|
+
section "Volley Requests"
|
|
96
|
+
run_grep '(StringRequest|JsonObjectRequest|JsonArrayRequest|ImageRequest|RequestQueue|Volley\.newRequestQueue)'
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# --- Hardcoded URLs ---
|
|
100
|
+
if [[ "$SEARCH_ALL" == true || "$SEARCH_URLS" == true ]]; then
|
|
101
|
+
section "Hardcoded URLs (http:// and https://)"
|
|
102
|
+
run_grep '"https?://[^"]+'
|
|
103
|
+
section "HttpURLConnection"
|
|
104
|
+
run_grep '(openConnection|setRequestMethod|HttpURLConnection|HttpsURLConnection)'
|
|
105
|
+
section "WebView URLs"
|
|
106
|
+
run_grep '(loadUrl|loadData|evaluateJavascript|addJavascriptInterface|WebViewClient|WebChromeClient)'
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# --- Auth patterns ---
|
|
110
|
+
if [[ "$SEARCH_ALL" == true || "$SEARCH_AUTH" == true ]]; then
|
|
111
|
+
section "Authentication & API Keys"
|
|
112
|
+
run_grep -i '(api[_-]?key|auth[_-]?token|bearer|authorization|x-api-key|client[_-]?secret|access[_-]?token)'
|
|
113
|
+
section "Base URLs and Constants"
|
|
114
|
+
run_grep -i '(BASE_URL|API_URL|SERVER_URL|ENDPOINT|API_BASE|HOST_NAME)'
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
echo
|
|
118
|
+
echo "=== Search complete ==="
|