Self-hosted service
rednaga/APKiD avatar
rednaga/APKiD

APKiD: Fingerprinting Android Build Tools, Packers and Protectors with YARA Rules

Android Application Identifier for Packers, Protectors, Obfuscators and Oddities - PEiD for Android

2,574 stars344 forksYARANOASSERTION

At a glance

What is it?
APKiD scans APK, DEX and nested zip entries with compiled YARA rules and reports which compiler, packer, obfuscator or shielding product produced them. It is a triage tool for malware analysts and reverse engineers, not a verdict engine.
Who is it for?
Adopt APKiD if you triage Android samples at volume and need a one-line answer about which toolchain or protector touched a file before you open it in a disassembler. Do not adopt it if you need a malicious/benign verdict, a confidence score, or a rule set you can maintain without writing YARA.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly YARA, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What APKiD answers that a disassembler does not

An APK arriving in a malware queue carries no metadata about how it was built. The DEX inside may be stock output from dx or d8, or it may have been rewritten by a commercial protector, wrapped by a packer that decrypts its payload at runtime, or instrumented by a RASP SDK that adds checks for root, emulators and debuggers. Opening each sample in a disassembler to find out is slow, and the answer is often visible in a few byte patterns rather than in the code logic. APKiD exists to answer that first question cheaply. The README describes it as giving "information about how an APK was made" and positions it as PEiD for Android, a reference to the classic Windows executable identifier. The intended audience is stated indirectly through the linked talks: Android compiler fingerprinting, detecting pirated and malicious apps, identifying AppShielding products, and identifying mobile RASP SDKs. That is a malware research and incident response audience, plus anyone doing app store integrity work or competitive teardown of protected apps.

YARA rules compiled into the package, applied to zip entries

The detection engine is YARA. The repository's primary language is YARA, and the README's hacking section instructs contributors to run prep-release.py after changing any rule, which recompiles them. The compiled rules ship inside the installed package, so a pip install gives you a working scanner without a separate rule download step. Scanning is not limited to the outer APK. The CLI exposes --scan-depth for "how deep to go when scanning nested zips" and --entry-max-scan-size for the maximum zip entry size to scan in bytes, with 0 meaning no limit. Those two flags describe the actual data flow: APKiD walks the zip container, extracts candidate entries, and applies rules to each one, which is why a single APK can produce several labeled results. The --typing flag decides which files get scanned at all, with three modes: magic, filename, or none. That choice matters because filename-based typing will miss entries whose extensions were stripped or falsified, while magic-based typing costs a header read per entry. A per-scan timeout is available through -t/--timeout, described as the Yara scan timeout in seconds, which is the practical guard against a crafted sample that makes matching expensive. Results are printed per file with an indented label line, as the Docker example shows for example.apk!classes.dex with the label compiler: dx.

Installing and running APKiD

The shortest path is the published package: pip install apkid. Docker is supported and the README gives the full sequence: git clone https://github.com/rednaga/APKiD, cd APKiD/, docker build . -t rednaga:apkid, then docker/apkid.sh ~/reverse/targets/android/example/example.apk. The sample output in the README shows the banner line, then the entry name, then the label. For rule development, the workflow is git clone, cd APKiD, python prep-release.py, pip install -e .[dev,test], with a --user variant suggested when permission errors occur outside a virtual environment. Windows users get a separate note: uninstall previous Yara and yara-python-dex, install yara-python==3.11.0 with wheel, build yara-python-dex from the MobSF fork with pip wheel --wheel-dir=yara-python-dex git+https://github.com/MobSF/yara-python-dex.git, then install it with pip install --no-index --find-links=yara-python-dex yara-python-dex. That pinning to 3.11.0 is a real constraint, not a suggestion. The CLI accepts apk, dex, or directory as positional input, -r to recurse into subdirectories, -j for JSON output, and -o DIR to write individual results, which the help text notes implies --json. Package maintainers are told to bump the version in apkid/__init__.py and to consult .travis.yml for how the dev and test environments are set up.

Where the fingerprinting stops being useful

