Patona
Patona
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: am_demodulation, apt_decoding, envelope_extraction
Summary
Walkthrough of the CUSTOM Reversing Patona. Task: Decode a flag from flag.raw file generated by an APT encoder binary. Solution: Reverse-engineered the NOAA APT signal format, extracted envelope from AM-modulated signal using 3 samples per pixe
Description
Analysis of the patona binary revealed that it implements an APT (Automatic Picture Transmission) encoder used by NOAA satellites. The binary takes a PGM image with a width of 909 pixels and encodes it into an AM-modulated signal with a 2400 Hz carrier frequency.
Analysis
Each line of the output file flag.raw contains 2080 "pixels", each encoded with 3 samples, resulting in 6240 samples per line. The total file size of 1,210,560 bytes corresponds to 194 lines (1210560 / 6240).
Solution
A Python script was written to solve this:
- Read
flag.rawas 8-bit samples. - Center the signal around 127.5.
- Calculate the envelope by averaging absolute deviations in groups of 3 samples.
- Extract the Image A region (samples 86-995 in each line of 2080).
python read-only • copy allowedimport numpy as np from PIL import Image # Constants from analysis SAMPLES_PER_PIXEL = 3 PIXELS_PER_LINE = 2080 SAMPLES_PER_LINE = PIXELS_PER_LINE * SAMPLES_PER_PIXEL # 6240 IMAGE_A_START = 86 IMAGE_A_END = 995 def solve(): # Read the raw signal with open('flag.raw', 'rb') as f: data = f.read() # Convert to numpy array of float32 for processing samples = np.frombuffer(data, dtype=np.uint8).astype(np.float32) # Center the signal (AM modulation around 127.5) samples -= 127.5 # Reshape to lines and pixels num_lines = len(samples) // SAMPLES_PER_LINE samples = samples[:num_lines * SAMPLES_PER_LINE] lines = samples.reshape((num_lines, PIXELS_PER_LINE, SAMPLES_PER_PIXEL)) # Calculate envelope by averaging absolute deviations in groups of 3 samples # This effectively demodulates the AM signal envelope = np.mean(np.abs(lines), axis=2) # Normalize for image saving envelope = (envelope - envelope.min()) / (envelope.max() - envelope.min()) * 255 envelope = envelope.astype(np.uint8) # Extract Image A region image_a = envelope[:, IMAGE_A_START:IMAGE_A_END] # Save the result img = Image.fromarray(image_a) img.save('correct_img_a.png') print(f"Decoded image saved to correct_img_a.png. Shape: {image_a.shape}") if __name__ == "__main__": solve()
The flag is clearly visible in the decoded image.
Key Takeaways / Lessons
- Mastering am_demodulation, apt_decoding, envelope_extraction was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2025-12-27 • CUSTOM • Patona • Difficulty: Medium