본문 바로가기

Rerversing/Exercise reversing

[Reversing.kr] - Music_Player 문제 풀이

네 번째 문제 풀이 시작.


이번 예제 파일에도 ReadMe.txt 파일이 존재한다. 읽어보자.


This MP3 Player is limited to 1 minutes.

You have to play more than one minute.


There are exist several 1-minute-check-routine.

After bypassing every check routine, you will see the perfect flag.


MP3 Player가 1분 밖에 재생을 못한다고 하는데, 그 1분을 체크하는 몇 몇 루틴을 모두 재껴버리면

Flag 값을 볼 수 있다고 한다.


나머지 첨부된 파일들을 보면 msvbvm60.dll, Music_Player.exe 가 존재하는데, msvbvm60.dll은 Visual Basic 엔진이다.

즉, 이번 문제는 Visual Basic으로 만들어진 녀석이란 건데.... 하아~ 난 VB에 정이 붙질 않는다. 쩝! ㅠㅠ






[그림. 1] 재생 화면


3분 넘는 곡을 재생해보니 Time Bar 부분이 01:00 으로 제한이 되어 있고, 실제로 1분만 재생된다.

저 1분 제한을 풀어주면 정답을 알 수 있단 말이지...






[그림. 2] 1분 제한 메시지


1분의 플레이가 모두 완료되면 [그림. 2]와 같은 메시지 박스가 출력된다.

자!~ 이 부분이 분석 시작에 도움을 주는 힌트가 될 터...






[그림. 3] ThunRTMain 함수 호출


VB 6.0으로 만들어진 파일은 Entry Point에 들어오자마자 VB 엔진 영역을 호출시킨다. 위 그림의 CALL 함수는 401472의 점프문을 호출하고, 그 점프문이 실행되면 VB 엔진 영역으로 이동하게 된다.

난 "개취" 상 디버거 옵션에서  show symbolic address 기능을 켜놓고 사용하기 때문에 CALL 뒤에 주소가 아닌 심볼명이 나타난 것이다. (착오 없으시길....)


해당 함수를 호출하기 전에 PUSH 된 것은 ThunRTMain 함수에 대한 인자값인데, 그 주소 영역에 RT_MainStruct 구조체가 셋팅이 되어지고, 그 구조체는 또 다른 구조체의 주소들로 구성되어 있다고 알려져 있다.

[그림. 3]에서 HEX 영역에 표기한 4017CC 영역 부분이 그 구조체가 세트되어 있는 영역이지만 그 구조체의 구조를 알지도 못하고, MS에서는 공개도 안 했다고 하니... 뭐가 뭔지 알 수가 없다. 

컴파일 옵션(P mode, N mode 라는 게 있다고 하네... 본 적은 없음.)에 따라서 VB의 저러한 구성이 달라진다고는 하지만 여태 본 VB 파일들은 죄다 저런 유형이었으며 그 점 때문에 암튼 VB로 만든 파일에 정이 가지 않는다.

(VB Decompiler 가 있다면 속은 좀 편해질지도.. 유료로 질러? -_-;)


자.. 복잡한 과정을 거치지 말고 역으로 접근을 해보자.

1분의 재생이 끝나고 발생한 이벤트인 "1분 미리듣기만 가능합니다." 메시지 박스....

Visual Basic 에서 메시지 박스를 발생시키는 함수 코드를 찾아서 그 기점으로 한 번 훑어보는 건 어떨까?






[그림. 4] rtcMsgBox 메시지 함수 호출 목록



Visual Basic 에서 메시지 함수를 호출하는 함수는 rtcMsgBox 이다.

그렇다면 1분 메시지를 발생시키는 함수는 어디일까?

모두 BP를 걸고 1분 재생을 시켜보면 알 수 있지 않을까 싶다.

BP를 다 걸고 파일 자체를 완전히 실행시켜서 플레이어가 구동되도록 하자.


참고로 내 Windows 7 x64 OS에서는 문제가 하나 생겼다. (다른 이들도 그랬을지 모르겠지만...)


