apkscope
Health Pass
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 10 GitHub stars
Code Pass
- Code scan — Scanned 9 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Android reverse engineering for humans and AI agents: typed Java in milliseconds, xrefs, API and secret recon, APK diff, re-signing, a native viewer and an MCP server. One Rust executable, no JVM.
apkscope
Open any Android app and see what it really does.
What it collects, how it makes money from you, what it exposes. In seconds, as readable Java.
Findings · Speed · Install · Commands · MCP · Viewer · Limits
In 10 seconds: one executable, no Java. Drop in an APK and get a security overview, readable
Java, every endpoint and who calls it. Use it as a viewer, a CLI, or an MCP server your
AI agent drives. Opens TikTok 11x faster than JADX with 9x less RAM.
What it found
Each one needed the manifest, the resources and the decompiled code read together. A grep forhttp:// finds none of it. Click a finding for the proof: real output, trimmed to the lines that matter.
Block Blast! 10.9.3 (Play build), 75,938 classes, scanned in 3.1 s.
Who gets your data: AppLovin MAX, AdMob, Meta, Unity, ironSource, Pangle, Liftoff/Vungle, InMobi,
Moloco, Amazon APS, Digital Turbine/Fyber, PubMatic, Bigo. Trackers: AppsFlyer, Firebase, Facebook and
TikTok events, ThinkingData, the studio's own cn.hsdata. Permissions: advertising ID and all four
Privacy Sandbox ad APIs.
Two endpoints aren't from any SDK. infer is a model call: what are this player's ads worth?
$ apkscope search blockblast.xapk urls
q.mb("https://low-ecpm.afafb.com/infer/v1/low_ecpm_cut", appActivity, jSONObject, new c() {
return "https://ecpm.afafb.com/infer/v1/ecpm";
$ apkscope decompile blockblast.xapk me.f # the code calls it AlgorithmInterCutManager
m2.mg(jSONObject, "ActUserInfo", ClassE.ma());
m2.me(jSONObject, "AdHistInfo", jSONArray);
m2.mg(jSONObject, "UserContext", ClassE.mc(str2, appActivity, z, UUID.randomUUID().toString(), "INTER"));
m2.mg(jSONObject, "UserInfo", ClassE.md());
Those fill in deviceModel, ram, disk, cpu, carrier, country, ip_country, timeZone,install_time, cold_start_num and your past ads with their revenue. The answer sets your floor
price, the lowest bid an advertiser must beat to show you an ad:
$ apkscope decompile blockblast.xapk v2.d --method Y # AlgorithmBy1004, AppLovin MAX
double d3 = d * d2; // floor = predicted eCPM x "floor_factor" (remote, default 2.0)
this.g_c.mi(d3);
String.format(Locale.locale_US, "算法接口成功更新底价 - FloorPrice: %.2f, ... // "algorithm API updated the floor price"
Verdict: legal, and how ad-funded games work. Now you can see it.
2. Block Blast's server can switch the game into "audit mode" · found in code the packer hidBlock Blast hides its game classes behind a NetEase packer: org.cocos2dx.javascript.AppActivity isn't
in the APK. apkscope dump let the game unpack itself and pulled 15 DEX out of memory in 25 s, about
3,100 hidden classes. The scripts call Java through JsCallJava; its methods show what they ask for:
$ apkscope dump com.block.juggle out/ --attach
$ apkscope decompile out/dex/classes9.dex org.cocos2dx.javascript.pay.o --method w # SPayManager.serverControl
if (jSONObject.has("isStatus")) {
boolean z = k0.ma("1", jSONObject.getString("isStatus"));
SPStore.mk().y(z);
JsCallJava.setGameAuditMode(z, "auditMode"); // → window.IPAUtils.respHearingState(1)
- A server switch. The payment manager's server reply turns
auditModeon in the game's scripts,
and the game remembers it. Games use this to act differently while a store reviews them; what
Block Blast changes is in its encrypted scripts, so we don't claim more. - Your phone, on request:
callNativeGetLeftBattery(battery %),callNativeIsInstallOtherApp
(is app X installed?),getDeviceInfoByAdb(CPU speeds, RAM, storage, screen, model). - Revenue per round:
trackGameEndRevenuestores revenue data at the end of each game. - Bluetooth is benign:
BleBumpKitpairs two phones nearby, after asking permission.
Not shown: how it decides your next blocks. That's in the encrypted scripts (see limits).
3. Nextcloud lets any app on the phone read and edit your file indexThe file-database provider is exported, and its <path-permission> tags name a permission literally
called "false". The only real guard is in code, and it skips file/, dir/ and the root:
$ apkscope decompile nextcloud.apk com.owncloud.android.providers.FileContentProvider
private boolean isCallerNotAllowed(Uri uri) {
switch (i) {
case 4: case 5: case 6: case 7: case 8: // shares, capabilities, uploads, ...
str = this.mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
}
return false; // file (1), dir (2), root (3): anyone
}
public Cursor query(Uri uri, ...) {
if (i != 1 && i != 2 && i != 3 && isCallerNotAllowed(uri)) {
(Case labels folded, comments added.) insert, update and delete use the same check. The table
holds path, path_decrypted, file_owner, sharees, share_by_link, metadata_gps...
Verdict: any installed app can read your file names, folders and shares, decrypted names of
end-to-end-encrypted files included, and change or delete rows. GitHub Security Lab noted it in 2021;
the SQL injection from that report was fixed, the open access is still there in 35.0.1. Read from
code, not run on a device.
$ apkscope resource antennapod.apk res/xml/network_security_config.xml
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="user" />
<certificates src="system" />
$ apkscope decompile antennapod.apk de.danoeh.antennapod.net.ssl.CompositeX509TrustManager --method checkServerTrusted
X509TrustManager x509TrustManager = (X509TrustManager) iterator.next();
try {
x509TrustManager.checkServerTrusted(x509CertificateArr, str);
Verdict: since Android 7 apps ignore user certificates; this one opts back in, so a managed
device or a "VPN" app that installs one can read its HTTPS. The custom TrustManager tries each real
one and throws if none accepts: a deliberate choice, not the trust-everything bug.
scan lists Jetpack Compose's PreviewActivity as exported. It runs any class named in the intent.
$ apkscope decompile thunderbird.apk androidx.compose.ui.tooling.PreviewActivity --method onCreate
int i = getApplicationInfo().flags & 2;
if (i == 0) {
Log.md(str, "Application is not debuggable. Compose Preview not allowed.");
finish();
Verdict: flags & 2 is FLAG_DEBUGGABLE, and release builds aren't. Every scanner flags this;
only the code says it's safe, until someone ships a debuggable build.
$ apkscope decompile keepassdx.apk com.kunzisoft.encrypt.aes.AESTransformer
cipher = Cipher.getInstance("AES/ECB/NoPadding");
key = (Key) new SecretKeySpec(bArr, "AES");
cipher.init(1, key);
while (UnsignedKt.ulongCompare(j2, j) < 0) {
Verdict: the KeePass AES-KDF encrypts one block with itself rounds times to slow down password
guessing. ECB on one block is the spec. Knowing which flags to drop is half the job.
Faster than JADX
| 11x faster than JADX to open TikTok, 9x less RAM | 12.4 s / 997 MB vs 2 min 18 s / 9.4 GB |
| 2.7x faster than rust_ASC per agent call | 70 ms vs 191 ms median, over MCP |
| Typed Java, not pseudocode | a reviewer, or an agent, can trust it |
| One tool: decompiler, xrefs, recon, diff, Frida, unpacking, re-signing, GUI, MCP | instead of five |
Every number comes from a script in bench/. All results →
For security researchers, mobile pentesters, privacy researchers, developers checking what a
library really does, and anyone who hands APKs to an AI agent.
Get started
1. Get it: apkscope.exe from Releases, or build:
cargo build --release # viewer + CLI + MCP server
cargo build --release --no-default-features # CLI + MCP only (Linux, macOS, servers)
2. Give it to your agent:
claude mcp add apkscope -- /path/to/apkscope mcp
Any MCP client works: { "mcpServers": { "apkscope": { "command": "/path/to/apkscope", "args": ["mcp"] } } }
3. Or use it directly: apkscope gui app.apk, or any command below.
Commands
# recon
apkscope scan app.apk # flags, exported components, weak crypto, TLS, keys, URLs
apkscope info app.apk # permissions, components, deep links, signature
apkscope search app.apk urls # every endpoint (also: secrets, http, code, res)
apkscope diff old.apk new.apk --strings # what changed in this update
# follow the code
apkscope refs app.apk string X-Goog-Api-Key --java # who uses it, with the Java line (53 ms cold)
apkscope decompile app.apk com.example.Api --method login # one method, as Java
apkscope callers app.apk com.example.Api login # every caller (callgraph: the tree)
apkscope access app.apk com.example.Session token # who reads / writes a field
apkscope decrypt app.apk # run string decryptors on their constant args
# go further
apkscope dump app.apk out/ --attach # packed app: save the DEX it unpacked in memory
apkscope il2cpp game.xapk --uses "https://" # Unity games: which C# method uses a string
apkscope frida app.apk com.example.Api login # ready-to-run hook (args, return, throws)
apkscope rename app.apk "com.a.b#c()" login # names and comments, kept across runs
apkscope export app.apk out/ # Gradle project for Android Studio
apkscope build app.apk out.apk --string "app_name=My App" # edit, rebuild, sign (v2 + v3)
--json, --limit N, --offset N work everywhere. Takes .apk, .apks, .xapk, .dex.apkscope --help lists everything.
decryptruns the app's own decryptor in a sandboxed Dalvik interpreter (no I/O, no reflection,
step-limited) and shows the result inline:a.b("x#9!") /* = "https://api.example.com" */.dumplets the app unpack itself under Frida, then pulls every DEX out of its memory, skipping
the ones already on disk. It also hooks nativeevalStringto save scripts after the engine
decrypted them. Needs a rooted device with frida-server.
Java you can actually read
| rust_ASC | apkscope |
|---|---|
|
|
Loops, switch, try/catch/finally, lambdas, enums, typed names and deobfuscation
(a.b → pkg_a.RunnableB). Faster than rust_ASC per class on 9 of 14 apps. Uncertain methods get a/* WARNING */ header; failures fall back to Smali, never silently.
Built for AI agents
| MCP tool | What the agent gets |
|---|---|
find_refs |
who uses a string, type, method or field, or implements an interface; with Java lines |
decompile |
Java or Smali of several classes, or one method |
search |
code, strings, usages, classes, resources, URLs, HTTP calls, secrets |
apk_info / get_manifest / diff_apks |
permissions, components, deep links, risky flags, what changed |
list_classes / list_methods / list_strings |
with prefix, filter and app-only |
get_resource / export_project / verify_signature |
resources, Gradle export, signatures |
frida_start / frida_hook / frida_events / frida_script |
live Frida: hook by name, read calls, args, returns |
Replies page with limit / offset and cap at 60k characters; app_only hides androidx, Play
services and ad SDKs. 39 agent calls on TikTok: 3.94 s vs rust_ASC's 6.54 s.
Ask "Can this app's HTTPS traffic be intercepted?" and the agent finds finding 4 on its own, in
under half a second of tool time.
The viewer

Double-click apkscope.exe and drop in an APK. Security overview first, then your app's code apart
from the libraries. Click a name to mark it, Ctrl+click to jump to it, right-click for
callers, call graph, field access, Frida hook, Smali, rename. Results jump to the exact line.
Edit → Build & sign with undo.
Honest limits
- Some complex methods still use
gotolabels (markedWARNING). - Cold one-shot queries: rust_ASC is a few ms quicker on many apps, 1.8x quicker listing TikTok's
436k classes. In agent sessions apkscope is faster. - Huge apps take about 1 GB in the viewer; the first full-code search takes a minute, then it's cached.
- The viewer is tested on Windows; CLI and MCP pass CI on Linux and macOS.
- Scans are heuristics and findings are leads, not verdicts (see finding 6).
decryptonly runs decryptors that compute from constants.dumpneeds a rooted device. Some protectors crash when Frida spawns the app: start it normally
and use--attach. Script capture needs an engine that exportsevalString, and isn't verified on
a real game yet (an x86 emulator can't hook ARM-only engines).il2cppreads arm64 builds and was checked on metadata v39 (Unity 6); older versions may misparse.- Callers, call graphs and Frida hooks see direct calls only, not reflection, JNI or dynamic code.
Written from scratch
DEX parser, decompiler, deobfuscator, resource decoder, search index, APK signer, MCP server and
viewer: all Rust, from zero. Not a JADX fork, not a wrapper.
Wrong output? Open an issue with the class name and what JADX shows. Apache 2.0;
"apkscope" and its logo are trademarks of Ahmad, see NOTICE.src/data/android_public.txt comes from AOSP (Apache 2.0).
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found