Skip to content

Instantly share code, notes, and snippets.

@apkunpacker
Forked from DavidBuchanan314/zshield_notes.md
Created August 10, 2024 06:40
Show Gist options
  • Save apkunpacker/184bcc0e19e7fb44932915eaefa689c4 to your computer and use it in GitHub Desktop.
Save apkunpacker/184bcc0e19e7fb44932915eaefa689c4 to your computer and use it in GitHub Desktop.

Zimperium zShield RE Notes

Newer versions of the Rabbit R1's APK are protected by https://www.zimperium.com/zshield/ (I don't know this for certain, somebody told me it is but I haven't really seen any identifying marks in the code yet)

Interesting assets within the APK:

lib/arm64-v8a/liboptipkawfn.so    ~3MB packed/encrypted ELF
assets/optipkawfn/0.odex          only 41 bytes (EDIT: I think this is part of an asset obfuscation scheme, the real file contents are likely elsewhere - inside the .szip maybe?)
assets/optipkawfn.szip            ~8MB - I predict containing encrypted+compressed bytecode

The substring "optipkawfn" is randomised between builds.

TODOs

  • Write an unpacker for "protected" .so files. DONE! (XXTEA decryption)
  • Figure out how asset encryption(?) works.
  • Figure out how to map method names to their corresponding native implementations.
  • Automate native code deobfuscation:
    • String decryption
    • Control-flow recovery

ELF/SO protection

The ELF entrypoint has a few anti-analysis tricks up its sleeve:

  • Per the marketing brief, the code is "diversified" meaning different builds might make slightly different checks in different orders.

  • Checking /proc/self/status for non-zero TracerPid (anti-debugger checks)

  • Finds libc via /proc/self/maps and calls pthread_create to spawn a sub-thread which:

    • Checks for the following Naughty Paths in the filesystem (via newfstatat):
/sbin/su
/system/bin/su
/system/xbin/su
/system/xbin/daemonsu
/su/bin/su
/su/bin/daemonsu
/system/xbin/bstk/su
/data/xposed/XposedBridge.jar
/storage/emulated/0/MagiskManager
/data/data/com.topjohnwu.magisk
/data/user_de/0/com.topjohnwu.magisk
/data/user/0/com.topjohnwu.magisk
/magisk
/data/magisk
/data/magisk.img
/root/magisk
/root/magiskinit
/system/lib/libxposed_art.so
/system/bin/app_process64_xposed
/data/dalvik-cache/xposed_XResourcesSuperClass.dex
/data/dalvik-cache/arm64/system@framework@[email protected]@xposed
/data/dalvik-cache/oat/arm64/xposed_XTypedArraySuperClass.odex
/system/lib/libriruloader.so
/system/lib64/libriruloader.so
  • (subthread continued):

    • In an infinite loop (every 10ms), it checks:
    • /proc/self/status (for a debugger, probably)
    • /proc/self/maps (looking for traces of frida, I believe)
    • Checks /proc/net/unix for... something (probably frida traces again).
    • I see mentions of /etc/hosts and /proc/cpuinfo in strings but I'm not sure they're ever checked.
  • (Back on the main thread now)

  • Checks /proc/net/unix similarly.

  • Self-decrypts the body of the ELF using the XXTEA cipher.

  • Joins the subthread

  • Checks for KernelSU via prctl(0xdeadbeef) (source)

  • I think it checks libc's environ, but I'm not sure what it actually checks for.

  • TODO: what happens with relocations?

  • Cleans everything up and returns from the entrypoint (back to dlopen I guess)

Aaaaand that's as far as I've got so far. I wrote an unpacker for the XXTEA stuff, but there's a lot more work to be done.

The code itself is control-flow flattened and obfuscated (OLLVM-style), and strings/buffers are "encrypted" with a weak made-up(?) cipher with 32-bit keys.

Asset Protection

A lot of the assets (such as 0.odex mentioned above) appear truncated, to between 17 and 41 bytes.

No idea how these get unpacked, or where they get unpacked from!

Java/DEX Protection

I haven't tried any proper dynamic analysis yet, I haven't even launched the app yet (my R1 is still in the post).

I'm pretty new to the world of android/java application protection.

Theory 1

My working theory is that the aforementioned .szip file contains encrypted and/or compressed DEX data, that's unpacked at runtime. I'll try to trace this process.

I found this, an open-source android DEX protector: https://github.com/KuNgia09/Bangcle, which might give me some ideas for what to expect. Some key JNI methods to watch out for:

  • env->RegisterNatives - does what it says on the tin
  • TODO: write some more words here

Other projects to look at:

Theory 2

My second theory (which is more likely now I think about it) is that all the "protected" code has been translated AOT to obfuscated native methods (gross!). Maybe the .szip just contains protected assets (szip = secure zip?).

HMMM I just zipped up the (unprotected) assets from v0.8.83 and they took up ~7.8MB. This correlates to the size of the szip.

If this is the case, then firstly I'll want to find a way to pull out the java-name-to-native-function mappings, and secondly maybe I'll want to think about writing a proper deobfuscator - control flow recovery?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment