============================================================================
본격적으로 코드엔진 리버싱 풀이에 대해 포스팅한다.
"제대로" 공부하기 위해 어떻게 프로그램을 바라보고 분석해야 하는지에 초점을 맞추고 "제대로" 풀이한다.
============================================================================
문제: Basic RCE L01
- HDD를 CD-Rom으로 인식시키기 위해서는 GetDriveTypeA의 리턴값이 무엇이 되어야 하는가..?
풀이
1. 실행 및 유추
분석할 프로그램을 받자마자 분석하는것은 개인적으로 어리석다고 생각한다.
우선 분석할 프로그램이 실행 가능하다면, 프로그램을 실행해보고 어떤 흐름을 갖는지 생각하는 것이 중요
사용자가 누를 수 있는 버튼은 Window MessageBox 확인 버튼 뿐이고 확인을 누르면 "Nah... This is not a CD-ROM Drive!"을 표시한 window MessageBox가 출력된다.
문제로 미루어 보았을 때 이 프로그램 내부에서 GetDriveTypeA의 return 값을 특정 값(?)과 비교하여 True/False로 분기하는 것 같다.
2. 간단한 정적 분석
필자는 주로 분석 프로그램을 분석하기 전에 패킹 유무나 유의미한 정보를 얻기 위해 간단한 정적 분석을 시도한다.
"Exeinfo pe"를 활용한 결과는 Fig 3.과 같다.
100% 신뢰할 수 없지만 Window GUI 프로그램인 것과 패킹이 되어 있지 않은 것을 확인 할 수 있다.
Fig 4.에서 Image base와 Base of Code를 이용해 0x401000번지가 Entry Point가 될 확률이 높다는 것을 확인할 수 있다.
3. OllyGDB를 활용한 바이너리 분석
Fig 5.처럼 MessageBoxA API를 호출한 뒤 GetDriveTypeA를 호출하고 "inc, dec, jmp, cmp, je" 명령어로 GetDriveTypeA의 return value(eax)를 연산하고 비교하는 것을 확인할 수 있다.
GetDriveTypeA의 return value를 설명한 것은 Fig 6.fh 나타낼 수 있다.
현재 RootPahtName="c:\"로 설정되어 있기 때문에 DRIVE_FIXED value 를 나타내는 3이 reutrn된다.
0x0040101D~0x00401026의 assembly를 C-type pseudo code로 나타내면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
|
eax = 3 // return value of GetDriveTypeA
esi = 0
esi++; // esi = 1
eax--; // eax = 2
esi++; // esi = 2
esi++; // esi = 3
eax--; // eax = 1
if(eax != esi)
MessageBox("Ok, I really think that your HD is a CD-ROM! :p");
else
MessageBox("Nah... This is not a CD-ROM Drive");
|
cs |
즉, 문제를 해결하기 위해서 eax - 2 => 3이 되는 값으로 GetDriveTypeA의 return value가 설정되어야 한다.
GetDriveTypeA의 return value가 DRIVE_CDROM(5)일 때가 이 문제의 정답이 된다.
docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea