01. Hello_World.exe

Posted by ORANG ORANG(오랑)
2014.10.20 04:50 Reversing/리버싱 공부







실습 환경 : Windows XP 32bit 가상머신 + 이뮤니티 디버거

 

main 함수를 찾은 후에,

Title 부분은 문자열을 직접 수정하고

message 부분은 빈공간에 문자열을 쓴 후, 문자열이 있는 주소로 주소를 수정함

 

 

p.s. 수정된 코드로 파일을 만들면 제대로 작동하지 않는다. message 부분이 문제

실행 파일이 메모리에 로딩되어 프로세스로 실행될 때 파일이 그대로 메모리로 로딩되는 것이 아니라,

어떤 규칙(메모리 관리기법.. 세그먼테이션+페이징 -> 가상메모리)에 의해 올라가게 되는데

프로세스 메모리는 존재하지만, 그에 해당하는 파일 오프셋이 존재하지 않기 때문이라고함 (p.44)


PE File Format 공부 후에 이부분 다시 확인 필요..

HelloWorld.exe


이 댓글을 비밀 댓글로

PE 파일 포맷 ( PE File Format ) 요약

Posted by ORANG ORANG(오랑)
2014.10.20 03:23 Reversing/리버싱 공부


PE File Format

 

PE(Portable Executable)파일 - Windows 운영체제에서 사용되는 실행 파일 형식

 

종류

- 실행 계열 : exe, scr

- 라이브러리 계열 : dll, ocx, cpl, drv

- 드라이버 계열 : sys, vxd

- 오브젝트 파일 계열 : obj

 

구조

PE Header : DOS Header ~ Section Header

PE Body : PE헤더 이후 Section들

 

파일을 실행하기 위한 모든 정보는 구조체 형식으로 PE 헤더에 저장되어 있다.

섹션 헤더에 각 섹션에 대한 크기/위치/속성이 정의되어 있고,

파일의 내용은 코드(.text), 데이터(.data), 리소스(.rsrc) 섹션에 나누어 저장한다.

 

파일에서는 offset으로 메모리에서는 VA로 위치 표현

VA(Virtual Address)는 프로세스 가상 메모리의 절대주소를 말하고

RVA(Relative Virtual Address)는 어느 기준 위치(ImageBase)에서부터의 상대주소를 말합니다.

(DLL Relocation이 일어날 경우를 대비해, 절대주소 대신 상대주소를 사용한다.)

 

RVA + ImageBase = VA


 

------------------------------------------------------------------------------------------------------

 

 

1. PE Header

 

1) DOS Header - DOS 파일에 대한 하위 호환성을 고려해서 만듬.

IMAGE_DOS_HEADER 구조체의 크기는 40

구조체 멤버 중.. 

e_magic : DOS Signatue (4D5A -> ASCII값 “MZ”)

e_lfanew : NT 헤더의 오프셋을 표시

 

2) DOS Stub - DOS 환경에서 실행되는 코드를 가진 영역, 일종의 옵션임(없어도 실행에 문제가 없으므로)

코드와 데이터의혼합으로 이루어짐

3) NT Header

IMAGE_NT_HEADERS 구조체 - 3개의 멤버로 이루어짐

  Signature : 표식, 일반적으로 50450000h(“PE”00)을 가짐

FileHeader 구조체

Optional Header 구조체

 

FileHeader 구조체 ( IMAGE_FILE_HEADER )

구조체 멤버 중..

Machine : CPU별로 고유한 값 

NumberOfSections : 섹션의 개수

SizeOfOptionalHeader : IMAGE_OPTIONAL_HEADER32 구조체의 크기

Characteristics : 파일의 속성(실행가능?, 시스템 파일? dll파일? 등)

 

Optional Header 구조체( IMAGE_OPTIONAL_HEADER32 )

구조체 멤버 중..

Magic : 32bit 형태는 10B, 64bit 형태는 20B 값을 가짐

AddressOfEntryPoint : EntryPoint의 RVA 값을 가짐

ImageBase : PE파일이 로딩되는 시작 주소

SectionAlignment : 섹션의 최소 단위

FileAlignment : 파일의 최소 단위

SizeOfImage : PE파일이 메모리에 로딩되었을 때 가상 메모리에서 PE 이미지 크기

SizeOfHeader : PE헤더의 전체 크기

Subsystem : 파일의 종류 구분(드라이버 파일? or CUI 파일 or GUI 파일)

NumberOfRvaAndSizes : DataDirectory 배열의 개수

DataDirectory : 구조체의 배열로 배열의 각 항목마다 정의된 값을 가짐

 

