본문 바로가기

리버스엔지니어링/크랙미 풀이

CodeEngn Basic RCE L01 문제 풀이

일단 프로그램을 무작정 뜯어보기 전에 프로그램에 대한 설명을 보겠습니다.

Korea : 로 써있는 부분에 "HDD(하드디스크)를 CD-Rom으로 인식시키기 위해서는 GetDriveTypeA의 리턴값이 무엇이 되어야 하는가" 라고 써있는데요.

이 GetDriveTypeA라는 함수가 어떤 함수인지 알아보겠습니다.

 

 

 

 

-출처 MSDN

 

이 함수의 리턴 값에 대한 것인데요

이 프로그램이 실행된 드라이브를 리턴값으로 하는데요 그 값들로는 각각 드라이브를 찾을수 없음(0), 최상위경로가 없음(1), 이동식디스크(2), 고정디스크(3), 네트워크드라이브(4), cd롬(5),램디스크(6) 으로 되있는 데요, 우리가 찾는 HDD와 CD롬은 각각 3과 5에 있습니다.

 

그냥 문제만 풀거라면 CD롬을 가리키는 □번을 정답으로 쓰면 되겠지만 당연히 답만 알기위해 이 문제를 풀진 않겠죠 ?

그럼 프로그램 분석에 호기심이 있을것이라 믿고 이정도로 프로그램을 실행하기 전 정적분석을 끝내고 이제 직접 프로그램을 돌려보는 동적분석을 하겠습니다.

 

 그림1-1

 프로그램을 켜보면 '이 하드디스크를 CD롬으로 인식하게 해라'라고 하는데요 그대로 하드디스크에서 실행하면

 그림1-2

이 드라이브는 CD롬이 아니라고 합니다.

 

그럼 이제 이 프로그램을 올리디버거를 이용해서 분석해보겠습니다.

 

소스를 보니까 굉장히 짧은데요 L01이라서 그런가 어셈블리어로 제작해 디버거로 열었을때도 소스가 짧고 간단하게 보입니다.

 

간단하게 중요한 부분들만 모아서 보면요

 

0040100E  call <jmp.&USER32.MessageBoxA>  //MessageBoxA API 함수 선언 => 그림1-1의 메시지를 띄웁니다.

 

00401018 call <jmp.&KERNEL32.GetDriveTypeA> //GetDriveTypeA API 함수 선언 => 프로그램이 실행된 드라이브 정보 얻음

 

00401024 cmp eax,esi //EAX,ESI 레지스터를 비교

00401026 je short Reverse_.0040103D // 그 결과 같으면 0040103D 주소로 이동

 

00401036 call <jmp.&USER32.MessageBoxA> // 타이틀:Error, 내용:Nah... This is not a CD-ROM Drive! 라는 메시지 창을 띄웁니다. (그림1-2)

 

0040104B call <jmp.&USER32.MessageBoxA> // 성공했다는 메시지 창을 띄웁니다.

 

저희가 실제로 원하는 메시지 창은 그림1-2의 실패창이 아니라 0040104B에서 선언하는 메시지창입니다.

그러기 위해서는 00401024에서 EAX와ESI 가 같아야 합니다.

그럼 여기서 EAX와 ESI는 각각 무었일까요? 그걸 위해 실제로 돌려보겠습니다.

 

일단 소스 한줄마다 어떤 일을 하는지 알기위해서 자동 실행이 아니라 한줄씩 내려가게 실행시켜볼건데요,

올리디버거가 한줄씩 실행시키게 지원하는 기능은 2가지가 있는데요

바로 F7,F8키를 이용하는 법입니다.

F7키와 F8키의 공통점으로는 모두 한번 누를때 마다 한줄씩 내려가면서 실행과정을 볼수 있는데요

차이점은 F7키는 함수를 만나면 그 함수 안으로 들어가서 한줄씩 모두 실행해보고,

F8키는 함수 안쪽부분은 자동으로, 함수 밖부분은 한줄씩 실행합니다.

 

아직 API함수를 선언하는것을 분석하는 능력은 없으므로 우리들은 모두 F8키를 이용해서 함수 밖 부분만 분석을 해보겠습니다.

F8키를 눌러서 계속 내려가다 보면 0040100E 에서 커서가 멈춰있는 상태로 움직이지 않을텐데요

이부분은 MessageBoxA 함수를 선언하여 그림 1-1의 창을 띄우게 됩니다.

그럼 확인을 누르면 바로 다음줄인 00401013으로 커서가 이동이 되는걸 보실수 있으실 겁니다.

 

저희가 원하는 00401018에 있는 GetDriveTypeA 함수이므로 한줄밖에 안되지만 F8키를 눌러 쭉 이동해서 GetDriveTypeA함수를 실행해봅시다.

실행하면 오른쪽에 있는 레지스터창에 EAX값이 바뀔텐데요

GetDriveTypeA의 리턴값이 EAX에 대입(?)되는것을 보실수 있을겁니다.

 

다시 저희가 실제로 Error라고 뜨느냐, Yeah 라고 뜨느냐를 결정짓는 00401024주소로 달려보겠습니다.

 

중간에 inc와 dec 명령이 많이 보이는데요 이것은 리버싱작업을 힘들게 하는 쓰레기코드라고도 합니다.

하지만 호기심이 넘치는 사람이라면 당연히 이것도 분석을 해봐야되는데요

0040101D주소부터 00401026까지 ESI와 EAX레지스터의 변화량을 보면 ESI는 3이 증가하고, EAX는 2가 감소한다는 것을 보실수 있습니다.

그리고나서 CD-ROM이라 인식되기 위한 리턴값인 □-2와 ESI의 값인 3을 비교하고(cmp eax,esi), 같으면 0040103D(성공구문)으로 점프(je)한다는것을 보실수 있습니다.

그럼 언제나 실패가 아니라 성공을 하기 위해서는 EAX와 ESI의 값이 같을때만이 아니라 언제나 0040103D주소로 이동을 해야 하므로 JE를 JMP로 바꿔주시면 되겠습니다.

소스를 바꾸는 방법은 그 주소를 클릭해서 회색으로 바꾼다음, 스페이스바를 눌러서 오른쪽에 보이는 Assemble창을 띄우고 원하는 명령으로 바꾸는 것입니다.

이제 분석을 끝내고 완전한 크랙버전으로 프로그램을 만들것인데요,

 저처럼 je를 jmp로 바꾸신 다음

명령을 바꾸신 부분을 포함하게 드래그를 하고 오른쪽 클릭을 하셔서 Copy to executable -> Selection을 누르시면 새로운 창이 뜹니다.

 

이런 새로운 창에서 Save file을 누르고 원하시는 이름으로 바꾼 다음에 실행시키면 됩니다.

 

 

저같은 경우는 구분하기 쉽게 원 파일이름+fixed라고 쓰는데요 이렇게 성공메시지가 뜨면 성공입니다.

 

이렇게 Basic RCE L01을 풀었는데요

중간 중간 소스를 모르는것이 굉장히 많을 것입니다.

하지만 영어를 할때도 핵심 단어들만 가지고도 의사소통은 어찌어찌 할 수 있지 않습니까?

그렇듯 모든 뜻을 알지는 못해도 프로그램의 흐름정도를 파악할 수 있다면 저는 어떤 프로그램을 리버싱해도 해내실수 있을거라고 믿습니다.