본문 바로가기

카테고리 없음

2024.8.10 리버싱 공부(나뭇잎 책)

https://forum.tuts4you.com/

 

여기서 리버싱 공부 팁을 얻을 수 있다.

 

PE 파일 포멧

PE(portable executable) 파일 포멧. - 윈도우에서 사용되는 실행 파일 형식

종류 exe,src,dll,ocx,cpl,drv,sys,vxd,obj

 obj 뺴고 다 실행 가능

 

파일을 헥스 에디터로 보면 PE파일 구조를 볼 수 있음.

 

PE구조

PE header(DOS header, DOS stub, NT header(file header, optional header), Section header(여러개))

PE body(header제외 섹션 부분들)

 

DOS header - MZ header ( 64 바이트)

맨 첫 값은 e_magic - MZ(DOS signature)

마지막 값은 e_lfanew - NT header의 offset(NT header 시작 위치)

 

DOS Stub

Dos header 밑에 있어도되고 없어도 되는 부분 DOS에서 실행되는 부분

 

NT header (크기 0xF8)

첫 값 signature - PE

두번째 값 - file header 구조체

세번째 값 - optional header 구조체

 

file header (크기 0x14)

- machine - cpu 고유 값

- numberOfsections - 섹션 개수(0보다 커야됨, 섹션 수와 실제 섹션 다르면 오류)

- sizeOfOptionalHeader - Optional header 크기

- characteristics - 파일의 속성 값, bit OR 형식으로 조합(exe인지 dll인지 등등)

 

optional header(크기가 가장 큼)

- magic - 32비트 - 0x10B, 64비트 - 0x20B 

- addressOfEntryPoint - 프로그램에서 최초로 실행되는 주소 (RVA값)

- ImageBase - PE파일이 로딩되는 시작주소 파일을 메모리에 로딩 후 EIP 레지스터를 ImageBase + AddressOfEntryPoint로 세팅함

- SectionAlignment, FileAlignment - 파일구조 바디 섹션의 최소 단위(FileAlignment), 메모리에서 섹션의 최소 단위(SectionAlignment)

- SizeOfImage - PE파일이 메모리에 로딩 되었을때 가상 메모리에서 PE Image가 차지하는 크기

- SizeOfHeader - PE 헤더의 전체 크기 , FileAlignment의 배수여야 함. 파일 시작에서 SizeOfHeader만큼 떨어진 곳에 첫번째 섹션 위치

- Subsystem - sys인지 dll,exe인지 구분 할 수 있게하는 값

- NumberOfRavAndSie - DataDirectory 배열의 개수

- DataDirectory - Data_Directory 구조체의 배열

 

Section header

-각 섹션의 속성을 정의한 헤더

- Name - 섹션 이름

- VirtualSize - 메모리에서 섹션의 크기  , (SectionAlignment 배수값)

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

- SizeofRawData - 파일에서 섹션의 크기  , (FileAlignment 배수값)

- PointerToRawData - 파일에서 섹션의 시작 위치

- Characteristics - 섹션의 속성

 

RVA TO RAW

RVA는 메모리에서 상대 위치

VA = ImageBase + RVA

VA(메모리에서 절대 주소) - 메모리 시작점(imagebase)+상대 주소(RVA)

 

- 1. RAV가 속해있는 섹션을 찾는다

- 2. 식으로 RAW를 찾는다.

RAW(절대 주소) = VA - VirtualAddress(메모리에서 섹션 시작 주소 (RVA값)) + ImageBase) + PointerToRawData(파일에서 섹션 시작 주소)

 

RAW = RVA - VirtualAddress(메모리에서 섹션 시작 주소) + PointerToRawData(파일에서 섹션 시작 주소)

 

RVA가 섹션에 있는지 확인 후 메모리에서 섹션 시작주소와 파일 섹션 시작주소를 알아내서 계산

 

의문점 메모리에서 섹션크기와 파일에서 섹션 크기가 다른데 메모리에서 더 클때 파일과 겹치지 않은 부분, 파일보다 큰 부분의 RVA는 어디에 매칭이 되는가? -> 책에선 RAW를 정의할수 없다고 나와있음.