4) Section Header - 각 섹션의 속성을 정의함

파일/메모리 에서의 시작 위치, 크기, 접근 권한 등

 

code 섹션 - 실행, 읽기 권한

data 섹션 - 비실행, 읽기, 쓰기 권한

resource 섹션 - 비실행, 읽기 권한

 

IMAGE_SECTION_HEADER 구조체

구조체 멤버 중..

VirtualSize : 메모리에서 섹션 크기

VirtualAddress : 메모리에서 섹션의 시작 주소(RVA)

SizeOfRawData : 파일에서 섹션 크기

PointerToRawData : 파일에서 섹션 시작 위치

Characteristics : 섹션의 속성

Name : 섹션 이름

 

 

------------------------------------------------------------------------------------------------------ 

 

 

 

RVA to RAW 계산


PE 파일이 메모리에 로딩되었을 때 각 섹션에서 메모리의 주소(RVA)와 파일 옵셋을 매핑하는 방법

 

1) RVA가 속한 섹션을 찾는다.

2) 간단한 비례식을 통해 파일 옵셋(RAW) 계산

 

RAW-PointerToRawData = RVA - VirtualAddress 이므로

 

RAW = RVA - VirtualAddress + PointerToRawData 가 됩니다.

 

파일의 오프셋 = 메모리 상대주소 - 메모리의 해당 섹션 시작 위치 + 파일의 해당 섹션 시작 위치


 

 

------------------------------------------------------------------------------------------------------ 

 

 

 

DLL

 

메모리 낭비를 피하기 위하여,

프로그램에 라이브러리를 포함시키지 말고, 별도의 파일(DLL)을 구성하여 필요할 때마다 불러쓴다.

한 번 로딩된 DDLL의 코드, 리소스는 Memory Mapping 기술로 여러 프로세스에서 공유해 사용

 

로딩방식

Explicit Linking : 프로그램에서 사용되는 순간에 로딩, 사용 후 해제

Implicit Linking : 프로그램 시작 시 로딩, 종료 시 해제

 

 

------------------------------------------------------------------------------------------------------ 

 

 

 

IAT ( Import Address Table )


프로그램이 어떤 라이브러리에서 어떤 함수를 사용하고 있는지 나타낸 테이블

DLL의 Implicit Linking 방식에 대한 메커니즘을 제공한다.

 

 

1) IMAGE_IMPORT_DESCRIPTOR (IID)

구조체 배열 중..

OriginalFirstThunk : INT(Import Name Table)의 주소(RVA)

Name : 라이브러리 이름 문자열의 주소(RVA)

FirstThunk : IAT의 주소(RVA)

INT와 IAT는 long 타입의 4바이트 자료형 배열

INT의 각 원소 값은 IMAGE_IMPORT_BY_NAME 구조체 포인터

 

2) IAT 입력 순서

1. IID의 Name 멤버를 읽어 라이브러리 이름 문자열을 찾는다.

2. 해당 라이브러리 로딩 -> LoadLibrary(“이름”)

3. IID의 OriginalFirstThunk 멤버를 읽어 INT의 주소를 찾는다.

4. INT의 배열에서 하나씩 값을 읽어, IMAGE_IMPORT_BY_NAME의 주소를 찾고

5. IMAGE_IMPORT_BY_NAME의 ordinal, Name 항목을 통해 해당 함수의 주소를 찾는다.

6. IID의 FirstThunk를 통해 IAT 주소를 찾고

7. 해당 IAT 배열에 찾은 함수의 주소 입력

8. 4~7 과정 반복

 

Ordinal 이란, 함수의 고유 번호를 나타내는 2바이트 값

 

 

------------------------------------------------------------------------------------------------------ 

 

 

EAT( Export Address Table )


라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 하는 메커니즘

 

1) IMAGE_EXPORT_DESCRIPTOR

구조체 배열 중.. 

NumberOfFunctions : 실제 Export 함수 개수

NumberOfNames : Export 함수 중 이름을 가진 함수 개수

AddressOfFunctions Export : 함수 주소 배열

AddressOfNames : 함수 이름 주소 배열

AddressOfNameOrdinals : Ordinal 주소 배열

 

2) GetProcAddress()

라이브러리에서 함수 주소를 얻는 API

 

동작 원리

1. AddressOfNames 멤버를 이용해 ‘함수 이름 배열’로 감

2. ‘함수 이름 배열’에 저장된 문자열 주소들을 문자열 비교하여 원하는 함수를 찾는다. -> index

