본문 바로가기

Rerversing/Exercise reversing

[Reversing.kr] - ImagePrc 문제 풀이

11, 12월에 잠시 딴 짓을 하다가 블로그를 너무 신경을 못 써서 이번엔 5번째 문제 풀자마자

바로 6번째 문제를 잡아봤다.


자~ 그럼 6번째 문제 풀이 시작..


결과부터 말하자면 C++의 API 함수 중에서 그래픽컬 한 부분은 전혀 모르기 때문에 -_-; 꼼수를 조금 도입했다. 쩝!~~






[그림. 1] ImagePrc 실행 화면


기존 것들처럼 또 뭔가 Check 하는 녀석인 것 같은데...

뭘 말하는지 설명 파일도 없고, 그냥 무작정 Check 를 눌러봤더니...






[그림. 2] Wrong 메시지 출력


또 뭔가 틀렸다는 메시지를 출력해준다. 이전에는 뭔가 값을 입력하고 비교 체크를 했는데 이번엔 뭔가 적는 것도 없고...

이게 뭔가 싶기도 했다. 뭐! 어쩌라고???

바보같이 샘플 파일의 이름은 완전히 배제한 체로 그냥 무조건 까보기로 했다. (뭐든 성급하면 손해 보는 듯.. ㅠㅠ)






[그림. 3] 사용되는 API 함수들...


EP에 접근한 뒤에 무슨 API 함수들이 사용되나 대충 보려고 열어봤더니만...

그래픽컬한 작업 등에 사용되는 API 함수들이 보이지 않던가!?


GetStockObject, GetDC, LoadCursor, BitBit, ReleaseDC 등등.. 솔직히 대~~~충 의미만 좀 알뿐, 정확히 사용해보라고 하면 할 줄 모르는.. 뭐 눈치밥으로는 대충 알만한 API 함수들의 목록~


혹시나 해서 ImagePrc.exe 파일을 실행하고 흰 공백에 마우스로 그려보니, 그림이 그려지더라. -_-;


는 뻥이고~~ [그림. 3]처럼 확인하기도 전에 EP에서 바로 트레이싱 좀 해보다가 초면에 맞딱들인 처음 보는 함수인 GetStockObject가  보여서 검색을 해보니 원색을 제외한, 흰색, 검은색, 회색의 선 모양을 그릴 때에 사용되는 오브젝트 함수라는 어느 분의 설명을 보고 냄새를 맡고 그 뒤에 [그림. 3]처럼 창을 열어 보니 그래픽 관련 API 함수들이 있었다.


예제 파일의 빈 화면에는 마우스로 펜 처럼 그림이 그려진다는 사실을 그 후에 알게 됨 ㅡㅡ;






[그림. 4] 여전히 Wrong~


아무튼 뭔가 써지기는 써지지만 여전히 Wrong... 기존에 풀었던 문제를 대조해보자면 뭔가 또 비교를 하긴 하겠지!

시작은 Wrong의 메시지를 출력해주는 부분에서 해보도록 하자.

EP에 접근했다면 "All referenced text strings" 기능을 이용해서 Wrong이라는 문자열을 사용하는 위치를 찾으면 쉽게 찾아진다.






[그림. 5] MessageBox API 함수


Wrong 을 출력해주는 API 함수를 찾았다.

저 함수로 분기를 태우는 곳은 4013AA 주소로 확인이 됐고, 그럼 분기문 타기 전에 비교하는 부분이 존재하겠지!

그 부분을 체크해보자.






[그림. 6] 메시지 분기점


Wrong 메시지로의 분기점 위로 레지스터에 뭔가 작업을 하고 CMP로 비교하는 부분이 보인다.

무슨 작업을 하는 걸까?


그 작업하는 영역 더 그 위로도 FindResourceA, LoadResource, LockResource 함수들이 보이는데 이 부분은 파일 내의

리소스를 찾고 그것이 존재하면 로드하는 행위이다.

물론 제작자는 리소스를 넣어놨으니 예외처리 따윈 없었고 바로바로 사용하도록 코딩한 듯...

검색을 해보니 이 리소스에는 이미지 말고도 dll이 들어갈 수도 있다고 나온 듯 한데.. 맞나? 기억도 가물거리고...

이미지 외에는 본 적이 없으므로.. 음~ pass


암튼 MSDN을 찾아보니 파일의 리소스 영역을 갖다 쓰려면 저 API 함수들을 순차적으로 모두 써야되는 것 같다.






