A trick of Keystore they forgot to hide.
A fully open-source, FOSS alternative to the proprietary TrickyStore Magisk module.
TrickyStore's author has a track record of violations and questionable practices
So this is a complete rewrite from scratch, built on:
- The projects credited in Acknowledgements
- Official changelogs and the expected behavior of newer releases
- Original fixes and features carried over from an earlier fork of the old codebase
Licensed under GPLv3 and it stays that way.
- 100% FOSS, no closed-source components
- Matches the proprietary implementation's behavior and feature set as closely as possible
- Android 10+
- Flash the module and reboot
- (Optional) Place an unrevoked hardware keybox at
/data/adb/tricky_store/keybox.xmlfor extended integrity - (Optional) Customize target packages in
/data/adb/tricky_store/target.txt - (Optional) Customize the security patch level in
/data/adb/tricky_store/security_patch.txt
All config files take effect immediately — no reboot needed after step 1.
<?xml version="1.0"?>
<AndroidAttestation>
<NumberOfKeyboxes>1</NumberOfKeyboxes>
<Keybox DeviceID="...">
<Key algorithm="ecdsa|rsa">
<PrivateKey format="pem">
-----BEGIN EC PRIVATE KEY-----
...
-----END EC PRIVATE KEY-----
</PrivateKey>
<CertificateChain>
<NumberOfCertificates>...</NumberOfCertificates>
<Certificate format="pem">
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</Certificate>
<!-- more certificates -->
</CertificateChain>
</Key>
</Keybox>
</AndroidAttestation>Tricky Store OSS supports two modes: leaf certificate hacking and certificate generation. On TEE-broken devices, leaf hacking won't work since the leaf certificate can't be retrieved from TEE. The module picks the right mode automatically per device.
Override per package with a suffix:
| Suffix | Behavior |
|---|---|
| (none) | Automatic mode |
? |
Force leaf hacking |
! |
Force certificate generation |
# target.txt
com.google.android.gsf # automatic
io.github.vvb2060.keyattestation? # leaf hacking
com.google.android.gms! # certificate generation
Optional. Lives at /data/adb/tricky_store/security_patch.txt. It sets the three patch levels a spoofed attestation reports: osPatchLevel (system), vendorPatchLevel, and bootPatchLevel. It only changes KeyAttestation output, not system properties. Changes apply on save, so no reboot is needed.
Lines starting with # are comments, and blank lines are ignored.
Settings above a package header are considered global and is the default for every app. A package header ([package.name]) on its own line targets one app; everything below it applies only to that app until the next header. This lets you give different apps different dates, for example an old system date for com.google.android.gms and a recent one everywhere else.
A package inherits anything it does not set from the global block. For example: [com.google.android.gms] block that sets only system= still picks up the global vendor= and boot=.
The keys are system, vendor, boot, and all. all sets all three at once and any single key overrides it.
Dates can be written as YYYY-MM-DD, YYYYMMDD, or YYYYMM. YYYY, MM, and DD work as placeholders for the current year, month, and day; they resolve on every attestation, so YYYY-MM-05 always lands on the 5th of the current month.
noomits that patch level tag entirely. The attestation reports nothing for it.device_defaultkeeps the device's real value for that component.propmirrors the system security-patch prop (ro.build.version.security_patch). It is kept for backward compatibility;device_defaultis the more accurate name for new configs.
Simple form, one date for all three levels:
20241101
Per partition:
# system patch level
system=202411
# report nothing for boot
boot=no
# vendor, alternate date format
vendor=2024-11-01
# keep the device's real boot level instead
# boot=device_default
Per-package overrides:
# global default for every app
system=YYYY-MM-05
vendor=device_default
boot=no
# GMS needs the old print date for a legacy <A13 STRONG verdict
[com.google.android.gms]
system=2024-10-01
# a demo app with its own set
[org.app.demo]
all=2025-09-15
boot=device_default
GMS overrides only system; it inherits vendor=device_default and boot=no from the global block. The demo app sets all three to 2025-09-15 via all, then carves boot back out to the real device value.
This only affects KeyAttestation results.
resetpropcan be used separately if you need to change system properties.
PRs welcome. Thanks for backing real open-source work.
- BootloaderSpoofer (dead, relies on forks/mirrors)
- FrameworkPatch (dead, relies on forks/mirrors)
- KeyAttestation
- KeystoreInjection
- PLTI
- LSPosed
- PlayIntegrityFork