3. AddressOfNameOrdinals 멤버를 이용해 ‘Ordinal 배열’로 감

4. ‘Ordinal 배열’에서 index를 이용해 해당 ordinal 값을 찾음

5. AddressOfFunctions 멤버를 이용해 ‘함수 주소 배열’ (EAT)로 감

6. EAT에서 아까 구한 ordinal을 배열 인덱스로 원하는 함수의 시작 주소를 얻는다.

 

이름 없이 ordinal만으로 함수의 주소를 찾을 땐

(Ordinal - IMAGE_EXPORT_DIRECTOR.BASE 멤버 )를 EAT의 인덱스로 함 



이 댓글을 비밀 댓글로

함수 호출 규약(Calling Convention)

Posted by ORANG ORANG(오랑)
2014.10.20 03:23 Reversing/리버싱 공부

함수 호출 규약(Calling Convention)


함수 호출 시 전달 되었던 파라미터들에 대하여

함수 호출이 끝난 후 스택을 정리하는 방법에 대한 약속( ESP를 정리하는 방법 )

 

caller : 함수를 호출한 쪽

callee : 호출 당한 함수

 

1. cdcel

- 주로 C언어에서 사용 됨

- caller에서 스택을 정리한다.

- 장점 : 가변 길이 파라미터를 전달할 수 있다.

2. stdcall

- Win32 API에서 사용됨

- callee에서 스택을 정리

- c언어에서 stdcall 방식을 사용하고 싶을 때는 함수이름 앞에 '_stdcall' 옵션 추가

3. fastcall

- stdcall 방식과 기본적으로 같지만, 전달하는 파라미터의 일부(2개)를

 레지스터(ECX, EDX)를 이용해 전달한다. 나머지는 스택을 통해 전달

- 장점 : 좀더 빠른 함수 호출 가능

- 단점 : ECX, EDX에 대하여 백업이 필요하거나,

    함수에서 ECX, EDX를 다른 용도로 써야할 경우, 파라미터를 따로 저장해야함



이 댓글을 비밀 댓글로

레지스터 ( Register )의 이해

Posted by ORANG ORANG(오랑)
2014.10.20 03:22 Reversing/리버싱 공부

 

IA-32(Intel Architecture 32bit)의 레지스터에 대해 정리하겠습니다. ( 리버싱 핵심원리 )

 

레지스터란 CPU 내부에 존재하는 다목적 저장 공간입니다. 일반적으로 메모리라고 얘기하는 RAM(Random Access Memory)과는 성격이 조금 다릅니다. CPU가 RAM에 있는 데이터에 접근하기 위해서는 물리적으로 돌아가야하기 때문에 오래걸리지만, 레지스터는 CPU 내부에 존재하므로 고속으로 데이터를 처리할 수 있습니다.

 

IA-32 레지스터의 종류는 다양하지만

초급 단계에서는 Basic program execution registers에 대해 알아두어야 합니다.

(중/고급 단계에 올라가면 Control registers, Memory management registers, Debug registers 등에 대해 추가적으로 공부해야 합니다.)

 

Basic program execution registers

- General Purpose Registers ( 범용 레지스터 )

- Segment Registers ( 세그먼트 레지스터 )

- Program Status and Control Register ( 프로그램 상태 & 컨트롤 레지스터 )

- Instruction Pointer 

 

  1. General Purpose Registers ( 범용 레지스터 )

 범용 레지스터는 ‘막’ 쓰는 레지스터이기 때문에 용도가 다양합니다.

 32bit(4바이트) 크기의 레지스터 8개로 구성되어 있으며 상수/주소를 저장할때 쓰이고 특정 어셈블리 명령어에서 특정 레지스터를 조작하거나 특수한 용도로 쓰이기도 합니다.

각 레지스터들은 16비트 하위 호환을 위해 몇개의 구획으로 나누어 집니다.

 

 

31

16

8

0

16bit

32bit

 

 

AH

AL

AX

EAX

 

 

BH

BL

BX

EBX

 

 

CH

CL

CX

ECX

 

 

DH

DL

DX

EDX

 

 

BP

 

EBP

 

 

SI

 

ESI

 

 

DI

 

EDI

 

 

SP

 

ESP

 

EAX를 예를 들면..

EAX : 0~31 -> 32비트

AX : 0~15 -> 16비트

AH : 8~15 -> AX의 상위 8비트

AL : 0~7 -> AX의 하위 8비트

가 되는거죠ㅎㅎ

 

각 레지스터들의 용도를 보면..

 

EAX ( Accumulator for operands and results data )

