[CodeEngn Basic 1] Do you Know GetDriveType?

2017. 8. 20. 01:180x02 Reverse Engineer/0x01. CodeEngn

728x90

문제 : 

What value must GetDriveTypeA return in order to make the computer recognize the HDD as a CD-Rom ? 


바이너리 동적 실행:


 

 [그림 1] 바이너리 실행

음.. CD-Rom인지에 대해서 생각을 해봐라고 주문하고 있다.


 

 


 [그림 2] 바이너리 실행

지금 현재의 상황은 CD-Rom 드라이브가 아닌가보다.


OllyDbg Let's get it! 


OllyDbg라는 프로그램으로 바이너리를 개봉해보면 엔트리포인트가 바로 휙 하고 보인다. 메인의 시작 주소는 00401000인것을 우선 파악하고 넘어가자.


아까전에 봤던 메시지 박스 구문이 4개의 매개변수로 묶여 있는 MessageBoxA API함수에 의해 나열이 되어 있다. 


그 후, GetDriveTypeA라는 함수의 매개변수가 c:\로 되어 있다.

그 말인 즉슨, 현재는 CD-Rom이 아니라는 것을 확실히 알 수가 있다.


 

 [그림 3] 메인 함수의 첫 부분에 두가지의 API함수가 나열되어 있음



GetDriveTypeA함수는 MSDN을 참고하지 않으면 감을 잡을 수가 없다. 

링크와 함께 자료를 수집해왔다.

 

 [그림 4] GetDriveTypeA 함수의 반환 값들...


funcA는  멀티바이트 함수 또는 변수를 의미합니다.

funcL은 문자열 앞에 L 을 붙이는 이유는 멀티바이트에서 유니코드를 사용하기 위해서 입니다.

funcW는 W는 유니코드 함수 또는 변수를 의미 합니다


https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa364939(v=vs.85).aspx  


우선 루틴을 F8(Step Over)로 트레이싱 해본다. GetDriveTypeA 함수가 끝나고 어떠한 반환값이 나타나는지 보기 위해서 이다.


 

 [그림 5] GetDriveTypeA 함수에서 반환 받은 값


0040101D  |.  46            inc esi

0040101E  |.  48            dec eax

0040101F  |.  EB 00         jmp short Reverse_.00401021

00401021  |>  46            inc esi

00401022  |.  46            inc esi

00401023  |.  48            dec eax

00401024  |.  3BC6          cmp eax,esi

00401026  |.  74 15         je short Reverse_.0040103D


현재 eax값은 3, esi는 0이었는데, dec eax를 만나서 2가 될 것이고, inc esi를 만나 1이 되며 jmp 명령어를 만나서 00401021주소로 점프하고, esi +2 시켜서 3이 되고, eax는 1이 되면서 cmp명령어를 만나서 뒤-앞 공식이 적용되게 된다. 


현재는 je가 성립하지 않기 때문에 00401026 밑의 주소에 접근하게 된다.

 

 [그림 6] cmp에서 je가 만족하지 않는 루틴 


자 je가 만족하지 않았기 때문에 이 메시지를 뿜어낸다.

 


 [그림 7] 정답이 아닌 루틴에 접근했을 시 화면 


자 그렇다면 이제 고민에 한번 빠져봐야한다. 아까 msdn의 문서를 떠올려보면 반환값 eax레지스터의 값이 5가 되어야 한다. 레지스터를 강제로 조작해보는 방법부터 해보자.


Stage1. 레지스터를 조작하라!

순조롭게 401018주소까진 쭉쭉 트레이싱하자.


00401000 >/$  6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL

00401002  |.  68 00204000   push Reverse_.00402000                   ; |Title = "abex' 1st crackme"

00401007  |.  68 12204000   push Reverse_.00402012                   ; |Text = "Make me think your HD is a CD-Rom."

0040100C  |.  6A 00         push 0x0                                 ; |hOwner = NULL

