본문 바로가기
카테고리 없음

13장. EAT - 실습 해보기

by HHack 2025. 1. 23.
반응형

1. Export Directroy의 Raw값 구하기

그림 1.kernel32.dll

1.1 PE Header 위치

  • e_lfanew 값(3C에 위치) : 0xF0
  • PE Header는 파일의 0xF0 오프셋에서 시작합니다.

1.2 PE Header 구조

PE Header는 다음과 같은 구조를 가지고 있습니다:

  1. PE Signature (4 bytes)
    • 값: 50 45 00 00 (ASCII로 'PE')
  2. COFF File Header (IMAGE_FILE_HEADER) (20 bytes)
  3. Optional Header (IMAGE_OPTIONAL_HEADER32)
    • 이 부분에서 DataDirectory를 찾을 수 있습니다.

1.3 Optional Header 위치

  • Optional Header는 PE Header의 시작 + 24바이트 지점에서 시작됩니다.
  • PE Header가 0xF0에 있으므로, Optional Header의 시작 오프셋은: 0xF0 + 0x18 = 0x108

1.4 Data Directory 위치

  • DataDirectory는 Optional Header 내에서 96바이트 오프셋부터 시작됩니다.
  • 따라서, DataDirectory[0]의 시작 위치는: 0x108 + 0x60 = 0x168

1.5 IMAGE_DATA_DIRECTORY 구조(0x168)

PE Header는 다음과 같은 구조를 가지고 있습니다:

  • VirtualAddress (4 bytes): 0x262C
  • Size (4 bytes): 0x6CFD

1.6 다음 단계: 파일 오프셋 계산

RVA는 메모리 상의 주소를 기준으로 합니다. 파일에서 해당 데이터를 읽으려면 RVA를 파일 오프셋으로 변환해야 합니다.

파일 오프셋을 계산하려면 Section Header 정보를 참조해야 합니다:

  1. PE 헤더의 NumberOfSections를 통해 섹션 수를 확인.
  2. 각 섹션의 VirtualAddressPointerToRawData를 이용해 매핑
    • VirtualAddress ≤ RVA < VirtualAddress + VirtualSize인 섹션을 찾습니다.
    • 해당 섹션의 파일 오프셋
      FileOffset = PointerToRawData + (RVA − Section.VirtualAddress)

1.7 Section Header 확인

Section Header는 Optional Header의 끝에 있습니다:

  1. Optional Header 크기는 PE Header의 SizeOfOptionalHeader 필드에서 확인 가능.
    • SizeOfOptionalHeader 필드는 PE Header + 20바이트(0x14) 위치에 있습니다.
      따라서 F0 + 0x14 = 0x104이며 그 값은 "E0 00"입니다.
    • 이를 리틀엔디언 방식으로 계산하면 "0x00E0"이며 이는 10진수로 224입니다.
  2. PE Header 위치 (0xF0) + 4 (Signature) + 20 (COFF Header) + SizeOfOptionalHeader로 Section Header 시작 위치를 찾습니다.
  3. IMAGE_SECTION_HEADER 구조를 읽어 Section 정보를 얻습니다.

1.8 Section Header 위치 계산

  1. Optional Header 끝 위치
    • Optional Header의 시작 위치는 PE Header 바로 뒤이므로
    • Optional Header 시작 = 0xF0 + 24 = 0x108.
    • Optional Header의 끝은 Optional Header 시작 + SizeOfOptionalHeader이므로
    • Optional Header 끝 = 0x108 + 0xE0 = 0x1E8.
  2. Section Header 위치
    • Section Header는 Optional Header 끝 위치에서 시작합니다.
    • 따라서 Section Header의 시작 위치는 0x1E8입니다.

1.9 Section Header 데이터 분석

PE 파일의 Section Header는 각 섹션당 40바이트로 구성됩니다. 따라서 주어진 데이터에서 각각 40바이트씩 나눠서 분석합니다.

2E 74 65 78 74 00 00 00   ; Name: .text
C9 30 08 00               ; Virtual Size: 0x000830C9
00 10 00 00               ; Virtual Address (RVA): 0x00001000
00 32 08 00               ; Size of Raw Data: 0x00083200
00 04 00 00               ; Pointer to Raw Data: 0x00000400
00 00 00 00               ; Pointer to Relocations: 0x00000000
00 00 00 00               ; Pointer to Line Numbers: 0x00000000
00 00                     ; Number of Relocations: 0
00 00                     ; Number of Line Numbers: 0
20 00 00 60               ; Characteristics: 0x60000020

 

  • Name: .text (코드 섹션)
  • Virtual Size: 0x000830C9 (메모리에서 차지하는 크기)
  • RVA: 0x00001000 (메모리 기준 시작 주소)
  • Size of Raw Data: 0x00083200 (파일에서 차지하는 크기)
  • Pointer to Raw Data: 0x00000400 (파일에서의 시작 위치)
  • Characteristics: 0x60000020 (섹션의 속성 - 실행 가능, 읽기 가능)