- 산술 연산시 상수/변수 값의 저장 용도

- 함수 리턴값 지정 ( 모든 Win32 API하무는 리턴값을 EAX에 저장 )

EBX ( Pointer to data in the DS segment )

-  산수/변수 저장

- 간접 주소 지정

ECX ( Counter for string and loop operations )

- 반복문(loop)에서 반복 카운트

EDX ( I/O pointer )

- EAX를 보조

EBP ( Pointer to data on the stack (in the SS segment) )

- 스택 프레임의 기준점

ESI ( source pointer for string operations )

- 출발지 주소 저장

EDI ( destination pointer for string operations )

- 도착지 주소 저장

ESP ( Stack pointer ( int the SS segment) )

- 스택 프레임의 최상단 주소 ( 스택의 현 위치 )

 

————초급 리버싱에선 범용 레지스터가 중요하므로 다른 레지스터는 가볍게 보겠습니다.—————

 

 

2) Segment Registers

 

세그먼트 란 메모리를 조각내어 각각의 조각마다 시작 주소, 범위, 접근 권한 등을 부여하여 메모리를 보호하는 기법을 말합니다.

16비트(2바이트) 크기의 레지스터 6개로 구성되어 있습니다.

 

CS : Code Segment

SS : Stack Segment

DS : Data Segment

ES : Extra(Data) Segment

FS : Data Segment

GS : Data Segment

 

ES, FS, GS는 추가적인 데이터 세그먼트 입니다.

 

 

3) Program Status and Control Register 

 

EFLAGS - 플래그 레지스터… 32비트(4바이트) 크기

플래그 레지스터는 각각의 비트마다 의미를 가지고 있습니다. 1또는 0.. true or false 를 나타냅니다

조건 분기 명령어 에서 Flag의 값을 확인하고 동작 수행 여부를 결정하기 때문에 ZF, OF, CF는 알아둬야 합니다.

 

ZF ( Zero Flag ) -> 비트 6

- 연산 명령 후에 결과 값이 0이 되면 ZF가 1(true)로 세팅됨

OF ( Overflow Flag ) -> 비트 11

- 부호 있는 수의 오버플로시 OF를 1(true)로 세팅

- MSB( Most Significant Bit )가 변경되었을 때 1(true)로 세팅

 CF ( Carry Flag ) -> 비트 0

- 부호 없는 수의 오버플로시 CF를 1(true)로 세팅

 

 

4) Instruction Pointer

EIP ( Instruction Pointer )

EIP는 CPU가 처리할 명령어의 주소를 나타내는 레지스터이다. 32비트(4바이트)

다음에 실행해야할 명령어의 주소를 담고 있으며, 값을 직접 변경할 수 없고 간접적으로 변경해야함 



이 댓글을 비밀 댓글로

바이트 오더링( 빅 엔디언, 리틀 엔디언 )

Posted by ORANG ORANG(오랑)
2014.10.20 03:21 Reversing/리버싱 공부

 

 

바이트 오더링이란 데이터를 저장하는 방식을 말합니다.

빅 엔디언 표기법과 리틀 엔디언표기법 2가지 방식이 있습니다

 

 

1. 빅 엔디언 표기법

대형 UNIX 서버에 사용되는 RSIC 계열의 CPU에 많이 사용되고, 네트워크프로토콜에 사용됩니다.

데이터를 저장할 때 사람이 보는 방식과 동일하게 순차적으로 저장합니다.

ex) 0x12345678 -> (빅 에디언 표기법) 0x12345678

 

 

2. 리틀 엔디언 표기법

리틀 엔디언은 Intel x86 CPU에서 사용되므로 Windows계열 리버싱을 위해 리틀 엔디언 방식을 잘 알아야 합니다. 

데이터를 저장할 때 역순으로 저장합니다.

ex) 0x12345678 -> (리틀 에디언 표기법) 0x78563412

데이터를 역순으로 저장시키기므로 산술 연산과 데이터의 타입이 확장/축소될 때 효율적입니다.

 


 

 

이 댓글을 비밀 댓글로

리버싱 ( Reversing )

Posted by ORANG ORANG(오랑)
2014.10.20 03:19 Reversing/리버싱 공부



Reverse Engineering 의 줄임말입니다.

 

제작된 프로그램의 동작방식을 관찰하며 원래 소스 코드를 복원해내는 작업입니다.


리버싱을 통해 프로그램의 흐름이나 구조, 취약점을 찾아낼 수 있고 패치나 크랙도 가능합니다ㅎㅎ

이 댓글을 비밀 댓글로