APKiD reports labels, not judgements. Nothing in the README claims a confidence score, a probability, or a maliciousness verdict, and the output format shown is a flat label line. A packer label means the patterns matched, not that the sample is hostile; commercial apps ship protectors for licence enforcement and code confidentiality, and the talks listed in the README are about identifying shielding products as a category, which includes legitimate vendors. The detection surface is also inherently reactive. New protectors and new versions of existing ones require new or updated rules, and the contribution process described in the README is manual: open an issue describing what you think the sample is, supply a file hash (MD5, SHA1 or SHA256), and for a pull request include a hash so the rule can be checked. That means coverage of a protector released last month is unlikely to exist until someone submits a sample. Two operational limits are visible in the flags themselves. --entry-max-scan-size with a finite value will skip large entries, and the default is not stated in the supplied material. --scan-depth bounds how far into nested zips the scanner goes, so a payload buried deeper than the configured depth is never examined. Neither default is documented in the README, so the effective coverage of a run depends on values you have to check yourself.

APKiD against a general purpose AV or a full unpacking framework

The closest comparison in the README's own framing is PEiD, the Windows tool that identified packers and compilers from signatures. The difference in approach is the rule language and the container handling. PEiD matched fixed byte signatures against a PE file; APKiD matches YARA rules against entries inside zip containers, which lets one rule target a DEX header pattern, another target a native library string, and another target an asset file, all within the same scan. Against a mobile antivirus engine, the difference is intent rather than technique. An AV engine returns a family name and a malicious classification and is tuned for end users; APKiD returns toolchain and protector labels and is tuned for an analyst who will do the unpacking themselves. Against a full unpacking or instrumentation framework, APKiD does not execute anything. It is static, which is why it is fast enough to run over a directory, and also why it cannot see a payload that only materializes in memory after a decryptor runs. For that class of sample, APKiD tells you a packer is present and leaves the rest to you. The README's contribution guidance is also broader than packers and compilers: it invites rules for anti-disassembler, anti-VM and other anti-* tricks, which pushes the tool toward a general Android oddity detector rather than a pure build-tool identifier.

Dual licensing and what it costs to keep rules current

The licence situation is the item most likely to block adoption inside a company. The README states the tool is available under a dual licence: a commercial one for closed source projects and a GPL licence for open source software, with the terms in LICENSE.COMMERCIAL and LICENSE.GPL. The repository metadata reports the licence as NOASSERTION, which is a signal that an automated licence classifier could not resolve the file, so anyone running licence scanning tooling should expect a flag and read both files directly. This is a description of what the project states, not legal advice; the choice between the two licences depends on how you distribute or host the tool. Maintenance cost has two parts. The software side is light: pip install apkid, or a Docker image you rebuild, and the release cadence visible in the repository is roughly annual for major versions, with v3.1.0 in April 2026, v3.0.0 in April 2025, and v2.1.5 in July 2023. The rule side is where the ongoing work sits. Every new protector needs a rule, rules must be recompiled with prep-release.py before they take effect, and the README asks contributors to attach a file hash so a rule can be validated. If you run APKiD in a pipeline and never touch the rules, your coverage is frozen at the version you installed, and a protector that changed its byte patterns stops matching.

Who should run this and what to check first

The tool fits a triage queue. If samples arrive faster than you can open them, a one-line label for compiler, packer or shielding product tells you whether to reach for a standard DEX decompiler or start with an unpacking plan. It also fits store integrity checks and research that needs to group a corpus by build toolchain, since the JSON output (-j) and per-file output directory (-o DIR) make results scriptable. It does not fit anyone who needs a malicious or benign answer, a family attribution, or a score they can threshold on; for those, an AV engine or a dynamic sandbox is the right layer, and APKiD's output becomes an input to that decision rather than the decision. It also does not fit teams unwilling to write YARA, because the rule set is the product. Before rolling it out, scan a handful of APKs whose provenance you already know and confirm the labels match: a stock Android Studio build should come back as dx or d8, and a sample you know was protected should come back with the protector name. If a known sample returns nothing, the rule set does not cover it, and the README's issue template is the route to change that. Check the defaults for --scan-depth and --entry-max-scan-size on your own sample set rather than assuming the scanner sees every nested entry, and settle the GPL versus commercial question against LICENSE.GPL and LICENSE.COMMERCIAL before the tool reaches a build pipeline.

Editorial conclusion

Adopt APKiD if you triage Android samples at volume and need a one-line answer about which toolchain or protector touched a file before you open it in a disassembler. Do not adopt it if you need a malicious/benign verdict, a confidence score, or a rule set you can maintain without writing YARA. Before committing, run it against a small set of APKs you already understand, confirm the compiler and packer labels match what you know, and read LICENSE.GPL and LICENSE.COMMERCIAL to see which side of the dual licence your deployment falls on.

Official sources

  1. Issues
  2. README
  3. rednaga/APKiD on GitHub
  4. Releases
Community notes

Community notes