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/
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 bytecodelib/— native libraries for multiple architectures (arm64-v8a, armeabi-v7a, x86, x86_64)libdefault.so— loaded by the applibnative-lib.so— NOT loaded (decoy)
- Standard Android resources
Java Layer Analysis (jadx):
- Package:
com.stego.saw - Loads
libdefault.soviaSystem.loadLibrary("default") - Requires intent extra
open=sesameto 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 methodaforcom/stego/saw/MainActivity- Native method validates an 8-character key using two XOR arrays in
.datasection:- Array
lat 0x3de0:[10, 11, 24, 15, 94, 49, 12, 15] - Array
mat 0x3e00:[108, 103, 40, 110, 42, 88, 98, 104] - Validation:
input[i] XOR l[i] == m[i]
- Array
- If key is correct, XOR-decrypts 792 bytes from
jni_defsymbol using mask0x64('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]
#!/usr/bin/env python3 l = [10, 11, 24, 15, 94, 49, 12, 15] m = [108, 103, 40, 110, 42, 88, 98, 104] key = ''.join(chr(l[i] ^ m[i]) for i in range(8)) print(f"XOR Key: {key}") # fl0ating
XOR Key: fl0ating
Step 2: Extract and Decrypt Hidden DEX
#!/usr/bin/env python3 # Extract encrypted data from libdefault.so and decrypt # Encrypted data location: jni_def symbol at offset 0x3180 # Size: 792 bytes (0x318) # XOR mask: 0x64 (character 'd') with open('libdefault.so', 'rb') as f: f.seek(0x3180) # jni_def offset in x86_64 version encrypted = f.read(792) decrypted = bytes([b ^ 0x64 for b in encrypted]) # Verify DEX magic print(f"Magic: {decrypted[:8]}") # dex\n035\x00 with open('decrypted.dex', 'wb') as f: f.write(decrypted)
Step 3: Extract Flag from DEX
The decrypted 792 bytes form a valid Dalvik DEX file containing:
- Class
xwith methodlogprint - String constant with the flag
strings decrypted.dex | grep HTB # HTB{SawS0DCLing}
Key Insight
The flag HTB{SawS0DCLing} = "Saw Sideloading" — referencing the Android malware technique of DEX sideloading, where encrypted code payloads are decrypted and loaded at runtime using DexClassLoader or InMemoryDexClassLoader to evade static analysis.
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar
Similar writeups
- [mobile][free]APKey— HackTheBox
- [mobile][free]Jigsaw— HackTheBox
- [mobile][free]Protected— HackTheBox
- [reverse][Pro]Андрей Андреевич (Andrew Andreevich)— duckerz
- [crypto][free]Cryptohorrific— hackthebox