Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.jaspervanzeir.be/llms.txt

Use this file to discover all available pages before exploring further.

The starting file provided for this challenge was named output.bmp, which suggested it was an image. To verify this, I opened my Kali Linux terminal and ran a basic file check.

Enumeration & Initial Triage

I started by running the file command to see what the system thought of it:
file output.bmp
File Output
The output indicated it was recognized as data, but it loosely resembled a BMP file, which isn’t inherently abnormal or unsafe. I decided to dig deeper and look at the actual bytes. Every file type has specific starting bytes (magic bytes). A standard BMP file always starts with BM. Looking at the hex dump:
xxd -l 128 output.bmp
Byte Map
I saw the hex values 42 4d, which translates to BM. This confirmed the file was actively disguising itself as a BMP. However, something else immediately caught my eye: there was a massive amount of 20 bytes. In hex, 20 represents a space character. Normally, binary headers are padded with null bytes (00), not spaces. I asked myself:
Why are there so many spaces where empty bytes should be?
The logical conclusion was that the file was obfuscated. Hoping to find some readable text or hints about potential malware, I ran the strings command:
strings output.bmp | head -100
This revealed a massive clue. Looking closely at the output, I noticed XML-like tags, but they were written backward:
>ylbmessa/<
>ytilibitapmoc/<
>noitacilppa/<
Strings Output
Reading them right-to-left, these translate to </assembly>, </compatibility>, and </application>. I realized the entire file had been reversed byte-by-byte.

De-obfuscation: Reversing and Patching

To fix this, I needed to reverse all the bytes and save them into a new file. I quickly wrote a Python script directly in the terminal to handle this:
python3 - << 'PY'
from pathlib import Path

b = Path("output.bmp").read_bytes()

# Reverse all bytes
b = b[::-1]

Path("reversed.bin").write_bytes(b)

print("Ready: reversed.bin created")
print("First bytes:", b[:10])
PY
I saved the output as a .bin file because I wasn’t entirely sure what the new file type would be yet. I inspected the newly created reversed.bin:
xxd -l 128 reversed.bin
Byte Map Reversed
This time, the magic bytes at the beginning changed to MZ (4d 5a). Based on common file signatures, MZ dictates that this is a DOS/Windows Executable (.exe). However, I still had the issue of the space characters. Earlier, I noticed that all null bytes (00) had been replaced by spaces (20). I wrote another Python script to patch the reversed file by replacing all 0x20 bytes with 0x00:
python3 - << 'PY'
from pathlib import Path

b = Path("output.bmp").read_bytes()

# First, reverse the bytes
b = b[::-1]

# Next, replace spaces with null-bytes
b = bytes(0 if x == 0x20 else x for x in b)

Path("recovered.exe").write_bytes(b)
PY
Byte Map Cleaned
I saved this output as recovered.exe. Running xxd -l 128 recovered.exe confirmed that the 20s were successfully replaced with 00s. The file structure looked much healthier and more logical.

Analyzing the Executable & Extracting the Payload

My next step was to run strings on the newly recovered executable, hoping to find malware artifacts or perhaps the flag itself:
strings recovered.exe
Strings Output Cleaned
I didn’t find the flag, but I did find a very clear hint pointing toward a dropper mechanism: “Application Error There been error while dropping malware have debug yourself.” Knowing this was likely a dropper (malware that unpacks or writes a second payload to the disk), I decided to dump the object headers to inspect the executable’s sections:
x86_64-w64-mingw32-objdump -x recovered.exe
Headers
This command reveals where sections like .text (code), .data (variables/data), and .rdata (read-only data) begin and end. The .data section is particularly interesting in malware analysis because droppers frequently hide their embedded payloads there. Looking at the output, I noted two key offsets:
  1. .data started at 0x2b800
  2. .rdata started at 0x30400
​Because .rdata comes immediately after .data, I could calculate the exact size of the .data section by subtracting the starting offsets (0x30400 - 0x2b800). Using Python, this gave me a size of 0x4c00.
Start Data
I inspected the first few bytes of the .data section:
xxd -s 0x2b800 -l 32 recovered.exe
Byte Map Recovered Exe
The first bytes were 7a 5c. Since I suspected this data contained a dropped Windows executable, I expected it to start with the MZ header (4d 5a). Because it didn’t, I knew the payload was encoded.

XOR Decryption

If the first byte is 7a and I need it to be 4d, I can use a logical XOR operation to find the key: 0x7a XOR 0x37 = 0x4d
Xor Decrypt
Therefore, the starting key had to be 0x37. Through the challenge context and some reverse engineering logic, I determined the payload was encrypted with a rolling XOR cipher, where the key updates after every byte using the formula: key = (key * 7 - 0x7b) & 0xff. I wrote a final Python script to extract and decrypt the .data section:
python3 - << 'PY'
from pathlib import Path

# IMPORTANT: Using reversed.bin, not recovered.exe
b = Path("reversed.bin").read_bytes()
enc = b[0x2b800:0x30400]

key = 0x37
dec = bytearray()

for byte in enc:
    dec.append(byte ^ key)
    key = (key * 7 - 0x7b) & 0xff

Path("payload.bin").write_bytes(dec)
print(dec[:2])
PY
I specifically read from reversed.bin instead of recovered.exe. In recovered.exe, I globally replaced all 0x20 bytes with 0x00. Doing that to the embedded encrypted payload would corrupt it. I needed the raw, unaltered bytes from the reversed file. After running the script, I extracted the strings from the newly decrypted payload:
strings payload.bin
Flag
Scrolling through the output, I found the success message: Almost therd :) Here is the flag: Followed immediately by the flag itself! Flag:745FFC1D8F526D6E6756BE00E069B24AD6115BFC5409EEED88147C9A2B1AC6E1D4B61FFE17A6AFB2B6872ECF2E

Tools Used

  • file: To determine initial file types.
  • xxd: To view hex dumps and identify magic bytes/offsets.
  • strings: To extract readable text from binaries.
  • Python 3: To script custom byte reversal, null-byte patching, and rolling XOR decryption.
  • x86_64-w64-mingw32-objdump: To analyze the PE headers and map out the executable’s sections.

Summary

  • Key Steps: I discovered that a disguised .bmp file was actually a fully reversed file with spaces replacing its null bytes. After writing Python scripts to reverse the bytes and patch the nulls, I recovered a Windows executable. By analyzing the executable’s headers with objdump, I located an embedded payload in the .data section, derived the starting XOR key (0x37), and wrote a decryption script to uncover the final binary containing the flag.
  • What I Learned: This challenge was a fantastic exercise in manual de-obfuscation. Calculating section sizes using header offsets and writing custom Python scripts to manipulate raw bytes on the fly are incredibly valuable reverse engineering skills.
  • Crucial Mistakes/Takeaways: The most critical takeaway was realizing the danger of globally replacing bytes. If I had tried to decrypt the payload using recovered.exe (where I replaced all spaces with null bytes), the decryption would have failed because the payload’s natural 0x20 bytes would have been destroyed. Using the untouched reversed.bin for extraction was vital to solving the challenge.