#include "header.h"
int offset = 0;
int main(int argc, char** argv)
{
FILE* file = NULL;
u_char* buf = NULL;
int file_size = 0, raw = 0;
if (argc < 2)
{
printf("분석하실 파일을 입력해주세요.\n");
return -1;
}
if ((file = fopen(argv[1], "rb")) == NULL)
{
printf("해당 파일을 읽을 수 없습니다.\n%s\n", strerror(errno));
return -1;
}
// 파일의 크기를 구하고 내용을 읽는다.
if ((buf = (u_char*)get_file_content(file, &file_size)) == NULL)
{
printf("파일의 내용을 읽어올 수 없습니다.\n%s\n", strerror(errno));
return -1;
}
/* dos header */
IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)buf;
/* dos header->e_lfanew : NT header 구조체의 시작 offset 값 */
IMAGE_NT_HEADERS* inh = (IMAGE_NT_HEADERS*)(buf + idh->e_lfanew);
/* Section header : NT header 구조체의 시작 부분 + 4byte + file header 크기 + sizeofOptionalheader의 값 한 offset */
IMAGE_SECTION_HEADER* ish = (IMAGE_SECTION_HEADER*)(buf + idh->e_lfanew + sizeof(inh->Signature) + sizeof(inh->FileHeader) + inh->FileHeader.SizeOfOptionalHeader);
// 프로그램이 dos 파일인지 검사
if ((idh->e_magic != IMAGE_DOS_SIGNATURE) || (inh->Signature != IMAGE_NT_SIGNATURE))
{
printf("해당 파일은 PE 파일이 아닙니다.\n");
return -1;
}
// 32bit 프로그램일 때
if (inh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
IMAGE_NT_HEADERS32* inh32 = (IMAGE_NT_HEADERS32*)(buf + idh->e_lfanew);
printf("\n32bit Program\n\n");
// 파일의 크기가 몇인지 출력
printf("File Size : %d byte\n\n", file_size);
/* dos header */
print_dos_header(file, idh);
/* 32bit용 NT Header */
print_nt_header(file, buf, OPERAND_NT32);
// print_section_header()에서 for문에 사용될 section 개수 구하기
WORD section_num = inh32->FileHeader.NumberOfSections;
/* Section header */
print_section_header(file, ish, section_num);
/* IMAGE_IMPORT_DESCRIPTOR */
printf("========== [IMAGE_IMPORT_DESCRIPTOR] ==========\n\n");
// IID 구조체 값 출력
print_image_import_descriptor(file, buf, OPERAND_IID32);
printf("===============================================\n\n");
/* IMAGE_EXPORT_DERECTORY */
printf("========== [IMAGE_EXPORT_DIRECTORY] ==========\n\n");
// EXPORT directory의 유무 확인
if (inh32->OptionalHeader.DataDirectory[0].VirtualAddress == 0x00000000)
printf("EXPORT DIRECTORY가 존재하지 않습니다.\n");
else
{
raw = (int)convert_rva_to_raw(buf, &(inh32->OptionalHeader.DataDirectory[0].VirtualAddress), OPERAND_DWORD);
printf("EXPORT Directory RAW : %08X\n\n", raw);
IMAGE_EXPORT_DIRECTORY* ied = (IMAGE_EXPORT_DIRECTORY*)(buf + raw);
//int export_directory_size = inh32->OptionalHeader.DataDirectory[0].Size / sizeof(IMAGE_EXPORT_DIRECTORY);
print_image_export_directory(file, buf, ied);
}
printf("\n==============================================\n\n");
}
// 64bit 프로그램일 때
else if (inh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
IMAGE_NT_HEADERS64* inh64 = (IMAGE_NT_HEADERS64*)(buf + idh->e_lfanew);
printf("\n64bit Program\n\n");
// 파일의 크기가 몇인지 출력
printf("File Size : %d byte\n\n", file_size);
/* dos header */
print_dos_header(file, idh);
/*64bit용 NT Header*/
print_nt_header(file, buf, OPERAND_NT64);
// print_section_header()에서 for문에 사용될 section 개수 구하기
WORD section_num = inh64->FileHeader.NumberOfSections;
/* Section header */
print_section_header(file, ish, section_num);
/* IMAGE_IMPORT_DESCRIPTOR */
printf("==================== [IMAGE_IMPORT_DESCRIPTOR] ====================\n\n");
//print_image_import_descriptor(file, buf, iid, import_descriptor_size);
print_image_import_descriptor(file, buf, OPERAND_IID64);
printf("===================================================================\n\n");
/* IMAGE_EXPORT_DERECTORY */
printf("========== [IMAGE_EXPORT_DIRECTORY] ==========\n\n");
// EXPORT directory의 유무 확인
if (inh64->OptionalHeader.DataDirectory[0].VirtualAddress == 0x00000000)
printf("EXPORT DIRECTORY가 존재하지 않습니다.\n");
else
{
raw = (int)convert_rva_to_raw(buf, &(inh64->OptionalHeader.DataDirectory[0].VirtualAddress), OPERAND_DWORD);
printf("EXPORT Directory RAW : %X\n", raw);
IMAGE_EXPORT_DIRECTORY* ied = (IMAGE_EXPORT_DIRECTORY*)(buf + raw);
//int export_directory_size = inh64->OptionalHeader.DataDirectory[0].Size / sizeof(IMAGE_EXPORT_DIRECTORY);
print_image_export_directory(file, buf, ied);
}
printf("\n==============================================\n\n");
}
free(buf);
fclose(file);
return 0;
}
main 함수 코드 설명
인자 검사 및 파일 검사
사용자가 프로그램 실행과 함께 분석할 대상 파일을 인자로 주지 않으면 "분석하실 파일을 입력해주세요" 라고 띄운다.
인자로 받은 파일을 열 수 없으면 "해당 파일을 읽을 수 없습니다"라고 띄운다.
파일의 내용을 동적 메모리 공간에 담는 데 실패하면 "파일의 내용을 읽어올 수 없습니다" 라고 띄운다.
PE 파일인지 검사
IMAGE_DOS_HEADER 구조체 멤버 e_magic과 IMAGE_NT_HEADER 구조체 멤버 Signature을 검사하여 dos 파일 및 pe 파일이 맞는지 확인한다.
32bit 모드, 64bit 모드 구분
IMAGE_NT_HEADER 구조체의 멤버 IMAGE_OPTIONAL_HEADER 구조체 멤버 magic를 검사하여 32bit 파일인지 64bit 파일인지 검사한다.
IMAGE_NT_HEADER 구조체의 멤버 IMAGE_FILE_HEADER 구조체 멤버 machine 값으로 구분해도 되지만, 심하게 꼬아버리는 패커들의 경우 해당 멤버의 값을 변조하기 때문에 변조의 가능성이 있고, SizeOfOptionalHeader 멤버의 값으로 구분할 수도 있지만, 해당 멤버의 값 역시 변조의 가능성이 있다.
하여 더 명확하게 판단하기 위해 Optional header 구조체의 멤버 magic으로 판별하는 것이다.
검사 후 32bit 파일이면 32bit 파일임을 출력하고, 64bit 파일이면 64bit 파일임을 출력한다.
파싱하여 출력하는 함수 호출
먼저 분석 대상 파일의 크기를 출력해준다.
그 후 차례대로 print_dos_header() 함수, print_nt_header() 함수, print_section_header() 함수, print_image_import_descriptor() 함수, print_image_export_directory() 함수를 호출하여 화면에 PE 구조를 출력한다.
'toy project > Reversing' 카테고리의 다른 글
[Toy project] PE Viewer 툴 만들기(8) print_ied.c (0) | 2023.07.27 |
---|---|
[Toy Project] PE Viewer 툴 만들기(7) print_iid.c (0) | 2023.07.27 |
[Toy Project] PE Viewer 툴 만들기(6) convert_rva_to_raw.c (0) | 2023.07.26 |
[Toy Project] PE Viewer 툴 만들기(5) print_section_header.c (0) | 2023.07.26 |
[Toy Project] PE Viewer 툴 만들기(4) print_inh_ioh_datadirectory.c (0) | 2023.07.26 |