📄 portableexecutable.cpp
字号:
// PortableExecutable.cpp: implementation of the CPortableExecutable class.
//
//////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "PortableExecutable.h"
using namespace std;
namespace PE {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPortableExecutable::CPortableExecutable()
: m_ddDebug(this), m_ddExport(this), m_ddImport(this), m_ddCopyright(this), m_ddResource(this)
{
m_flIsLoaded = FALSE;
}
CPortableExecutable::~CPortableExecutable()
{
Cleanup();
}
PE_ERROR CPortableExecutable::LoadByHandle(HANDLE hFile)
{
DWORD dwStubStart;
CSection sctSection;
DWORD dwCount;
PIMAGE_NT_HEADERS pNtHeaders;
HANDLE hMap;
LPBYTE pMap;
// Clean up before loading
Cleanup();
if (hFile == INVALID_HANDLE_VALUE)
return(PE_OPEN);
// Make sure file isn't empty
FileSize = GetFileSize(hFile, NULL);
if (FileSize == 0) {
return(PE_SIZE);
}
// Try to create file mapping
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap == NULL) {
return(PE_MAP);
}
// Get a mapping view of the file
pMap = (LPBYTE )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (pMap == NULL) {
CloseHandle(hMap);
return(PE_VIEW);
}
// Get DOS header
if (IsBadReadPtr(pMap, sizeof(IMAGE_DOS_HEADER))) {
UnmapViewOfFile(pMap);
CloseHandle(hMap);
return(PE_MEM);
}
// Check if MZ executable
m_Headers.SetDos(*(PIMAGE_DOS_HEADER )pMap);
if (m_Headers.m_hdrDos.e_magic != IMAGE_DOS_SIGNATURE) {
UnmapViewOfFile(pMap);
CloseHandle(hMap);
return(PE_NOTMZ);
}
// Check if this is a new executable
if (m_Headers.m_hdrDos.e_lfanew == 0) {
// No new header
UnmapViewOfFile(pMap);
CloseHandle(hMap);
return(PE_NOTPE);
}
// Get NT headers
pNtHeaders = (PIMAGE_NT_HEADERS )(pMap + m_Headers.m_hdrDos.e_lfanew);
if (IsBadReadPtr(pNtHeaders, sizeof(IMAGE_NT_HEADERS))) {
UnmapViewOfFile(pMap);
CloseHandle(hMap);
return(PE_NOTPE);
}
// Check if PE executable
m_Headers.SetNt(*pNtHeaders);
if (m_Headers.m_hdrNt.Signature != IMAGE_NT_SIGNATURE) {
UnmapViewOfFile(pMap);
CloseHandle(hMap);
return(PE_NOTPE);
}
// Get DOS stub
dwStubStart = (m_Headers.m_hdrDos.e_cs << 4) + m_Headers.m_hdrDos.e_ip + (m_Headers.m_hdrDos.e_cparhdr << 4);
if (dwStubStart >= (65536 << 4)) dwStubStart -= (65536 << 4);
m_Headers.SetHeaderSize((signed long )dwStubStart < sizeof(IMAGE_DOS_HEADER) ? sizeof(IMAGE_DOS_HEADER) : dwStubStart);
m_DOSStub.Set((pMap + dwStubStart), ((m_Headers.m_hdrDos.e_cp - 1) * 512) + m_Headers.m_hdrDos.e_cblp - dwStubStart);
// Load sections
for (dwCount = 0; dwCount < m_Headers.m_hdrNt.FileHeader.NumberOfSections; dwCount++) {
if (IsBadReadPtr((LPBYTE )pNtHeaders + pNtHeaders->FileHeader.SizeOfOptionalHeader + (sizeof(IMAGE_SECTION_HEADER) * dwCount) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER), sizeof(IMAGE_SECTION_HEADER)) == FALSE) {
sctSection.SetHeader(*(PIMAGE_SECTION_HEADER )((LPBYTE )pNtHeaders + pNtHeaders->FileHeader.SizeOfOptionalHeader + (sizeof(IMAGE_SECTION_HEADER) * dwCount) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER)));
if (sctSection.m_hdr.SizeOfRawData && sctSection.m_hdr.PointerToRawData) {
if (IsBadReadPtr(&pMap[sctSection.m_hdr.PointerToRawData], sctSection.m_hdr.SizeOfRawData) == FALSE)
sctSection.SetData(&pMap[sctSection.m_hdr.PointerToRawData], sctSection.m_hdr.SizeOfRawData);
}
m_lstSections.push_back(sctSection);
}
}
// We don't need the file anymore
UnmapViewOfFile(pMap);
CloseHandle(hMap);
// Set the Loaded flag
m_flIsLoaded = TRUE;
// Fix various stuff
FixSectionOffsets();
FixSectionSizes();
FixImageSize();
m_Headers.FixSizeOfHeaders();
// Set up data directories
m_ddDebug.Assign(GetDataAtRVA(m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress), m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
m_ddExport.Assign(GetDataAtRVA(m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
m_ddImport.Assign(GetDataAtRVA(m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress), m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size);
m_ddCopyright.Assign(GetDataAtRVA(m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress), m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size);
m_ddResource.Assign(GetDataAtRVA(m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress), m_Headers.m_hdrNt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
return(PE_NONE);
}
// Load a portable executable
PE_ERROR CPortableExecutable::Load(LPSTR pszFileName)
{
HANDLE hFile;
// Clean up before loading
Cleanup();
// Try to open the file
hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile)
{
PE_ERROR peerror = LoadByHandle (hFile);
CloseHandle (hFile);
strcpy (FileName, pszFileName);
return peerror;
}
return(PE_OPEN);
}
// Write portable executable
PE_ERROR CPortableExecutable::Write(LPSTR pszFileName, BOOL flSetChecksum)
{
HANDLE hFile;
sctIterator i;
DWORD dwAlign;
DWORD dwCurrent;
CSection *pCurrentSection;
LPBYTE pStub;
BYTE byNull;
DWORD dwWritten;
// Change checksum
if (flSetChecksum == TRUE)
m_Headers.m_hdrNt.OptionalHeader.CheckSum = CalcCheckSum();
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_LOAD);
// Open output file
hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == NULL)
return(PE_OPEN);
// Write MZ header
WriteFile(hFile, &m_Headers.m_hdrDos, m_Headers.GetHeaderSize(), &dwWritten, NULL);
// Write DOS stub
if (m_DOSStub.Get(NULL)) {
pStub = new BYTE [m_DOSStub.Get(NULL)];
if (pStub) {
m_DOSStub.Get(pStub);
WriteFile(hFile, pStub, m_DOSStub.Get(NULL), &dwWritten, NULL);
delete [] pStub;
}
}
// Seek to new PE header offset
SetFilePointer(hFile, m_Headers.m_hdrDos.e_lfanew, NULL, FILE_BEGIN);
// Write PE header
WriteFile(hFile, &m_Headers.m_hdrNt, sizeof(IMAGE_NT_HEADERS), &dwWritten, NULL);
// Write section headers
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
WriteFile(hFile, &(*i).m_hdr, sizeof(IMAGE_SECTION_HEADER), &dwWritten, NULL);
}
// Pad to alignment
dwCurrent = SetFilePointer(hFile, 0L, NULL, FILE_CURRENT);
dwAlign = m_Headers.FileAlignment(dwCurrent);
byNull = 0;
while (dwCurrent < dwAlign) {
WriteFile(hFile, &byNull, 1, &dwWritten, NULL);
dwCurrent++;
}
// Write section data
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
pCurrentSection = &(*i);
if (pCurrentSection->m_hdr.PointerToRawData && pCurrentSection->m_hdr.SizeOfRawData) {
SetFilePointer(hFile, pCurrentSection->m_hdr.PointerToRawData, NULL, FILE_BEGIN);
if (IsBadReadPtr(pCurrentSection->m_pData, pCurrentSection->m_hdr.SizeOfRawData) == FALSE)
WriteFile(hFile, pCurrentSection->m_pData, pCurrentSection->m_hdr.SizeOfRawData, &dwWritten, NULL);
}
}
// Close file
CloseHandle(hFile);
return(PE_NONE);
}
// Clean up variables
void CPortableExecutable::Cleanup()
{
// Free section list
if (m_lstSections.empty() == FALSE)
m_lstSections.clear();
// Reset Loaded flag
m_flIsLoaded = FALSE;
}
// Relative Virtual Address to File Offset
DWORD CPortableExecutable::RVA2FO(DWORD dwRVA)
{
CSection *pSection;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
pSection = GetSectionByRVA(dwRVA);
if (pSection) {
// Convert RVA to File Offset
dwRVA -= pSection->m_hdr.VirtualAddress;
dwRVA += pSection->m_hdr.PointerToRawData;
// In section but not in file
if (dwRVA >= (pSection->m_hdr.PointerToRawData + pSection->m_hdr.SizeOfRawData))
dwRVA = PE_INVALID;
} else {
dwRVA = PE_INVALID;
}
return(dwRVA);
}
// Virtual Address to File Offset
DWORD CPortableExecutable::VA2FO(DWORD dwVA)
{
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
// Convert Virtual Address to Relative Virtual Address
if (dwVA != PE_INVALID)
dwVA -= m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(RVA2FO(dwVA));
}
// File Offset to Relative Virtual Address
DWORD CPortableExecutable::FO2RVA(DWORD dwFO)
{
CSection *pSection;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
pSection = GetSectionByFO(dwFO);
if (pSection) {
// Convert File Offset to RVA
dwFO += pSection->m_hdr.VirtualAddress;
dwFO -= pSection->m_hdr.PointerToRawData;
} else {
dwFO = PE_INVALID;
}
return(dwFO);
}
// File Offset to Virtual Address
DWORD CPortableExecutable::FO2VA(DWORD dwFO)
{
DWORD dwVA;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
// Convert File Offset to Virtual Address
dwVA = FO2RVA(dwFO);
if (dwVA != PE_INVALID)
dwVA += m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(dwVA);
}
// Get section by Relative Virtual Address
CSection * CPortableExecutable::GetSectionByRVA(DWORD dwRVA)
{
CSection *pSection;
sctIterator i;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(NULL);
pSection = NULL;
// Search which section contains the RVA
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
if ((*i).WithinRVA(dwRVA) == TRUE) {
pSection = &(*i);
break;
}
}
// RVA isn't in the file limits
if (i == m_lstSections.end())
return(NULL);
// Return the section that the RVA is within
return(pSection);
}
// Get section by Virtual Address
CSection * CPortableExecutable::GetSectionByVA(DWORD dwVA)
{
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(NULL);
dwVA -= m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(GetSectionByRVA(dwVA));
}
// Get section by File Offset
CSection * CPortableExecutable::GetSectionByFO(DWORD dwFO)
{
CSection *pSection;
sctIterator i;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(NULL);
pSection = NULL;
// Search which section contains the RVA
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
if ((*i).WithinFO(dwFO) == TRUE) {
pSection = &(*i);
break;
}
}
// RVA isn't in the file limits
if (i == m_lstSections.end())
return(NULL);
// Return the section that the RVA is within
return(pSection);
}
// Get pointer to data at Relative Virtual Address
LPBYTE CPortableExecutable::GetDataAtRVA(DWORD dwRVA)
{
CSection *pSection;
pSection = GetSectionByRVA(dwRVA);
if (pSection) {
dwRVA -= pSection->m_hdr.VirtualAddress;
if (dwRVA < pSection->m_hdr.SizeOfRawData)
return(&pSection->m_pData[dwRVA]);
}
return(NULL);
}
// Get pointer to data at Virtual Address
LPBYTE CPortableExecutable::GetDataAtVA(DWORD dwVA)
{
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(NULL);
dwVA -= m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(GetDataAtRVA(dwVA));
}
// Virtual Address to Relative Virtual Address
DWORD CPortableExecutable::VA2RVA(DWORD dwVA)
{
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
if (dwVA != PE_INVALID)
dwVA -= m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(dwVA);
}
// Relative Virtual Address to Virtual Address
DWORD CPortableExecutable::RVA2VA(DWORD dwRVA)
{
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_INVALID);
if (dwRVA != PE_INVALID)
dwRVA += m_Headers.m_hdrNt.OptionalHeader.ImageBase;
return(dwRVA);
}
// Remove a section
PE_ERROR CPortableExecutable::RemoveSection(CSection *pSection)
{
sctIterator i;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_LOAD);
if (pSection) {
// Fix offset of all sections that go after pSection
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
if ((*i).m_hdr.PointerToRawData > pSection->m_hdr.PointerToRawData) {
(*i).m_hdr.PointerToRawData -= pSection->m_hdr.SizeOfRawData;
}
}
// Decrease number of section in file header
m_Headers.m_hdrNt.FileHeader.NumberOfSections--;
// Remove section from list
for (i = m_lstSections.begin(); i != m_lstSections.end(); i++) {
if (&(*i) == pSection) {
m_lstSections.erase(i);
break;
}
}
}
FixImageSize();
m_Headers.FixSizeOfHeaders();
return(PE_NONE);
}
// Insert a section
PE_ERROR CPortableExecutable::InsertSection(CSection *pToAdd, CSection *pNext)
{
sctIterator iNext;
sctIterator i;
// Check if a file was loaded
if (m_flIsLoaded == FALSE)
return(PE_LOAD);
if (pToAdd) {
// Find where to insert the section
if (pNext) {
for (iNext = m_lstSections.begin(); iNext != m_lstSections.end(); iNext++) {
if (&(*iNext) == pNext) {
// Found where to insert the section
break;
}
}
} else {
// Insert at end
iNext = m_lstSections.end();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -