为什么我的放牧功能无法从PE文件读取NT/可选标头? 该程序的目的是打印我想要的便携式可执行文件的区域,包括IAT偏移量,食用偏移量,并用其地址和模块打印所有导入的功能。

问题描述 投票:0回答:1

[>] Number of Sections: 10 [>] Size of Optional Header: 240 [>] File is an EXE [>] Architecture: x64 [>] Image Base: 0x0000000140000000 [>] Image Size: 0x00026000 [>] Section Alignment: 0x00001000 [>] File Alignment: 0x00000200 [>] Subsystem: 0x0003 [>] Number of Data Directories: 16 [>] Size of Stack Reserve: 0x0000000000100000 bytes [>] Size of Stack Commit: 0x0000000000001000 bytes [>] Size of Heap Reserve: 0x0000000000100000 bytes [>] Size of Heap Commit: 0x0000000000001000 bytes Unknown optional header size Failed to read NT headers

是的,我未能阅读可选标题和NT标题

我为RVA用于提交偏移的功能:

uint32_t rva_to_offset(uint32_t rva, IMAGE_SECTION_HEADER* sections, int numberOfSections) {
    for (int i = 0; i < numberOfSections; i++) {
        uint32_t sectionStartRVA = sections[i].VirtualAddress;
        uint32_t sectionEndRVA = sectionStartRVA + sections[i].Misc.VirtualSize;

        if (rva >= sectionStartRVA && rva < sectionEndRVA) {
            // calculate and return the offset
            uint32_t offset = sections[i].PointerToRawData + (rva - sectionStartRVA);
            printf("RVA 0x%08X maps to offset 0x%08X in section %d\n", rva, offset, i);
            return offset;
        }
    }
    return 0xFFFFFFFF; // err
}
then parse标题:

