-->

PE Viewer 개발 (3) - IMAGE_SECTION_HEADER

반응형

 

C언어로 개발하는 PE Viewer(PE 뷰어) 세번째 포스팅에서는 지난 포스팅의 NT 헤더에 이어서 섹션 헤더(IMAGE_SECTION_HEADER) 구조체 배열을 파싱해볼 것이다. 섹션 헤더는 정해진 갯수대로 있는 것이 아니라 PE 파일마다 다르기 때문에 분석 후 파싱하는 코드를 짤 때 주의해야 한다. 

 

 

Section Header (IMAGE_SECTION_HEADER)

섹션 헤더의 IMAGE_SECTION_HEADER 구조체는 하나가 아니라 구조체 배열이다. 

 

 

 

IMAGE_SECTION_HEADER 정의

IMAGE_NT_HEADER 구조체에 이어서 IMAGE_SECTION_HEADER 구조체의 배열이 온다. PE 파일은 code, data, resource 등을 각각의 섹션으로 나누어 저장하는데 이에 관한 각 섹션의 속성을 정의하는 곳이 IMAGE_SECTION_HEADER 부분이다.

 

- 시작 위치 : IMAGE_OPTIONAL_HEADER 뒤

- 배열 수 : IMAGE_FILE_HEADER.NumberOfSections 값

- 크기 : 40바이트

 

IMAGE_SECTION_HEADER 구조체는 아래와 같이 정의될 수 있다.

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize; // 메모리에서 섹션이 차지하는 크기
  } Misc;
  DWORD VirtualAddress; // 메모리에서의 섹션의 시작 주소 (RVA)
  DWORD SizeOfRawData; // 파일에서 섹션이 차지하는 크기
  DWORD PointerToRawData; // 파일에서 섹션의 시작 위치
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics; // 섹션의 특징 (bit OR)
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

 

 

IMAGE_SECTION_HEADER 구조체 변수 선언

IMAGE_SECTION_HEADER 구조체는 배열의 형태로 오며 IMAGE_OPTIONAL_HEADER의 바로 뒤부터 배열이 시작된다.

int pe_print_32(char* file, char* option)
{
	// 코드...
    
	// IMGAE_SECTION_HEADER
	// IMGAE_SECTION_HEADER는 IMAGE_NT_HEADER (크기:0xF8)이 끝나고 시작됨
	PIMAGE_SECTION_HEADER ish = (PBYTE)buffer + (idh->e_lfanew) + 24 + (ifh->SizeOfOptionalHeader);
    
	// 코드...
}   

 

 

IMAGE_SECTION_HEADER 구조체 배열 파싱 및 출력

일단 섹션 헤더의 수는 IMAGE_FILE_HEADER의 NumberOfSenctions에 정의되어있기 때문에 해당 값만큼 반복문을 돌려주었다. PE파일마다 갖고 있는 섹션헤더의 수가 가변적이기 때문에 고정적인수를 사용하면 안된다. 반복문 끝에서 ish++를 해주어 다음 IMAGE_SECTION_HEADER 구조체가 파싱될 수 있게 한다.

int pe_print_32(char* file, char* option)
{
	// 코드...
    
	// IMGAE_SECTION_HEADER
	printf("******************************** [IMAGE_SECTION_HEADER] *********************************\n\n");

	// 섹션의 수만큼 반복
	for (i=0; i < (ifh->NumberOfSections); i++)
	{
		file_offset = (idh->e_lfanew) + 24 + (ifh->SizeOfOptionalHeader) + 40 * i;
		printf("************************************** [SECTION %s] **************************************\n\n", ish->Name);
		printf("- pFile: %04X | Data: %04X | Description: Name\n", file_offset, ish->Name);
		printf("- pFile: %04X | Data: %04X | Description: VirtualAddress\n", file_offset + 1, ish->VirtualAddress);
		printf("- pFile: %04X | Data: %04X | Description:SizeOfRawData\n", file_offset + 2, ish->SizeOfRawData);
		printf("- pFile: %04X | Data: %04X | Description: PointerToRawData\n", file_offset + 3, ish->PointerToRawData);
		printf("- pFile: %04X | Data: %04X | Description: PointerToRelocations\n", file_offset + 4, ish->PointerToRelocations);
		printf("- pFile: %04X | Data: %04X | Description: PointerToLinenumbers\n", file_offset + 5, ish->PointerToLinenumbers);
		printf("- pFile: %04X | Data: %04X | Description: NumberOfRelocations\n", file_offset + 6, ish->NumberOfRelocations);
		printf("- pFile: %04X | Data: %04X | Description: NumberOfLinenumbers\n", file_offset + 7, ish->NumberOfLinenumbers);
		printf("- pFile: %04X | Data: %04X | Description: Characteristics\n\n", file_offset + 8, ish->Characteristics);

		ish++;
	}
    
    	// 코드...
}

 

 

system32 폴더의 ntdll.dll의 경우 섹션 헤더 수 (ifh->NumberOfSections 값) 가 총 7개로 '.text', 'RT', '.data', '.mrdata', '00cfg', 'rsrc', 'reloc' 섹션이 파싱된 출력 결과를 볼 수 있다.

 

 

 

다음 PEViewer 개발 포스팅부터는 Import Directory Table (IDT), Import Address Table (IAT), Import Name Table (INT)에 대해 작성할 예정이다.

 

댓글

Designed by JB FACTORY