37 Commits

Author SHA1 Message Date
Simone Avogadro 0c7cf89830 docs: add third-party software notices
List the tools the plugin drives (jadx, Vineflower, Fernflower, dex2jar,
Apktool, adb, Java) with their licenses and upstream links, and state that
none of them is bundled or redistributed. Link the notices from README and
PRIVACY.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 19:43:27 +02:00
Simone Avogadro 990aed0614 docs: add privacy policy and homepage/documentation/privacy URLs
PRIVACY.md documents that the plugin collects nothing, processes files
locally, reads no credentials, and only makes network requests to download
dependencies via install-dep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 19:41:55 +02:00
Simone Avogadro a06ab17efc chore: add support and terms URLs to plugin.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 19:40:30 +02:00
Simone Avogadro 9ac132bfd9 chore: address marketplace policy holds
- /decompile: pre-approve only check-deps.sh and decompile.sh instead of a
  scripts/* wildcard; install-dep.sh now asks the user each time
- find-api-calls.ps1: rename -Auth switch to -AuthPatterns (matches the .sh
  rename; -Auth still works via PowerShell parameter-prefix matching)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 19:14:44 +02:00
Simone Avogadro 78bd5ca926 fix: case-insensitive sections in find-api-calls.sh always returned nothing
run_grep took its first argument as the pattern, so calls like
`run_grep -i '(api[_-]?key|...)'` passed "-i" as the pattern. grep then
parsed it as an option, used the source dir as the pattern and errored;
2>/dev/null || true hid the failure. The Auth, Request Signing, Hardcoded
Secrets and Base URLs sections were always empty.

Accept an optional leading -i and pass the pattern with -e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 19:10:39 +02:00
Simone Avogadro 3e04b45cb1 chore: prepare plugin for marketplace submission
- Scope allowed-tools in /decompile to the plugin's own scripts and drop Write/Edit
- Rename internal SEARCH_AUTH flag and add reviewer notes to find-api-calls scripts
- Add plugin icon

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DcUE1A6iyBfWDmpdR5JzNF
2026-10-11 12:20:06 +02:00
WeTool 04fe39c7dc fix: use portable grep -oE for Java version detection (#28)
BSD grep on macOS does not support the GNU-only -P flag, causing check-deps.sh to fail with 'invalid option -- P' for OpenJDK versions that report a plain major version such as 25. Use grep -oE '[0-9]+' instead.
Thanks @WeToolX
2026-09-08 08:55:03 +02:00
Vasu Garg 9a39fa7fcc fix: add missing name property to SKILL.md frontmatter (#23) 2026-09-08 08:40:49 +02:00
Simone Avogadro e8dde9d058 chore: bump plugin version to 1.5.0 2026-06-10 11:49:02 +02:00
Simone Avogadro f68d9ce3be feat: post-filter --urls to drop dictionary noise while keeping IPs and apex hosts
The hardening patch widened STRICT_URL to recover IPv4 literals, apex
2-label domains and internal hosts that the PR's strict-only regex
discarded as collateral while killing Kotlin-stdlib dictionary noise.
Widening alone reopened a narrow noise class: 'word.word' fragments such
as "www.this" / "this.introduction" pass as apex domains.

Keep extraction permissive and add a small awk pass that decides per host:
- IPv4 literal: always keep (dict fragments are words, never dotted-quads)
- >=3 labels: always keep (any TLD; same tolerance as the original regex)
- any host with a :port or /path: always keep (structured = high signal)
- bare 2-label apex: keep only when the TLD is a real one, matched as a
  whole field (so "introduction" != "in" — the prefix-match bug a single
  mega-regex would have)

Trade-off documented inline: a first-party host referenced bare with an
uncommon TLD (e.g. https://foo.store with no path) is dropped; a path or
port keeps it. awk is POSIX (sub/split/~/print) — more portable than the
bash>=4 'declare -A' already used in the summary header.

Verified: dictionary noise dropped; IPs, apex, internal and subdomain
hosts kept; --all on a zero-match tree still exits 0; host list and
full-URL list stay consistent (no orphan hosts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:06:30 +02:00
Simone Avogadro ed97b8508b docs: document PR #16 features in README (Kotlin name recovery, fingerprint, Ktor/Apollo/Koin)
The PR #16 additions were wired into SKILL.md and references/ but the
human-facing README was never updated. Surface them, with prominent
emphasis on first-class Kotlin support:

- Top blurb: callout for R8 Kotlin name recovery + Ktor/Apollo/Koin
- "What it does" table: Phase 0 fingerprint, Kotlin name recovery,
  modern Kotlin/KMP stacks (Ktor, Apollo, Koin, HMAC)
- Usage: fingerprint.sh example, --ktor/--apollo/--paths flags, and a
  dedicated "Kotlin name recovery (R8 deobfuscation)" subsection
- Repository Structure: add the three new scripts + two new references
- Acknowledgments: credit @tajchert (#16)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:33:53 +02:00
Simone Avogadro 2047f99d01 fix: harden find-api-calls.sh and recover-kotlin-names.sh from PR #16 review
- find-api-calls.sh: add missing '|| true' on the --paths inventory and
  --urls extraction pipelines; with set -euo pipefail a zero-match grep
  aborted the whole script (including the default --all run) with exit 1.
- find-api-calls.sh: widen STRICT_URL to also match IPv4 literals, apex
  2-label domains and bare single-label hosts followed by :port or /path
  (localhost, internal backends) while still rejecting dictionary-fragment
  noise from the Kotlin stdlib.
- recover-kotlin-names.sh: sanitize the by_package/ filename with
  os.path.basename; a crafted absolute path in untrusted @DebugMetadata
  package names could otherwise escape the output directory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:22:16 +02:00
Michał Tajchert a2a0a97f23 docs: call out BuildConfig.java and adopt a two-tier endpoint doc template
Two small changes that together meaningfully reduce wasted effort:

1. Phase 3 now explicitly tells the agent to read every BuildConfig.java.
   These files are almost never obfuscated and routinely contain the
   single highest-signal constants in the APK — base URLs, flavor names,
   build types, third-party API keys, feature flags. They were not
   mentioned in the previous workflow despite being the cheapest possible
   high-value target. One grep, finds them all.

2. The Phase 5 documentation template was a single per-endpoint block
   asking for path params, query params, request body, response type,
   and call chain. On apps with 100+ endpoints that easily becomes hours
   of work for output the consumer will not read.

   Replace it with two tiers:

     * Tier 1 — flat table covering every endpoint (host, method, path,
       auth required, source file). Always produced. Takes ~5 minutes
       from the --paths output.

     * Tier 2 — the existing detailed block, but explicitly reserved for
       high-value endpoints: the entire auth flow, payment/checkout, and
       anything the user specifically asked about. Default cap of ~10
       Tier-2 entries unless asked for more.

   This matches the natural shape of how analysts actually use this work
   (one inventory table to know the surface area, plus a deep dive on
   auth and a couple of flows) and prevents over-investment in detail
   for endpoints nobody will read about.
2026-04-29 01:40:50 +02:00
Michał Tajchert 627889a4c6 feat: add summary header to find-api-calls.sh
Without an overview the script dumps thousands of file:line: matches
across many sections, leaving the reader to figure out which framework
even applies. A short summary at the top makes the rest of the output
actionable.

The summary counts hits per framework / DI / auth-signal category in a
single grep pass over the source tree (8 separate greps would have
roughly octupled the runtime on a large decompile). Output is a 3-line
table:

  HTTP framework:   Retrofit=N OkHttp=N Ktor=N Apollo=N Volley=N
  DI framework:     Hilt/Dagger=N Koin=N
  Auth signals:     Bearer=N HMAC/Sign=N

A reader can immediately see which framework the app actually uses,
whether auth is bearer-token or signed, and whether to spend time on a
section or skip it. The summary is suppressed when a single section flag
(--retrofit, --ktor, --paths, ...) is given, so the existing single-section
workflows are unchanged.

A reminder of the available section flags is printed below the counts
so the agent does not have to consult --help.
2026-04-29 01:39:55 +02:00
Michał Tajchert ec2b14c171 feat: detect Koin DI and HMAC request-signing schemes
Two gaps in the previous coverage:

1. Koin was not mentioned anywhere — Hilt/Dagger got a full section in
   call-flow-analysis.md but Koin (the dominant DI in KMP and a large
   share of Kotlin-only Android apps) had zero patterns. Add a Koin
   subsection with the runtime-DSL patterns (module {}, single<>,
   factory<>, viewModel<>, by inject, by viewModel) plus the practical
   trick for resolving an interface to its impl after R8 obfuscation:
   intersect "files that import org.koin.core.module" with "files that
   reference the interface name".

2. The --auth mode caught Bearer / API-key / OAuth header patterns but
   missed HMAC and other request-signing schemes. A hardcoded HMAC
   secret embedded in an APK is a security finding worth surfacing —
   the same kind of authority the user gets is the same authority a
   decompiler grants to anyone. Add patterns for:

     * JCA primitives:  HmacSHA{1,256,512}, Mac.getInstance(...),
       SecretKeySpec(...), Signature.getInstance(...)
     * Header conventions: X-Signature, X-Hmac, X-Amz-Signature,
       X-Client-Authorization, AWS4-HMAC, signRequest(), signaturev2/3
     * Likely secret-bearing identifiers: app_secret, client_secret,
       signing_key, hmac_secret, consumer_secret, private_key
     * Ktor BearerTokens / loadTokens / refreshTokens DSL

These survive R8 because the JCA and Ktor APIs are public and not
shrunk. On a real-world app with a homegrown HMAC scheme they pinpoint
the signing class and its hardcoded key directly.
2026-04-29 01:26:40 +02:00
Michał Tajchert 2e6fc63453 feat: bucketed --urls output with strict regex and third-party denylist
The previous --urls mode was a plain grep for "https?://..." which on a
real APK produced thousands of lines, half of them junk strings extracted
from Kotlin stdlib's compression dictionary ("http://An Introduction to..."
fragments) and the other half SDK URLs (Google, Firebase, AppsFlyer,
Datadog, Sentry, ...) that the analyst is not looking for. The signal —
first-party backend hosts — was buried.

Two changes:

1. Strict URL regex: hostname must have at least one dot and end in a 2+
   letter TLD, with no whitespace / angle brackets / non-printables in the
   path. This eliminates the dictionary-fragment noise.

2. Bucket the surviving URLs into "likely first-party" vs "third-party"
   using references/third_party_hosts.txt — a curated denylist of
   ~80 patterns covering Google/Firebase/Apple/Microsoft/Adobe, attribution
   and observability vendors (AppsFlyer, Datadog, Sentry, Bugsnag, ...),
   payments (Stripe, PayU, Adyen, ...), support/chat SDKs, CAs, and
   standards namespaces (w3.org, etc.).

The new output starts with a frequency-sorted list of likely first-party
hosts — which is the artifact every reverse-engineer wants on the first
page — followed by the collapsed third-party list and the full URL set
for first-party hosts only.

The denylist is a sidecar text file (one regex per line) so users can
extend or override it without editing the script.
2026-04-29 01:23:56 +02:00
Michał Tajchert dbb19f0a22 feat: add --paths mode for obfuscation-resistant endpoint extraction
When R8 inlines call sites — client.get("/api/users") becomes
a.b(c, "/api/users") — the existing framework-specific patterns find
nothing, but the path string literal itself is never obfuscated. This
single observation is the most useful endpoint-extraction technique on
heavily shrunk apps; the existing --urls mode only catches full
"https://..." URLs, missing every relative path.

Add a --paths mode that greps for quoted strings matching either:

  * an absolute path with at least two slash-separated segments, or
  * a relative path beginning with a known API root keyword
    (api, v1/v2/v3, graphql, users, auth, profile, cart, order, ...)

with a {0,8}-segment cap and a small denylist for MIME types and system
paths (image/png, /proc/, /sys/, /dev/, etc.) which would otherwise pollute
results.

The output is a deduplicated inventory followed by the full call-site
list. On a real-world Kotlin/Ktor app this produced ~240 distinct API
paths in one shot — paths that the Retrofit/OkHttp/Ktor patterns missed
entirely because every call was inlined. This is the recommended first
extraction step on any obfuscated app.

Document the regex and rationale in references/api-extraction-patterns.md.
2026-04-29 01:21:25 +02:00
Michał Tajchert 371d3d4bed feat: add Ktor and Apollo (GraphQL) API-extraction patterns
The previous find-api-calls.sh covered only Retrofit, OkHttp, and Volley.
Modern Kotlin and KMP apps increasingly ship Ktor as their HTTP client
(used by ~25 % of new Kotlin apps as of 2025), and many product apps use
Apollo Kotlin for GraphQL. Both produced zero hits with the old patterns.

Add two new modes to find-api-calls.sh:

  --ktor    Ktor client calls (client.get/post/...), HttpRequestBuilder,
            defaultRequest blocks, and the Auth bearer DSL
            (BearerTokens / loadTokens / refreshTokens)

  --apollo  ApolloClient, .serverUrl(), HttpNetworkTransport, and
            .query/.mutation/.subscription operation calls

Document both in references/api-extraction-patterns.md with example
post-decompile snippets and a note on R8 obfuscation: Ktor call sites
get inlined to obfuscated method calls, but the path string literals
and Ktor library symbols (BearerTokens, URLProtocol, etc.) survive,
so library-internal patterns still work as anchors.
2026-04-29 01:16:43 +02:00
Michał Tajchert 5b63fcb418 feat: recover original Kotlin class names from R8-stripped binaries
R8 obfuscates JVM symbols but cannot strip the Kotlin metadata strings —
the Kotlin runtime needs them at runtime for reflection, coroutines, and
data-class features. The original FQNs leak through:

  * @DebugMetadata(c = "<real.fqn>")  emitted for every coroutine
    SuspendLambda (~ every suspend function in modern apps)
  * @Metadata(d2 = {"L<real/fqn>;"})  on every Kotlin class

Add scripts/recover-kotlin-names.sh that walks decompiled sources, mines
both annotations, and writes an obf -> real mapping (TSV + JSON + per-real-
package index). On a real-world Kotlin app this recovers ~100 % of
*Repository / *ViewModel / *UseCase / *Impl classes — exactly the classes
worth reading.

Add scripts/lookup-name.sh as a CLI over the mapping with four modes:
search by real-name substring, resolve obf -> real, list a real package,
and an annotated `--grep` that suffixes every hit with the owning real
class. This is a strict upgrade over plain grep against decompiled sources.

Replace the misleading 'use --deobf' tip in call-flow-analysis.md with a
pointer to this technique. --deobf only renames symbols with synthetic
placeholders; metadata recovery returns actual developer-written names.

Document the technique, expected recovery rates, and limitations in
references/kotlin-name-recovery.md, and reference it from SKILL.md as
optional Phase 3.5 (only when Phase 0 reports an obfuscated Kotlin app).
2026-04-29 01:12:31 +02:00
Michał Tajchert 213818fc27 feat: add Phase 0 fingerprint script for fast pre-decompile triage
Decompiling Java is wasted effort for Flutter, React Native, Cordova/
Capacitor, and Xamarin apps — their code lives in libapp.so, the JS bundle,
assets/www/, or .NET DLLs respectively. The previous workflow jumped
straight to Phase 1 (install deps) and Phase 2 (decompile), so the agent
had no way to know which path to take until after a full jadx run.

The new fingerprint.sh inspects an APK/XAPK in seconds and reports:

* Detected mobile framework with the file marker that triggered it
* HTTP stack hints (Retrofit, OkHttp, Ktor, Apollo, Volley) via DEX
  string scanning — survives R8 obfuscation
* DI and serialization libraries
* Obfuscation level estimate
* Notable third-party SDKs found in assets/ and DEX
* Consolidated native libraries across base + split APKs (split bundles
  often place .so files only in config.<abi>.apk)
* A framework-specific recommendation for the next step

SKILL.md documents this as Phase 0 and explicitly tells the agent to
stop and switch tooling if the app is non-native.

PowerShell port (fingerprint.ps1) intentionally not included — happy to
add if needed; behavior is straightforward to mirror.
2026-04-29 01:07:40 +02:00
Simone Avogadro 6a31ed3fa2 chore: bump plugin version to 1.1.0
Reflects features integrated since 1.0.0:
- PowerShell support for Windows (#8)
- dex2jar fork migration to ThexXTURBOXx (#12)
- Decompile partial-success and Fernflower timeout handling (#10)
- Chinese localization (#4)
- README badges, TOC, Acknowledgments

Updates:
- .claude-plugin/marketplace.json (metadata.version + plugins[0].version)
- plugins/android-reverse-engineering/.claude-plugin/plugin.json (version)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1.1.0
2026-04-27 22:58:48 +02:00
YIPEI WEI cedc1a3368 docs: improve README with badges, TOC, and features table 2026-04-27 10:53:49 +02:00
Simone Avogadro f3fb1e9484 chore(install-dep.ps1): align dex2jar to ThexXTURBOXx fork
Mirrors the bash counterpart updated in #12. Switches the GitHub repo,
the fallback tag (v2.4 -> 2.4.35), and the URL pattern order so that the
canonical ThexXTURBOXx naming (dex-tools-2.4.35.zip, no leading 'v') is
tried first, with the pre-2.4.30 naming as fallback.

Closes drift items 9-11 from post-merge-followup-2026-04. Functional bugs
in decompile.ps1 and PR #10 drift items remain pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 10:26:42 +02:00
Simone Avogadro 87388d06b3 docs: add PowerShell support disclaimer and Acknowledgments section
Add a top-level note flagging PS1 scripts as experimental and pointing
issues to this repo. Add an Acknowledgments section crediting the four
external contributors of the recent PR wave (#4, #8, #10, #12).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 10:23:31 +02:00
Phil Nachreiner f8d394a69e Feature/windows powershell support (#8)
* feat: add Windows/PowerShell support

Add PowerShell equivalents of all bash scripts for Windows users:
- check-deps.ps1: Dependency verification with PATH refresh
- install-dep.ps1: Install via winget/scoop/choco or direct download
- decompile.ps1: APK/XAPK/JAR/AAR decompilation with split APK detection
- find-api-calls.ps1: API endpoint extraction (Retrofit, URLs, auth)

Update SKILL.md with Windows-specific instructions and notes for
each workflow phase.

PowerShell scripts support the same options as their bash counterparts
and automatically refresh PATH after installations.

* fix: check-deps.ps1 jadx fallback path version check, decompile.md lint fixes
2026-04-27 10:14:59 +02:00
Roshan Warrier 5a810d94b3 fix: use maintained dex2jar fork (#12)
Co-authored-by: txhno <198242577+txhno@users.noreply.github.com>
2026-04-27 09:59:14 +02:00
muqiao215 c25dfd78d2 fix(decompile): handle partial-success flows (#10)
Allow jadx-only mode to succeed when jadx exits non-zero after writing usable Java output.

Keep both-mode resilient when jadx partially succeeds, normalize Fernflower APK output handling, and make timeout/no-output failures explicit for Vineflower runs.

Co-authored-by: root <root@dbyqhnca.colocrossing.cloud>
2026-04-27 09:59:05 +02:00
kevinaimonster 5bc7cd53e6 feat: add Chinese localization / 添加中文支持 (#4)
Add Chinese trigger words to SKILL.md description and trigger field
for better discoverability by Chinese-speaking users.
2026-04-27 09:58:56 +02:00
Simone Avogadro ddeb9bc332 ADDED: .gitattributes for better WSL/Windows cooperation v1.0.1 2026-03-02 11:36:38 +01:00
Simone Avogadro ec0f6700f8 Improve plugin discoverability and metadata completeness
- Add keywords, skills and commands paths to plugin.json
- Add argument-hint to decompile command for better UX
- Add description to SKILL.md frontmatter for skill auto-matching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:30:57 +01:00
Simone Avogadro 3276266788 Improve marketplace metadata compatibility with official Anthropic schema
Add $schema and top-level description fields to align with the dominant
pattern used in anthropics/claude-code and anthropics/claude-plugins-official.
Existing metadata wrapper preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:30:03 +01:00
Simone Avogadro bcbe078c52 Clarified this is a Skill 2026-02-02 21:34:07 +01:00
Simone Avogadro 3a87948331 Fix GitHub username in all repository URLs and LICENSE
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
v1.0
2026-02-02 21:06:15 +01:00
Simone Avogadro b092b3aeea Add legal disclaimer to README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 20:25:08 +01:00
Simone Avogadro d7fefe54f2 Update README to highlight API extraction, fix author name in metadata
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 20:19:18 +01:00
Simone Avogadro fc9a722359 FIXED: relative paths 2026-02-02 16:36:48 +01:00
Simone Avogadro 5ec451e352 commit iniziale 2026-02-02 16:18:11 +01:00