2E 64 61 74 61 00 00 00   ; Name: .data
00 44 00 00               ; Virtual Size: 0x00004400
00 50 08 00               ; Virtual Address (RVA): 0x00085000
26 00 00 00               ; Size of Raw Data: 0x00000026
36 08 00 00               ; Pointer to Raw Data: 0x00000836
00 00 00 00               ; Pointer to Relocations: 0x00000000
00 00 00 00               ; Pointer to Line Numbers: 0x00000000
00 00                     ; Number of Relocations: 0
00 00                     ; Number of Line Numbers: 0
40 00 00 C0               ; Characteristics: 0xC0000040

 

  • Name: .data (데이터 섹션)
  • Virtual Size: 0x00004400
  • RVA: 0x00085000
  • Size of Raw Data: 0x00000026
  • Pointer to Raw Data: 0x00000836
  • Characteristics: 0xC0000040 (섹션의 속성 - 읽기/쓰기 가능)
2E 72 73 72 63 00 00 00   ; Name: .rsrc
94 FE 09 00               ; Virtual Size: 0x0009FE94
00 A0 08 00               ; Virtual Address (RVA): 0x0008A000
00 0A 00 00               ; Size of Raw Data: 0x00000A00
5C 08 00 00               ; Pointer to Raw Data: 0x0000085C
00 00 00 00               ; Pointer to Relocations: 0x00000000
00 00 00 00               ; Pointer to Line Numbers: 0x00000000
00 00                     ; Number of Relocations: 0
00 00                     ; Number of Line Numbers: 0
40 00 00 40               ; Characteristics: 0x40000040

 

  • Name: .rsrc (리소스 섹션)
  • Virtual Size: 0x0009FE94
  • RVA: 0x0008A000
  • Size of Raw Data: 0x00000A00
  • Pointer to Raw Data: 0x0000085C
  • Characteristics: 0x40000040 (섹션의 속성 - 읽기 가능)
2E 72 65 6C 6F 63 00 00   ; Name: .reloc
80 5C 00 00               ; Virtual Size: 0x00005C80
00 A0 12 00               ; Virtual Address (RVA): 0x00012A000
5E 00 00 00               ; Size of Raw Data: 0x0000005E
5C 12 00 00               ; Pointer to Raw Data: 0x0000125C
00 00 00 00               ; Pointer to Relocations: 0x00000000
00 00 00 00               ; Pointer to Line Numbers: 0x00000000
00 00                     ; Number of Relocations: 0
00 00                     ; Number of Line Numbers: 0
40 00 00 42               ; Characteristics: 0x40000042

 

  • Name: .reloc (재배치 정보 섹션)
  • Virtual Size: 0x00005C80
  • RVA: 0x00012A000
  • Size of Raw Data: 0x0000005E
  • Pointer to Raw Data: 0x0000125C
  • Characteristics: 0x40000042 (섹션의 속성 - 읽기 가능)

