본문 바로가기

2. Reversing (리버싱)/1) Write UP

[2022 . 9. 17] R4 활동일지

일시: 2022.09.17

스터디원: 정현수, 엄설인, 유예지, 이유빈

 

활동내용: 도서 [리버싱 입문] 1장, 부록 페이지 개별학습 후 발표 및 피드백

http://www.yes24.com/Product/Goods/27628413

 

리버싱 입문 - YES24

따라 하며 자연스레 익히는 리버싱기존의 리버싱 관련 서적은 리버싱에 필요한 다양한 지식을 전달하기 위해 많은 공을 들여 배경 지식을 설명하고 있다. 즉, 리버싱을 하려면 굉장히 다양한 지

www.yes24.com

활동내용 정리

 

 

 

1장 - 엄설인

PE파일(exe 파일…): 윈도우 운영체제에서 사용하는 실행 파일 형식

 프로그램을 실행하는 데 필요한 기본 정보와 파일을 메모리 어디에 저장해야할지 알려주는 배치 정보가 들어있음

 구성: 헤더(PE.섹션헤더, 중요한 정보/어떻게 동작해야하는지에 대한 규칙)+보디(코드, 데이터) - PE 헤더에 있는 정보를 분석해서 PE 보디에 있는 코드와 데이터를 메모리에 배치

 

 

IAT(Import Address Table): 실행(PE)파일 안에 어떤 라이브러리의 어떤 함수를 가져다 사용하는지 기록해놓은 정보

 코드에서 라이브러리를 참조하는 부분은 IAT 내부에 있는 함수 주소를 사용하고 있음

 

 

레지스터: CPU에서 사용하는 고속의 기억장치

 CPU는 연산을 수행하기 위해 메모리에 있는 데이터를 CPU 내부에 있는 레지스터로 가지고 옴→ 연산 중간에도 레지스터에 데이터를 저장함

 

1.   EAX(Extended Accumulator Register): 곱셈과 나눗셈 명령에서 사용. 함수의 반환값 저장

2.   EDX(Extended Datat Register): EAX와 같이 사용. 부호 확장 명령 등에 활용

3.   ESI(Extended Source Index): 데이터 복사하거나 조작할 때 소스 데이터 주소 저장

4.   EDI(Extended Destination Index): 복사 작업을 할 때 목적지 주소 저장

5.   EBX(Extended Base Register): ESI나 EDI와 결합해 인덱스에 사용(ESI+EDI)

6.   ECX(Extended Counter Register): 반복 명령어를 사용할 때 반복 카운터 저장

7.   EGP(Extended Base Pointer): 하나의 스택 프레임의 시작 주소 저장

현재 사용한 스택 프레임이 사라지면 이전에 사용되던 스택 프레임 가리킴

8.   ESP(Extended Stack Pointer): 하나의 스택 프레임의 끝 지점 주소가 저장

                           PUSH, POP에 따라 4bite씩 값 변함

9.   EIP(Extended Instruction Pointer): 다음에 실행할 명령어가 저장된 메모리 주소 저장

                                   현재 명령어 모두 실행한 다음 EIP에 저장된 주소에 명령어 실행

 

-PUSH: 데이터를 스택에 집어넣는 명령어

-POP: 데이터를 스택에서 꺼내는 동작

—> 프로그램은 이 2개 명령어를 가지고 스택 제어함

 

 

 

스택: 메모리의 한 부분. LIFO(후입선출)방식으로 동작하는 자료구조

 한 방향으로만 데이터 쌓임(시작주소에서 주소가 작아지는 방향으로)

 위치: 스택 포인터라고 불리는 ESP(하나의 스택 프레임의 끝지점 주소 저장됨) 레지스터에 저장

 PUSH→ 스택의 주소는 4bite만큼 감소하면서 데이터가 스택으로 들어감→POP→ 스택으로부터 데이터가 꺼내지고 스택의 주소는 다시 4bite만큼 증가

 서브루틴(함수)로 인자 전달→서브루틴 내부에서 사용하는 지역 변수가 저장되는 공간 제공하며, 서브루틴이 종료될 때 되돌아갈 주소를 저장하는 역할 함

