C++ WINDOWS 获取PE文件特征

PE是Portable Executable File Format(可移植的执行体)简写,它是目前Windows平台上的主流可执行文件格式,我们可以使用各种技术和库来获取PE文件特征,它包含了程序的代码,数据以及资源等信息,本文将介绍如何使用C++来获取PE文件的一些特征。

1.检查文件是否是PE文件,并判断PE文件类型(驱动程序,图形界面,控制台/DLL)

BOOL GetPEFileType(CString strFilePath, int& nPEType)
{
    if (!PathFileExists(strFilePath))
    {
        //文件不存在
        return FALSE;
    }

    HANDLE hFile = CreateFile(strFilePath, 
        GENERIC_READ, 
        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 
        NULL, 
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, 
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        //打开文件失败,可以用GetLastError()获取原因
        return FALSE;
    }

    //获取文件大小
    DWORD dwFileSize = GetFileSize(hFile, NULL);
    CHAR *pFileBuf = new(std::nothrow) CHAR[dwFileSize];
    DWORD ReadSize = 0;
    ReadFile(hFile, pFileBuf, dwFileSize, &ReadSize, NULL);
    CloseHandle(hFile);

    //检查是否是PE文件
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuf;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }

    //检查是否是有效的PE文件
    PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBuf + pDosHeader->e_lfanew);
    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }

    //获取文件类型  驱动程序(1) 图形界面(2) 控制台/DLL(3)
    PIMAGE_OPTIONAL_HEADER	pOptionalHeader	= &(pNtHeader->OptionalHeader);
    nPEType = pOptionalHeader->Subsystem;

    return TRUE;
}

2.获取PE文件版本

BOOL GetPEFileVer(const CString& strFile, CString& strVer)
{	
    DWORD dwHight = 0;
    DWORD dwLow = 0;

    if (!GetFileVer(strFile, dwHight, dwLow))
        return FALSE;

    strVer.Format(_T("%d.%d.%d.%04d"), HIWORD(dwHight), LOWORD(dwHight), HIWORD(dwLow), LOWORD(dwLow));

    return TRUE;
}

BOOL GetFileVer(const CString& strFile, DWORD& dwHight, DWORD& dwLow)
{
    DWORD dwVerSize;
    DWORD dwHandle;

    TCHAR  szVersionBuffer[1024 * 16] = { 0 };
    TCHAR szVer[1024] = { 0 };

    dwVerSize = GetFileVersionInfoSize(strFile, &dwHandle);
    if( dwVerSize == 0 || dwVerSize > (sizeof(szVersionBuffer) - 1))
        return FALSE;

    if(!GetFileVersionInfo(strFile, 0, dwVerSize, szVersionBuffer))
        return FALSE;

    unsigned int nInfoLen = 0;
    VS_FIXEDFILEINFO* pInfo = NULL;

    if(!VerQueryValue(szVersionBuffer, _T("\\"), (void**)&pInfo, &nInfoLen))
        return FALSE;

    dwHight = pInfo->dwFileVersionMS;
    dwLow = pInfo->dwFileVersionLS;
    return TRUE;
}

3.检查PE文件是否有捆绑

bool FindPEHeader(LPBYTE pAddr, int nLen)
{
    if (pAddr == NULL || nLen <= 0)
    {
        return false;
    }

    int nOffset = 0;

    while (nOffset+sizeof(IMAGE_DOS_HEADER) < nLen)
    {
        if (*pAddr != 0x4d || *(pAddr+1) != 0x5a)
        {
            pAddr++;
            nOffset++;
            continue;
        }

        _IMAGE_DOS_HEADER dosHeader;
        memcpy(&dosHeader, pAddr, sizeof(IMAGE_DOS_HEADER));

        if (dosHeader.e_lfanew < 0 || dosHeader.e_lfanew > nLen)
        {
            pAddr++;
            nOffset++;
            continue;
        }

        if ( ((DWORD)nOffset + dosHeader.e_lfanew + 10) < nLen)
        {
            LPBYTE pCurAddr = pAddr + dosHeader.e_lfanew;
            if (*pCurAddr == 0x50 && *(pCurAddr+1) == 0x45 && *(pCurAddr+2) == 0 && *(pCurAddr+3) == 0)
            {
                return true;
            }
        }

        pAddr++;
        nOffset++;
    }


    return false;
}



