【问题标题】:Loading PE Headers加载 PE 标头
【发布时间】:2012-02-05 15:42:20
【问题描述】:

基本上,我要做的是找到 PE 文件的最后一部分。我已经非常仔细地阅读了 PE 规范,但我无法发现我的代码失败的地方。

PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)(pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)(pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));

buffer 是一个包含已加载可执行文件的字节数组,pish 是指向最后一节的指针。由于某种原因,部分的数量似乎超过了 20 000。

有什么想法吗? 提前致谢

【问题讨论】:

  • “我无法发现我的代码失败的地方。” - 它是如何失败的?
  • 就像我说的,部分数量超过 20k。因此,当取消引用 pish 程序的成员时会崩溃。

标签: c winapi portable-executable


【解决方案1】:

我看到了一个问题:e_lfanew 是 bytesIMAGE_NT_HEADERS 结构的偏移量。您将此字节数添加到 IMAGE_DOS_HEADER 指针,因此您将向前移动 sizeof(IMAGE_DOS_HEADER)*pidh->e_lfanew 字节。

固定版本:

PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE*)pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)((BYTE*)pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));

调试此类问题的最佳方法是使用调试器进入代码并自己查看内存中的 PE 数据。例如,您可以打开 Visual Studio 十六进制编辑器并查看所有字节数据,以及您实际读取的值。

以下是在 VS 2010 中查看程序内存的一些信息: http://msdn.microsoft.com/en-us/library/s3aw423e.aspx

【讨论】:

  • 嗯,非常感谢,看来问题在于我(不)知道指针运算。 :)
  • @jowo 是来自IMAGE_DOS_HEADERe_magic 应该匹配IMAGE_FILE_HEADERMagic?如果是这样,我不知道为什么我的行为不正确。我已将我的 EXE 加载到 std::vector<char> bytes 对象中并尝试设置 IMAGE_DOS_HEADER* img_dos_header = (IMAGE_DOS_HEADER*)&bytes[0]; 但幻数与我的 IMAGE_FILE_HEADER* coff_file_header = (IMAGE_FILE_HEADER*)&bytes[coff_file_header_offset]; 不一致,这肯定​​会加载正确的信息。知道我需要解决什么吗?或者另一种加载 IMAGE_DOS_HEADER 的方式?
  • 好的,所以,IMAGE_DOS_HEADERe_magic 实际上是 PE 格式的 签名...所以 &bytes[0] 实际上是正确的,评估为 0x5A4D :)
  • 这是一本好书,顺便说一句:what-when-how.com/windows-forensic-analysis/…
  • 好的,最后一个问题 ^_^ 为什么在获取 NT 标头时将pidh 转换为(BYTE*)?尝试遵循思考过程来解决未来的潜在问题。
【解决方案2】:

你只是做错了。 我给你写了一些代码,希望对你有帮助。它可以显示PE文件最后一段的数据。

#include <stdio.h>
#include <malloc.h>
#include <windows.h>

void ShowHexData(BYTE *ptr,DWORD len)
{
    int index = 0;
    int i = 0;
    const int width = 16;
    while(index + width < len)
    {
        int i;
        for(i = 0; i < width; ++i)
        {
            printf(" %02X",ptr[index + i]);
        }
        printf("    \t");
        for(i = 0; i < width; ++i)
        {
            if(ptr[index + i] >= 0x20 &&
                        ptr[index + i] <= 0x7F)
            {
                putchar(ptr[index + i]);
            }else{
                putchar('.');
            }
        }
        index += width;
        putchar('\n');
    }

    for(i = 0; index  + i < len; ++ i)
    {
        printf(" %02X",ptr[index + i]);
    }
    while(i < width)
    {
        printf("   ");
        i += 1;
    }
    printf("    \t");
    for(i = 0; index + i < len; ++ i)
    {
        if(ptr[index + i] >= 0x20 &&
                    ptr[index + i] <= 0x7F)
        {
            putchar(ptr[index + i]);
        }else{
            putchar('.');
        }
    }
    putchar('\n');


}
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage : %s filename\n",argv[0]);
        return -1;
    }else{
        FILE *fp = fopen(argv[1],"rb");
        IMAGE_DOS_HEADER DosHeader = {0};
        IMAGE_FILE_HEADER FileHeader = {0};
        IMAGE_SECTION_HEADER SectionHeader = {0};
        DWORD Signature = 0;
        DWORD RawPointerToPeHeader = 0, SizeOfFile = 0;
        DWORD SectionCount = 0;
        DWORD ByteCount = 0;
        BYTE *pData = NULL;
        if(!fp)
        {
            perror("");
            return -1;
        }
        fseek(fp,0,SEEK_END);
        SizeOfFile = ftell(fp);
        if(SizeOfFile <
            sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS))
            goto not_pe_file;
        fseek(fp,0,SEEK_SET);
        fread(&DosHeader,1,sizeof DosHeader,fp);
        if(DosHeader.e_magic != 'M' + 'Z' * 256)
            goto not_pe_file;
        RawPointerToPeHeader = DosHeader.e_lfanew;
        if(SizeOfFile <=
            RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS))
            goto not_pe_file;
        fseek(fp,RawPointerToPeHeader,SEEK_SET);
        fread(&Signature,1,sizeof(DWORD),fp);
        if(Signature != 'P' + 'E' * 256)
            goto not_pe_file;
        fread(&FileHeader,1,sizeof FileHeader,fp);
        if(FileHeader.SizeOfOptionalHeader !=
            sizeof(IMAGE_OPTIONAL_HEADER))
            goto not_pe_file;
        SectionCount = FileHeader.NumberOfSections;
        if(SectionCount == 0)
        {
            printf("No section for this file.\n");
            fclose(fp);
            return -1;
        }
        if(SizeOfFile <=
            RawPointerToPeHeader +
            sizeof(IMAGE_NT_HEADERS) +
            SectionCount * sizeof(IMAGE_SECTION_HEADER))
            goto not_pe_file;
        fseek(fp,
            RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS) +
            (SectionCount - 1) * sizeof(IMAGE_SECTION_HEADER),
                SEEK_SET);
        fread(&SectionHeader,1,sizeof SectionHeader,fp);

        ByteCount = SectionHeader.Misc.VirtualSize < SectionHeader.PointerToRawData ?
            SectionHeader.Misc.VirtualSize : SectionHeader.PointerToRawData;

        if(ByteCount == 0)
        {
            printf("No data to read for target section.\n");
            fclose(fp);
            return -1;
        }else if(ByteCount + SectionHeader.PointerToRawData > SizeOfFile)
        {
            printf("Bad section data.\n");
            fclose(fp);
            return -1;
        }
        fseek(fp,SectionHeader.PointerToRawData,SEEK_SET);

        pData = (BYTE*)malloc(ByteCount);

        fread(pData,1,ByteCount,fp);

        ShowHexData(pData,ByteCount);
        free(pData);
        fclose(fp);
        return 0;