디버거 어셈블러) 함수 호출할 때 정확하게 인자를 스택으로 PUSH→ 서브루틴(함수)이 종료될 때 복귀 주소를 스택에서 POP

스택 동작 방식을 이해 못하면 리버싱 이해할 수 없음!

 

 

 

스택 프레임: 서브루틴(함수)이 가지는 자신만의 스택 영역

 서브루틴 내부에서 사용하는 데이터 저장

 

OllyDbg: 윈도우용 어셈블러를 분석할 수 있는 디버거

 직관적인 사용자 화면 제공. 다양한 플로그인 통해 기능 확장할 수 있음

 

 

어셈블러: 컴퓨터가 이해할 수 있는 연속적인 비트로 구성된 기계어를 사람이 알아볼 수 있도록 만든 일종의 매크로 모음

 

 

 

 

 

부록: 올리디버거 설치-유예지

OllyDbg 개요

  • 윈도우용 어셈블러를 분석할 수 있는 디버거
  • 32비트 지원

기본 설정

[Options]-> udd 저장 폴더 설정

CPU

  • 운영체제가 프로그램을 실행한다는 것:
  • 저장된 PE(실행 파일)을 메모리에 로딩하고 프로세스로 만들어 CPU가 동작을 수행하도록 명령하는 것
  • 메모리에 있는 정보를 레지스터로 가지고 와서 제어 장치과 연산 장치에서 이를 처리
  • 어떤 정보를 사용하고 어디에 정보를 저장하는지 살펴 볼 수 있음.

코드 영역

  • 주소(메모리에 저장된 절대 주소), 기계어(운영체제가 인식할 수 있는 연속적인 바이너리 조합), 어셈블러(사람이 알아볼 수 잇는 매크로로 변환), 주석(올리디버거가 어셈블러를 분석해서 해석을 달아둔 것. 직접 달기 가능)
  • 실행 파이의 어셈블러 코드를 보여줌.
  • 왼쪽 기계어, 오른쪽 어셈블러.
  • 리버싱시에는 어셈블러 코드 중심으로.
  • 디버거로 프로그램을 열면 PE 헤더에 저장된 엔트리 포인트에서 실행이 멈춤

힌트 영역

  • 어셈블러 코드에 있는 상대 주소와 아스키 코드, 16진수 등을 우리가 알기 쉬운 언어로 표현해 주는 영역.
  • 어셈블러를 따라가는 과정을 자동화하여 힌트 영역에서 보여줌
  • 스택, 함수가 반환하는 EAX 레지스터에 대한 정보 등을 보여줌.

메모리 영역

  • 어셈블러가 사용하는 메모리를 보여줌. PE 헤더에서 데이터 영역으로 지정된 부분을 보여줌.
  • 다른 섹션으로 넘어가려면: [Go to]=>[Expression]
  • Address, Hexdump, ASCII 영역으로 구분
  • Address: 메모리에 실제로 저장된 주소
  • Hex dump; 바이너리 스트링을 16진수로 변경
  • ASCII: 16진수에 해당하는 아스키 코드 값을 보여줌.
  • 문자열은 연석된 값으로 저장, 맨 마지막에 문자열의 끝을 의미하는 널 문자(00)가 저장됨.

레지스터 영역

  • CPU가 연산을 수행하면서 사용하는 데이터 영역
  • CPU는 연산을 위해 메모리로부터 레지스터로 데이터를 가지고 오며, 프로그램 흐름을 제어하기 위한 정보를 레지스터에 저장.
  • EAX~EIP 레지스터, ZERO FLAG 레지스터 사용
  • EAX: 연산의 결과 저장
  • EBP: 프레임 포인터 저장
  • ESP: 스택의 맨 위를 가리킴.
  • EIP: 다음에 실행할 명령어 주소 저장
  • ZERO FLAG: 비교 연산의 결과 저장, JMP 명령어의 기준값으로 사용.

