반응형
#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 구조를 출력한다.
 
 
 
 
 
 

반응형

+ Recent posts