F9를 눌러서 플레이어를 우선 실행 시키고, OPEN 버튼을 눌러서 내가 재생시킬 MP3 파일을 선택을 해봐야 할텐데....

OPEN 버튼을 눌러서 파일창이 실행이 되려다가 난데없이 디버거에서 EXCEPTION이 걸린다.

Exception 0000006BA 라는 코드가 뜨는데, 검색해보니 윈도우 7에서의 다이얼로그 관련 버그라고 하는 글귀도 있다.

예외가 걸린 주소 자체를 디버거의 exception ignore 기능을 이용하면 되는데, 그렇게 해도 그 다음에도 예외가 걸리더라.

그 후에도 또 걸리고... 이거~ 일일히 예외 무시를 걸어주기도 지겨워서 OPEN 버튼 안 누르고 경로 이름 적는 곳에 파일 이름을
직접 적고 재생 버튼 클릭하니 예외 안 뜨고 재생이 잘만 된다. (괜히 예외 걸리는 부분 하나씩 다 해본 게 억울.. ㅋ)


또 한가지....


노래 1분 끝날 때 까지 언제 기다리나? 플레이 타임바를 1분 끝나는 지점 쪽으로 끌어다가 1분 재생을 순식간에 완료하려고 잔머리를 굴렸지만 디버깅 상태에서 그 짓을 하면.... 여지없이 EXCEPTION 에 또 걸린다.

이 부분은 편의를 위해서라도 역시나 예외가 걸리는 지점을 디버거 옵션에서 수동으로 ignore 시켜주자.

그렇게 하면 반복 분석을 위해 몇 번이나 타임바를 움직여도 예외가 걸리는 일은 없을 것이다.






[그림. 5] 메시지 함수로의 분기문



내 PC에서는 메시지 함수의 발생 주소가 4045D8로 나타났다. 1분이라는 조건에 걸려서 메시지 함수로 넘어왔으니 분명 그 쪽

주소로 태우는 분기문이 존재할 터... 코드를 위로 올려보니 40456B 분기문이 메시지 함수로 보낼지 말지를 결정하는 곳이다.


분기문 바로 위에 보니 EAX 레지스터와 0x0EA60 값을 비교하고 EAX 값은 [EBP-18] 위치로 저장시킨 후에 분기문을 태운다.

0x0EA60 을 10진수로 변환하면 60000이라는 값이 나온다. 이는 아마도 60000ms(60sec)를 의미하는 것일 터...

404563 주소에 BP를 걸고 처음부터 재생을 하면 그 위치에 걸리는 것을 보게 될 것이다.

F9를 눌러서 재생을 강행시킬 때 마다 EAX 값이 변하는 것을 볼 수 있다. 즉, 곡을 재생하면서 계속해서 시간을 체크한다는 뜻...

60초가 넘어가면 1분 메시지 발생 함수가 실행되니 아예 40456B의 JL문을 JMP로 바꿔서 계속 점프되도록 하자.






[그림. 6] 두 번째 분기문



[그림. 5]에서 수정된 점프문을 타고 4045FE 주소로 이동하는데, 여기서도 곧바로 EAX 값을 -1 (0xFFFFFFFF) 값과 비교한다.

0xFFFFFFFF 값과 같으면 점프하고 아니면 그냥 코드를 쭉 진행하게 되는데, 곡이 10분 짜리라고 해도 10분의 시간을 16진수로 변경하면 0x00927C0 이기 때문에 0xFFFFFFFF 과 같아질 수가 없기에 일반적으로 점프할 일은 없을 것이다.

만약 이 부분의 JE 코드를 그냥 JMP 시키면 곡이 줄창 끝날 때 까지 잘재생된다.

그러나 플레이바의 미동도 없고, 곡이 끝날 때 까지 정답은 나오지 않는다.

즉, 이 영역의 코드를 점프시키지 말고 원활하게 돌게해야 뭔 일이 일어나도 일어난다는 걸 예상할 수 있겠다.

