Skip to content

UltraSina/android-assembly-signature-verification

Repository files navigation

Android Assembly Signature Verification

Unhookable signature verification using raw ARM syscalls.

The Problem

Standard Android signature checks get bypassed easily:

  • Frida hooks Java methods and native functions
  • Xposed/LSPosed intercepts framework APIs
  • Lucky Patcher patches verification logic
  • NP Manager hooks libc functions like open(), read()

These tools work because apps use high-level APIs that create hookable attack surfaces.

The Solution

This library implements signature verification using inline ARM assembly with direct syscalls (svc instructions):

  • No libc function calls → Can't hook open(), read(), etc.
  • No named functions → Can't hook by symbol
  • No PLT/GOT entries → Can't hook imports
  • Direct kernel syscalls → Bypasses all userspace hooking frameworks
  • String obfuscation → Signature hash hidden from static analysis
  • Inline assembly → No clear function boundaries to patch

Without root access and kernel-level hooks, this is unhookable at runtime. Static patching is extremely difficult due to inline assembly and lack of clear hook points.

How It Works

Instead of calling open() or fopen(), the code does:

mov x8, #56        // __NR_openat
svc #0             // Direct syscall

All file I/O and signature verification happens through raw syscalls. Standard hooking tools operate in userspace and never see these calls. The inline assembly makes it nearly impossible to identify where to patch without extensive reverse engineering.

What This Defeats

✓ Frida
✓ Xposed/LSPosed
✓ Lucky Patcher
✓ NP Manager
✓ Any userspace hooking framework
✓ Automated static patching tools

What Can Still Break This

✗ Root + kernel hooks (eBPF, seccomp-bpf, ptrace)
✗ Manual reverse engineering + careful static patching (extremely time-consuming)
✗ Custom ROM with syscall logging

Usage

  1. Get your app's SHA256 signature:
keytool -list -v -keystore your.jks -alias your-alias
  1. Replace the hash in native-lib.cpp:
const string MySignature = OBF("YOUR_SHA256_HERE");
  1. Build and integrate into your app

Requirements

  • Android 5.0+ (API 21+)
  • NDK
  • All architectures supported and tested (armeabi-v7a, arm64-v8a, x86, x86_64)

Limitations

  • This is defense in depth, not a silver bullet
  • Determined attackers with root can still bypass it
  • Manual static analysis can eventually defeat it (but it's a pain in the ass)
  • Should be combined with obfuscation and other protections

License

MIT - Use responsibly. I'm not responsible for how you use this.


Why This Exists: I wanted to see if signature verification could survive modern hooking frameworks. Turns out, going low-level works. Feel free to try breaking it (without root).