상세 컨텐츠

본문 제목

리버싱 입문 1.1 ~ 1.6

REVERSING/Reversing Study

by koharin 2021. 3. 26. 18:03

본문

728x90
반응형

1. 프로그램 실행 구조


PE (Portable Executable) 파일

  • 윈도우 실행 파일
  • PE 포맷 = header + body
    • header: 프로그램 실행하는데 필요한 기본 정보, 배치 정보(파일의 메모리 상 위치 정보)
    • body: 코드, 데이터
  • exe, dll, ocx 등 다양한 종류가 있다.
  • PE 포맷인 실행파일을 클릭하면, 운영체제의 **Loader(로더)**는 PE 헤더에 있는 정보를 분석해서 PE 바디의 코드, 데이터를 메모리에 배치한다.
  • 메모리 구성
    • Code 영역: 프로그램 코드 들어가는 영역
    • Data 영역: 정적 변수, 전역 변수 저장
    • Stack 영역: 함수 호출 시 사용되는 매개 변수, 지역변수 저장
    • Heap 영역: 동적 메모리 할당에 사용
  • PE가 로딩되면 코드 영역, 데이터 영역에 데이터가 들어가고, 프로그램 실행되면 스택 영역, 힙 영역에 데이터가 쌓인다.

 

엔트리 포인트(Entry Point)

  • PE 파일 실행이 시작되는 주소
  • 운영체제는 메모리의 PE 파일을 실행하기 위해 PE 헤더 정보에서 Entry Point를 찾아 그곳에서부터 프로그램을 실행한다.

 

2. 레지스터


  • CPU에서 사용하는 고속 기억장치
  • CPU는 연산 수행 위해 메모리의 데이터를 CPU 내부의 레지스터로 가지고 온다. 연산 중간마다 레지스터에 데이터를 저장한다.
Register Description
EAX (Extended Accumulator Register) 곱셈, 나눗셈 명령에 사용. 함수 반환값 저장
EBX(Extended Base Register) 인덱스로 사용한다.
ECX(Extended Counter Register) 반복 명령어 반복 횟수를 저장하고 반복 작업 수행한다.
EDX(Extended Data Register) EAX와 같이 사용한다. 부호 확장 명령 등에 활용
ESI(Extended Source Index) ESI 레지스터가 가리키는 주소의 데이터를 EDI 레지스터가 가리키는 주소로 복사하는 용도로 사용
EDI(Extended Destination Index) ESI 레지스터가 가리키는 주소의 데이터가 EDI가 가리키는 주소로 복사된다.
EBP(Extended Base Pointer) 스택 프레임 시작 주소가 저장된다.
사용하는 스택 프레임이 살아있는 동안 EBP 값은 변경되지 않고, 현재 사용하던 스택 프레임이 사라지면 이전 스택 프레임을 가리킨다.
ESP(Extended Stack Pointer) 스택 프레임 끝 지점 주소를 저장한다.
PUSH, POP 명령어 따라 ESP의 값이 4바이트씩 (32bit이므로) 변한다.
EIP(Extended Instruction Pointer) 다음에 실행할 명령어가 저장된 메모리 주소가 저장되어, 현재 실행하던 명령어가 끝나면 EIP 레지스터에 저장된 주소에 있는 명령어가 실행된다.

 

 

3. 스택과 스택 프레임


스택(Stack)

  • LIFO(Last In First Out) 방식으로 동작하는 자료 구조
    • 가장 마지막에 들어간 데이터가 가장 처음에 나오는 방식
  • 스택은 high address에서 low address로 데이터가 쌓인다. 따라서 스택의 Top은 low address이다
  • ESP 레지스터는 현재 프로그램이 사용하는 스택 위치를 저장하는 stack pointer
  • PUSH
    • 데이터를 스택에 넣는 명령어.
    • ESP + 4h == 주소가 4byte 감소하여 데이터가 스택에 들어간다.
  • POP
    • 데이터를 스택에서 꺼내는 명령어POP: 데이터를 스택에서 꺼내는 명령어
    • ESP - 4h == 주소가 4byte 증가하여 스택에서 데이터를 꺼낸다.

 

스택 프레임(Stack Frame)

  • 서브루틴(함수)이 가지는 자신만의 스택 영역
  • 서브루틴 내부에서 사용하는 데이터가 스택 프레임에 저장된다.
  • 함수가 호출될 때 해당 함수의 스택 프레임이 생성되며, 함수 종료 후 해당 함수를 호출한 함수로 리턴하여, 즉 복귀 주소로 돌아가면 해당 함수의 스택 프레임은 사라진다.
    • 복귀 주소는 서브루틴 실행 전 스택에 넣고, 이전 루틴이 사용한 EBP 레지스터 내용을 백업해놓는다.
  • EBP(Extended Base Pointer)는 스택 프레임에서 데이터 참조 위한 기준 주소인 Frame Pointer이다. 스택 내의 데이터 접근 시 사용한다.
    • ESP는 프로그램이 실행하면서 계속 변하므로 변하지 않는 EBP를 프레임 포인터로 사용한다.

 

 

4. PE 파일


Compiler

  • 고급 언어(Java, C 같은)를 운영체제가 이해할 수 있는 기계어로 번역하는 프로그램

 

PE (Portable Executable) 파일

  • 운영체제가 이해할 수 있는 기계어
  • 윈도우 운영체제에서 사용하는 실행 파일 형식 중 하나