파일에서 섹션과 메모리에서 섹션 크기가 다른 이유는 뭔지 궁금함.. 그대로 복사하는게 아니라 뭔가 있나.. 저 계산식에 의하면 겹치는 모든 부분은 매칭이 된다는 것으로 보이는데 넘치거나 부족한 부분은 무슨 데이터가 있는가

peviewer와 x64dgb로 본 결과 큰 부분에 다 0x00이 채워져 있고 매칭되는 부분은 다 같은 내용임. 그래서 저 비례식이 성립함

 

IAT(Import Address Table) - 프로그램이 어떤 라이브러리의 어떤 함수를 사용하고 있는지 기술한 테이블

DLL(Dynamic Linked Library) - IAT는 프로그램이 로딩될때 DLL을 로딩하고 종료할때 DLL을 해제하는 메커니즘을 제공하는 역할.

INT(Import Name Table) - 임포트 하는 함수의 정보(Ordinal, name이 담긴 구조체 포인터 배열)

 

IAT 입력 순서

Import table의 name을 읽어서 문자열을 얻음(kernel32.dll)

해당 라이브러리를 로딩 함 -> loadlibrary("kernel32.dll")

import table의 INT주소를 얻음

INT 배열에서 배열 값을 하나씩 읽으면서 함수 이름 주소를 얻음

이름과 index를 얻어서 IAT의 배열로 매핑

IAT는 PE로더에 의해 실제 DLL의 함수 주소가 써짐

 

optional header의  DataDirectory[1]에  Import table 시작 위치와 개수가 있음.

시작 위치(RVA로)부터 나온 개수만큼 Import_Descriptor 구조체가 나옴

Import_Descriptor 구조체크기 - 20바이트

 내 컴퓨터 메모장

 

Import table 시작 점 - 2647C       크기  21C -> 540 바이트 -> 27개 dll 

 

header 크기 400

.text 크기 223B8, 시작점 1000

.data  크기 1f74, 시작점 24000

.idata 크기 214E , 시작점 26000, file 시작점 , 23200

import table RAW =

2647C - 26000 + 23200 =2367C

 

첫번째 Import_Descriptor인

2367C로 가보면 

INT - 26700      RAW = 23900     가보면 주소 배열이 있음. 첫번째 주소 26D3C  RAW = 23F3C 가보면 ordinal = 2B0, 이름은 GetProcAddress라는 함수의 정보가 있음

name - 27110   RAW = 24310              가보면 KERNEL32.dll이 있음

IAT - 26068        RAW = 23268       가보면 주소 배열이 있음. 첫번째 주소 26D3C RAW = 23F3C INT 와 같음. 파일이 실행될때 실제 함수의 주소가 써짐.

 

두번째 Import_Descriptor인

23690으로 가보면

INT - 266A4           RAW = 238A4   가보면 주소 배열이 있음. 첫번째 주소 27256 RAW = 24456 가보면 ordinal = 34, 이름은 CreateDCW라는 함수의 정보가 있음

Name - 27262      RAW = 24462       가보면 GDI32.dll이 있음

IAT - 2600C          RAW = 2320C     가보면 주소 배열이 있음. 첫번째 주소 27256 RAW = 24456 INT 와 같음. 파일이 실행될때  PE loader에 의해 실제 함수의 주소가 써짐.

 

 

INT가 null이라면 IAT에 접근해서 정보를 얻고 IAT에 주소를 덮어씀.  INT와 IAT가 같은 영역이어도 잘 작동함.

 

EAT

-다른 프로그램에서 불러 쓸 수 있도록 관련 함수를 모아놓은 파일.

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

 

IAT와 다르게 EAT는 하나만 존재. 임포트는 여러개 할 수 있지만 export는 하나만 하니까.

 

IAT는 kernel32.dll, GID32.dll 등 여러개 임포트 가능. export는 하나 함수는 여러개

 

EXPORT_DIRECTORY 구조체 하나.

 

optional header의 directory[0]에 주소, 사이즈가 있음.

 

Name - 라이브러리 이름

NumberOfFunctions - export 함수 개수

NumberOfNames  - export 함수 중에서 이름을 가지는 함수 개수( <= numberofFunctions)

