ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6 abex’ crackme #1 분석
    리버싱 엔지니어링/리버싱 핵심 원리 2022. 3. 13. 23:45

    crackme : 크랙 연습 목적으로 작성되어 공개된 프로그램

    • crackme 샘플을 분석하여 디버거와 디스어셈 코드에 익숙해질 수 있음

     

    6.1 abex’ crackme #1

    6.1.1 프로그램 실행

    : 디버깅 전 파일을 실행하여 어떤 프로그램인지 살펴보기

     

    1) 프로그램 실행

    • “Make me think your HD is a CD-Rom” 메시지 박스 출력
      • CD-ROM : CD를 이용해 정보를 기억시키고, 저장하고 검색할 수 있는 컴퓨터 데이터 저장기구

    • CD-ROM을 통해 HD가 HDD(Hard Disk Drive)를 의미한다고 추측할 수 있음

    2) 1번 메시지창 확인 버튼 클릭

    • Error 메시지 박스 출력 후 종료

    6.1.2 디버깅 시작

    : OllyDbg를 통해 abex’ crackme #1 실행

     

    • EP에 main 함수가 바로 나타남
      • 어셈블리 언어로 만들어진 실행파일이기 때문
      • 개발툴을 사용하면 작성한 소스코드 외에 컴파일러가 *Stub Code를 추가하기 때문에 디스어셈을 하면 복잡하게 보임
      • *Stub Code : 고급언어로 구현된 바이너리 파일을 실행하기 위해 어셈블리 언어로 작성한 코드
      • 에섬블리 언어로 작성하면 어셈 코드가 곧 디스어셈 코드가 됨

    6.1.3 코드 분석

    1) Win32 API 호출 위주로 살펴보기

    MessageBox("Make me think your HD is a CD-Rom")
    GetDriveType("C:\\\\")
    ..
    MessageBox("Nah... This is not a CD-ROM Drive!")
    MessageBox("OK, I really think that yout HD is a CD-ROM! :p")
    ExitProcess()
    
    • GetDriveType("C:\\”) : C드라이브의 타입을 얻어옴
    • 조작을 통해 CD-ROM 타입으로 인식하도록 만들어 "OK, I really think that yout HD is a CD-ROM! :p" 메시지 박스가 출력되도록 만들기

    2) 코드 상세 분석

    : 분석을 통한 에셈블리 명령어 익히기

    ; MessageBoxA() 호출 
    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
    
    ; GetDriveType() 호출
    00401013  |>PUSH 402094                  ; /RootPathName = "c:\\"
    00401018  |>CALL 00401055                ; \\GetDriveTypeA
    
    0040101D  |>INC ESI                      ; ESI = 0 ; 값을 1을 증가 
    0040101E  |>DEC EAX                      ; EAX = 2 ; 값을 1 감소 
    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과 ESI 비교 
    00401026  |>JE SHORT 0040103D            ; JE(Jump if Equal) 조건 분기 명령
                                             ; 두 값이 같으면 0040103D로 점프 
                                             ; 다르면 그냥 밑 401028로 진행
                                             ; 0040103D 주소는 제작자가 원하는 메시지 박스 출력코드   
     
    ; 실패 MessageBoxA() 호출 
    00401028  |>PUSH 0                       ; /Style = MB_OK|MB_APPLMODAL
    0040102A  |>PUSH 402035                  ; |Title = "Error"
    0040102F  |>PUSH 40203B                  ; |Text = "Nah... This is not a CD-ROM Drive!"
    
    00401034  |>PUSH 0                       ; |hOwner = NULL
    00401036  |>CALL 00401061                ; \\MessageBoxA
    0040103B  |>JMP SHORT 00401050           ;  abexcm1-.00401050
    
    ; 성공 MessageBoxA() 호출 
    0040103D  |>PUSH 0                       ; |/Style = MB_OK|MB_APPLMODAL
    0040103F  |>PUSH 40205E                  ; ||Title = "YEAH!"
    00401044  |>PUSH 402064                  ; ||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
    
    • 에셈블리 명령어 정리
    명령어 설명
    PUSH 스택에 값을 입력
    CALL 지정된 주소의 함수를 호출
    INC 값을 1 증가
    DEC 값을 1 감소
    JMP 지정된 주소로 점프
    CMP 주어진 두개의 operand(피연산자 : 연산에 사용되는 변수나 상수) 비교
    *SUB 명령어와 동일하나 operand 값이 변경되지 않고 EFLAGS 레지스터만 변경됨
    (두 operand의 값이 동일하다면 ZF = 1로 세팅)
    JE 조건 분기(Jump if equal)
    *ZF = 1이면 점프

     

    6.2 크랙

    : 코드를 패치(다른 코드로 덮어 쓰는 행위)하여 프로그램을 크랙하기

    • 조건 분기(JE) 명령어를 점프(JMP) 명령어로 변경
      • 무조건 점프하기 때문에 목적 주소로 이동 가능
    • ‘JE SHORT 0040103D’ 명령어를 Assemble 기능[Space]을 이용하여 ‘JMP SHORT 0040103D’ 명령어로 변경

     

    6.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
    

    위 어셈블리 코드를 C 언어로 변역하면 아래와 같다

    MessageBox(NULL, "Make me think your HD is a CD-Rom.", "abex' 1st crackme"); 
    
    • 실제 C언어 소스코드에서 함수에 넘기는 파라미터의 순서가 어셈블리 언어에서는 역순으로 넘어간다
      • 스택 메모리 구조(FILO : First In Last Out, LIFO : Last In First Out)

     

    스택

    • 함수의 첫째 파라미터가 스택의 제일 위에 취하고 마지막 파라미터가 아래에 쌓임
    • 따라서, 스택에서 파라미터를 하나씩 꺼낼 때 FILO 구조에 따라 첫번째 파라미터부터 꺼낼 수 있다
      • 함수 입장에서는 스택에 파라미터가 순서대로 들어 있는 셈

     

    '리버싱 엔지니어링 > 리버싱 핵심 원리' 카테고리의 다른 글

    9 Process Explorer - 작업 관리자  (0) 2022.03.15
    8. abex’ crackme #2  (0) 2022.03.13
    7 스택 프레임  (0) 2022.03.13
    5 스택  (0) 2022.02.06
    2 Hello World! 리버싱(2) - 문자열 패치  (0) 2022.02.06

    댓글

Designed by Tistory.