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;
}