스택 영역

  • 메모리에 위치한 스택을 보여줌.
  • 메인 함수에서 서브루틴으로 들어갈 때 넘겨주는 인자와 복귀할 주소, 그리고 서브루틴 내부에서 사용하는 변수가 스택에 저장됨.

메모리 맵

  • 스택 구조, 히프 메모리 . 현재 PE 파일이 메모리에 로딩된 주소 영역 알 수 있음

실행 모듈

  • 프로그램에서 사용하는 실행 모듈의 세부 정보 열람 가능.
  • 현재 메모리에 로딩된 실행 모듈의 이름과 버전, PE 파일 경로까지 구체적인 정보 보여줌.
  • 분석 대상 프로그램도 하나의 실행파일로 간주.

콜 스택

  • 서브루틴 호출 구조

코드 영역 메뉴

  • [Copy as table]: 주소, 바이너리, 어셈블러 전체를 복사할 수 있는 기능. 코드 영역에서 볼 수 있는 데이터 전체 복사
  • [BIinary copy] : 바이너리만 복사 가능. 실행 파일 수정할 때 사용
  • [Binary edit]: 코드를 직접 수정할 때 많이 사용.
  • [Copy to executable]: 수정된 코드를 실행 파일로 저장하는 역할.
  • [Add comments]: 주석입력
  • [Assemble]: 디버거 화면에서 직접 어셈블러 코드를 입력할 수 있게 해줌.
  • [New origin here]: 다음에 실행할 명령어 주소를 현재 선택된 명령어 주소로 강제적으로 변경하는 기능 제공.
  • [Follow in dump]:
  • Immediate constant: 명령어에 인수로 오는 메모리 주소로 이동
  • Selection: 선책된 명령어가 저장된 주소로 바로 이동.
  • Go to
  • Origin: 레지스터에 들어 있는 주소로 바로 이동
  • Expression: 주소를 검색해서 해당 위치로 바로 이동하는 기능 제공
  • Previous location: 이전에 분석한 코드를 다시 보고 싶을 때 사용
  • Executable file: PE 파일 전체를 하나의 화면에 보여줌
  • [Search for]: 다양한 검색 기능 제공.
  • [Find reference to]: 현재 선택한 명령어를 호출하는 부분을 찾음.

 

 

부록: PE 파일 구조 - 이유빈

 

  • PE 파일(Portable Executable File)
  • 우리가 만든 File이 실행할 수 있는, 이식가능한 다른 곳에 옮겨져도(Portable) 실행가능하도록(Executable) 만들어 놓은 파일
  • 윈도우 실행파일이라고도 부르며, 윈도우 운영체제에서 사용되는 실행파일 형식을 말함
  • 예를 들어, 우리가 간단히 만든 hello,world를 출력하는 프로그램도 PE 구조를 가지고 있으며, 윈도우에 기본적으로 내장되어 있는 notepad.exe, calc.exe 프로그램도 PE 구조를 가지고 있다.

 

 

PE 파일의 구조

  • 헤더: PE 파일이 어떻게 동작해야 하는 지의 규칙, 파일 구성 관련 정보

PE Header(모든 PE 파일이 동일하게 소유)

Section Header(파일마다 내용이 다름)

  • 보디: 헤더에 적힌 규칙따라 실행되는 기계어 

Section Data(파일마다 내용이 다름)

  • 구조체 형식이 아님.

💠 PE Header

  1. IMAGE_DOS_HEADER

윈도우 운영체제의 하위 호환성 지원

