Forensics
Hard
500 points
Painted
Recuite 2025 - HCMUS
6 tháng 10, 2025
Memory Dump
Paint
BMP
Entropy Analysis

Forensics
Painted#
Thông tin Challenge#
- Thể loại: Forensics
- Điểm: 500
- Tệp tin: mspaint.dmp (575 MB)
- Kích thước canvas: 960x520 pixel
Mô tả Challenge#
Một họa sĩ đã vẽ nên một bức tranh tuyệt đẹp trong MS Paint nhưng lại quên lưu lại trước khi đóng ứng dụng.
May mắn thay, chúng ta có bản dump toàn bộ bộ nhớ tiến trình (process memory dump) của ứng dụng đó.
Nhiệm vụ: khôi phục lại bức tranh từ dữ liệu trong bộ nhớ!
Phân tích#
Cấu trúc của file Memory Dump#
Offset Kích thước Nội dung
─────────────────────────────────────────
0x00000000 ~16 MB Header & Metadata
0x01000000 Biến động Process Memory
0x04000000 Biến động Heap Memory
...
0x0ac00000 ◄── 1.9 MB ★ DỮ LIỆU CANVAS ★
...
Tổng cộng: 575,325,048 bytes (575 MB)
Hướng giải quyết#
Bước 1: Xác định kích thước canvas#
Tìm kiếm các giá trị chiều rộng (960) và chiều cao (520) được lưu dưới dạng số nguyên 32-bit little-endian trong bộ nhớ.
Đây là dấu hiệu giúp xác định vị trí vùng nhớ có chứa dữ liệu ảnh.
Bước 2: Phân tích entropy#
Đặc trưng của vùng dữ liệu ảnh:
- Nền trắng → chứa rất nhiều byte
0xFF - Các vùng có màu sắc → entropy cao, giá trị byte thay đổi mạnh
pythonexpected_size_32bit = 960 * 520 * 4 # 1,996,800 bytes (RGBA)
# Quét vùng nhớ để tìm khu vực có nhiều pixel trắng
for offset in range(0, len(data), 1MB):
sample = data[offset:offset+10000]
white_count = sample.count(0xFF)
if white_count > suitable_threshold:
# Có khả năng đây là vùng chứa canvas
print(f"Candidate offset: {hex(offset)}")
Bước 3: Trích xuất và dựng lại hình ảnh BMP#
pythondef create_bmp(pixel_data, width, height, bits_per_pixel, filename):
# Header của BMP (14 bytes)
file_header = struct.pack('<2sIHHI',
b'BM', file_size, 0, 0, header_size)
# Thông tin ảnh (40 bytes - BITMAPINFOHEADER)
info_header = struct.pack('<IiiHHIIiiII',
40, width, -height, # Âm = hiển thị top-down
1, bits_per_pixel, 0, pixel_data_size,
2835, 2835, 0, 0)
# Ghi file BMP ra đĩa
with open(filename, 'wb') as f:
f.write(file_header)
f.write(info_header)
f.write(pixel_data)
Xác định vị trí đúng của canvas#
Thử nhiều offset khác nhau trong file:
- 0x0 (bắt đầu file)
- 0x1000000 (16 MB)
- 0x4000000 (64 MB)
- 0xac00000 ✓ ← Vị trí đúng, chứa dữ liệu canvas
- 0xad00000
- 0x20000000 (512 MB)
Kiểm chứng#
- Entropy hợp lý ✓
- Tỷ lệ pixel trắng phù hợp ✓
- Hiển thị ảnh thành công ✓
- Flag đọc được trên canvas ✓
Kết quả#
Tệp tạo ra: white_bg_3_0xac00000_bottomup.bmp
- Offset: 0xac00000 (180,355,072 bytes)
- Định dạng: 32-bit RGBA, bottom-up
- Kết quả: Hình ảnh khôi phục hiển thị flag rõ ràng trên canvas!
Flag#
Đọc trực tiếp từ hình ảnh đã khôi phục.
Bài học rút ra#
- Kỹ thuật phân tích bộ nhớ: Process dump có thể chứa dữ liệu giá trị, đặc biệt là dữ liệu thô của ứng dụng.
- Hiểu cấu trúc ảnh BMP: Việc nắm vững header và định dạng ảnh là chìa khóa để khôi phục.
- Phân tích entropy: Giúp xác định khu vực chứa thông tin hình ảnh trong khối dữ liệu lớn.
- Thử nghiệm và sai sót: Việc thử nhiều offset và cách hiển thị (top-down/bottom-up) là cần thiết.
- Cách lưu của Paint: Ảnh trong Paint thường được lưu trực tiếp dưới dạng pixel thô trong heap.
Thống kê#
- Kích thước file dump: 575 MB
- Kích thước canvas: 960×520 pixel
- Dữ liệu pixel: 1,996,800 byte (RGBA)
- Offset đúng: 0xac00000
- Thời gian xử lý: 30–60 phút
- Số vị trí thử nghiệm: hơn 50 offset
500
Points
Hard
Difficulty
Forensics
Category