Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

978 lines
30 KiB

//////////////////////////////////////////////////////////////////////////////
//
//
// 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.