bool CheckBind(const WCHAR* pszExeFile)
{
    if (pszExeFile == NULL)
        return false;

    HANDLE hFile = CreateFile(pszExeFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hFile)
    {
        return false;
    }

    int nFileSize = GetFileSize(hFile, NULL);

    HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hFileMapping == NULL || hFileMapping == INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFile);
        return false;
    }

    LPBYTE pBaseAddr = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if (pBaseAddr == NULL)
    {
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return false;
    }

    LPBYTE pAddr = pBaseAddr;
    _IMAGE_DOS_HEADER dosHeader;
    memcpy(&dosHeader, pAddr, sizeof(IMAGE_DOS_HEADER));

    pAddr += dosHeader.e_lfanew;
    _IMAGE_NT_HEADERS peHeader;
    memcpy(&peHeader, pAddr, sizeof(_IMAGE_NT_HEADERS));

    //DWORD dwImageSize = peHeader.OptionalHeader.SizeOfImage;

    //获取区段个数
    DWORD nSecCount = peHeader.FileHeader.NumberOfSections;

    pAddr += sizeof(_IMAGE_NT_HEADERS);
    pAddr += sizeof(IMAGE_SECTION_HEADER) * nSecCount;

    int nLen = nFileSize - dosHeader.e_lfanew - sizeof(_IMAGE_NT_HEADERS) - sizeof(IMAGE_SECTION_HEADER) * nSecCount;
    bool bRet = FindPEHeader(pAddr, nLen);
	//找到第二个pe头说明有捆绑
    UnmapViewOfFile(pBaseAddr);
    CloseHandle(hFileMapping);
    CloseHandle(hFile);

    return bRet;
}

4.检查PE文件入口点是否异常

bool CheckEntryPoint(const WCHAR* pszExeFile)
{
	if (pszExeFile == NULL)
		return false;

	bool bRet = false;
	DWORD nEntryPoint = 0;
	PIMAGE_SECTION_HEADER pHeader = NULL;
	int nSecCount = 0;

	bRet = GetPeInfo(pszExeFile, nEntryPoint, pHeader, nSecCount);
	if (!bRet)
	{
		if (pHeader != NULL)
		{
			delete[] pHeader;
			pHeader = NULL;
		}	
		return false;
	}

	for (int i = 0; i < nSecCount; i++)
	{
		if (pHeader->Characteristics & 0x00000020 == 0)
		{
			pHeader++;
			continue;
		}

		if (nEntryPoint >= pHeader->VirtualAddress && nEntryPoint < (pHeader->VirtualAddress + pHeader->Misc.VirtualSize))
		{
			bRet = false;
			//PE入口点正常
		}
		else
		{
			bRet = true;
			//存在PE入口点异常
		}

		break;
	}

	delete[] pHeader;

	return bRet;
}



bool GetPeInfo(const WCHAR* pszExeFile, DWORD& dwEntryPoint, PIMAGE_SECTION_HEADER& pSecHeader, int& nSecCount)
{
	HANDLE hFile = CreateFile(pszExeFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
		return false;
	}

	HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (hFileMapping == NULL || hFileMapping == INVALID_HANDLE_VALUE)
	{
		CloseHandle(hFile);
		return false;
	}

	LPBYTE pBaseAddr = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
	if (pBaseAddr == NULL)
	{
		CloseHandle(hFileMapping);
		CloseHandle(hFile);
		return false;
	}

	LPBYTE pAddr = pBaseAddr;
	_IMAGE_DOS_HEADER dosHeader;
	memcpy(&dosHeader, pAddr, sizeof(IMAGE_DOS_HEADER));

	pAddr += dosHeader.e_lfanew;
	_IMAGE_NT_HEADERS peHeader;
	memcpy(&peHeader, pAddr, sizeof(_IMAGE_NT_HEADERS));

	dwEntryPoint = peHeader.OptionalHeader.AddressOfEntryPoint;

	//获取区段个数
	nSecCount = peHeader.FileHeader.NumberOfSections;

	//获取区段表头指针
	pSecHeader = new IMAGE_SECTION_HEADER[nSecCount];
	memset(pSecHeader, 0, sizeof(IMAGE_SECTION_HEADER)*nSecCount);
	pAddr += (sizeof(_IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER32) + peHeader.FileHeader.SizeOfOptionalHeader);
	memcpy(pSecHeader, pAddr, sizeof(IMAGE_SECTION_HEADER)*nSecCount);

	UnmapViewOfFile(pBaseAddr);
	CloseHandle(hFileMapping);
	CloseHandle(hFile);
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值