ImagePcr

The program compares a drawing against a bitmap held in its resources; the flag is the image it expects.

2026.08.18 Reversing original post

프로그램을 실행해보자! 그림을 그리고 검사를 받는다. 아무렇게나 그림을 그려 넣으면 Wrong!, 탈락한 것 같다.

Figure 1

x32dbg 로 먼저 열어본다. 문자열 찾기에서 Wrong 을 사용하는 주소로 가본다. 일단 GetDIBits 로 비트맵 이미지를 가져온다. 아마 내가 그린 그림이다! 그리고 FindResourceA, LoadResource 로 비교할 파일을 가져온다. 비트 하나씩 비교해서, 틀리면 바로 Wrong 을 출력하는 것 같다. 그렇다면, 그 파일에 정답이 있을 거다!

Figure 2

Figure 3

PE Viewer 로 열어봤는데, .rsrc 섹션에 리소스 데이터가 있다. 정답 이미지의 파일을 위의 정보들로 알아낼 수 있다.

Figure 4

0960 (f 가 시작하는 곳) ~ (0960 + 15FF0)

비트맵 이미지 파일이다. 밑으로 쭉 내려보니까 중간에 00 도 있다는 걸 확인했다. 그러기 위해선 높이와 너비를 알아야 한다. 다시 코드를 분석해보자. 주변 위쪽을 찾아보니까 GetDIBits 가 있다. GetDIBits 는 비트맵(Bitmap)의 실제 픽셀 데이터를 메모리 버퍼로 가져오는 Windows GDI API 이다.

Figure 5

push edx, GetDIBits 주소의 hex 값을 (첫 번째 줄) 보면 데이터들을 볼 수 있다. BITMAPINFOHEADER 구조체는 이렇게 생겼다.

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;       // 0x00
    LONG  biWidth;      // 0x04
    LONG  biHeight;     // 0x08
    WORD  biPlanes;     // 0x0C
    WORD  biBitCount;   // 0x0E
} BITMAPINFOHEADER;

이걸 정리하면:

OffsetHEXSize필드의미
+0x0028 00 00 004B (DWORD)biSize구조체 크기0x28 = 40 bytes
+0x04c8 00 00 004B (LONG)biWidth가로 픽셀0xC8 = 200 px
+0x0896 00 00 004B (LONG)biHeight세로 픽셀0x96 = 150 px
+0x0C01 002B (WORD)biPlanes플레인 수1 (고정값)
+0x0E18 002B (WORD)biBitCount색 깊이0x18 = 24 bit

이 정보들을 가지고 그림판에서 비트맵을 만든다. (24 비트맵으로 저장해야 함; 픽셀 사이즈도 맞추고)

이제 비트맵의 내용을 채워 플래그(답 이미지) 를 볼 차례다. 헥스 에디터에 ImagePcr.exe 파일과 bmp 파일을 열어준다. 아까 구한 오프셋으로 ImagePcr.exe 에서 원하는 헥스 부분을 추출한다.

Figure 6

카피앤페이스트한 다음에, 헤더가 끝나고 바디가 시작하는 주소인 0x36 에 클릭 후 페이스트해준다. (딱 맞는다)

Figure 7

이렇게 저장 후 bmp 파일을 열어주면 플래그를 볼 수 있다.

Figure 8

모자이크 처리함!