🚩 문제 설명
BMP 파일에서 이런 중요한 값들을 지워버리다니!
빨리 복구해서 플래그를 읽어주세요!
플래그 형식은 DH{...}로, flag.bmp를 올바르게 복구하면 찾을 수 있습니다.
with open('flag.bmp', 'rb') as f:
data = bytearray(f.read())
data[:0x1C] = b'\x00' * 0x1C
data[0x22:0x36] = b'\x00' * 0x14
with open('flag.bmp.broken', 'wb') as f:
f.write(data)
코드를 보면 0:1C 까지 0으로 채우고 다시 0x22:0x36까지 0으로 채운다.
즉, 우리가 복구해야 할 영역이다.
저 부분만 훼손하지 않았다. 픽셀당 바이트 수를 담은 영역이다. 24비트면 3바이트이고 1픽셀당 3바이트로 표현된다. 잘 기억해두자.
일단 코드를 보며 어떻게 복구해야 될지 알아보자.
with open('flag.bmp.broken', 'rb') as f:
data = bytearray(f.read())
total_bytes = 14309622 # 전체 파일 바이트 크기
header_size = 54 # BMP 파일 헤더 크기
info_header_size = 40
bitplane_value = 1
bytes_per_pixel = 3 # 픽셀당 바이트 수 (24비트 = 3바이트)
# 이미지 데이터 크기 계산
image_data_size = total_bytes - header_size
# 전체 픽셀 수 계산
num_pixels = image_data_size // bytes_per_pixel
data[0x0] = 0x42
data[0x1] = 0x4D
data[0x2:0x6] = total_bytes.to_bytes(4, byteorder='little')
data[0xA:0xE] = header_size.to_bytes(4, byteorder='little')
data[0xE:0x12] = info_header_size.to_bytes(4, byteorder='little')
data[0x1A:0x1C] = bitplane_value.to_bytes(2, byteorder='little')
data[0x22:0x26] = image_data_size.to_bytes(4, byteorder='little')
# 가능한 가로와 세로 조합 찾기
for width in range(1, int(num_pixels**0.5) + 1):
if num_pixels % width == 0:
height = num_pixels // width
data[0x12:0x16] = width.to_bytes(4, byteorder='little')
data[0x16:0x1A] = height.to_bytes(4, byteorder='little')
with open(f'flag_{width}.bmp', 'wb') as f:
f.write(data)
data[0x12:0x16] = height.to_bytes(4, byteorder='little')
data[0x16:0x1A] = width.to_bytes(4, byteorder='little')
with open(f'flag_{height}.bmp', 'wb') as f:
f.write(data)
나머지는 리틀 엔디안과 몇 바이트 크기로 넣어줄 건지 정하고
가로x세로 조합을 찾으면 된다.
가로x세로 조합의 경우의 수는 width
x height
또는 height
x width
2개이다. bmp
파일의 width
영역과 height
영역이 고정되어 있기 때문이다.
width
와 height
중 하나만 정해지면 나머지 값도 정해진다. 이 관계는 전체 파일 바이트 값과 관련이 있는데, 전체 파일 바이트 값을 100
이라고 가정하면 가능한 가로x세로 조합은 10x10
5x20
4x25
2x50
1x100
이다. 즉 width
와 height
둘중 하나도 전체 파일 바이트 값의 제곱근을 넘길 수 없다.
따라서 다음과 같은 식이 탄생한다.
for width in range(1, int(num_pixels**0.5) + 1):
num_pixels?
# 전체 픽셀 수 계산
num_pixels = image_data_size // bytes_per_pixel
여기서 num_pixels
변수는 전체 바이트 값에서 3을 나눈 값이다. 이유는 아까 기억하라고 했던 1픽셀당 3바이트로 표현되기 때문인데 3을 나눈 num_pixels
값에서 가로x세로 값을 구하면 된다.
All Case
width
1개에 대한 경우만 구했기 때문에width
와 height
을 바꿔서 1번 더 복구해주면 모든 경우의 수가 구해진다.flag
가 들어있는 파일을 찾으면 된다.