Information Security ˗ˋˏ ♡ ˎˊ˗

Security/Reversing

[Reversing 실습] abex’ crackme #1

토오쓰 2020. 4. 1. 03:18

abex’ crackme #1

: crack 연습 목적용 공개 프로그램

 

Ollydbg(v1.1)

코드의 특징: 어셈블리로 작성된 코드, 시작 주소가 EP로 매우 간단하고 명확하게 작성(stub code가 없음)

- 여기서 MessageBoxA 총 3개의 API 함수를 사용

 

코드의 목적: MessageBoxA 순서대로 1, 2, 3으로 볼 때, 원래는 1->2로 이동하는데 1->3으로 이동하길 원한다.

 

코드 분석

00401000 PUSH 0 ; Style = MB_OK|MB_APPLMODAL

00401002 PUSH 402000 ; Title = "abex' 1st crackme"

00401007 PUSH 402012 ; Text = "Make me think your HD is a CD-Rom."

0040100C PUSH 0 ; hOwner = NULL

0040100E CALL 00401061 ; MessageBoxA라는 API 함수를 호출, 함수 내부에서 ESI=FFFFFFFF로 셋팅

 

; GetDriveTypeA( ) 호출

00401013 PUSH 402094 ; RootPathName = "c:\"

00401018 CALL 00401055 ; GetDriveTypeA(API함수 호출),

;리턴 값(EAX)은 3(DRIVE_FIXED)입니다. EAX는 레지스터의 함숫값을 리턴해주는 레지스터이다. EAX=3

                                                                                          

0040101D INC ESI ; ESI = 0

0040101E DEC EAX ; EAX = 2

0040101F JMP SHORT 00401021 ; 의미 없는 JMP 명령어 (garbage code), 다음 라인으로 이동

00401021 INC ESI ; ESI = 1

00401022 INC ESI ; ESI = 2

00401023 DEC EAX ; EAX = 1

 

; 조건 분기 (401028 또는 40103D)

00401024 CMP EAX,ESI ; EAX(1)와 ESI(2)를 비교(=CMP)

00401026 JE SHORT 0040103D

; JE(Jump if Euqal) 조건 분기 명령

; 두 값이 같으면 40103D로 점프하고, 다르면 그냥 밑(401028)으로 진행

; 40103D주소는 제작자가 원하는 메시지 박스 출력 코드

 

; 실패 MessageBoxA( ) 호출

00401028 PUSH 0 ; Style = MB_OK|MB_APPLMODAL

0040102A PUSH 00402035 ; Title = "Error"

0040102F PUSH 0040203B ; Text = "Nah... This is not a CD-ROM Drive!"

00401034 PUSH 0 ; hOwner = NULL

00401036 CALL 00401061 ; MessageBoxA

0040103B JMP SHORT 00401050

 

; 성공 MessageBoxA( ) 호출

0040103D PUSH 0 ; Style = MB_OK|MB_APPLMODAL

0040103F PUSH 0040205E ; Title = "YEAH!"

00401044 PUSH 00402064 ; Text = "Ok, I really think that your HD is a CD-ROM! :p"

00401049 PUSH 0 ; hOwner = NULL

0040104B CALL 00401061 ; MessageBoxA

 

;프로세스 종료

00401050 CALL 0040105B ; ExitProcess , 종료(API 함수 실행)

 

; API 호출

00401055 JMP DWORD PTR DS:[<&KERNEL32.GetDriveTyp> ; KERNEL32.GetDriveTypeA

0040105B   JMP DWORD PTR DS:[<&KERNEL32.ExitProcess> ;  KERNEL32.ExitProcess

00401061   JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ;  USER32.MessageBox

- API 호출에서 USER32: USER32.dll 윈도우에서 많이 사용하는 API 함수들의 DLL 목록이다. 윈도우 API 기반으로 어셈블리를 바로 코딩한 것이기 때문에 USER32에서 제공하는 DLL함수를 쓰는 것이다. CALL 명령어를 이용하여 호출할 것이다.

- API 호출에서 KERNEL32.GetDriveTypeA(API함수): KERNEL32.DLL 윈도우 API를 제공하는 라이브러리에서 제공한다는 것을 알 수 있다.

 

첫 번째 방법

- JE를 JMP로 변경

변경 후 결과는 모두 같다.

 

결과

 

두 번째 방법

- CMP EAX, ESI를 통해 EAX와 ESI를 비교하여

- JE SHORT 0040103D에서 두 값이 같으면 0040103D(3번째 메시지 박스)로 점프를 한다.

- 하지만 지금은 EAX와 ESI 값이 다르기 때문에 0040103D이 주소로 이동할 수 없게 된다.

- 어셈블리어 JE 명령어가 아닌 JNZ(Jump if not zero) 명령어를 이용해서 비교한 결과 값이 거짓이라면 점프시킨다.

결과

 

세 번째 방법

- EAX와 ESI 값이 다르기 때문에 JE 명령어를 통과하게 된다.

- EAX와 ESI 값을 갖게 해 준다.

CMP로 비교하기 전에 EAX의 값을 ESI의 값으로 변경 -> JE

 

세 번째 메시지 박스로 이동한 것을 볼 수 있다.

 

결과

 

스택에 파라미터 전달하는 방법

MessageBoxA()를 c코드에서 작성을 했을 때의 순서는 메시지 박스에 필요한 파라미터를 순서대로 넣어주었다.

 

하지만 ollydbg를 통해 보면 파라미터가 먼저 들어가고 맨 뒤에 API 함수가 들어간다.

그 이유는 스택을 사용하기 때문이다. 스택은 처음에 넣은 것을 마지막에 쓸 수 있다.(선입 후출)

 

<Stack Window>

stack window 보자!

stack window를 살펴보면 Null 값과 문자열 순서로 들어가는 것을 볼 수 있다.