PIMAGE_NT_HEADERS ParseHeaders(FILE* pefile, OUT uint16_t* architecture) { IMAGE_DOS_HEADER DOSHeader; if (fread(&DOSHeader, sizeof(IMAGE_DOS_HEADER), 1, pefile) != 1) { printf("Failed to read DOS header \n"); return NULL; } // Move the file pointer to the NT headers location if (fseek(pefile, DOSHeader.e_lfanew, SEEK_SET) != 0) { printf("Failed to seek to NT headers \n"); return NULL; } PIMAGE_NT_HEADERS NtHeaders = (PIMAGE_NT_HEADERS)malloc(sizeof(IMAGE_NT_HEADERS)); if (NtHeaders == NULL) { printf("Failed to allocate memory for NT headers \n"); return NULL; } if (fread(NtHeaders, sizeof(IMAGE_NT_HEADERS), 1, pefile) != 1) { printf("Failed to read NT headers \n"); return NULL; } // Check the signature if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) { printf("Invalid NT headers signature \n"); return NULL; } // File header IMAGE_FILE_HEADER* FileHeader = &NtHeaders->FileHeader; printf("\t[>] Number of Sections: %u\n", FileHeader->NumberOfSections); printf("\t[>] Size of Optional Header: %u\n", FileHeader->SizeOfOptionalHeader); // Check if DLL or EXE if (FileHeader->Characteristics & IMAGE_FILE_DLL) { printf("\t[>] File is a DLL \n"); } if (FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) { printf("\t[>] File is an EXE \n"); } if (NtHeaders->OptionalHeader.OptionalHeader32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { printf("\t[>] Architecture: x86 \n"); *architecture = IMAGE_NT_OPTIONAL_HDR32_MAGIC; // Access 32-bit optional header fields i print parsed PE stuff here, i wont include it bc its long } else if (NtHeaders->OptionalHeader.OptionalHeader64.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { printf("\t[>] Architecture: x64 \n"); *architecture = IMAGE_NT_OPTIONAL_HDR64_MAGIC; // Access 64-bit optional header fields i print parsed PE stuff here, i wont include it bc its long } else { printf("\t[>] Architecture: ?"); *architecture = 0; free(NtHeaders); return NULL; } return NtHeaders; }

I使用RVA来抵消解析部分的函数(此处出现“未知的可选标题大小”):
PIMAGE_SECTION_HEADER ParseSections(FILE* pefile, IN IMAGE_NT_HEADERS* NtHeaders) {

    // Calculate offset from the start of the file
    size_t sizeOfHeaders = 0;
    if (NtHeaders->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) {
        sizeOfHeaders = NtHeaders->OptionalHeader.OptionalHeader32.SizeOfHeaders;
    }
    else if (NtHeaders->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) {
        sizeOfHeaders = NtHeaders->OptionalHeader.OptionalHeader64.SizeOfHeaders;
    }
    else {
        printf("Unknown optional header size \n");
        return NULL;
    }

    // Calculate the offset to the section headers
    if (fseek(pefile, sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + sizeOfHeaders, SEEK_SET) != 0) {
        printf("Failed to seek to section headers \n");
        return NULL;
    }

    // Allocate memory for section headers
    PIMAGE_SECTION_HEADER SectionHeaders = (PIMAGE_SECTION_HEADER)malloc(NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
    if (SectionHeaders == NULL) {
        printf("Allocation failed (section headers) \n");
        return NULL;
    }

    // Read section headers from the file
    size_t readCount = fread(SectionHeaders, sizeof(IMAGE_SECTION_HEADER), NtHeaders->FileHeader.NumberOfSections, pefile);
    if (readCount != NtHeaders->FileHeader.NumberOfSections) {
        printf("Failed to read section headers \n");
        free(SectionHeaders);
        return NULL;
    }

    return SectionHeaders;
}

thressing IAT(“未能读取nt标题”在这里发生)

void ParseIAT(FILE* pefile, uint16_t architecture) {
    if (!pefile) {
        printf("Invalid PE file\n");
        return;
    }

    if (architecture != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
        printf("Error: Not x64 but trying to parse x64.\n");
        return;
    }

    // Seek to the start of the NT headers to read them properly
    fseek(pefile, 0, SEEK_SET);

    IMAGE_NT_HEADERS NtHeaders;
    if (fread(&NtHeaders, sizeof(IMAGE_NT_HEADERS), 1, pefile) != 1) {
        printf("Failed to read NT headers \n");
        return;
    }

    PIMAGE_SECTION_HEADER SectionHeaders = ParseSections(pefile, &NtHeaders);
    if (SectionHeaders == NULL) {
        printf("Failed to parse sections \n");
        return;
    }

    IMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NtHeaders.OptionalHeader.OptionalHeader64;

    // Get import directory RVA
    IMAGE_DATA_DIRECTORY ImportDirectory = OptionalHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    uint32_t ImportDirectoryRVA = ImportDirectory.VirtualAddress;
    uint32_t ImportDirectorySize = ImportDirectory.Size;

    if (ImportDirectoryRVA == 0) {
        printf("No import directory \n");
        return;
    }

    printf("\t[>] Import Directory Address: 0x%08X - Size: 0x%08X\n\n", ImportDirectoryRVA, ImportDirectorySize);

    // Convert import directory RVA to a file offset
    uint32_t ImportDirectoryOffset = rva_to_offset(ImportDirectoryRVA, SectionHeaders, NtHeaders.FileHeader.NumberOfSections);

    if (ImportDirectoryOffset == 0xFFFFFFFF) {
        printf("Invalid import directory offset\n");
        return;
    }

    // Seek to the import directory
    if (fseek(pefile, ImportDirectoryOffset, SEEK_SET) != 0) {
        printf("Failed to seek to import directory\n");
        return;
    }

    IMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
    while (fread(&ImportDescriptor, sizeof(ImportDescriptor), 1, pefile) == 1) {

        if (ImportDescriptor.Name == 0) {
            break; // end of descriptors
        }

        // Get module name
        uint32_t moduleNameRVA = ImportDescriptor.Name;
        uint32_t moduleNameOffset = rva_to_offset(moduleNameRVA, SectionHeaders, NtHeaders.FileHeader.NumberOfSections);

        if (moduleNameOffset == 0xFFFFFFFF) {
            printf("Invalid module name offset\n");
            return;
        }

        char moduleName[256];

        fseek(pefile, moduleNameOffset, SEEK_SET);

        if (fread(moduleName, 1, sizeof(moduleName) - 1, pefile) <= 0) {
            printf("Failed to read module name\n");
            return;
        }

        moduleName[sizeof(moduleName) - 1] = '\0';

        printf("[+] Module: %s\n", moduleName);

        uint32_t iatRVA = ImportDescriptor.FirstThunk;
        uint32_t iatOffset = rva_to_offset(iatRVA, SectionHeaders, NtHeaders.FileHeader.NumberOfSections);

        if (iatOffset == 0xFFFFFFFF) {
            printf("Invalid IAT offset\n");
            return;
        }

        if (fseek(pefile, iatOffset, SEEK_SET) != 0) {
            printf("Failed to seek IAT offset\n");
            return;
        }

        // Read and print addresses to all functions in this module's IAT
        uint32_t iatEntry;
        printf("[+] Import Address Table Offset: 0x%08X\n", iatOffset);

        while (fread(&iatEntry, sizeof(iatEntry), 1, pefile) == 1) {
            if (iatEntry == 0) {
                break; // end of entries
            }

            printf("\t[>] Function Address: 0x%08X ", iatEntry);

            if (iatEntry & 0x80000000) {
                uint16_t ordinal = (uint16_t)(iatEntry & 0xFFFF); // extract ordinal
                printf("\t\t[>] Function imported by ordinal: %u\n", ordinal);
            }
            else {
                uint32_t functionNameOffset = rva_to_offset(iatEntry, SectionHeaders, NtHeaders.FileHeader.NumberOfSections);

                if (functionNameOffset == 0xFFFFFFFF) {
                    printf("Invalid function name offset\n");
                    return;
                }

                fseek(pefile, functionNameOffset, SEEK_SET);

                IMAGE_IMPORT_BY_NAME functionName;
                if (fread(&functionName, sizeof(functionName), 1, pefile) != 1) {
                    printf("Failed to read function name\n");
                    return;
                }

                printf("\t\t[>] Name: %s\n", functionName.Name);
            }
        }
    }
}

我怎么称它们为主要:

    PE pe;
    pe.FilePath = argv[1];
    
    FILE* pefile = fopen(pe.FilePath, "rb");
    
    uint16_t architecture;

    PIMAGE_NT_HEADERS NtHeaders = ParseHeaders(pefile, &architecture);

    PIMAGE_SECTION_HEADER SectionHeaders = ParseSections(pefile, NtHeaders);

    // PE32+ (x64)
    if (architecture == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
        ParseEAT(pefile, architecture);
        ParseIAT(pefile, architecture);
    }
我对很多代码表示歉意,我只是不知道这个问题是什么

the toge a Gook for for
为什么说Image_optional_header没有固定尺寸?

为什么您会比较
SizeOfOptionalHeader
而不是使用

OptionalHeader.Magic

? 由于this this rimply
c windows parsing portable-executable
1个回答
0
投票

IMAGE_OPTIONAL_HEADER32

IMAGE_OPTIONAL_HEADER64

:“目录的数量未固定。
在寻找特定之前检查
NumberOfRvaAndSizes
成员
目录。
因此,您不应该使用SizeOfOptionalHeader

进行比较,而是通过
OptionalHeader.Magic

.

进行比较。
    

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.