암튼 코드 수정은 하지 않는 걸로 하고 이 상태로 곡을 1분간 재생시키면 곡이 다 끝났기 때문에 또 다시 EXCEPTION 이 발생하게 되는데 발생된 EXCEPTION 역시 ignore 처리를 해주고 재차 확인하자. 이 파일의 목적은 시리얼 키를 알아내는 것이니...






[그림. 7] Run time error 380 오류 발생


[그림. 6]에서 설명한 듯이 1분 재생 완료 시의 예외 처리를 ignore 시켜버리면 이렇게 오류 메시지가 발생하게 된다.

곡은 쭈욱 재생되고 있지만 확인 버튼을 클릭하면 프로그램 자체가 강제 종료된다.

그렇다면 코드 내에서 특정 조건 시에 예외 이벤트를 발생시키는 영역이 존재할텐데, 어디일지를 한 번 찾아보자.






[그림. 8] vbaHresultCheckObj 함수


[그림. 6]에서 언급된 분기문 아래 영역에 존재하는 나머지 코드들을 훑어보면 RETN 하기 전 까지 존재하는 함수들은 대개 스트링 관련 함수들과 vbaHResultCheckObj 라는 함수로 짜여져 있다.

HResult 라는 단어가 왠지 좀 걸리적 거렸는데, C언에서 try ~ catch에서 쓰던 걸로 기억한다.

try문에서 오류 발생 시에 MAKE_HRESULT 함수로 오류의 상태 정보를 만들어서 catch 문에 HRESULT이라는 타입으로 던져서 썼는데, VB에서의 해당 함수도 오류 관련 시에 쓰이는 것이라고 판단... 

(좀 더 정확히 알고 싶지만 구글신에서 검색이 잘 안 되고 있음. ㅠㅠ)


뭐 솔직히 애러난 부분에서 call stack 을 확인해보면 VB 엔진의 vbaHresultCheckObj 함수가 동작된 걸 볼 수 있다. -_-;


2개의 vbaHResultCheckOb 함수에 BP를 걸어보니, 곡 재생이 완료된 후에 첫 번째 vbaHResultCheckObj 함수에서 걸렸고,  그 함수를 실행하면 [그림. 7]의 오류 창을 발생시키는 것이 확인되었다.


해당 함수 위에 4046AB 주소를 보면 JGE 분기문이 보이는데, 1분 미만 재생 시에는 해당 점프문을 타고 점프하다가 1분이 넘어가면 점프를 하지 않고 vbaHResultCheckObj 함수로 진입을 해버리는 것이 확인이 되었기에 JGE 코드에 걸리지 않도록 무조건 점프를 시키도록 해보자.






[그림. 9] 패스워드 겟~


드디어 패스워드가 제목 표시줄에 표기되었다. 재생도 멈추지 않고 계속 된다. 이로서 성공~~


지문에도 나왔듯이 1분 체크 루틴을 bypass 시키면서 그 뒤에 벌어지는 현상들을 예외처리 하며 접근해오니 정답을 알게 됐지만 이렇게 푸는 건 글쎄~~~ 수학 문제를 꼼수로 풀준 알았을지언정 정석대로 착착 풀었다는 느낌이 들지 않은 것과 같다고 해야 할까? 그래서 좀 찝찝하긴 하다.


초기에는 시간 체크 방식에 대한 기준을 여러 방면으로 생각하다보니 너무 어렵게만 시작을 해버렸는데

막상 풀고나니  너무 헛짓을 많이 했다는 느낌이 든다. 그러나 정작 풀고나서도 그 과정이 상당히 찜찜하다.

정답만 맞추면 망고 땡~ 이라는 건 위험한 발상이긴 하니....


만약 제시된 문제가 1분만 재생되는 것을 해제하고 플레이 타임바도 시간에 맞게 움직이게 만들라고 했으면....

아마도 나는 혀를 내두르고 포기했을 것이다.

(UI쪽은 전혀 모르므로... -_-)


머 암튼 특정 비교 구간 및 예외(애러 발생)로 빠지는 부분들을 무력화 시키면 접근하지 못했던 코드들이 실행되면서 자연스럽게 몇 개로 쪼개져 있던 패스워드 문자열을 하나로 모아서 UI에 뿌려주는 구조였다.