not_pe_file:
        printf("Not a PE file.\n");
        fclose(fp);
        return -1;
    }


    return 0;
}

总之,你不知道数据在哪里,直到你根据文件头分析数据。

【讨论】:

    【解决方案3】:

    各种段地址和数据也可以通过以下方式获得:

    #include<windows.h>
    #include<iostream>
    
    int main()
    {
        LPCSTR fileName="inputFile.exe";
        HANDLE hFile;
        HANDLE hFileMapping;
        LPVOID lpFileBase;
        PIMAGE_DOS_HEADER dosHeader;
        PIMAGE_NT_HEADERS peHeader;
        PIMAGE_SECTION_HEADER sectionHeader;
    
        hFile = CreateFileA(fileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    
        if(hFile==INVALID_HANDLE_VALUE)
        {
            std::cout<<"\n CreateFile failed \n";
            return 1;
        }
    
        hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
    
        if(hFileMapping==0)
        {
            std::cout<<"\n CreateFileMapping failed \n";
            CloseHandle(hFile);
            return 1;
        }
    
        lpFileBase = MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);
    
        if(lpFileBase==0)
        {
            std::cout<<"\n MapViewOfFile failed \n";
            CloseHandle(hFileMapping);
            CloseHandle(hFile);
            return 1;
        }
    
        dosHeader = (PIMAGE_DOS_HEADER) lpFileBase;
        if(dosHeader->e_magic==IMAGE_DOS_SIGNATURE)
        {
            std::cout<<"\n DOS Signature (MZ) Matched \n";
    
            peHeader = (PIMAGE_NT_HEADERS) ((u_char*)dosHeader+dosHeader->e_lfanew);
            if(peHeader->Signature==IMAGE_NT_SIGNATURE)
            {
                std::cout<<"\n PE Signature (PE) Matched \n";
                sectionHeader = IMAGE_FIRST_SECTION(peHeader);
                UINT nSectionCount = peHeader->FileHeader.NumberOfSections;
    
                //No of Sections
                std::cout<<"\n No of Sections : "<<nSectionCount<<"  \n";
    
                //sectionHeader contains pointer to first section
                //sectionHeader++ will move to next section
                for( UINT i=0; i<nSectionCount; ++i, ++sectionHeader )
                {
                    std::cout<<"\n-----------------------------------------------\n";
                    std::cout<<"\n Section Name : "<<sectionHeader->Name<<" \n";
                    //address can be obtained as (PBYTE)lpFileBase+sectionHeader->PointerToRawData
                    std::cout<<"\n Size of section data : "<<sectionHeader->Misc.VirtualSize<<" \n";
                    std::cout<<"\n-----------------------------------------------\n";
                }
    
                //Now sectionHeader will have pointer to last section
                //if you add sectionHeader++ in for loop instead of ++sectionHeader it will point to memory after last section
    
            }
            else
            {
                return 1;
            }
        }
        else
        {
            return 1;
        }
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      节指针:

      PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); // 定义 在winnt.h

      PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER )((BYTE*)pioh + pifh->SizeOfOptionalHeader);

      最后一节指针是:

      PIMAGE_SECTION_HEADER pilsh = &pish[pifh->NumberOfSections-1]

      【讨论】:

        猜你喜欢
        • 2011-01-06
        • 2010-12-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-12
        • 2012-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多