본문 바로가기

Reverse Engineering

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

이번에 풀어볼 문제는 upx로 패킹이 되있는 문제로 upx -d 옵션으로 압축을 풀어도 되지만 메뉴얼 언패킹하는 방법을 간단하게 설명하기 위해서 올리디버거의 덤프 플러그인을 사용하여문제를 풀어보도록 하겠다.
다음을 다운받아 Plugin 폴더에 넣는다.


올리디버거의 메모리 덤프의 리빌드 기능만으로도 upx 압축은 풀리기 떄문에 쉽게 따라할 수 있는 문제이다.


먼저 PEID로 바이너리를 확인해본다.
               (PEID 사용법 참고 : http://dakuo.tistory.com/entry/바이너리-분석)


upx 압축되어 있는 문제 파일인 CrackMe2.exe를 올리디버거로 열어본다.


코드가 압축되었으며, 분석을 더할 것인지 묻는다. 예를 누른 후 아래쪽으로 내려가다 보면 압축이 모두 풀려서 메모리에 올라가 있는 초기 상태인 OEP(Original Entry Point)부분으로 가는 JMP문이 나타난다.


upx 같은 경우는 프로세스를 보호하기 위해서 압축하는 것이 아니기 때문에 OEP를 찾는 것이 어렵지 않다.
JMP구문에서 Breakpoint(F2)를 설정하고, Run(F9)을 하면 이 주소에서 Paused가 된다.
Step Over(F8)을 한 번 해주면 OEP(Original Entry Point) 위치로 이동한다.

PUSH EBP 위치에서 올리디버거의 plugin의 덤프를 하면 된다.


마우스 우클릭 후 Dump debugged process를 선택하거나 플러그인 메뉴에서 선택을 해도 된다.



올리디버거의 덤프 플러그인에 import 테이블을 리빌드하는 옵션이 있다. upx로 된 경우에는 옵션을 체크한 후에 덤프 버튼을 누르면 메모리상의 프로그램이 덤프가 되어 압축이 풀린다. 파일을 저장하고 정확하게 되었는지 PEID로 확인해보면


upx 압축이 풀리고 제작 툴인 볼렌드 델파이라고 탐지해주는 것을 확인할 수 있다.

upx가 패킹을 하는 원리는 기존의 소스 코드 부분들을 모두 새로 만든 upx 섹션에 압축하여 저장을 해놓고, 실행 부분에서는 upx 섹션에 저장해놓은 부분을 풀어서 메모리에 올리게 된다. 이런 원리로 압축이 다 풀려서 OEP(Original Entry Point)로 가게되는데, 이 부분에서 메모리상의 프로그램을 덤프받는 것이다. 그냥 덤프받으면 IAT 정보가 정확하지 않으므로 덤프 플러그인의 옵션에서 Rebuild Import를 체크하는 것이다. 저장한 파일을 올리디버거로 열어서 Run(F9)을 눌러 프로그램이 어떤 문제인지 확인해보면


실행 후 시리얼을 넣는 editbox가 있으며 시리얼을 넣고 check the serial 버튼을 누르면 Wrong Serial이라는 타이틀의 메시지 창이 나타난다.


스트링 검색을 해서 이벤트 시점을 찾아도 되지만 새로운 방법으로 풀어보겠다. 메시지 창이 나타나는 경우 더 빠르게 이벤트를 찾을 수 있는 방법이다.


Back to user mode : 
특정 이벤트를 일어나기 전에 설정해두고 Call 명령이 일어난 바로 다음 위치를 잡을 수 있다.

사용순서 :

1. 프로세스 attach(open)
2. Run(F9)
3. 프로그램을 메시지 창과 같은 정지된 상태로 만든다.
4. paused(F12)
5. back to user mode(Alt+F9) 설정
6. 프로그램에서 이벤트 발생(메시지 창에서는 확인 버튼 클릭)
7. 올리디버거에서 해당 부분에 커서가 설정된다.

(주의할 점 : back to user mode 기능은 브라우저나 내부 스레드가 작동하는 프로그램의 경우에는 내부 이벤트가 수시로 일어나서 해당 모드가 풀려버리니 사용하려면 메시지 박스와 같이 프로세스가 멈추는 상태에서 사용한다)

Wrong Serial 창이 뜬 상태에서 올리디버거에서 일시정지(F12)를 시킨 후에 back to user mode 설정키인 Alt + F9를 눌러준다.
Debug 메뉴에서 Excute till user code를 선택해도 된다.


일시정지(F12)를 하면 Paused라고 표시가 되고,


Alt + F9를 누르면 back to user mode가 표시된다.


이런 상태에서 CrackMe 문제의 메시지 창의 확인 버튼을 눌러준다.

보이는 것과 같이 MessageBoxA 함수가 호출된 다음의 위치가 선택된다.
틀렸다는 메시지 창이 나타나는 곳은 찾았으니 그 메시지 내용이 설정되는 곳을 찾기 위해 파라미터를 확인한다.

MessageBoxA를 Winapi 확인을 해보면 다음과 같다.


메시지 내용인 "You are a bad cracker!"가 어디에서 입력됬는지 어셈블리 코드에서 Text 부분이 입력되는 곳을 확인한다.


PUSH ESI를 통해서 파라미터가 들어갔음을 알 수 있다.
올리디버거의 CPU 레지스터값을 보면 우리가 찾는 Text가 있다.


Ctrl+G 단축키를 이용하여 ESI가 가리키고 있는 주소인 00442C68를 입력하면 다음과 같은 곳으로 이동한다.


문자열들이 보인다. 이 부분에서 한 페이지만 위로 올려보면 값들이 구분되는 부분이 보인다.


첫 줄에서 Value 창을 확인하면서 Breakpoint를 잡아놓고 StepOver하다 보면 내가 입력한 값이 들어가는 것을 볼 수 있다.



1234라고 입력한 값이 Value창에 찍히는 것을 볼 수 있다.


다음 줄에서 시리얼같은 값이 EDX에 저장되고, CALL 명령이 실행되면서 StepInto(F7)을 하여 내부로 들어가서 확인해보면 CMP를 통해 입력한 값과 시리얼 키를 비교하는 부분이 나타난다.



결정적으로 JNZ 구문에서 "Congrats! You were successful!"과 "You are a bad cracker!"가 구분된다.

이 문제 같은 상황에서는 back to user mode 기능을 사용하면 보다 빠르게 분석을 할 수 있다.

이제 "12011982" 숫자 값을 넣어서 확인해보자.