SAW
SAW
Platform: HackTheBox | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-03-24 | Status: Solved Techniques: apk_decompilation, dex_payload_extraction, dynamic_code_loading_analysis, jni_reverse_engineering, xor_key_recovery
Summary
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.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
hackthebox| ID:20260324_hackthebox_saw - Tags: xor, android, apk, malware_analysis, native_library, jni, dynamic_dex_loading, sideloading
- Indicators: System.loadLibrary in Android app, XOR arrays in native library .data section, encrypted blob with DEX magic after decryption, dialog hints like 'XOR XOR XOR, native method taking file path and user input
- Source:
20260324_hackthebox_saw.md
Foothold
Vulnerability / Misconfiguration
- Apk_decompilation
- Dex_payload_extraction
- Dynamic_code_loading_analysis
- Jni_reverse_engineering
- Xor_key_recovery
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- apk_decompilation
- dex_payload_extraction
- dynamic_code_loading_analysis
- jni_reverse_engineering
- xor_key_recovery
- Tags: xor, android, apk, malware_analysis, native_library, jni, dynamic_dex_loading, sideloading
Original Writeup
<details><summary>Click to expand original content</summary>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] - 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{REDACTED}
Key Insight
The flag HTB{REDACTED} = "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.
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR