PE Viewer 개발 (3) - IMAGE_SECTION_HEADER
- 리버싱/리버싱
- 2020. 2. 11. 23:27
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)에 대해 작성할 예정이다.
'리버싱 > 리버싱' 카테고리의 다른 글
[원데이 취약점] GOM Player 2.0.12.3375 - '.asx' Local Stack Overflow (0) | 2020.03.11 |
---|---|
IDA 사용법 및 분석 시 유용한 팁 (0) | 2020.03.07 |
바이너리 디핑을 위한 bindiff 설치 및 사용법 (0) | 2020.02.21 |
PE Viewer 개발 (2) - IMAGE_NT_HEADERS (0) | 2020.02.09 |
PE Viewer 개발 (1) - IMAGE_DOS_HEADER (0) | 2020.02.09 |