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를 살펴보면 Null 값과 문자열 순서로 들어가는 것을 볼 수 있다.
'Security > Reversing' 카테고리의 다른 글
[PE 파일] 구조(2) - PE 파일 헤더(DOS_HEADER, DOS Stud Code) (2) | 2020.04.09 |
---|---|
[PE 파일] 구조(1) - PE파일 정의, 구조(PEview.exe) (2) | 2020.04.09 |
[Reversing 실습] Little Endian 표기법 (305) | 2020.04.01 |
[Reversing 실습] 문자열 패치 두 가지 방법 (428) | 2020.04.01 |
[Reversing 실습] 기본 디버깅 (1) | 2020.04.01 |