← Back to Writeups
HTBN/AReversing

SAW

XESXOR8/23/20264 min read
#reversing#htb#n/a

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
PortServiceVersionNotes
<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

  1. Apk_decompilation
  2. Dex_payload_extraction
  3. Dynamic_code_loading_analysis
  4. Jni_reverse_engineering
  5. 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

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

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 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]

#!/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 x with method logprint
  • 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.

</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR