본문 바로가기

INTERTLUDE/리버싱 스터디

[리버싱 스터디]_1주차 Codeengn Basic RCE 1

Codeengn Basic RCE 1
Q. HDD를 CD-Rom으로 인식시키기 위해서는 GetDriveTypeA의 리턴값이 무엇이 되어야 하는가?

먼저, 해당 문제를 풀기 위해서는 Immunity Debugger에서 1.exe 파일을 열어야 한다.

Immunity Debugger로 abex1st_crackme.exe 파일을 열고, F8로 코드를 한 줄씩 실행하였다.

  • F8 (Step Over)를 통해서, 사진과 같은 프로그램 전체 흐름(사용자 메시지 박스 출력 등)을 빠르게 확인할 수 있다.
  • 첫 번째 메시지박스 "Make me think your HD is a CD-Rom."가 뜨는 것을 확인하였다. 그 다음으로는, 계속 F8을 진행하니 두 번째 메시지박스("Nah... This is not a CD-ROM Drive!")가 출력되는 지점을 확인하였다.
  • 프로그램은 내부적으로 GetDriveTypeA의 반환값을 검사하고, 검사 결과에 따라 서로 다른 MessageBox로 분기한다.            현재 실행 경로는 ‘실패 분기’로 들어가고 있음을 확인할 수 있었다. 

  • 디스어셈블리에서 GetDriveTypeA 호출 이후의 분기 제어 지점을 찾을 수 있었다. 해당 라인은 0040101F에 위치했고,         원래 JMP SHORT 00401021(또는 EB 00) 형태로 되어 있었다.
  • JMP/JCC 명령이 분기 흐름을 결정한다 --> 라는 개념을 바탕으로, 해당 줄을 바꾸면 분기 경로를 강제로 변경할 수 있다.       곧 흐름을 제어할 수 있다는 것을 파악해 볼 수 있었다. 
더보기

해결 방법 결정 — JMP 패치 선택한 이유? 

** 고려한 옵션들

 

a) 런타임에 EAX를 5로 바꿔서 성공 경로로 가게 하기
b) 메모리/파일을 패치해서 분기(JMP) 대상을 성공 분기로 바꾸기

 

--> 디버거에서 Assemble로 JMP 한 줄 바꾸는 게 직관적이고 곧바로 검증 가능하고, 코드 흐름 제어를 직접 확인할 수        있다고 생각되어 선택하였음. 

  • 0040101F 줄을 더블클릭 → Assemble 창을 띄워 JMP 0040103D(세 번째 MessageBox가 위치한 주소)로 입력한 뒤 Assemble → 적용하였다. (Fill with NOPs 체크 상태로 패치 적용)
  • 어셈블리 창을 통해 어셈블리 명령을 직접 변경하면, 디버거가 기계어 바이트를 재생성하여 해당 명령을 메모리(또는 파일)에 덮어쓴다. 상대점프(rel/short jmp) 길이가 달라질 때는 NOP로 채우는 처리가 필요할 수 있다.
  • 0040101F의 명령이 JMP SHORT 0040103D로 바뀜. 

  • Ctrl+F2로 재시작(또는 재로딩)한 뒤 F8로 다시 한 줄씩 실행. 
  • 첫 번째 메시지박스 확인 후 계속 진행하면, 원래 뜨던 두 번째 박스가 건너뛰어지고 곧장 세 번째(성공) MessageBox가        뜨는 것을 확인하였다.

  • 성공 메시지박스("YEAH! Ok, I really think that your HD is a CD-ROM! :p")가 뜨는지 확인하였음. 
  • 분기 제어를 조작함으로써 프로그램은 마치 GetDriveTypeA가 DRIVE_CDROM(=5)을 반환한 것처럼 성공 경로를 실행하였다. (그렇지만, 실제 API의 리턴이 바뀐 건 아님 — 흐름만 변경함) --> 문제 요구에 부합하는 성공 상태를 얻음 -!