1.10  Export Directory의 RVARAW로 변환

  1. 필요한 정보
    • Export Directory의 RVA : 0x262C
    • Export Directory가 속한 섹션의 시작 RVA Pointer to Raw Data
      • 섹션 .text
      • Virtual Address (RVA): 0x1000
      • Pointer to Raw Data: 0x400
  2. 변환 공식
    • RAW = Pointer to Raw Data + (RVA - Section's Virtual Address)
  3. 계산
    1. RVA : 0x262C
    2. Section's Virtual Address : 0x1000
    3. Pointer to Raw Data : 0x400
    4. RAW = 0x400 + (0x262C − 0x1000) = 0x1A2C
  4. 결과  
    • Export Directory의 RAW 값은 "0x1A2C"입니다.

2. kernel32.dll 파일의 EAT에서 AddAtomW 함수 주소 찾기

[그림 2] kernel32.dll의 IMAGE_EXPORT_DIRECTORY 구조체 시작부분

2.1 각 멤버 해석

구조체 멤버 Offset 값 (리틀 엔디언) 해석된 값
Characteristics 0x1A2C 00 00 00 00 예약된 값 (사용되지 않음)
TimeDateStamp 0x1A30 48 02 5B E1 타임스탬프 : 0x48025BE1
MajorVersion 0x1A34 00 00 주요 버전 : 0
MinorVersion 0x1A36 00 00 부 버전 : 0
Name 0x1A38 00 00 4B 8E DLL 이름의 RVA : 0x00004B8E
Base 0x1A3C 00 00 00 01 Ordinal 시작 번호 : 1
NumberOfFunctions 0x1A40 00 00 03 B9 함수 개수(EAT) : 0x000003B9 (953개)
NumberOfNames 0x1A44 00 00 03 B9 함수 이름 테이블의 항목 개수 : 0x000003B9 (953개)
AddressOfFunctions 0x1A48 00 00 26 54 EAT의 RVA : 0x00002654
AddressOfNames 0x1A4C 00 00 35 38 Export Name Table의 RVA : 0x00003538
AddressOfNameOrdinals 0x1A50 00 00 44 1C Export Ordinal Table의 RVA : 0x0000441C

2.2 필요한 정보의 RAW 값 계산

  1. AddressOfFunctions의 RVA(0x2654) → RAW 변환
    • .text 섹션: RVA = 0x1000, RAW = 0x400
    • 변환 결과: 0x2654 - 0x1000 + 0x400 = 0x1A54
      → 함수 주소 배열의 RAW 값: 0x1A54
  2. AddressOfNames의 RVA(0x3538) → RAW 변환
    • .text 섹션: RVA = 0x1000, RAW = 0x400
    • 변환 결과: 0x3538 - 0x1000 + 0x400 = 0x2938
      → 이름 배열의 RAW 값: 0x2938
  3. AddressOfNameOrdinals의 RVA(0x441C) → RAW 변환
    • .text 섹션: RVA = 0x1000, RAW = 0x400
    • 변환 결과: 0x441C - 0x1000 + 0x400 = 0x381C
      → 이름 Ordinals 배열의 RAW 값: 0x381C

2.3 AddAtomW 이름 찾기

2.3.1 AddressOfNames(0x2938)에서 AddAtomW 문자열 위치 확인

[그림 3] AddressOfNames(0x2938)
  • 배열에서 AddAtomW 문자열의 RVA를 찾습니다.
  • 해당 RVA로 이동하여 문자열 매칭을 수행합니다.

1. AddressOfNames에서 시작

AddressOfNames 필드에 있는 값들은 함수 이름의 RVA 값들입니다. 각 RVA는 함수 이름의 문자열이 저장된 위치를 나타냅니다. 우리가 해야 할 일은 이 중에서 AddAtomW가 저장된 위치를 찾아야 합니다.

 

2. 각 RVA를 .text의 RAW 주소로 변환

AddressOfNames의 각 엔트리는 RVA 값이므로 이를 RAW 주소로 변환해야 합니다. 변환 공식은 다음과 같습니다:

RAW = RVA − Section RVA + Raw Data Start

  • .text 섹션의 시작 RVA : 0x1000
  • .text 섹션의 시작 RAW : 0x400

예를 들어, 첫 번째 RVA (0x4B9B)를 변환하면

RAW = 0x4B9B − 0x1000 + 0x400 = 0x3F9B

[그림 4] 0x3F9B 주소 확인

3. 이름 데이터에서 AddAtomW 찾기

  1. 변환된 RAW 주소로 HxD에서 데이터를 확인합니다.
  2. 각 문자열을 확인하며 AddAtomW 이름이 포함된 위치를 찾습니다.(0x3FB3)
  3. AddAtomW의 인덱스는 3번째입니다.

4. AddressOfNameOrdinals에서 Ordinal 값 확인

  1. AddressOfNameOrdinals의 RAW값인 0x381C로 갑니다.
  2. Ordinal 값2바이트 값(WORD)으로 저장되어 있습니다.
  3. 3번째 index 값(2)을 찾습니다.
[그림 5] AddressOfNameOrdinals의 3번째 인덱스 값(2)

5. 함수 주소 배열에서 AddAtomW 찾기

  1. 함수 주소 배열의 RAW 값은 "0x1A54" 입니다.
  2. 여기서 3번째 인덱스에 해당하는 값을 찾습니다.
  3. 이 값은 AddAtomW의 RVA 값입니다.(0326D9)
[그림 6] AddressOfFunction의 3번째 값(AddAtomW)

 

6. AddAtomW 함수 주소 확인하기

  1. kernel32.dll의 ImageBase값과 AddAtomW의 RVA 값을 더합니다.
  2. ImageBase = 7C800000
  3. AddAtomW의 RVA = 326D9
  4. AddAtomW 함수 주소 = 7C8326D9
[그림 7] x32dbg로 확인한 AddAtomW 실제 주소

※ ImageBase 구하는 법

1. PE Header 위치 찾기

PE Header의 위치는 0x3C 위치에 있습니다. 그 값은 F0입니다. 즉, PE 헤더 파일은 F0부터 시작합니다.(그림 1 참조)

2. PE 헤더의 Optional Header에서 ImageBase 확인

  1. PE 헤더의 시작 위치:
    • e_lfanew 값이 0xF0입니다.
    • 따라서, PE 헤더0xF0에서 시작합니다.
  2. Optional Header의 시작 위치:
    • PE 헤더에서 Optional Header0x18 오프셋 이후에 시작합니다.
    • Optional Header 시작 위치 = 0xF0 + 0x18 = 0x108입니다.
  3. ImageBase 필드 위치:
    • Optional Header에서 ImageBase는 0x1C 오프셋에 있습니다.
    • 따라서, ImageBase 위치 = 0x108 + 0x1C = 0x124입니다.
    • ImageBase 값은 "7C800000" 입니다.
[그림 8] ImageBase값

 

  •  
반응형