reversefreeeasy

SAW

hackthebox

English summary: Given an Android APK file that uses a native library to dynamically decrypt and load hidden code. The goal is to reverse engineer the native library, recover the XOR key, decrypt the hidden DEX payload, and extract the flag.

$ ls tags/ techniques/
xor_key_recoveryapk_decompilationjni_reverse_engineeringdex_payload_extractiondynamic_code_loading_analysis

$ cat /etc/rate-limit

Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.

SAW — HackTheBox

Description

The malware forensics lab identified a new technique for hiding and executing code dynamically. A sample that seems to use this technique has just arrived in their queue. Can you help them?

English summary: Given an Android APK file that uses a native library to dynamically decrypt and load hidden code. The goal is to reverse engineer the native library, recover the XOR key, decrypt the hidden DEX payload, and extract the flag.

Analysis

The challenge provides an APK file (SAW.apk). Initial extraction reveals:

  • classes.dex — main Dalvik bytecode
  • lib/ — native libraries for multiple architectures (arm64-v8a, armeabi-v7a, x86, x86_64)
    • libdefault.so — loaded by the app
    • libnative-lib.so — NOT loaded (decoy)
  • Standard Android resources

Java Layer Analysis (jadx):

  • Package: com.stego.saw
  • Loads libdefault.so via System.loadLibrary("default")
  • Requires intent extra open=sesame to proceed
  • Native method: public native String a(String str, String str2);
    • str = FILE_PATH_PREFIX (app's data directory)
    • str2 = user input from EditText dialog
  • Dialog titled "XOR XOR XOR" with message "XOR ME !" — hints at XOR operation

Native Library Analysis (libdefault.so):

  • JNI_OnLoad: Registers native method a for com/stego/saw/MainActivity
  • Native method validates an 8-character key using two XOR arrays in .data section:
    • Array l at 0x3de0: [10, 11, 24, 15, 94, 49, 12, 15]
    • Array m at 0x3e00: [108, 103, 40, 110, 42, 88, 98, 104]
    • Validation: input[i] XOR l[i] == m[i]
  • If key is correct, XOR-decrypts 792 bytes from jni_def symbol using mask 0x64 ('d')
  • Writes decrypted result to a file (dynamic DEX loading)

Solution

Step 1: Recover XOR Key

The key validation uses: input[i] XOR l[i] == m[i]

Therefore: key[i] = l[i] XOR m[i]

...

$ grep --similar

Similar writeups