首页
社区
课程
招聘
[旧帖] 如何解析出PE文件中的资源数据中的版本信息?(非硬盘PE文件) 0.00雪花
发表于: 2010-11-30 22:07 3680

[旧帖] 如何解析出PE文件中的资源数据中的版本信息?(非硬盘PE文件) 0.00雪花

2010-11-30 22:07
3680

//////////////////////////////////////////////////////////////////////////////////
/*
最近学习PE结构,想从已经读取到内存里的PE文件的数据里,直接从内存里解析出一些资源数据。
(当然,微软也已经提供了相关的API来直接操作,但为了加深PE结构了解,自己写了个蛋疼的程序来验证)

通过 GetFileVersionInfoSize GetFileVersionInfo VerQueryValue 这3个API, 我们很容易获取一个硬盘上的文件的详细的版本信息.

理论上, 加载到内存里的数据,只要知道对应数据结构和偏移,也能获取出正确的对应信息.
但是第一个想法就搁浅了,看了半天的PE的资源数据,居然就是不知道如何获取对应的版本信息。

所以特来请教各位PE帝,PE达人,如何从内存里直接获取对应的版本信息。请看下面的代码:

问题集中在GetVersionInfoFromMem函数中获取到对应的资源PIMAGE_RESOURCE_DIRECTORY_ENTRY后,
如果才能获取VS_VERSIONINFO这个数据结构是变长的版本信息呢?
*/
//////////////////////////////////////////////////////////////////////////////////

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

DWORD RVA2Offset(void *pImage, DWORD dwRVA)
{
        PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER )pImage;
        PIMAGE_NT_HEADERS pNtHeads = (PIMAGE_NT_HEADERS)((DWORD)pDos + pDos->e_lfanew);
       
        DWORD NumOfSection = pNtHeads->FileHeader.NumberOfSections;
        PIMAGE_SECTION_HEADER    pSectionHead = (PIMAGE_SECTION_HEADER )(sizeof(IMAGE_FILE_HEADER) + 4 + pNtHeads->FileHeader.SizeOfOptionalHeader + (DWORD)pNtHeads);
        DWORD RawOfEntryPoint = 0;
        DWORD RawinSection = 0;
        WORD count=0;
        while(count<NumOfSection)
        {
                if((dwRVA >= pSectionHead->VirtualAddress)
                        &&(dwRVA < pSectionHead->VirtualAddress+pSectionHead->Misc.VirtualSize))
                {
                        RawinSection=dwRVA-pSectionHead->VirtualAddress;
                        RawOfEntryPoint=pSectionHead->PointerToRawData+RawinSection;
                        break;
                }
                pSectionHead++;
                count++;
        }
        if (RawOfEntryPoint == 0)
        {
                return 0;
        }
        return RawOfEntryPoint;         
}

DWORD CheckFileSize(char *filename)
{
        HANDLE hFile=NULL;
        WIN32_FIND_DATA wfd;
       
        if((hFile=FindFirstFile(filename,&wfd))==INVALID_HANDLE_VALUE)
        {
                FindClose(hFile);
                return 0;
        }
       
        FindClose(hFile);
        return wfd.nFileSizeHigh*MAXDWORD+wfd.nFileSizeLow;
}

//从内存里获取版本资源信息
//lpFileData: 存放dll数据的内存缓冲区
//nDataLength: dll文件的长度
BOOL GetVersionInfoFromMem(void* lpFileData, int nDataLength)
{
        PIMAGE_DOS_HEADER m_pDosHeader;
        PIMAGE_NT_HEADERS m_pNTHeader;
        PIMAGE_SECTION_HEADER m_pSectionHeader;

        //检查长度
        if (nDataLength < sizeof(IMAGE_DOS_HEADER))
        {
                return FALSE;
        }
        m_pDosHeader = (PIMAGE_DOS_HEADER)lpFileData;  // DOS头
        //检查dos头的标记
        if (m_pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
        {
                return FALSE;  //0x5A4D : MZ
        }
       
        //检查长度
        if ((DWORD)nDataLength < (m_pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)))
        {
                return FALSE;
        }
        //取得pe头
        m_pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)lpFileData + m_pDosHeader->e_lfanew); // PE头
        //检查pe头的合法性
        if (m_pNTHeader->Signature != IMAGE_NT_SIGNATURE)
        {
                return FALSE;  //0x00004550 : PE00
        }
        if ((m_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000  : File is a DLL
        {
                return FALSE;  
        }
        if ((m_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行
        {
                return FALSE;
        }
        if (m_pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
        {
                return FALSE;
        }       
       
        //取得节表(段表)
        m_pSectionHeader = (PIMAGE_SECTION_HEADER)((PBYTE)m_pNTHeader + sizeof(IMAGE_NT_HEADERS));
        //验证每个节表的空间
        for (int i=0; i< m_pNTHeader->FileHeader.NumberOfSections; i++)
        {
                if ((m_pSectionHeader[i].PointerToRawData + m_pSectionHeader[i].SizeOfRawData) > (DWORD)nDataLength)
                {
                        return FALSE;
                }
        }

        if(m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != 0 &&m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size != 0 )
        {
                int nEntries;
                DWORD dwOffset = RVA2Offset(lpFileData,m_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
                PIMAGE_RESOURCE_DIRECTORY pResRootDir = (PIMAGE_RESOURCE_DIRECTORY )((LPBYTE)lpFileData+dwOffset);
                PIMAGE_RESOURCE_DIRECTORY_ENTRY pResTypeDirEnt = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)pResRootDir+sizeof(IMAGE_RESOURCE_DIRECTORY));

                nEntries = pResRootDir->NumberOfNamedEntries+pResRootDir->NumberOfIdEntries;

                for (i = 0; i < nEntries; i++)
                {
                        if(!pResTypeDirEnt->NameIsString&&pResTypeDirEnt->Id==16)
                        {
                                //VS_FIXEDFILEINFO FixedInfo;
                                printf("\r\nFound Version Resouce\r\n");
                               
                                //通过 GetFileVersionInfoSize GetFileVersionInfo VerQueryValue 这3个API, 我们很容易获取一个硬盘上的文件的详细的版本信息.
                                //理论上, 加载到内存里的数据,只要知道对应数据结构和偏移,也能获取出正确的对应信息.

                                //到了这步,看了半天PE资料,GOOGLE了一天,找了很久的资料,
                                //继续GOOGLE,VS_VERSIONINFO居然是个可变长结构体.到此彻底蒙了.

                                //该如何从内存里取出对应的版本信息? 就如同使用上面的3个API?

                                /*
                                ?????????????????????????????????????????????
                                */

                        }               
                        // Reference next entry in directory entries array.
                        pResTypeDirEnt++;
                }
        }

        return TRUE;
}

void main(int argc, char *argv[])
{
        if(argc==2)
        {

                char* pFileMemBuffer;
                DWORD dFileSize=CheckFileSize(argv[1]);

                if(dFileSize)
                {
                        pFileMemBuffer=new char[dFileSize];
                        if (!pFileMemBuffer)
                        {
                                return;
                        }
                        else
                        {
                                FILE* fp = fopen(argv[1], "rb");
                                int nLen = static_cast<int>(fread(pFileMemBuffer, 1, dFileSize, fp));
                                fclose(fp);
                        }
                        GetVersionInfoFromMem(pFileMemBuffer,dFileSize);
                }
        }
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//