AddressOfFunctions - export 함수 주소 배열 (NumberOfFunctions)

AddressOfNames - 함수 이름 주소 배열 (NumberOfNames)

AddressOfnameOrdinals - Ordinal 배열 ( NumberOfNames)

 

GetProcAddress 동작 원리

 

AddressOfNames 멤버를 이용해 함수 이름 배열로 감

함수 이름 배열은 문자열 주소가 저장되어 있음. 문자열 비교를 통해 원하는 함수의 이름을 찾음.찾은 index = name_index

AddressOfNameOrdinals 배열을 이용해서 name_index로 Ordinal 값을 찾음.

AddressOfFunctions 멤버를 이용해 함수 주소 배열(ETA)로 감.

함수 주소 배열에서 구한 Ordinal을 배열 인덱스로 하여 원하는 함수의 주소를 얻음.

 

 

실행 압축

 

데이터 압축

-비손실 압축

압축해서 크기를 줄임. 압축 해제시 원본과 똑같음.

 

 

-손실 압축

 멀티미디어 파일을 압축률을 올리기 위해 사람의 눈과 귀가 알아채지 못하는 만큼 손상을 주어 압축

압축된 걸 원본으로 바꿀 수 없음.

 

실행 압축

PE파일을 압축한 PE파일.

압축된 PE파일과 decoding 루틴이 존재

압축된 PE파일을 원본으로 decoding해서 PE 파일을 실행

 

패커(Run time packer)

-PE파일을 압축해서 압축된 PE 생성

안티 리버싱 기법에 특화된 패커를 프로텍터라 함

 

PE 파일 크기 줄이기

PE 파일 내부 코드와 리소스 감추기

 

PE 프로텍터

- 리버싱으로 부터 보호하기 위한 유틸

- 원본 PE보다 커지는 경향이 있음

크래킹 방지

코드 및 리소스 보호

 

 

Base Relocation table

 

PE 재배치 - PE파일이 로딩 될 때 이미 그 주소를 사용중이면 다른 주소에 로딩되는것.

exe는 맨 처음 메모리에 올라오기때문에 발생 안함

dll같은 경우 발생 할 수 있으나 os 주요한 dll은 고유 imagebase가 있어서 relocation이 발생할 일이 없음.

 

PE파일에 주소가 하드코딩되어있는 경우 이를 메모리에 올릴때 바꿔줘야 함.

 

PE재배치 원리

1. 하드코딩 된 위치를 찾는다.

2. 하드코딩 된 주소를 imagebase만큼 뺀다

3. 실제 로딩 된 주소를 더한다.

 

하드코딩된 주소가 모여있는 테이블 - Relocation table ( 컴파일 되는 과정에서 제공됨)

 

Optional header의 directory[5]에 base relocation table이 있음

BASE RELOCATION TABLE 해석방법

virtual address 4바이트

sizeofblock 4바이트

typeoffset 2바이트

 

sizeofblock개수만큼 수정할게 있고 typeoffset이 sizeofblock 만큼의 배열

sizeofblock의 앞 4비트는 type 뒤 12비트는 offset

virtual address + offset이 수정할 RVA 주소

 

base relocation table의 RVA = 2B000 ,RAW = 26200

파일의 26200으로 가면 base reloaction table 시작 

virtual address = 1000

sizeofblock = 218

typeoffset = 3000,3004,3008,300C, ....

계산 법

 imagebase =400000

1000+0 -> RVA 1000 -> RAW = 400 찾아가면, 4248D8 값이 있음  -> 248D8 + 로딩된 실제 주소

1000+4 -> RVA 1004  -> RAW = 404 찾아가면 424928 -> 24928 + 실제 로딩된 주소

1000+8 -> RVA 1008  -> RAW = 408 찾아가면 401424 -> 1424 + 실제 로딩된 주소

1000+C -> RVA 100C  -> RAW = 40C 찾아가면 4226E0 -> 226E0 + 실제 로딩된 주소

 

 

 

섹션 추가 제거 방법

1.섹션 헤더 추가 / 정리

2. 섹션 제거 / 추가

3.FIle_header , numberofSection 수정

4.optionalheader sizeOfImage 수정