주어지는 파일
실행 모습
하얀색 부분에 낙서가 가능하다.
Check 버튼을 누르면 Wrong이라고 뜬다.
분석
먼저, 프로그램에 사용된 스트링들을 보자.
"Wrong" 문자열 부근을 봐서 어떤 비교를 거친 건지 살펴보자.
반복문이 있고 반복문에서 jne 명령어를 통해서 "Wrong" 메시지 창을 띄우는 부분으로 분기하는 것을 볼 수 있다.
반복문은 dl과 bl을 비교하면서 같은 지 확인한다.
총, 0x15F90만큼 반복된다.
먼저 첫번째 dl로 들어가는 ecx 부분은 위의 사진과 같다.
bl에 들어가는 eax+ecx 부분은 위와 같다.
ImagePrc.exe에 그리는 그림과 정답 이미지를 한 비트씩 비교해서 맞는지 틀린 지 확인하는 것 같다.
이런 식으로 그리고 Check 해보니, ecx가 사용자가 입력한 그림인 것 같다.
그럼 프로그램에 저장돼있는 정답 이미지(eax+ecx →0x47e060)를 비트맵 이미지로 만들어서 어떤 그림인지 확인해 보자.
문제 풀이
PEview로 보았을 때, rsrc 섹션에 해당 이미지가 있는 것 같다.
디버깅할 때 정답 이미지의 주소가 0x47E060이었으므로,
.rsrc 섹션에 해당한다.
정답 이미지의 파일 offset은
0x9060 ~ (0x9060 + 0x15F90 - 1)
이다.
그럼 이번엔 비트맵 파일을 만들 준비를 하자.
비트맵 파일을 만들려면 가로, 세로 같은 부가 정보가 필요하다.
프로그램에 사용된 API 중에 GetDIBits 함수가 있다.
int GetDIBits(
[in] HDC hdc,
[in] HBITMAP hbm,
[in] UINT start,
[in] UINT cLines,
[out] LPVOID lpvBits,
[in, out] LPBITMAPINFO lpbmi,
[in] UINT usage
);
여기서 6번째 파라미터가 bitmap의 정보들을 가지고 있는 구조체의 포인터다.
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
여기서 첫 번째 파라미터인 BITMAPINFOHEADER에 우리가 원하는 정보가 있다.
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
여기서 필요한 정보는 3가지이다.
2번째 - biWidth - 가로(픽셀 단위)
3번째 - biHeight - 세로(픽셀 단위)
5번째 - biBitCount - 픽셀 당 비트 수
이 함수에 bp를 걸어놓고 이 3가지 정보를 찾아보자.
edi에 GetDIBits 주소를 옮기고서 edi로 호출한다.
7개의 인수가 들어가는 걸 볼 수 있는데, 우리가 찾는 건 6번째 edx이다.
edx의 주소를 따라가 보자.
다음과 같이 tagBITMAPINFO의 첫 번째 멤버인 tagBITMAPINFOHEADER가 저장되어 있다.
width → 0xc8 (200)
height → 0x96 (150)
픽셀 당 비트 수 → 0x18 (24)
이 정보를 바탕으로 비트맵 파일을 만들어보자.
그림판에서 크기 조정 버튼을 눌러 픽셀 단위의 그림을 하나 생성한다.
다른 이름으로 저장하기를 통해서 24비트 비트맵 파일로 저장한다.
이제 비트맵 파일의 내용을 채울 차례다.
HxD로 ImagePrc.exe의 내용을 먼저 복사한다.
아까 구한 오프셋으로 파일에서의 이미지를 추출한다. (블록 선택, Ctrl + E)
그다음, 방금 만든 bmp 파일을 HxD로 열어준다.
그러면 저장했던 bmp파일이 하얀색 백지였기 때문에, 0xFF로 가득 찬 내용을 볼 수 있다.
0x36부터 헤더가 끝나고 바디가 시작되기 때문에,
0x36 ~ (0x36 + 0x15F90 - 1) 부분을 아까 추출(복사)한 내용으로 바꾼다.
(0x36 + 0x15F90 - 1)이 파일의 끝에 딱 들어맞는다.
이렇게 고쳐준 다음 저장하고, 파일을 열게 되면 Flag를 얻을 수 있다.
'리버싱' 카테고리의 다른 글
Position 파이썬 코드 해설 (0) | 2023.07.03 |
---|---|
Reversing.kr Position 문제 풀이 (0) | 2023.07.03 |
Reversing.kr Replace 문제 풀이 (0) | 2023.06.16 |
Reversing.kr Music Player 문제 풀이 (0) | 2023.06.15 |
Reversing.kr Easy Keygen 문제 풀이 (0) | 2023.06.02 |