Reversing⚓
Static analysis and decompilation of Android applications.
The goal of static analysis is to read the app's code and resources without running it. Different tools give you different views of the same binary — understanding what each one does, when to reach for it, and how to chain them together is the core skill.
Tool Overview — When to Use What⚓
| Tool | Input | Output | Best for |
|---|---|---|---|
| apktool | APK | Smali + resources | Patching code, reading resources/manifest |
| jadx | APK / DEX / AAR | Java (pseudo-source) | Reading logic, searching strings, tracing call graphs |
| dex2jar | APK / DEX | .jar (Java bytecode) |
Getting a JAR to open in JD-GUI or IntelliJ |
| JD-GUI | .jar |
Java source view | Quick visual read of a JAR; export all sources |
| MobSF | APK | Full automated report | First-pass: permissions, hardcoded secrets, endpoints |
| APKHunt | APK | OWASP-mapped findings | MASVS/OWASP compliance checks, CI integration |
| apkleaks | APK | Secrets + URLs | Fast regex scan for keys, tokens, endpoints |
| androguard | APK / DEX | Call graph, CFG, fingerprint | Call graph / CFG analysis, APK fingerprinting, diffs |
apktool — Decode, Patch, Rebuild⚓
What it does: Decodes an APK into Smali (human-readable Dalvik bytecode) and raw XML resources. You can edit the Smali or resources and rebuild a working APK. This is the primary tool when you need to patch the app — remove a root check, disable certificate pinning, flip a flag.
What it does not do: Produce readable Java. Smali is low-level assembly — readable with practice but not the same as reading decompiled Java.
# Decode — produces smali/, res/, AndroidManifest.xml, assets/ in the output dir
apktool d app.apk -o decoded/
# Decode without resource decoding (faster, use when you only care about smali/manifest)
apktool d app.apk -o decoded/ -r
# Rebuild after editing
apktool b decoded/ -o patched_unsigned.apk
# Align + sign (required before reinstalling)
zipalign -v 4 patched_unsigned.apk patched_aligned.apk
apksigner sign --ks my.keystore --ks-key-alias mykey patched_aligned.apk
# Install
adb install -r patched_aligned.apk
Typical workflow — disable a root check:
apktool d app.apk -o decoded/grep -r "isRooted\|checkRoot\|RootBeer" decoded/smali/— find the check- Open the smali file — find the branch (
if-eqz,if-nez) that leads to the "rooted — abort" path - Change the branch condition to its inverse, or replace the method body with
return-void apktool b decoded/ -o patched_unsigned.apk→ align → sign → install
Common errors:
| Error | Fix |
|---|---|
brut.AndrolibException: Could not decode |
Update apktool: apktool --version, download latest jar |
| Resources fail to decode | Use -r flag to skip resource decoding |
| Rebuild fails on unknown opcode | The app uses newer DEX features — use --use-aapt2 flag |
jadx — DEX to Java (Primary Analysis Tool)⚓
What it does: Decompiles DEX bytecode back into readable Java (pseudo-source). This is the first tool to open on any APK — it gives you class structure, method bodies, string literals, and full text search across the entire codebase in a GUI.
When to use: Reading logic, tracing what a method does, finding hardcoded values, understanding the call graph, locating where a permission is checked.
# GUI — opens the APK and shows a class tree + decompiled source
jadx-gui app.apk
# CLI — dumps all decompiled Java into output/ directory
jadx -d output/ app.apk
# CLI with extra options
jadx -d output/ \
--show-bad-code \ # show methods jadx couldn't fully decompile
--export-gradle \ # generate a build.gradle so you can open it in Android Studio
app.apk
Key jadx GUI shortcuts:
| Action | Shortcut |
|---|---|
| Full text search across all decompiled code | Ctrl+Shift+F |
| Find all usages of a class / method / field | Right-click → Find Usage |
| Jump to declaration | Ctrl+Click or F4 |
| Navigate back | Alt+Left |
| Search class by name | Ctrl+N |
What jadx produces vs reality:
jadx produces pseudo-Java — it is a best-effort reconstruction, not real source. Some constructs decompile poorly:
- Heavy obfuscation → single-letter class/method names everywhere
- Reflection → you see
Class.forName("...")but the actual class resolved at runtime is opaque - Native methods →
nativekeyword, no body, need to look inlib/*.so - ProGuard / R8 → control flow mangling, inlined methods, synthetic accessors
When jadx shows /* JADX WARNING: ... */ or marks a method with // decompile error, the smali for that method (from apktool) is more reliable.
dex2jar — DEX to JAR⚓
What it does: Converts a DEX file (or APK) into a standard Java .jar file containing .class files. The JAR is not runnable on Android but any Java bytecode viewer — JD-GUI, CFR, IntelliJ's built-in decompiler, Procyon — can open it.
When to use: When jadx fails or produces unreadable output on a specific class. Different decompilers have different strengths — dex2jar + a second decompiler often recovers code that jadx garbles. Also useful when you want to open the app in IntelliJ IDEA as a regular Java project.
# Convert APK → JAR (extracts all DEX files inside the APK first)
d2j-dex2jar app.apk -o app.jar
# If the APK has multiple DEX files (multidex), they are merged into one JAR
# Check what DEX files exist first:
unzip -l app.apk | grep "\.dex"
# Convert a single DEX directly
d2j-dex2jar classes2.dex -o classes2.jar
# Handle errors — dex2jar sometimes crashes on heavily obfuscated DEX
# --force skips bad classes and continues
d2j-dex2jar --force app.apk -o app.jar
# Verify the JAR is valid
jar tf app.jar | head -20
After converting — open in another tool:
# Open in JD-GUI (see below)
jd-gui app.jar
# Or use CFR decompiler (often handles obfuscation better than JD-GUI)
java -jar cfr.jar app.jar --outputdir cfr_output/
# Or Procyon
java -jar procyon.jar -jar app.jar -o procyon_output/
dex2jar vs jadx — which wins:
| Scenario | Prefer |
|---|---|
| General analysis, search, navigation | jadx (all-in-one) |
| jadx fails on a specific class | dex2jar → CFR or Procyon |
| Need a JAR for IntelliJ / other tooling | dex2jar |
| Want to script decompilation | jadx CLI or androguard |
JD-GUI — Java Decompiler GUI⚓
What it does: Opens a .jar file and shows decompiled Java source in a point-and-click GUI. Simpler than jadx — no search across multiple files, no navigation graph — but fast to spin up and sometimes produces cleaner output than jadx on certain code patterns.
When to use: Quick inspection of a specific JAR, exporting all sources to disk for grep-based analysis, or as a fallback when jadx output is unreadable.
# Launch (assumes jd-gui is on PATH, or run the .jar directly)
jd-gui app.jar
# Or run the jar
java -jar jd-gui-*.jar app.jar
Inside JD-GUI:
- Left panel — package/class tree
- Right panel — decompiled Java source for the selected class
File → Save All Sources— exports every class as a.javafile into a ZIP — useful for then grepping across everything:
# Export from JD-GUI: File → Save All Sources → sources.zip
unzip sources.zip -d sources/
grep -r "password\|api_key\|secret" sources/
grep -rE "https?://" sources/
Limitation: JD-GUI has no cross-reference navigation, no search across files in the GUI, and frequently fails on obfuscated code. It is best used as a "dump sources then grep" pipeline, not as an interactive analysis environment.
MobSF — Automated Static Analysis⚓
What it does: Uploads an APK and runs a full automated analysis: manifest permissions, exported components, hardcoded secrets, dangerous API calls, URL endpoints, certificate info, and an overall risk rating. Output is a browsable HTML report.
When to use: First-pass analysis at the start of every engagement. MobSF surfaces the obvious issues in minutes — then you do manual deep-dive on the findings it flags.
Setup — Python virtual environment:
# Prerequisites: Python 3.10+, JDK 17+, Git
git clone https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
cd Mobile-Security-Framework-MobSF
# Create and activate a venv
python -m venv venv
source venv/bin/activate # Linux / macOS
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# First-time setup (creates the database, downloads rules)
python manage.py migrate
# Start the server
python manage.py runserver 127.0.0.1:8000
Open http://127.0.0.1:8000 in a browser, drag-and-drop the APK, and the analysis runs automatically.
Subsequent runs — just activate the venv and start the server:
cd Mobile-Security-Framework-MobSF
source venv/bin/activate
python manage.py runserver 127.0.0.1:8000
API — automate uploads without the browser:
# Get your API key from http://127.0.0.1:8000 → REST API docs
export MOBSF_KEY="your-api-key-here"
# Upload
curl -F "file=@app.apk" \
http://127.0.0.1:8000/api/v1/upload \
-H "Authorization: $MOBSF_KEY"
# Returns: {"analyzer":"static_analyzer","status":"success","hash":"<hash>", ...}
# Trigger analysis
curl -X POST \
--url http://127.0.0.1:8000/api/v1/scan \
--data "scan_type=apk&file_name=app.apk&hash=<hash>" \
-H "Authorization: $MOBSF_KEY"
# Get JSON report
curl -X POST \
--url http://127.0.0.1:8000/api/v1/report_json \
--data "hash=<hash>" \
-H "Authorization: $MOBSF_KEY" \
-o report.json
# Get PDF report
curl -X POST \
--url http://127.0.0.1:8000/api/v1/download_pdf \
--data "hash=<hash>" \
-H "Authorization: $MOBSF_KEY" \
-o report.pdf
What to look at in the MobSF report:
| Section | What to check |
|---|---|
| Manifest Analysis | Exported components, dangerous permissions, allowBackup, debuggable |
| Binary Analysis | Hardcoded strings, API keys, URLs |
| Code Analysis | Dangerous API calls: Runtime.exec, reflection, crypto misuse |
| Network Security | Cleartext traffic allowed, pinning disabled, custom trust managers |
| File Analysis | Files inside the APK — look for embedded DBs, config files, certs |
| Signer Certificate | Who signed it, which scheme (v1/v2/v3), self-signed vs store cert |
MobSF as CI gate: You can POST an APK to the API and get a JSON score back — integrate as a pipeline step to catch obvious issues on every build.
APKHunt — OWASP MASVS Static Scanner⚓
What it does: Scans a decoded APK against the OWASP Mobile Application Security Verification Standard (MASVS) and outputs findings mapped to specific MASVS controls. Produces a text report you can reference directly in pentest reports.
When to use: When you need OWASP-aligned findings for a report, or want a second automated opinion after MobSF. APKHunt focuses on code-level patterns — it reads smali and resources — while MobSF focuses more on manifest and network config.
# Install
pip install apkhunt
# or clone and run directly
git clone https://github.com/Cyber-Buddy/APKHunt
cd APKHunt
# Run against an APK
python3 apkhunt.py -p app.apk
# Output goes to a .txt report in the current directory
# Each finding references the MASVS control it violates (e.g. MSTG-STORAGE-2)
What APKHunt checks:
| Category | Examples |
|---|---|
| Storage | Hardcoded credentials, world-readable files, SharedPreferences with sensitive data |
| Crypto | Hardcoded keys/IVs, ECB mode, weak algorithms |
| Network | Cleartext HTTP, disabled hostname verification, custom trust managers |
| Platform | Exported components with no permission, JavaScript enabled in WebViews, intent injection |
| Code quality | Logging of sensitive data, stack traces exposed, debug flags |
apkleaks — Fast Secrets and Endpoint Extraction⚓
What it does: Runs a set of regex patterns against strings extracted from the APK to find hardcoded secrets, API keys, tokens, and URLs. Much faster than manual grep — finishes in seconds.
When to use: At the very start of an engagement alongside MobSF. Run it immediately on every APK to surface any obvious credential leaks before diving into code.
# Install
pip install apkleaks
# Run
apkleaks -f app.apk
# Output to JSON
apkleaks -f app.apk -o findings.json
# Use a custom pattern file (add your own regexes)
apkleaks -f app.apk -p custom_patterns.json
Sample output:
[!] Google API Key
AIzaSyD...
[!] Firebase URL
https://myapp-default-rtdb.firebaseio.com
[!] AWS Access Key
AKIAIOSFODNN7EXAMPLE
[!] URL
https://api.internal.example.com/v2/admin
Each finding includes the pattern name and the matched value. False positives happen — validate any finding before reporting.
androguard — CLI Analysis Tool⚓
What it does: Parses APKs and DEX files to produce call graphs, control flow graphs, APK fingerprints, and decompiled output. Install it and run directly from the terminal.
When to use: Call graph and CFG analysis, APK fingerprinting, quick diffs between two APK versions — things that would be tedious to trace manually in jadx.
Fingerprint an APK⚓
Sample output:
file_type : APK
magic : Zip archive data
app_name : MyApp
package : com.example.app
version_name : 1.4.2
version_code : 42
main_act : com.example.app.MainActivity
min_sdk : 21
target_sdk : 33
cert_sha1 : AB:CD:EF:...
cert_issuer : CN=Android Debug, O=Android, C=US
# Broader analysis summary — class/method/string counts, permissions, activities
androguard analyze app.apk
Call Graph⚓
The call graph maps every method-to-method call in the app. It lets you see which code paths are reachable from an entry point (an exported Activity, Service, etc.) and whether they reach sensitive methods.
# Export call graph to DOT format (render with graphviz)
androguard cg app.apk -o callgraph.dot
# Export to GML format (open in Gephi or Cytoscape for interactive exploration)
androguard cg app.apk -o callgraph.gml
Render the DOT file:
# PNG — good for small apps
dot -Tpng callgraph.dot -o callgraph.png
# SVG — scalable, better for large graphs
dot -Tsvg callgraph.dot -o callgraph.svg
# Open the SVG in a browser and use Ctrl+F to search for class/method names
Reading the call graph:
Each node is a method in Dalvik descriptor format:
Lcom/example/app/MainActivity;->onCreate(Landroid/os/Bundle;)V
│ │ │ │
class (L...;) method name argument types return type
Edges point from caller → callee. To trace an attack path:
- Open the rendered graph or load the GML into Gephi
- Find the exported entry point (e.g.
MainActivity->onCreate) - Follow edges forward — does any path reach
rawQuery,exec,decrypt, or other sensitive methods?
Gephi workflow for large graphs:
1. Open Gephi → File → Open → callgraph.gml
2. Run Layout → ForceAtlas2 to space out nodes
3. Use Filters → Topology → Ego Network on your entry point node
→ shows only methods reachable from that node
4. Ctrl+F to search for a method name
Decompile + Control Flow Graphs (androguard decompile)⚓
CFGs are not a separate command — they are generated by androguard decompile using the -f flag. The -o output directory is required. Running it produces:
.javafiles — decompiled pseudo-Java for each class.agfiles — smali-like instruction dump per method- CFG image or DOT file per method (when
-fis specified)
# Basic decompile — output Java to a directory (-o is required)
androguard decompile -o output/ app.apk
# Decompile + generate PNG CFG for every method
androguard decompile -o output/ -f png app.apk
# Generate SVG CFGs (better for zooming large methods)
androguard decompile -o output/ -f svg app.apk
# Generate raw DOT files (render manually with graphviz)
androguard decompile -o output/ -f raw app.apk
# Limit to a specific package namespace (regex) — much faster on large apps
androguard decompile -o output/ -f png \
--limit "^Lcom/example/app/.*" app.apk
# Limit to a single class
androguard decompile -o output/ -f png \
--limit "^Lcom/example/app/LicenseCheck;.*" app.apk
# Use DEX2JAR to also produce a JAR file alongside
androguard decompile -o output/ -j app.apk
# Use a specific decompiler (default is DAD)
androguard decompile -o output/ -d dad app.apk
Prerequisites for CFG image output:
What the output directory contains:
output/
com/example/app/
LicenseCheck.java ← decompiled pseudo-Java
LicenseCheck.ag ← smali-like per-method instruction dump
LicenseCheck_validate.png ← CFG image for the validate() method (if -f png)
...
Reading the .ag file:
The .ag file is a smali-like text dump of each method's basic blocks — useful when the Java decompilation is garbled:
# Lcom/example/app/LicenseCheck;->validate(Ljava/lang/String;)Z
validate-BB@0x0 : [ validate-BB@0x12 validate-BB@0x1e ]
0 (00000000) invoke-virtual v0, Ljava/lang/String;->isEmpty()Z
1 (00000006) move-result v1
2 (00000008) if-eqz v1, +7 ← branch: if v1==0 go to BB@0x12
validate-BB@0x12 : [ validate-BB@0x1e ]
3 (00000012) const/4 v0, 0x0
4 (00000014) return v0 ← returns false (invalid)
validate-BB@0x1e :
5 (0000001e) ... (rest of real validation)
The [ ... ] after each block header lists the successor blocks — that is the branch table in text form.
Reading the CFG image:
Each box is a basic block. Arrows are:
- Solid → unconditional jump or fall-through
- Dashed / labelled true/false → conditional branch (
if-eqz,if-nez,if-gt, etc.)
To find the bypass point:
- Find the block that calls the check method (
invoke-virtual isRooted) - Follow the
move-result→ find theif-eqz/if-nezbranch - One branch leads to normal execution, the other to an exception or
return false - In the smali file, flip the branch condition or replace the block with a constant return
┌──────────────────────────────┐
│ invoke-virtual isRooted()Z │
│ move-result v0 │
│ if-eqz v0, +offset │ ← v0==0 means not rooted → normal
└──────┬─────────────┬─────────┘
│ (false/0) │ (true/not 0)
┌────▼──────┐ ┌───▼──────────┐
│ continue │ │ throw Sec.Ex │ ← patch: change if-eqz → if-nez to invert
└───────────┘ └──────────────┘
Obfuscation — Identifying and Working Around It⚓
Modern Android apps are usually processed by ProGuard or R8 before release. The goal is not real secrecy; it is to slow static analysis by renaming classes, methods, and fields and sometimes flattening control flow.
How to Recognise It⚓
Common signs in jadx or JD-GUI:
- Class names like
a,a0,b1,c$a - Packages that look like
x.y.zinstead of meaningful namespaces - Methods named
a(),b(),c()everywhere - Real third-party package names still intact:
okhttp3,retrofit2,androidx,kotlin - Meaningful strings and manifest component names still present
What usually survives obfuscation:
AndroidManifest.xmlcomponent names- URL paths, domains, JSON keys, SQL table names
- Third-party library APIs
- Resource names and string constants
- Native library names loaded by
System.loadLibrary
Practical Strategy⚓
When names are useless, pivot from names to behaviour:
- Start at the manifest — exported components, deep links, services, receivers
- Search for stable strings:
login,premium,token,auth,purchase,root,debug - Follow network clients (
okhttp3,retrofit2) and parsers (Gson,Moshi,JSONObject) - Cross-check suspicious methods in smali when jadx output becomes unclear
Useful searches:
# Search for meaningful strings instead of class names
grep -ri "login\|token\|premium\|root\|debug\|purchase" output/
# Search for common library anchors
grep -ri "okhttp3\|retrofit2\|RootBeer\|WebView" output/
If You Have a Mapping File⚓
If the client accidentally ships or leaks a ProGuard / R8 mapping file (mapping.txt), use it immediately. It restores real class and method names.
In practice, pentests rarely get the mapping file. Assume you need to work without it.
When to Drop to Smali⚓
Obfuscation often hurts the decompiler more than the bytecode. Switch from JADX to Smali when:
- JADX shows
/* JADX WARNING */or decompile errors - Control flow looks impossible or heavily flattened
- Multiple short methods appear to forward to one real check
- You need the exact branch that decides
truevsfalse
The names may still be ugly, but the bytecode is definitive.
Native Libraries and JNI⚓
Not all interesting logic is in DEX. Apps frequently move checks and secrets into native libraries under lib/ to make reversing harder.
What to Look For in lib/⚓
Common high-value targets:
- Root / emulator / debugger detection
- Crypto helpers and hardcoded keys
- Certificate pinning or custom TLS wrappers
- License checks and anti-tamper logic
- Game logic or protobuf parsers
Static recon:
# List libraries inside the APK
unzip -l app.apk | grep "\.so$"
# Extract and inspect one library
unzip app.apk "lib/arm64-v8a/libfoo.so" -d extracted/
# Quick strings pass
strings extracted/lib/arm64-v8a/libfoo.so | less
# Search for suspicious strings
strings extracted/lib/arm64-v8a/libfoo.so | grep -Ei "token|secret|apikey|root|magisk|frida|debug|https://|http://"
JNI Recon⚓
Search the decompiled Java for the bridge layer:
If you find:
then libsecurity.so is the next file to inspect in Ghidra, IDA, Binary Ninja, or radare2 / rizin.
Useful ELF Triage Commands⚓
# Architecture and file type
file libfoo.so
# Imported and exported symbols
readelf -Ws libfoo.so | less
# Dynamic dependencies
readelf -d libfoo.so
# Section headers
readelf -S libfoo.so
# Exported symbol names only
nm -D libfoo.so
If the binary is stripped, symbol names may be sparse. Fall back to strings, cross-references to JNI_OnLoad, and JNI registration tables.
Secrets Hidden in Native Code⚓
Developers often move keys from Java into native code assuming that is "secure enough". It is not. Search for:
- API keys and bearer tokens in
.rodata - Certificate pins and hashes
- AES keys, IVs, salts
- Hostnames for staging, admin, or internal APIs
Even when the key is built at runtime, the source fragments often still exist as strings or constant byte arrays.
Ghidra Workflow for Android .so Files⚓
- Import the
.sointo Ghidra - Confirm the correct processor (
AArch64,ARM,x86_64) - Find
JNI_OnLoadand cross-reference outward - Search for exported
Java_*symbols orRegisterNatives - Search the Strings window for
root,frida,debug,premium,token, URLs - Rename functions as you identify them to build your own map
This is usually enough to bridge static reversing into a precise Frida native hook.
Diffing Two APK Versions⚓
When a vendor fixes a bug quietly, the fastest way to understand the change is to diff the old and new APKs. This is especially useful for:
- Reproducing a patched vulnerability
- Identifying exactly where auth logic changed
- Finding newly added pinning, integrity, or root checks
- Spotting updated API endpoints or feature flags
Fast Triage⚓
# Fingerprint both APKs
androguard apkid old.apk
androguard apkid new.apk
# Compare manifest summaries
aapt dump badging old.apk > old.badging.txt
aapt dump badging new.apk > new.badging.txt
diff -u old.badging.txt new.badging.txt
Things to compare first:
versionCode/versionNametargetSdkVersion- Permissions added or removed
- New exported components
- New native libraries or removed ones
Decode Both and Diff the Trees⚓
apktool d old.apk -o old_decoded/
apktool d new.apk -o new_decoded/
diff -ru old_decoded/ new_decoded/
This quickly surfaces:
- Manifest changes
- New XML config like
network_security_config.xml - Smali changes in security-sensitive methods
- New assets, certs, or feature flags
Diff Decompiled Java⚓
Use this when you want a semantic view rather than raw smali.
Prioritise High-Value Diffs⚓
Start by searching only the code likely to matter:
If the diff is huge, focus on:
AndroidManifest.xmlres/xml/network_security_config.xml- Classes containing
login,auth,session,payment,premium lib/*.soadditions or changes
Diff Native Libraries⚓
# Compare library inventories
find old_decoded/lib -type f | sort > old_libs.txt
find new_decoded/lib -type f | sort > new_libs.txt
diff -u old_libs.txt new_libs.txt
# Compare strings for a specific library
strings old_decoded/lib/arm64-v8a/libfoo.so > old_libfoo.txt
strings new_decoded/lib/arm64-v8a/libfoo.so > new_libfoo.txt
diff -u old_libfoo.txt new_libfoo.txt
If a new security library appears, assume the patch likely moved there.
What to Look For⚓
Hardcoded Secrets⚓
# In decoded smali / resources
grep -ri "api_key\|apikey\|secret\|password\|token\|bearer\|authorization" decoded/
# In decompiled Java sources (after JD-GUI export or jadx CLI)
grep -ri "api_key\|secret\|password\|token" output/
# Or let apkleaks do it automatically
apkleaks -f app.apk
Endpoints and URLs⚓
grep -riE "https?://[a-zA-Z0-9./_-]+" decoded/smali/
grep -riE "https?://[a-zA-Z0-9./_-]+" output/
# Native libraries too
find extracted/ -name "*.so" -exec strings {} \; | grep -Ei "https?://[a-zA-Z0-9./_-]+"
Crypto Misuse⚓
Look for in jadx:
AES/ECB— ECB mode, deterministic, insecure- Hardcoded byte arrays near
SecretKeySpec— hardcoded AES key - Hardcoded byte arrays near
IvParameterSpec— hardcoded IV MD5orSHA1used as password hash — weakSecureRandomseeded with a constant — predictable
Logging Sensitive Data⚓
Check what is being logged — auth tokens, passwords, and PII in logcat are common findings.
SQLite — Raw Query Injection Surface⚓
Any string concatenation into these calls is SQL injection.
WebView JavaScript⚓
addJavascriptInterface with @JavascriptInterface on methods exposes Java to loaded web content — high risk if the WebView loads remote URLs.
Root / SSL Pin Detection⚓
# Root checks
grep -ri "isRooted\|RootBeer\|checkRoot\|/system/xbin/su\|/system/bin/su" output/
# Certificate pinning
grep -ri "CertificatePinner\|X509TrustManager\|checkServerTrusted\|OkHttp\|TrustKit" output/
Native Libraries⚓
# Strings and high-signal keywords in .so files
find extracted/ -name "*.so" -exec strings {} \; | grep -Ei "token|secret|apikey|root|magisk|frida|debug|premium|license"
# JNI exports
find extracted/ -name "*.so" -exec nm -D {} \; | grep "Java_"
If Java-side analysis looks clean but the app still behaves defensively at runtime, assume the interesting logic may be native.
Recommended Analysis Order⚓
For a new APK:
1. apkleaks -f app.apk — secrets and URLs in 10 seconds
2. MobSF upload — automated first-pass report
3. jadx-gui app.apk — manual read of manifest, key classes
4. APKHunt -p app.apk — OWASP-mapped findings for report
5. apktool d app.apk -o decoded/ — when you need to patch or read smali
6. dex2jar → CFR/JD-GUI — fallback for classes jadx fails on
7. Review obfuscation + native libs — identify `.so` targets and ugly code paths
8. androguard cg / decompile -f — call graph + per-method CFG images
9. Diff old vs new APKs — identify silent fixes and moved logic