DOS 운영체제가 윈도우용 PE 파일을 실행했을 때 적절한 오류 메시지를 보여주고 실제 윈도우용 PE 헤더(IMAGE_NT_HEADERS) 위치를 가리킴

  1. MS-DOS Stub Program

DOS 운영체제에서 윈도우용 PE 파일 실행 시 보여줄 오류 메시지를 저장함

  1. IMAGE_NT_HEADERS

4바이트 Signature 2개, IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER로 구성

 

  1. IMAGE_DATA_DIRECTORY

RVA와 Size로 구성된 8바이트 구조체 16개로 구성

16번째 구조체는 마지막을 의미하는 null

리버싱에서 자주 사용되는 구조체:

  1. Export Table: 외부에 공개하고자 하는 함수 정보를 저장하는 곳
  2. Import Table: PE 파일이 다른 라이브러리로부터 가져와 사용하는 함수 정보 저장->리버싱에서 굉장히 중요한 내용
  3. Resource Table: PE 파일에서 사용하는 리소스가 저장된 영역
  4. Base Relocation Table: PE 헤더에 있는 Image Base 값 사용을 못할 때, PE 파일 내부 절대 주소를 변경할 시 사용되는 구조체
  5. TLS Table: 엔트리 포인트 이전에 실행되는 함수 지정 시 사용
  6. Import Address Table: 리버싱에서 핵심적 역할을 하는 구조체

💠Section Header

  • 로더(Loader:OS 일부분)가 섹션 데이터를 메모리로 로딩하고 속성을 설정하는데 필요한 정보가 저장돼 있다.
  • 즉, 섹션 데이터 사용을 위한 기본 정보가 들어 있다.
  • PE 파일에는 다양한 섹션 데이터를 포함할 수 있는데, 각각 섹션 데이터에 해당하는 섹션 헤더가 존재

💠Section Data

  • 제 프로그램을 실행하기 위한 데이터가 들어가 있음(PE 헤더는 데이터에 접근하기 위한 설정 정보만 있다.)
  • 일정 구조체 형식이 아님 -> 데이터가 자유롭게 분포
  • PE 헤더에서 섹션데이터의 각 영역에 어떤 형식의 데이터가 저장될 것인지 지정하느냐에 따라 저장 데이터 종류가 달라짐
  • IAT(Import Address Table)
  • PE 파일 안에 어떤 라이브러리에서 어떤 함수를 가져다 쓰는지 기록해놓은 정보
  • PE File 내의 특정 구조체인 'IMAGE_IMPORT_DESCRIPTOR'에 Import에 관한 정보를 저장
  • PEView에서 실행 파일 내용
  • Raw Data: 실제 파일에 들어 있는 바이너리 데이터
  • pFile: 파일 내부에서 오프셋(파일 처음 위치부터 해당 바이트가 얼마나 떨어져 있는지)
  • Value: 바이너리 데이터를 ASCII 코드로 변환한 값
  • 주소 지정 방식
  • PE 파일 분석 시 내가 찾는 데이터 위치가 어디에 있는지는 헤더에 있는 정보로 찾음, 이때 사용하는 값이 주소
  • 종류 : pFile, RVA, VA
  1. RVA(Relative Virtual Address)
  • 메모리가 로드 됐을 때, 기준값에서 얼마나 떨어져 있는지 나타내는 상대 위치(상대 주소)
  • 기준값: PE Header 속 IMAGE_NT_HEADERS->IMAGE_OPTIONAL_HEADER에 Image Base가 있는데, 이는 PE 파일이 메모리에 로드될 때 데이터가 저장되는 기준 주소를 의미함. 즉, 기준값 = Image Base
  1. VA(Virtual Address)
  • PE 파일이 메모리에 로드 됐을 때, 가상 메모리상 저장되는 실제 주소
  • 디스크에 저장된 PE 파일이 기준값(Image Base)에서 PE 헤더 파일에 지정된 RVA값만큼 떨어진 위치 = VA