본문 바로가기

Reverse Engineering

올리디버거(OllyDBG)를 이용한 CrackMe 문제 풀이


crackme author : abex
type                 : cdrom check
level                 : easy
tute author         : HaQue


Ollydbg.exe 실행해서 abexcm1.exe를 open한다.
프로그램이 어떻게 작동되는지 보기 위해 Run(F9)을 한다.


첫 번째 메시지박스가 나타나고, 확인을 클릭하면 두 번째 메시지박스가 나타난다.


확인을 클릭하고 올리디버거를 보면 프로그램이 종료되었음을 알 수 있다.


첫번째 메시지박스에는 CD-ROM을 체크하는 루틴을 우회하라고 나오고
두번째 메시지박스에는 CD-ROM이 아니라고 하며 프로그램이 종료되었다.


이 문제를 푸는 방법에는 메모리 주소 흐름을 바꾸는 방법과, CD-ROM을 체크하는 함수의
리턴값을 변경해서 푸는 방법 2가지 방법이 있다.


1번 방법 풀이(메모리 주소 흐름 변경) : 

취약한 프로그램 리버싱 순서 :
1. 프로그램 흐름 분석
2. 문자열을 이용한 특정 이벤트 시점 찾기
3. 성공이었을 경우의 문자열 위치를 찾아 무조건 성공하도록 흐름 변경

프로그램의 흐름을 파악했으니 문자열을 통해 특정 이벤트 시점을 찾아보겠다.
프로그램이 종료되어 있는 상태니 Restart한다.(Ctrl + F2)  어셈블리코드가 보이는 화면에서 우클릭후 Search for -> All referenced text strings 를 선택후 문자열을 확인해본다.


문자열 목록을 보면, CD-ROM이 인식되었을때는 00401044 주소의 값이 출력되는 것을 예상
할수 있다. 해당 문자열을 더블 클릭하여 해당 주소지로 이동하자.


위에 GetDriveTypeA라는 드라이브의 유형을 리턴해주는 API가 보인다.(두번째 풀이는 이 API를 이용한다)
또 JE문에 의해 점프를 할때에는 성공 메시지박스가 점프를 안할 때는 실패 메세지박스가 뜬다. 실패메시지박스가 뜬 뒤에는 JMP구문에 의해 프로세스가 종료된다. 그러므로 JE문을 JMP문으로 바꿔준다면 ZF플래그와 상관없이 무조건 성공메시지박스만이 뜰것이다.

                  (어셈블리어 참고 : http://dakuo.tistory.com/entry/기초-어셈블리어)


수정을 하고 나서 Run(F9)을 하면 문제가 풀어진 것을 알수 있다.
수정한 내용을 파일로 저장을 하기 위해 수정한 부분에서 우클릭 후 Copy to executable -> All modifications를 선택한 후 Copy all을 클릭한다.


수정된 어셈블리어들이 나타난 창에서 우클릭 후 Save file을 선택한다.




2번 방법 풀이(WinAPI함수의 리턴값 변경) :

E 버튼을 눌러서 Executable modules창을 연다.
실행중인 문제 파일인 abexcm1.exe 항목에서 우클릭 후 View Names를 선택한다.


사용되고 있는 api함수 목록을 볼수 있다.
GetDriveTypeA라는 함수가 드라이브의 유형을 리턴해줄것 같다. 원형을 보기 위해서 우클릭후 Help on symbolic name을 선택한다. 기존에 연결시켜 놓은 헬프 파일에서 해당 api이름을 검색해서 보여준다.


레퍼런스를 확인하면 목적, 파라미터, 리턴값을 알 수 있다.
그런데 리턴값에서 0, 1 다음에는 문자열로 지정되어 있다. 정확한 값을 알기 위해 MSDN에서 검색해보면 CDROM은 5가 리턴된다. 이제 Breakpoint를 설정하여 해당 api가 실행되는 과정을 분석하고, 리턴 값을 수정해주면 된다. 해당 api함수에 우클릭 후 Set breakpoint on every reference 메뉴를 선택한다. Command Line이라는 플러그인에서 bpx 함수명으로 명령을 주는 것과 비슷한 기능이다.(이플러그인은 기본플러그인이다) plugin메뉴 -> Command line -> Command line을 선택해주면 창이 생긴다. 여기서 bpx GetDriveTypeA라고 명령어를 치면 해당 api에 모두 브레이크 포인트를 설정해준다. 익숙해지면 디버깅 속도를 단축시킬수 있어서 편리하며, 찾고 싶은 api를 미리 알고 있다면 특정 시점을 찾기가 쉬워진다.


(참고로 Command Bar(cmdbar.dll)라는 플러그인을 사용하면 올리디버거 하단에 붙어있어서 자주 커맨드 명령을 사용할 경우 Command Bar를 사용하는것이 효율적이다. 올리디버거 플러그인이 잘 정리된 곳으로는 OpenRCE가 있다)

 

CPU창에서 Run(F9)을 해보면 GetDriveTypeA에서 멈추게 된다. Step Over(F8)시켜서 api를 실행시킨다.


위부분은 api가 실행된 후부터 (성공or실패)메시지박스를 만나기 위한 분기점까지의 어셈코드이다. 이부분을 해석하면


마지막에 DEC EAX 구문만 없으면 CMP EAX ESI 에서 2 : 2로 똑같아져서 JE문에서 점프를 하게 된다. DEC EAX 를 NOP로 바꾸자. 변경을 한 후에 Run(F9)를 해보면 문제를 푼 것을 확인 할수 있다. 변경한 코드를 저장하면 모든 풀이가 끝이 난다.