0040100E  |.  E8 4E000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA

00401013  |.  68 94204000   push Reverse_.00402094                   ; /RootPathName = "c:\"

00401018  |.  E8 38000000   call <jmp.&KERNEL32.GetDriveTypeA>       ; \GetDriveTypeA


아니다.. cmp eax, esi까지 과감하게 트레이싱 하자!


0040101D  |.  46            inc esi

0040101E  |.  48            dec eax

0040101F  |.  EB 00         jmp short Reverse_.00401021

00401021  |>  46            inc esi

00401022  |.  46            inc esi

00401023  |.  48            dec eax

00401024  |.  3BC6          cmp eax,esi


그 후에 이쁜 사진을 한 장 가져오겠다.

 

 [그림 8] EAX와 ESI를 같게 해버렸다.


 


 [그림 9] 올바른 위치로 점프가 되었다.


 

 [그림 10] 올바른 결과 값 도출 !! 


Stage 2. GetDriveTypeA 함수의 반환 값을 조작해볼까? (정석)


 

 [그림 11] 레지스터 값 조작 (feat. GetDriveType의 흐름에 맡겨)


0040101D  |.  46            inc esi

0040101E  |.  48            dec eax

0040101F  |.  EB 00         jmp short Reverse_.00401021

00401021  |>  46            inc esi

00401022  |.  46            inc esi

00401023  |.  48            dec eax

00401024  |.  3BC6          cmp eax,esi


이 루틴을 다시 거치면 eax=3, esi=3 이 되어 

00401026  |. /74 15         je short Reverse_.0040103D가 만족된다.


Stage 3. 왠만하면 하지말았으면 하는 je -> jmp 우회 


이런 유형에서부터 이렇게 익숙해져버리면 크랙미나 키젠 문제에서 정확한 플래그 값을 찾을 수가 없긴 하지만, 점프를 꼭 우회해야 하는 문제나 실제 프로그램도 있기 때문에 설명한다.


레지스터를 조작하지 않았다면, cmp eax,esi를 만났을 때 eax는 1, esi는 3으로 같지 않다. 그러면, 00401026  |. /74 15         je short Reverse_.0040103D

불 만족하기 때문에 


00401028  |.  6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL

0040102A  |.  68 35204000   push Reverse_.00402035                   ; |Title = "Error"

0040102F  |.  68 3B204000   push Reverse_.0040203B                   ; |Text = "Nah... This is not a CD-ROM Drive!"

00401034  |.  6A 00         push 0x0                                 ; |hOwner = NULL

00401036  |.  E8 26000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA


여기로 갈 수 밖에 없다. 그런데 만약 je를 jmp로 고친다면?

00401026  |. /74 15         jmp short Reverse_.0040103D

00401028  |. |6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL

0040102A  |. |68 35204000   push Reverse_.00402035                   ; |Title = "Error"

0040102F  |. |68 3B204000   push Reverse_.0040203B                   ; |Text = "Nah... This is not a CD-ROM Drive!"

00401034  |. |6A 00         push 0x0                                 ; |hOwner = NULL

00401036  |. |E8 26000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA

0040103B  |. |EB 13         jmp short Reverse_.00401050

0040103D  |> \6A 00         push 0x0                                 ; |/Style = MB_OK|MB_APPLMODAL

0040103F  |.  68 5E204000   push Reverse_.0040205E                   ; ||Title = "YEAH!"

00401044  |.  68 64204000   push Reverse_.00402064                   ; ||Text = "Ok, I really think that your HD is a CD-ROM! :p"

00401049  |.  6A 00         push 0x0                                 ; ||hOwner = NULL

0040104B  |.  E8 11000000   call <jmp.&USER32.MessageBoxA>           ; |\MessageBoxA


레지스터 두개 비교 할 필요 없이 성공을 뜻하는 메시지로 점프하게 된다.