[그림. 7] 리소스 호출


FindResourceA 함수 사용 결과 리소스 자원의 참조 위치인 0x0047E048를 알 수 있다.

(LoadResource 시킬 인자 값으로 EAX가 PUSH 되고 있으니 FindResourceA의 결과는 EAX에 저장된 해당 주소인 것...)






[그림. 8] Resource Section


PEView로 확인해보니 리소스 섹션이 존재하며 실제로 리소스의 위치를 저장하는 포인터가 0x7E048 임을 알 수 있다.

(ImageBase가 0x400000이기 때문에 메모리 로드 시 최종적으로 0x47E048이 되겠지..)


저 포인터의 값을 참조하면 그 값이 바로 리소스가 있는 주소 되시겠다.

Size도 딱 보니 0x15F90 인데, [그림. 6]의 4013AE 주소의 코드인 CMP EDI, 15F90 이라는 것과 뭔가 좀 같은 부분도 보인다.

자~ 그렇다면 리소스를 로드한 뒤에 분기문이 뛰기 전 사이의 코드들은 무엇을 하는 걸까?

다시 한 번 훑어보자.






[그림. 9] 데이터 비교


[그림. 6]과 같은 곳의 코드 영역이다. 화면에 선택된 부분이 사용자가 그린 그림과 리소스 영역의 그림의 데이터를 비교하는 영역 되시겠다. 


40139D 주소 부분까지 트레이싱 하면 ESI 레지스터에는 사용자가 그린 그림의 데이터 영역 주소가 저장되고,

EAX에는 리소스 영역의 주소가 셋팅된다.


저 코드를 간단히 설명하자면 사용자가 입력한 그림과 리소스 영역의 그림을 한 개의 데이터(즉 하나의 pixel에 해당되는 16진수 값)를 모두 일일히 비교하면서 다른 게 있을 경우 JNZ 분기문을 타서 Wrong 메시지 함수로 보내버리고 다르지 않다면 0x15F90 번 만큼 비교 작업을 뺑뺑이 돌리겠다는 코드이다.


모든 데이터가 맞아 떨어져서 뺑뺑이가 끝나면 특정 영역을 CALL 하고 아무 일도 일어나지 않는다.

Wrong이 출력되지 않았으니 성공이라고 볼 수 있겠지만...


"이러면 정답을 뭐라고 사이트에 기재해야 하나?" 라는 생각을 잠깐 했다


비트맵 화면이니깐 그 화면을 봐야 정답을 알 수 있을 것 같은데, 어떻게 출력시키지?

리소스에 저장된 데이터가 정답일텐데, 그게 어떤 이미지 일지를 API 함수를 이용해서 보는 방법을 나는 모른다. ㅠㅠ

그것만 알아도 코드 패치 좀 하는 건데.. 뭐 암튼 gg


C++에서 그래픽컬한 함수를 전혀 사용할 줄 모르므로... 정답은 그냥 꼼수로 확인하기로 맘 먹음.


해당 예제 파일은 CreateWindowExA 함수를 이용하여 X:200 Y:150의 창을 생성하는데, 이 창 자체가 페인팅이 가능한 창이었다.

즉, 비트맵 이미지 영역은 X: 200, Y:150이라는 소리


포토샵을 켜서 가로 200과 세로 150의 비트맵 화면을 만들고 그 영역을 전부 빨간색으로 Fill 시킨 후에 BMP 파일로 저장.

BMP를 사용한 이유는 무압축 방식이니깐 포맷 방식도 아주 심플할 것이라는 단순 사고에서 나옴 -_-;


hxd로 bmp 파일을 까보니깐 내가 채워넣은 색수에 해당되는 16진수 값이 채워진 영역은 그냥 봐도 딱 알정도로 나오더라.

(내가 채운 색의 hex 값은 포토샵에서도 나오니깐 확인하기 참으로 편하다. ㅋ)


자~~ 사이즈도 같게 했고, 그 영역에 예제 파일의 리소스 영역의 hex 값을 몽땅 over write 시키고 저장하니

그 BMP를 출력한 결과 정답이 짜잔 하고 나옴.


정답은 사람들이 뭔가 딱 그 거시기 했을 때 환호하는 문장에 포함되는 단어였다. 게임에서도 꽤 나오는... -_-;


이번 문제는 그림을 어떻게 API 함수를 이용해서 출력시켜야 하냐를 무쟈게 고민한 것 빼고는 빠르게 풀렸다.