|
|
//////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) Microsoft Corporation, 1996-2001.
//
// File: addsect.cpp
//
// Contents: Add a data section to a PE binary.
//
// History: 01-Nov-2000 GalenH Created from Detours setdll.cpp.
//
//////////////////////////////////////////////////////////////////////////////
#define UNICODE
#define _UNICODE
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define arrayof(a) (sizeof(a)/sizeof(a[0]))
///////////////////////////////////////////////////////////////////////////////
//
class CImage { public: CImage(); ~CImage();
public: // File Functions
BOOL Read(HANDLE hFile); BOOL Check(PCSTR pszSection); BOOL Write(HANDLE hFile, PBYTE pbData, UINT cbData, PCSTR pszSection); BOOL Close();
public: // Manipulation Functions
PBYTE DataSet(PBYTE pbData, DWORD cbData);
protected: BOOL CopyFileData(HANDLE hFile, DWORD nOldPos, DWORD cbData); BOOL ZeroFileData(HANDLE hFile, DWORD cbData); BOOL AlignFileData(HANDLE hFile);
BOOL SizeOutputBuffer(DWORD cbData); PBYTE AllocateOutput(DWORD cbData, DWORD *pnVirtAddr);
PVOID RvaToVa(DWORD nRva); DWORD RvaToFileOffset(DWORD nRva);
DWORD FileAlign(DWORD nAddr); DWORD SectionAlign(DWORD nAddr);
private: HANDLE m_hMap; // Read & Write
PBYTE m_pMap; // Read & Write
DWORD m_nNextFileAddr; // Write
DWORD m_nNextVirtAddr; // Write
BOOLEAN m_f64bit;
IMAGE_FILE_HEADER m_FileHeader; IMAGE_OPTIONAL_HEADER64 m_OptionalHeader; IMAGE_SECTION_HEADER m_SectionHeaders[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
DWORD m_nFileHeaderOffset; DWORD m_nOptionalHeaderOffset; DWORD m_nSectionsOffset; DWORD m_nSectionsEndOffset; DWORD m_nSectionsMaxCount; DWORD m_nExtraOffset; DWORD m_nFileSize;
PBYTE m_pbOutputBuffer; DWORD m_cbOutputBuffer;
DWORD m_nOutputVirtAddr; DWORD m_nOutputVirtSize; DWORD m_nOutputFileAddr; };
//////////////////////////////////////////////////////////////////////////////
//
static inline DWORD Max(DWORD a, DWORD b) { return a > b ? a : b; }
static inline DWORD Min(DWORD a, DWORD b) { return a < b ? a : b; }
static inline DWORD Align(DWORD a, DWORD size) { size--; return (a + size) & ~size; }
static inline DWORD QuadAlign(DWORD a) { return Align(a, 8); }
//////////////////////////////////////////////////////////////////////////////
//
CImage::CImage() { m_hMap = NULL; m_pMap = NULL;
m_nFileHeaderOffset = 0; m_nSectionsOffset = 0;
m_pbOutputBuffer = NULL; m_cbOutputBuffer = 0; }
CImage::~CImage() { Close(); }
BOOL CImage::Close() { if (m_pMap != NULL) { UnmapViewOfFile(m_pMap); m_pMap = NULL; }
if (m_hMap) { CloseHandle(m_hMap); m_hMap = NULL; }
if (m_pbOutputBuffer) { delete[] m_pbOutputBuffer; m_pbOutputBuffer = NULL; } return TRUE; }
//////////////////////////////////////////////////////////////////////////////
//
BOOL CImage::SizeOutputBuffer(DWORD cbData) { if (m_cbOutputBuffer < cbData) { if (cbData < 1024) //65536
cbData = 1024; cbData = FileAlign(cbData);
PBYTE pOutput = new BYTE [cbData]; if (pOutput == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; }
if (m_pbOutputBuffer) { CopyMemory(pOutput, m_pbOutputBuffer, m_cbOutputBuffer);
delete[] m_pbOutputBuffer; m_pbOutputBuffer = NULL; }
ZeroMemory(pOutput + m_cbOutputBuffer, cbData - m_cbOutputBuffer),
m_pbOutputBuffer = pOutput; m_cbOutputBuffer = cbData; } return TRUE; }
PBYTE CImage::AllocateOutput(DWORD cbData, DWORD *pnVirtAddr) { cbData = QuadAlign(cbData);
PBYTE pbData = m_pbOutputBuffer + m_nOutputVirtSize;
*pnVirtAddr = m_nOutputVirtAddr + m_nOutputVirtSize; m_nOutputVirtSize += cbData;
if (m_nOutputVirtSize > m_cbOutputBuffer) { SetLastError(ERROR_OUTOFMEMORY); return NULL; }
ZeroMemory(pbData, cbData);
return pbData; }
//////////////////////////////////////////////////////////////////////////////
//
DWORD CImage::FileAlign(DWORD nAddr) { return Align(nAddr, m_OptionalHeader.FileAlignment); }
DWORD CImage::SectionAlign(DWORD nAddr) { return Align(nAddr, m_OptionalHeader.SectionAlignment); }
//////////////////////////////////////////////////////////////////////////////
//
PVOID CImage::RvaToVa(DWORD nRva) { if (nRva == 0) { return NULL; }
for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) { DWORD vaStart = m_SectionHeaders[n].VirtualAddress; DWORD vaEnd = vaStart + m_SectionHeaders[n].SizeOfRawData;
if (nRva >= vaStart && nRva < vaEnd) { return (PBYTE)m_pMap + m_SectionHeaders[n].PointerToRawData + nRva - m_SectionHeaders[n].VirtualAddress; } } return NULL; }
DWORD CImage::RvaToFileOffset(DWORD nRva) { DWORD n; for (n = 0; n < m_FileHeader.NumberOfSections; n++) { DWORD vaStart = m_SectionHeaders[n].VirtualAddress; DWORD vaEnd = vaStart + m_SectionHeaders[n].SizeOfRawData;
if (nRva >= vaStart && nRva < vaEnd) { return m_SectionHeaders[n].PointerToRawData + nRva - m_SectionHeaders[n].VirtualAddress; } } return 0; }
//////////////////////////////////////////////////////////////////////////////
//
BOOL CImage::CopyFileData(HANDLE hFile, DWORD nOldPos, DWORD cbData) { DWORD cbDone = 0; return WriteFile(hFile, m_pMap + nOldPos, cbData, &cbDone, NULL); }
BOOL CImage::ZeroFileData(HANDLE hFile, DWORD cbData) { if (!SizeOutputBuffer(4096)) { return FALSE; }
ZeroMemory(m_pbOutputBuffer, m_cbOutputBuffer);
for (DWORD cbLeft = cbData; cbLeft > 0;) { DWORD cbStep = cbLeft > m_cbOutputBuffer ? m_cbOutputBuffer : cbLeft; DWORD cbDone = 0;
if (!WriteFile(hFile, m_pbOutputBuffer, cbStep, &cbDone, NULL)) { return FALSE; } if (cbDone == 0) break;
cbLeft -= cbDone; } return TRUE; }
BOOL CImage::AlignFileData(HANDLE hFile) { DWORD nLastFileAddr = m_nNextFileAddr;
m_nNextFileAddr = FileAlign(m_nNextFileAddr); m_nNextVirtAddr = SectionAlign(m_nNextVirtAddr);
if (hFile != INVALID_HANDLE_VALUE) { if (m_nNextFileAddr > nLastFileAddr) { if (SetFilePointer(hFile, nLastFileAddr, NULL, FILE_BEGIN) == ~0u) { return FALSE; } return ZeroFileData(hFile, m_nNextFileAddr - nLastFileAddr); } } return TRUE; }
BOOL CImage::Read(HANDLE hFile) { DWORD n; IMAGE_OPTIONAL_HEADER32 oh32;
if (hFile == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; }
///////////////////////////////////////////////////////// Create mapping.
//
m_nFileSize = GetFileSize(hFile, NULL); if (m_nFileSize == ~0ul) { return FALSE; }
m_hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (m_hMap == NULL) { return FALSE; }
m_pMap = (PBYTE)MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0); if (m_pMap == NULL) { return FALSE; }
////////////////////////////////////////////////////// Process DOS Header.
//
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)m_pMap; if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { m_nFileHeaderOffset = pDosHeader->e_lfanew + sizeof(DWORD); m_nOptionalHeaderOffset = m_nFileHeaderOffset + sizeof(m_FileHeader);
} else { m_nFileHeaderOffset = 0; m_nOptionalHeaderOffset = m_nFileHeaderOffset + sizeof(m_FileHeader); }
/////////////////////////////////////////////////////// Process PE Header.
//
CopyMemory(&m_FileHeader, m_pMap + m_nFileHeaderOffset, sizeof(m_FileHeader)); if (m_FileHeader.SizeOfOptionalHeader == 0) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; }
///////////////////////////////////////////////// Process Optional Header.
//
CopyMemory(&oh32, m_pMap + m_nOptionalHeaderOffset, sizeof(oh32));
if (oh32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // Convert 32-bit optional header to internal 64-bit optional header
m_f64bit = FALSE;
ZeroMemory(&m_OptionalHeader, sizeof(m_OptionalHeader)); m_OptionalHeader.Magic = oh32.Magic; m_OptionalHeader.MajorLinkerVersion = oh32.MajorLinkerVersion; m_OptionalHeader.MinorLinkerVersion = oh32.MinorLinkerVersion; m_OptionalHeader.SizeOfCode = oh32.SizeOfCode; m_OptionalHeader.SizeOfInitializedData = oh32.SizeOfInitializedData; m_OptionalHeader.SizeOfUninitializedData = oh32.SizeOfUninitializedData; m_OptionalHeader.AddressOfEntryPoint = oh32.AddressOfEntryPoint; m_OptionalHeader.BaseOfCode = oh32.BaseOfCode; m_OptionalHeader.ImageBase = oh32.ImageBase; m_OptionalHeader.SectionAlignment = oh32.SectionAlignment; m_OptionalHeader.FileAlignment = oh32.FileAlignment; m_OptionalHeader.MajorOperatingSystemVersion = oh32.MajorOperatingSystemVersion; m_OptionalHeader.MinorOperatingSystemVersion = oh32.MinorOperatingSystemVersion; m_OptionalHeader.MajorImageVersion = oh32.MajorImageVersion; m_OptionalHeader.MinorImageVersion = oh32.MinorImageVersion; m_OptionalHeader.MajorSubsystemVersion = oh32.MajorSubsystemVersion; m_OptionalHeader.MinorSubsystemVersion = oh32.MinorSubsystemVersion; m_OptionalHeader.Win32VersionValue = oh32.Win32VersionValue; m_OptionalHeader.SizeOfImage = oh32.SizeOfImage; m_OptionalHeader.SizeOfHeaders = oh32.SizeOfHeaders; m_OptionalHeader.CheckSum = oh32.CheckSum; m_OptionalHeader.Subsystem = oh32.Subsystem; m_OptionalHeader.DllCharacteristics = oh32.DllCharacteristics; m_OptionalHeader.SizeOfStackReserve = oh32.SizeOfStackReserve; m_OptionalHeader.SizeOfStackCommit = oh32.SizeOfStackCommit; m_OptionalHeader.SizeOfHeapReserve = oh32.SizeOfHeapReserve; m_OptionalHeader.SizeOfHeapCommit = oh32.SizeOfHeapCommit; m_OptionalHeader.LoaderFlags = oh32.LoaderFlags; m_OptionalHeader.NumberOfRvaAndSizes = oh32.NumberOfRvaAndSizes;
for (n = 0; n < oh32.NumberOfRvaAndSizes; n++) { m_OptionalHeader.DataDirectory[n] = oh32.DataDirectory[n]; } } else if (oh32.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { m_f64bit = TRUE; CopyMemory(&m_OptionalHeader, m_pMap + m_nOptionalHeaderOffset, sizeof(m_OptionalHeader)); } else { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } m_nSectionsOffset = m_nOptionalHeaderOffset + m_FileHeader.SizeOfOptionalHeader;
///////////////////////////////////////////////// Process Section Headers.
//
if (m_FileHeader.NumberOfSections > arrayof(m_SectionHeaders)) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; } CopyMemory(&m_SectionHeaders, m_pMap + m_nSectionsOffset, sizeof(m_SectionHeaders[0]) * m_FileHeader.NumberOfSections);
////////////////////////////////////////////////////////// Parse Sections.
//
m_nSectionsEndOffset = m_nSectionsOffset + sizeof(m_SectionHeaders); m_nExtraOffset = 0; for (n = 0; n < m_FileHeader.NumberOfSections; n++) { m_nExtraOffset = Max(m_SectionHeaders[n].PointerToRawData + m_SectionHeaders[n].SizeOfRawData, m_nExtraOffset);
if (m_SectionHeaders[n].PointerToRawData != 0) { m_nSectionsEndOffset = Min(m_SectionHeaders[n].PointerToRawData, m_nSectionsEndOffset); } }
m_nSectionsMaxCount = (m_nSectionsEndOffset - m_nSectionsOffset) / sizeof(IMAGE_SECTION_HEADER);
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
//
BOOL CImage::Check(PCSTR pszSection) { CHAR szName[IMAGE_SIZEOF_SHORT_NAME];
ZeroMemory(szName, sizeof(szName)); strncpy(szName, pszSection, sizeof(szName));
if ((DWORD)(m_FileHeader.NumberOfSections + 1) > m_nSectionsMaxCount) { SetLastError(ERROR_EXE_MARKED_INVALID); return FALSE; }
for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) { if (memcmp(szName, m_SectionHeaders[n].Name, sizeof(szName)) == 0) { SetLastError(ERROR_DUPLICATE_TAG); return FALSE; } }
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
//
BOOL CImage::Write(HANDLE hFile, PBYTE pbSectData, UINT cbSectData, PCSTR pszSection) { if (hFile == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; }
//////////////////////////////////////////////////////////////////////////
//
m_nNextFileAddr = 0; m_nNextVirtAddr = 0;
//////////////////////////////////////////////////////////// Copy Headers.
//
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!CopyFileData(hFile, 0, m_OptionalHeader.SizeOfHeaders)) { return FALSE; }
m_nNextFileAddr = m_OptionalHeader.SizeOfHeaders; m_nNextVirtAddr = 0; if (!AlignFileData(hFile)) { return FALSE; }
/////////////////////////////////////////////////////////// Copy Sections.
//
for (DWORD n = 0; n < m_FileHeader.NumberOfSections; n++) { if (m_SectionHeaders[n].SizeOfRawData) { if (SetFilePointer(hFile, m_SectionHeaders[n].PointerToRawData, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!CopyFileData(hFile, m_SectionHeaders[n].PointerToRawData, m_SectionHeaders[n].SizeOfRawData)) { return FALSE; } } m_nNextFileAddr = Max(m_SectionHeaders[n].PointerToRawData + m_SectionHeaders[n].SizeOfRawData, m_nNextFileAddr); m_nNextVirtAddr = Max(m_SectionHeaders[n].VirtualAddress + m_SectionHeaders[n].Misc.VirtualSize, m_nNextVirtAddr); m_nExtraOffset = Max(m_nNextFileAddr, m_nExtraOffset);
if (!AlignFileData(hFile)) { return FALSE; } }
/////////////////////////////////////////////////////////////// Old WriteSection
DWORD cbDone;
if (pbSectData) {
/////////////////////////////////////////////////// Insert .detour Section.
//
DWORD nSection = m_FileHeader.NumberOfSections++;
ZeroMemory(&m_SectionHeaders[nSection], sizeof(m_SectionHeaders[nSection]));
strcpy((PCHAR)m_SectionHeaders[nSection].Name, pszSection); m_SectionHeaders[nSection].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
m_nOutputVirtAddr = m_nNextVirtAddr; m_nOutputVirtSize = 0; m_nOutputFileAddr = m_nNextFileAddr;
//////////////////////////////////////////////////////////////////////////
//
if (!SizeOutputBuffer(QuadAlign(cbSectData))) { return FALSE; }
DWORD vaData = 0; PBYTE pbData = NULL;
if ((pbData = AllocateOutput(cbSectData, &vaData)) == NULL) { return FALSE; }
CopyMemory(pbData, pbSectData, cbSectData);
//////////////////////////////////////////////////////////////////////////
//
m_nNextVirtAddr += m_nOutputVirtSize; m_nNextFileAddr += FileAlign(m_nOutputVirtSize);
if (!AlignFileData(hFile)) { return FALSE; }
//////////////////////////////////////////////////////////////////////////
//
m_SectionHeaders[nSection].VirtualAddress = m_nOutputVirtAddr; m_SectionHeaders[nSection].Misc.VirtualSize = m_nOutputVirtSize; m_SectionHeaders[nSection].PointerToRawData = m_nOutputFileAddr; m_SectionHeaders[nSection].SizeOfRawData = FileAlign(m_nOutputVirtSize);
m_OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; m_OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
//////////////////////////////////////////////////////////////////////////
//
if (SetFilePointer(hFile, m_SectionHeaders[nSection].PointerToRawData, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!WriteFile(hFile, pbData, m_SectionHeaders[nSection].SizeOfRawData, &cbDone, NULL)) { return FALSE; } }
///////////////////////////////////////////////////// Adjust Extra Data.
//
LONG nExtraAdjust = m_nNextFileAddr - m_nExtraOffset; for (n = 0; n < m_FileHeader.NumberOfSections; n++) { if (m_SectionHeaders[n].PointerToRawData > m_nExtraOffset) m_SectionHeaders[n].PointerToRawData += nExtraAdjust; if (m_SectionHeaders[n].PointerToRelocations > m_nExtraOffset) m_SectionHeaders[n].PointerToRelocations += nExtraAdjust; if (m_SectionHeaders[n].PointerToLinenumbers > m_nExtraOffset) m_SectionHeaders[n].PointerToLinenumbers += nExtraAdjust; } if (m_FileHeader.PointerToSymbolTable > m_nExtraOffset) m_FileHeader.PointerToSymbolTable += nExtraAdjust;
m_OptionalHeader.CheckSum = 0; m_OptionalHeader.SizeOfImage = m_nNextVirtAddr;
////////////////////////////////////////////////// Adjust Debug Directory.
//
DWORD debugAddr = m_OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; DWORD debugSize = m_OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; if (debugAddr && debugSize) { DWORD nFileOffset = RvaToFileOffset(debugAddr); if (SetFilePointer(hFile, nFileOffset, NULL, FILE_BEGIN) == ~0u) { return FALSE; }
PIMAGE_DEBUG_DIRECTORY pDir = (PIMAGE_DEBUG_DIRECTORY)RvaToVa(debugAddr); if (pDir == NULL) { return FALSE; }
DWORD nEntries = debugSize / sizeof(*pDir); for (DWORD n = 0; n < nEntries; n++) { IMAGE_DEBUG_DIRECTORY dir = pDir[n];
if (dir.PointerToRawData > m_nExtraOffset) { dir.PointerToRawData += nExtraAdjust; } if (!WriteFile(hFile, &dir, sizeof(dir), &cbDone, NULL)) { return FALSE; } } }
///////////////////////////////////////////////// Copy Left-over Data.
//
if (m_nFileSize > m_nExtraOffset) { if (SetFilePointer(hFile, m_nNextFileAddr, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!CopyFileData(hFile, m_nExtraOffset, m_nFileSize - m_nExtraOffset)) { return FALSE; } }
//////////////////////////////////////////////////// Finalize Headers.
//
if (SetFilePointer(hFile, m_nFileHeaderOffset, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!WriteFile(hFile, &m_FileHeader, sizeof(m_FileHeader), &cbDone, NULL)) { return FALSE; } if (SetFilePointer(hFile, m_nOptionalHeaderOffset, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (m_f64bit) { if (!WriteFile(hFile, &m_OptionalHeader, sizeof(m_OptionalHeader), &cbDone, NULL)) {
return FALSE; } } else { // Convert 32-bit optional header to internal 64-bit optional header
IMAGE_OPTIONAL_HEADER32 oh32;
ZeroMemory(&oh32, sizeof(oh32)); oh32.Magic = m_OptionalHeader.Magic; oh32.MajorLinkerVersion = m_OptionalHeader.MajorLinkerVersion; oh32.MinorLinkerVersion = m_OptionalHeader.MinorLinkerVersion; oh32.SizeOfCode = m_OptionalHeader.SizeOfCode; oh32.SizeOfInitializedData = m_OptionalHeader.SizeOfInitializedData; oh32.SizeOfUninitializedData = m_OptionalHeader.SizeOfUninitializedData; oh32.AddressOfEntryPoint = m_OptionalHeader.AddressOfEntryPoint; oh32.BaseOfCode = m_OptionalHeader.BaseOfCode; oh32.ImageBase = (ULONG)m_OptionalHeader.ImageBase; oh32.SectionAlignment = m_OptionalHeader.SectionAlignment; oh32.FileAlignment = m_OptionalHeader.FileAlignment; oh32.MajorOperatingSystemVersion = m_OptionalHeader.MajorOperatingSystemVersion; oh32.MinorOperatingSystemVersion = m_OptionalHeader.MinorOperatingSystemVersion; oh32.MajorImageVersion = m_OptionalHeader.MajorImageVersion; oh32.MinorImageVersion = m_OptionalHeader.MinorImageVersion; oh32.MajorSubsystemVersion = m_OptionalHeader.MajorSubsystemVersion; oh32.MinorSubsystemVersion = m_OptionalHeader.MinorSubsystemVersion; oh32.Win32VersionValue = m_OptionalHeader.Win32VersionValue; oh32.SizeOfImage = m_OptionalHeader.SizeOfImage; oh32.SizeOfHeaders = m_OptionalHeader.SizeOfHeaders; oh32.CheckSum = m_OptionalHeader.CheckSum; oh32.Subsystem = m_OptionalHeader.Subsystem; oh32.DllCharacteristics = m_OptionalHeader.DllCharacteristics; oh32.SizeOfStackReserve = (ULONG)m_OptionalHeader.SizeOfStackReserve; oh32.SizeOfStackCommit = (ULONG)m_OptionalHeader.SizeOfStackCommit; oh32.SizeOfHeapReserve = (ULONG)m_OptionalHeader.SizeOfHeapReserve; oh32.SizeOfHeapCommit = (ULONG)m_OptionalHeader.SizeOfHeapCommit; oh32.LoaderFlags = m_OptionalHeader.LoaderFlags; oh32.NumberOfRvaAndSizes = m_OptionalHeader.NumberOfRvaAndSizes;
for (int n = 0; n < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; n++) { oh32.DataDirectory[n] = m_OptionalHeader.DataDirectory[n]; }
if (!WriteFile(hFile, &oh32, sizeof(oh32), &cbDone, NULL)) { return FALSE; } }
if (SetFilePointer(hFile, m_nSectionsOffset, NULL, FILE_BEGIN) == ~0u) { return FALSE; } if (!WriteFile(hFile, &m_SectionHeaders, sizeof(m_SectionHeaders[0]) * m_FileHeader.NumberOfSections, &cbDone, NULL)) { return FALSE; } return TRUE; }
//////////////////////////////////////////////////////////////////// CFileMap.
//
class CFileMap { public: CFileMap(); ~CFileMap();
public: BOOL Load(PCWSTR pszFile); PBYTE Seek(UINT32 cbPos); UINT32 Size(); VOID Close();
protected: PBYTE m_pbData; UINT32 m_cbData; };
CFileMap::CFileMap() { m_pbData = NULL; m_cbData = 0; }
CFileMap::~CFileMap() { Close(); }
VOID CFileMap::Close() { if (m_pbData) { UnmapViewOfFile(m_pbData); m_pbData = NULL; } m_cbData = 0; }
UINT32 CFileMap::Size() { return m_cbData; }
PBYTE CFileMap::Seek(UINT32 cbPos) { if (m_pbData && cbPos <= m_cbData) { return m_pbData + cbPos; } return NULL; }
BOOL CFileMap::Load(PCWSTR pszFile) { Close();
HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; }
ULONG cbInFileData = GetFileSize(hFile, NULL); if (cbInFileData == ~0ul) { CloseHandle(hFile); return FALSE; }
HANDLE hInFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(hFile); if (hInFileMap == NULL) { return FALSE; }
m_pbData = (PBYTE)MapViewOfFile(hInFileMap, FILE_MAP_COPY, 0, 0, 0); CloseHandle(hInFileMap); if (m_pbData == NULL) { return FALSE; } m_cbData = cbInFileData; return TRUE; }
BOOL addsect_files(PCWSTR pszOutput, PCWSTR pszInput, PCWSTR pszData, PCSTR pszSection) { HANDLE hInput = INVALID_HANDLE_VALUE; HANDLE hOutput = INVALID_HANDLE_VALUE; BOOL bGood = TRUE; CFileMap cfData; CImage image;
if (!cfData.Load(pszData)) { fprintf(stderr, "ADDSECT: Could not open input data file: %ls\n", pszData); goto end; }
hInput = CreateFile(pszInput, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hInput == INVALID_HANDLE_VALUE) { printf("ADDSECT: Couldn't open input file: %ls, error: %d\n", pszInput, GetLastError()); bGood = FALSE; goto end; }
hOutput = CreateFile(pszOutput, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hOutput == INVALID_HANDLE_VALUE) { printf("ADDSECT: Couldn't open output file: %ls, error: %d\n", pszOutput, GetLastError()); bGood = FALSE; goto end; }
if (!image.Read(hInput)) { fprintf(stderr, "ADDSECT: Image read failed: %d\n", GetLastError()); bGood = FALSE; goto end; }
if (!image.Check(pszSection)) { fprintf(stderr, "ADDSECT: Can't insert section `%hs' into image: %d\n", pszSection, GetLastError()); bGood = FALSE; goto end; }
if (!image.Write(hOutput, cfData.Seek(0), cfData.Size(), pszSection)) { fprintf(stderr, "ADDSECT: Image write failed: %d\n", GetLastError()); bGood = FALSE; }
image.Close();
if (bGood) { printf("ADDSECT: Added new section `%hs' of %d bytes to `%ls'.\n", pszSection, cfData.Size(), pszOutput); }
end: if (hOutput != INVALID_HANDLE_VALUE) { CloseHandle(hOutput); hOutput = INVALID_HANDLE_VALUE; } if (hInput != INVALID_HANDLE_VALUE) { CloseHandle(hInput); hInput = INVALID_HANDLE_VALUE; } if (!bGood) { DeleteFile(pszOutput); }
return TRUE; }
int __cdecl wmain(int argc, PWCHAR *argv) { BOOL fNeedHelp = FALSE; PCWSTR pszData = NULL; PCWSTR pszInput = NULL; PCWSTR pszOutput = NULL; CHAR szSection[IMAGE_SIZEOF_SHORT_NAME + 1] = ".ramfs\0\0";
for (int arg = 1; arg < argc; arg++) { if (argv[arg][0] == '-' || argv[arg][0] == '/') { PWCHAR argn = argv[arg]+1; // Argument name
PWCHAR argp = argn; // Argument parameter
while (*argp && *argp != ':' && *argp != '=') { argp++; } if (*argp == ':' || *argp == '=') *argp++ = '\0';
switch (argn[0]) {
case 'd': // Input file.
case 'D': pszData = argp; break;
case 'i': // Input file.
case 'I': pszInput = argp; break;
case 'o': // Output file.
case 'O': pszOutput = argp; break;
case 's': // Section Name.
case 'S': _snprintf(szSection, arrayof(szSection)-1, "%ls", argp); szSection[arrayof(szSection)-1] = '\0'; break;
case 'h': // Help
case 'H': case '?': fNeedHelp = TRUE; break;
default: fprintf(stderr, "ADDSECT: Unknown argument: %ls\n", argv[arg]); fNeedHelp = TRUE; break; } } }
if (pszInput == NULL) { fNeedHelp = TRUE; }
if (pszOutput == NULL) { fNeedHelp = TRUE; }
if (pszData == NULL) { fNeedHelp = TRUE; }
if (argc == 1) { fNeedHelp = TRUE; }
if (fNeedHelp) { printf( "Usage:\n" " ADDSECT [options] /I:input /O:output /D:data\n" "Options:\n" " /O:output Specify output file.\n" " /I:input Specify input file.\n" " /D:data Specify data file.\n" " /S:section Symbol (defaults to .ramfs).\n" " /H or /? Display this help screen.\n" "Summary:\n" " Adds a new section to a PE binary.\n" ); return 1; }
if (!addsect_files(pszOutput, pszInput, pszData, szSection)) { return 2; } return 0; } //
///////////////////////////////////////////////////////////////// End of File.
|