PE 포맷

  • 윈도우에서 프로그램을 실행하기 위해 준수해야 하는 규칙
  • 이 규칙을 지켜야 윈도우 환경에서 프로그램이 실행될 수 있다.

PE 파일 종류

  • 윈도우에서 사용하는 실행 파일에는 EXE, DLL, OCX, SYS 등이 있다.

PE 파일 구조

Header

  • PE 파일 동작에 대한 규칙, 파일 구성 관련 정보 저장
  • PE Header, Section Header로 구성된다.
    • PE Header
      • IMAGE_DOS_HEADER: 윈도우용 PE 헤더 위치 가리키는 역할, DOS 운영체제가 윈도우 PE 파일 실행 시 오류 메시지를 보여준다.
      • MS-DOS Stub Program: DOS 운영체제에서 윈도우 PE 파일 실행 시 보여줄 오류 메시지 저장
      • IMAGE_NT_HEADERS
        • Signature (4byte) 2개
        • IMAGE_FILE_HEADER
        • IMAGE_OPTIONAL_HEADER
          • PE 구조에서 핵심적인 역할
          • 이 구조체 뒤에는 16개의 IMAGE_DATA_DIRECTORY 구조체가 있다.
          • Image Base: 메모리에 PE 파일이 저장되는 시작 주소
    • Section Header: PE 파일은 최소 1개 이상의 Section Header를 가진다.

Body

  • 실행되는 기계어, 프로그램에 사용되는 코드, 데이터 저장
  • Header에 적힌 규칙에 따라 Body에 저장된 기계어들이 실행된다.

RVA(Relative Virtual Address)

  • 메모리에 로딩되면서 Image Base 값과 합산된 주소인 VA(Virtual Address)에 저장된다.
  • 디버거로 프로그램 열었을 때 코드 영역의 맨 윗부분 주소

Entry Point의 주소

  • 프로그램 실행에 대한 제어권이 커널 영역에서 코드 영역으로 처음 넘어오는 주소인 Entry Point를 가리킨다.

Base of Code

  • 코드 영역이 시작되는 주소(RVA)를 가리킨다.

 

주소 지정 방법

  • PE 파일 분석 시 찾는 데이터 위치를 헤더 내의 주소 값을 통해 찾을 수 있다.
  • pFile, RVA(Relative Virtual Address), VA(Virtual Address) 세 가지의 주소 형식이 있다.

pFile

  • PE 파일 내부 오프셋 값
  • 파일
  • PE 파일이 하드디스크에 저장되었을 때 의미있다.

RVA(Relative Virtual Address)

  • PE 파일이 메모리로 로드됐을 때 저장되는 상대 주소(기준값에서 떨어진 정도)
  • 메모리
  • 메모리에 로드됐을 때 의미있다.

VA(Virtual Address)

  • 가상 메모리 상에서 저장되는 실제 주소
  • 메모리
  • 메모리에 로드됐을 때 의미있다.

DLL(Dynamic Linking Library)

  • 프로그램에서 사용하는 라이브러리를 사용 시점에서 동적으로 연결한다.

IAT(Import Address Table)

  • PE 파일(실행 파일) 안에서 어떤 라이브러리의 어떤 함수를 가져다 쓰는지 기록해놓은 정보
  • Loader는 PE 파일을 메모리로 로딩 시 IAT에 기록된 API 이름을 참조해서 실제 주소를 찾아 IAT에 API를 가리키는 주소를 적는다.
  • 코드에서 라이브러리 참조 시 IAT 내부 함수 주소를 이용한다.

 

6. 어셈블러


어셈블러

  • 어셈블러: 기계어를 사람이 알아볼 수 있도록 만든 매크로 모음
  • 어셈블러와 기계어는 1:1로 매칭된다.

 

어셈블러 기본 구조

윈도우 어셈블러 기본 구조

  • 어셈블러는 최대 3개 인자까지 받아들일 수 있다.
  • 어셈블러 명령어 흐름: 오른쪽에서 왼쪽으로

인자 2개 명령어

  • ADD EAX, EBX: EAX 레지스터 값에 EBX 레지스터 값을 더해 EAX 레지스터에 저장한다.
  • 16진수로 표현하면 0x01D8에 해당한다.

 

인자 1개 명령어

  • INS ESI: ESI 레지스터 값을 1만큼 증가시키는 명령어.
  • 고급언어로 ESI = ESI + 1 또는 ESI++로 구현된다.
  • 16진수 46으로 표현될 수 있다.

 

  • PUSH 인자: 인자를 스택의 맨 위에 입력한다.
  • PUSH 0: 스택 맨 위에 '00000000'을 입력한다.
  • PUSH는 16진수 0x6A에 해당하며, 인자 값을 그대로 헥사 코드로 사용한다.

 

인자 없는 명령어

RETN

  • 뒤에 하나의 인자를 입력받을 수 있다.
  • 스택 맨 위의 값을 EIP 레지스터(다음 실행할 명령어 저장)에 저장한다.
  • RETN 명령어로 스택 맨 위 주소의 명령어를 실행한다.
  • 현재 루틴에서 서브루틴으로 이동 시 돌아올 주소를 스택에 넣어주고, 서브루틴 동작이 완료되면 스택에서 돌아올 주소를 꺼내 프로그램 실행 흐름이 변경되도록 한다.
  • 서브루틴의 맨 마지막엔 대부분 RETN 명령어가 있다.
728x90
반응형

관련글 더보기