|
|
/*++
(C) Copyright Microsoft Corporation 1988-1992
Module Name:
updres.h
Author:
Floyd A Rogers 2/7/92
Revision History: Floyd Rogers Created --*/
#define DPrintf(a)
#define DPrintfn(a)
#define DPrintfu(a)
#define cbPadMax 16L
#define DEFAULT_CODEPAGE 1252
#define MAJOR_RESOURCE_VERSION 4
#define MINOR_RESOURCE_VERSION 0
#define BUTTONCODE 0x80
#define EDITCODE 0x81
#define STATICCODE 0x82
#define LISTBOXCODE 0x83
#define SCROLLBARCODE 0x84
#define COMBOBOXCODE 0x85
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define MAXSTR (256+1)
//
// An ID_WORD indicates the following WORD is an ordinal rather
// than a string
//
#define ID_WORD 0xffff
//typedef WCHAR *PWCHAR;
typedef struct MY_STRING { ULONG discriminant; // long to make the rest of the struct aligned
union u { struct { struct MY_STRING *pnext; ULONG ulOffsetToString; USHORT cbD; USHORT cb; WCHAR *sz; } ss; WORD Ordinal; } uu; } SDATA, *PSDATA, **PPSDATA;
#define IS_STRING 1
#define IS_ID 2
// defines to make deferencing easier
#define OffsetToString uu.ss.ulOffsetToString
#define cbData uu.ss.cbD
#define cbsz uu.ss.cb
#define szStr uu.ss.sz
typedef struct _RESNAME { struct _RESNAME *pnext; // The first three fields should be the
PSDATA Name; // same in both res structures
ULONG OffsetToData;
PSDATA Type; ULONG SectionNumber; ULONG DataSize; ULONG_PTR OffsetToDataEntry; USHORT ResourceNumber; USHORT NumberOfLanguages; WORD LanguageId; } RESNAME, *PRESNAME, **PPRESNAME;
typedef struct _RESTYPE { struct _RESTYPE *pnext; // The first three fields should be the
PSDATA Type; // same in both res structures
ULONG OffsetToData;
struct _RESNAME *NameHeadID; struct _RESNAME *NameHeadName; ULONG NumberOfNamesID; ULONG NumberOfNamesName; } RESTYPE, *PRESTYPE, **PPRESTYPE;
typedef struct _UPDATEDATA { ULONG cbStringTable; PSDATA StringHead; PRESNAME ResHead; PRESTYPE ResTypeHeadID; PRESTYPE ResTypeHeadName; LONG Status; HANDLE hFileName; } UPDATEDATA, *PUPDATEDATA;
//
// Round up a byte count to a power of 2:
//
#define ROUNDUP(cbin, align) (((cbin) + (align) - 1) & ~((align) - 1))
//
// Return the remainder, given a byte count and a power of 2:
//
#define REMAINDER(cbin,align) (((align)-((cbin)&((align)-1)))&((align)-1))
#define CBLONG (sizeof(LONG))
#define BUFSIZE (4L * 1024L)
/* functions for adding/deleting resources to update list */
LONG AddResource( IN PSDATA Type, IN PSDATA Name, IN WORD Language, IN PUPDATEDATA pupd, IN PVOID lpData, IN ULONG cb );
PSDATA AddStringOrID( LPCWSTR lp, PUPDATEDATA pupd );
BOOL InsertResourceIntoLangList( PUPDATEDATA pUpd, PSDATA Type, PSDATA Name, PRESTYPE pType, PRESNAME pName, INT idLang, INT fName, INT cb, PVOID lpData );
BOOL DeleteResourceFromList( PUPDATEDATA pUpd, PRESTYPE pType, PRESNAME pName, INT idLang, INT fType, INT fName );
/* Prototypes for Enumeration done in BeginUpdateResource */
BOOL EnumTypesFunc( HANDLE hModule, LPWSTR lpType, LPARAM lParam );
BOOL EnumNamesFunc( HANDLE hModule, LPWSTR lpName, LPWSTR lpType, LPARAM lParam );
BOOL EnumLangsFunc( HANDLE hModule, LPWSTR lpType, LPWSTR lpName, WORD languages, LPARAM lParam );
/* Prototypes for genral worker functions in updres.c */
LONG WriteResFile( IN HANDLE hUpdate, IN WCHAR *pDstname );
VOID FreeData( PUPDATEDATA pUpd );
PRESNAME WriteResSection( PUPDATEDATA pUpdate, INT outfh, ULONG align, ULONG cbLeft, PRESNAME pResSave );
//
// Template for patch debug information function.
//
template<class NT_HEADER_TYPE> LONG PatchDebug( int inpfh, int outfh, PIMAGE_SECTION_HEADER pDebugOld, PIMAGE_SECTION_HEADER pDebugNew, PIMAGE_SECTION_HEADER pDebugDirOld, PIMAGE_SECTION_HEADER pDebugDirNew, NT_HEADER_TYPE *pOld, NT_HEADER_TYPE *pNew, ULONG ibMaxDbgOffsetOld, PULONG pPointerToRawData )
{
PIMAGE_DEBUG_DIRECTORY pDbgLast; PIMAGE_DEBUG_DIRECTORY pDbgSave; PIMAGE_DEBUG_DIRECTORY pDbg; ULONG ib; ULONG adjust; ULONG ibNew;
if (pDebugDirOld == NULL || pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size==0) return NO_ERROR;
pDbgSave = pDbg = (PIMAGE_DEBUG_DIRECTORY)RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( RES_TAG ), pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size); if (pDbg == NULL) return ERROR_NOT_ENOUGH_MEMORY;
if (pDebugOld) { DPrintf((DebugBuf, "Patching dbg directory: @%#08lx ==> @%#08lx\n", pDebugOld->PointerToRawData, pDebugNew->PointerToRawData)); } else adjust = *pPointerToRawData; /* passed in EOF of new file */
ib = pOld->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress - pDebugDirOld->VirtualAddress; MuMoveFilePos(inpfh, pDebugDirOld->PointerToRawData+ib); pDbgLast = pDbg + (pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size)/sizeof(IMAGE_DEBUG_DIRECTORY); MuRead(inpfh, (PUCHAR)pDbg, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
if (pDebugOld == NULL) { /* find 1st entry - use for offset */ DPrintf((DebugBuf, "Adjust: %#08lx\n",adjust)); for (ibNew=0xffffffff ; pDbg<pDbgLast ; pDbg++) if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld && pDbg->PointerToRawData < ibNew ) ibNew = pDbg->PointerToRawData;
if (ibNew != 0xffffffff) *pPointerToRawData = ibNew; else *pPointerToRawData = _llseek(inpfh, 0L, SEEK_END); for (pDbg=pDbgSave ; pDbg<pDbgLast ; pDbg++) { DPrintf((DebugBuf, "Old debug file offset: %#08lx\n", pDbg->PointerToRawData)); if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld) pDbg->PointerToRawData += adjust - ibNew; DPrintf((DebugBuf, "New debug file offset: %#08lx\n", pDbg->PointerToRawData)); } } else { for ( ; pDbg<pDbgLast ; pDbg++) { DPrintf((DebugBuf, "Old debug addr: %#08lx, file offset: %#08lx\n", pDbg->AddressOfRawData, pDbg->PointerToRawData)); pDbg->AddressOfRawData += pDebugNew->VirtualAddress - pDebugOld->VirtualAddress; pDbg->PointerToRawData += pDebugNew->PointerToRawData - pDebugOld->PointerToRawData; DPrintf((DebugBuf, "New debug addr: %#08lx, file offset: %#08lx\n", pDbg->AddressOfRawData, pDbg->PointerToRawData)); } }
MuMoveFilePos(outfh, pDebugDirNew->PointerToRawData+ib); MuWrite(outfh, (PUCHAR)pDbgSave, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size); RtlFreeHeap(RtlProcessHeap(), 0, pDbgSave);
return NO_ERROR; }
//
// Template for patch debug information function.
//
template<class NT_HEADER_TYPE> LONG PatchRVAs( int inpfh, int outfh, PIMAGE_SECTION_HEADER po32, ULONG pagedelta, NT_HEADER_TYPE *pNew, ULONG OldSize )
{ ULONG hdrdelta; ULONG offset, rvaiat, offiat, iat; IMAGE_EXPORT_DIRECTORY Exp; IMAGE_IMPORT_DESCRIPTOR Imp; ULONG i, cmod, cimp;
hdrdelta = pNew->OptionalHeader.SizeOfHeaders - OldSize; if (hdrdelta == 0) { return NO_ERROR; }
//
// Patch export section RVAs
//
DPrintf((DebugBuf, "Export offset=%08lx, hdrsize=%08lx\n", pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, pNew->OptionalHeader.SizeOfHeaders)); if ((offset = pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) == 0) { DPrintf((DebugBuf, "No exports to patch\n")); } else if (offset >= pNew->OptionalHeader.SizeOfHeaders) { DPrintf((DebugBuf, "No exports in header to patch\n")); } else { MuMoveFilePos(inpfh, offset - hdrdelta); MuRead(inpfh, (PUCHAR) &Exp, sizeof(Exp)); Exp.Name += hdrdelta; (ULONG)Exp.AddressOfFunctions += hdrdelta; (ULONG)Exp.AddressOfNames += hdrdelta; (ULONG)Exp.AddressOfNameOrdinals += hdrdelta; MuMoveFilePos(outfh, offset); MuWrite(outfh, (PUCHAR) &Exp, sizeof(Exp)); }
//
// Patch import section RVAs
//
DPrintf((DebugBuf, "Import offset=%08lx, hdrsize=%08lx\n", pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, pNew->OptionalHeader.SizeOfHeaders)); if ((offset = pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) == 0) { DPrintf((DebugBuf, "No imports to patch\n")); } else if (offset >= pNew->OptionalHeader.SizeOfHeaders) { DPrintf((DebugBuf, "No imports in header to patch\n")); } else { for (cimp = cmod = 0; ; cmod++) { MuMoveFilePos(inpfh, offset + cmod * sizeof(Imp) - hdrdelta); MuRead(inpfh, (PUCHAR) &Imp, sizeof(Imp)); if (Imp.FirstThunk == 0) { break; } Imp.Name += hdrdelta; MuMoveFilePos(outfh, offset + cmod * sizeof(Imp)); MuWrite(outfh, (PUCHAR) &Imp, sizeof(Imp));
rvaiat = (ULONG)Imp.FirstThunk; DPrintf((DebugBuf, "RVAIAT = %#08lx\n", (ULONG)rvaiat)); for (i = 0; i < pNew->FileHeader.NumberOfSections; i++) { if (rvaiat >= po32[i].VirtualAddress && rvaiat < po32[i].VirtualAddress + po32[i].SizeOfRawData) {
offiat = rvaiat - po32[i].VirtualAddress + po32[i].PointerToRawData; goto found; } } DPrintf((DebugBuf, "IAT not found\n")); return ERROR_INVALID_DATA; found: DPrintf((DebugBuf, "IAT offset: @%#08lx ==> @%#08lx\n", offiat - pagedelta, offiat)); MuMoveFilePos(inpfh, offiat - pagedelta); MuMoveFilePos(outfh, offiat); for (;;) { MuRead(inpfh, (PUCHAR) &iat, sizeof(iat)); if (iat == 0) { break; } if ((iat & IMAGE_ORDINAL_FLAG) == 0) { // if import by name
DPrintf((DebugBuf, "Patching IAT: %08lx + %04lx ==> %08lx\n", iat, hdrdelta, iat + hdrdelta)); iat += hdrdelta; cimp++; } MuWrite(outfh, (PUCHAR) &iat, sizeof(iat)); // Avoids seeking
} } DPrintf((DebugBuf, "%u import module name RVAs patched\n", cmod)); DPrintf((DebugBuf, "%u IAT name RVAs patched\n", cimp)); if (cmod == 0) { DPrintf((DebugBuf, "No import modules to patch\n")); } if (cimp == 0) { DPrintf((DebugBuf, "No import name RVAs to patch\n")); } }
return NO_ERROR; }
//
// Template for write resource function.
//
template<class NT_HEADER_TYPE> LONG PEWriteResource( INT inpfh, INT outfh, ULONG cbOldexe, PUPDATEDATA pUpdate, NT_HEADER_TYPE *NtHeader )
{
NT_HEADER_TYPE Old; /* original header */ NT_HEADER_TYPE New; /* working header */ PRESNAME pRes; PRESNAME pResSave; PRESTYPE pType; ULONG clock = 0; ULONG cbName=0; /* count of bytes in name strings */ ULONG cbType=0; /* count of bytes in type strings */ ULONG cTypeStr=0; /* count of strings */ ULONG cNameStr=0; /* count of strings */ LONG cb; /* temp byte count and file index */ ULONG cTypes = 0L; /* count of resource types */ ULONG cNames = 0L; /* Count of names for multiple languages/name */ ULONG cRes = 0L; /* count of resources */ ULONG cbRestab; /* count of resources */ LONG cbNew = 0L; /* general count */ ULONG ibObjTab; ULONG ibObjTabEnd; ULONG ibNewObjTabEnd; ULONG ibSave; ULONG adjust=0; PIMAGE_SECTION_HEADER pObjtblOld, pObjtblNew, pObjDebug, pObjResourceOld, pObjResourceNew, pObjResourceOldX, pObjDebugDirOld, pObjDebugDirNew, pObjNew, pObjOld, pObjLast; PUCHAR p; PIMAGE_RESOURCE_DIRECTORY pResTab; PIMAGE_RESOURCE_DIRECTORY pResTabN; PIMAGE_RESOURCE_DIRECTORY pResTabL; PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirL; PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirN; PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirT; PIMAGE_RESOURCE_DATA_ENTRY pResData; PUSHORT pResStr; PUSHORT pResStrEnd; PSDATA pPreviousName; LONG nObjResource=-1; LONG nObjResourceX=-1; ULONG cbResource; ULONG cbMustPad = 0; ULONG ibMaxDbgOffsetOld;
MuMoveFilePos(inpfh, cbOldexe); MuRead(inpfh, (PUCHAR)&Old, sizeof(NT_HEADER_TYPE)); ibObjTab = cbOldexe + sizeof(NT_HEADER_TYPE);
ibObjTabEnd = ibObjTab + Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); ibNewObjTabEnd = ibObjTabEnd;
DPrintfn((DebugBuf, "\n"));
/* New header is like old one. */ RtlCopyMemory(&New, &Old, sizeof(NT_HEADER_TYPE));
/* Read section table */ pObjtblOld = (PIMAGE_SECTION_HEADER)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); if (pObjtblOld == NULL) { cb = ERROR_NOT_ENOUGH_MEMORY; goto AbortExit; }
RtlZeroMemory((PVOID)pObjtblOld, Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER)); DPrintf((DebugBuf, "Old section table: %#08lx bytes at %#08lx(mem)\n", Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), pObjtblOld)); MuMoveFilePos(inpfh, ibObjTab); MuRead(inpfh, (PUCHAR)pObjtblOld, Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); pObjLast = pObjtblOld + Old.FileHeader.NumberOfSections; ibMaxDbgOffsetOld = 0; for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++) { if (pObjOld->PointerToRawData > ibMaxDbgOffsetOld) { ibMaxDbgOffsetOld = pObjOld->PointerToRawData + pObjOld->SizeOfRawData; } } DPrintf((DebugBuf, "Maximum debug offset in old file: %08x\n", ibMaxDbgOffsetOld ));
/*
* First, count up the resources. We need this information * to discover how much room for header information to allocate * in the resource section. cRes tells us how * many language directory entries/tables. cNames and cTypes * is used for the respective tables and/or entries. cbName totals * the bytes required to store the alpha names (including the leading * length word). cNameStr counts these strings. */ DPrintf((DebugBuf, "Beginning loop to count resources\n"));
/* first, count those in the named type list */ cbResource = 0; //DPrintf((DebugBuf, "Walk type: NAME list\n"));
pType = pUpdate->ResTypeHeadName; while (pType != NULL) { if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) { //DPrintf((DebugBuf, "Resource type "));
//DPrintfu((pType->Type->szStr));
//DPrintfn((DebugBuf, "\n"));
cTypes++; cTypeStr++; cbType += (pType->Type->cbsz + 1) * sizeof(WORD);
//DPrintf((DebugBuf, "Walk name: Alpha list\n"));
pPreviousName = NULL; pRes = pType->NameHeadName; while (pRes) { //DPrintf((DebugBuf, "Resource "));
//DPrintfu((pRes->Name->szStr));
//DPrintfn((DebugBuf, "\n"));
cRes++; if (pPreviousName == NULL || wcscmp(pPreviousName->szStr, pRes->Name->szStr) != 0) { cbName += (pRes->Name->cbsz + 1) * sizeof(WORD); cNameStr++; cNames++; } cbResource += ROUNDUP(pRes->DataSize, CBLONG); pPreviousName = pRes->Name; pRes = pRes->pnext; }
//DPrintf((DebugBuf, "Walk name: ID list\n"));
pPreviousName = NULL; pRes = pType->NameHeadID; while (pRes) { //DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
cRes++; if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) { cNames++; } cbResource += ROUNDUP(pRes->DataSize, CBLONG); pPreviousName = pRes->Name; pRes = pRes->pnext; } } pType = pType->pnext; }
/* second, count those in the ID type list */ //DPrintf((DebugBuf, "Walk type: ID list\n"));
pType = pUpdate->ResTypeHeadID; while (pType != NULL) { if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) { //DPrintf((DebugBuf, "Resource type %hu\n", pType->Type->uu.Ordinal));
cTypes++; //DPrintf((DebugBuf, "Walk name: Alpha list\n"));
pPreviousName = NULL; pRes = pType->NameHeadName; while (pRes) { //DPrintf((DebugBuf, "Resource "));
//DPrintfu((pRes->Name->szStr));
//DPrintfn((DebugBuf, "\n"));
cRes++; if (pPreviousName == NULL || wcscmp(pPreviousName->szStr, pRes->Name->szStr) != 0) { cNames++; cbName += (pRes->Name->cbsz + 1) * sizeof(WORD); cNameStr++; } cbResource += ROUNDUP(pRes->DataSize, CBLONG); pPreviousName = pRes->Name; pRes = pRes->pnext; }
//DPrintf((DebugBuf, "Walk name: ID list\n"));
pPreviousName = NULL; pRes = pType->NameHeadID; while (pRes) { //DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal));
cRes++; if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) { cNames++; } cbResource += ROUNDUP(pRes->DataSize, CBLONG); pPreviousName = pRes->Name; pRes = pRes->pnext; } } pType = pType->pnext; } cb = REMAINDER(cbName + cbType, CBLONG);
/* Add up the number of bytes needed to store the directory. There is
* one type table with cTypes entries. They point to cTypes name tables * that have a total of cNames entries. Each of them points to a language * table and there are a total of cRes entries in all the language tables. * Finally, we have the space needed for the Directory string entries, * some extra padding to attain the desired alignment, and the space for * cRes data entry headers. */ cbRestab = sizeof(IMAGE_RESOURCE_DIRECTORY) + /* root dir (types) */ cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) + cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir2 (names) */ cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) + cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir3 (langs) */ cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) + (cbName + cbType) + /* name/type strings */ cb + /* padding */ cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY); /* data entries */
cbResource += cbRestab; /* add in the resource table */
// Find any current resource sections
pObjResourceOld = FindSection(pObjtblOld, pObjLast, ".rsrc"); pObjResourceOldX = FindSection(pObjtblOld, pObjLast, ".rsrc1"); pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
if ((pObjResourceOld == NULL)) { cb = 0x7fffffff; /* can fill forever */ } else if (pObjResourceOld + 1 == pObjResourceOldX) { nObjResource = (ULONG)(pObjResourceOld - pObjtblOld); DPrintf((DebugBuf,"Old Resource section #%lu\n", nObjResource+1)); DPrintf((DebugBuf,"Merging old Resource extra section #%lu\n", nObjResource+2)); cb = 0x7fffffff; /* merge resource sections */ } else if ((pObjResourceOld + 1) >= pObjLast) { nObjResource = (ULONG)(pObjResourceOld - pObjtblOld); cb = 0x7fffffff; /* can fill forever (.rsrc is the last entry) */ } else { nObjResource = (ULONG)(pObjResourceOld - pObjtblOld); DPrintf((DebugBuf,"Old Resource section #%lu\n", nObjResource+1)); if (pObjOld) { cb = (pObjResourceOld+1)->VirtualAddress - pObjResourceOld->VirtualAddress; } else { cb = 0x7fffffff; } if (cbRestab > (ULONG)cb) { DPrintf((DebugBuf, "Resource Table Too Large\n")); return ERROR_INVALID_DATA; } }
/*
* Discover where the first discardable section is. This is where * we will stick any new resource section. * * Note that we are ignoring discardable sections such as .CRT - * this is so that we don't cause any relocation problems. * Let's hope that .reloc is the one we want!!! */
if (pObjResourceOld != NULL && cbResource > (ULONG)cb) { if (pObjOld == pObjResourceOld + 1) { DPrintf((DebugBuf, "Large resource section pushes .reloc\n")); cb = 0x7fffffff; /* can fill forever */ } else if (pObjResourceOldX == NULL) { DPrintf((DebugBuf, "Too much resource data for old .rsrc section\n")); nObjResourceX = (ULONG)(pObjOld - pObjtblOld); adjust = pObjOld->VirtualAddress - pObjResourceOld->VirtualAddress; } else { /* have already merged .rsrc & .rsrc1, if possible */ DPrintf((DebugBuf, ".rsrc1 section not empty\n")); nObjResourceX = (ULONG)(pObjResourceOldX - pObjtblOld); adjust = pObjResourceOldX->VirtualAddress - pObjResourceOld ->VirtualAddress; } }
/*
* Walk the type lists and figure out where the Data entry header will * go. Keep a running total of the size for each data element so we * can store this in the section header. */ DPrintf((DebugBuf, "Beginning loop to assign resources to addresses\n"));
/* first, those in the named type list */
cbResource = cbRestab; /* assign resource table to 1st rsrc section */ /* adjust == offset to .rsrc1 */ /* cb == size availble in .rsrc */ cbNew = 0; /* count of bytes in second .rsrc */ DPrintf((DebugBuf, "Walk type: NAME list\n")); pType = pUpdate->ResTypeHeadName; while (pType != NULL) { if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) { DPrintf((DebugBuf, "Resource type ")); DPrintfu((pType->Type->szStr)); DPrintfn((DebugBuf, "\n")); pRes = pType->NameHeadName; while (pRes) { DPrintf((DebugBuf, "Resource ")); DPrintfu((pRes->Name->szStr)); DPrintfn((DebugBuf, "\n")); cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew); } pRes = pType->NameHeadID; while (pRes) { DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal)); cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew); } } pType = pType->pnext; }
/* then, count those in the ID type list */
DPrintf((DebugBuf, "Walk type: ID list\n")); pType = pUpdate->ResTypeHeadID; while (pType != NULL) { if (pType->NameHeadName != NULL || pType->NameHeadID != NULL) { DPrintf((DebugBuf, "Resource type %hu\n", pType->Type->uu.Ordinal)); pRes = pType->NameHeadName; while (pRes) { DPrintf((DebugBuf, "Resource ")); DPrintfu((pRes->Name->szStr)); DPrintfn((DebugBuf, "\n")); cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew); } pRes = pType->NameHeadID; while (pRes) { DPrintf((DebugBuf, "Resource %hu\n", pRes->Name->uu.Ordinal)); cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew); } } pType = pType->pnext; } /*
* At this point: * cbResource has offset of first byte past the last resource. * cbNew has the count of bytes in the first resource section, * if there are two sections. */ if (cbNew == 0) cbNew = cbResource;
/*
* Discover where the Debug info is (if any)? */ pObjDebug = FindSection(pObjtblOld, pObjLast, ".debug"); if (pObjDebug != NULL) { if (Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress == 0) { DPrintf((DebugBuf, ".debug section but no debug directory\n")); return ERROR_INVALID_DATA; } if (pObjDebug != pObjLast-1) { DPrintf((DebugBuf, "debug section not last section in file\n")); return ERROR_INVALID_DATA; } DPrintf((DebugBuf, "Debug section: %#08lx bytes @%#08lx\n", pObjDebug->SizeOfRawData, pObjDebug->PointerToRawData)); } pObjDebugDirOld = NULL; for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++) { if (Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress >= pObjOld->VirtualAddress && Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress < pObjOld->VirtualAddress+pObjOld->SizeOfRawData) { pObjDebugDirOld = pObjOld; break; } }
/*
* Discover where the first discardable section is. This is where * we will stick any new resource section. * * Note that we are ignoring discardable sections such as .CRT - * this is so that we don't cause any relocation problems. * Let's hope that .reloc is the one we want!!! */ pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
if (nObjResource == -1) { /* no old resource section */ if (pObjOld != NULL) nObjResource = (ULONG)(pObjOld - pObjtblOld); else if (pObjDebug != NULL) nObjResource = (ULONG)(pObjDebug - pObjtblOld); else nObjResource = New.FileHeader.NumberOfSections; New.FileHeader.NumberOfSections++; }
DPrintf((DebugBuf, "Resources assigned to section #%lu\n", nObjResource+1)); if (nObjResourceX != -1) { if (pObjResourceOldX != NULL) { nObjResourceX = (ULONG)(pObjResourceOldX - pObjtblOld); New.FileHeader.NumberOfSections--; } else if (pObjOld != NULL) nObjResourceX = (ULONG)(pObjOld - pObjtblOld); else if (pObjDebug != NULL) nObjResourceX = (ULONG)(pObjDebug - pObjtblOld); else nObjResourceX = New.FileHeader.NumberOfSections; New.FileHeader.NumberOfSections++; DPrintf((DebugBuf, "Extra resources assigned to section #%lu\n", nObjResourceX+1)); } else if (pObjResourceOldX != NULL) { /* Was old .rsrc1 section? */ DPrintf((DebugBuf, "Extra resource section deleted\n")); New.FileHeader.NumberOfSections--; /* yes, delete it */ }
/*
* If we had to add anything to the header (section table), * then we have to update the header size and rva's in the header. */ adjust = (New.FileHeader.NumberOfSections - Old.FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER); cb = Old.OptionalHeader.SizeOfHeaders - (Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) + sizeof(NT_HEADER_TYPE) + cbOldexe ); if (adjust > (ULONG)cb) { int i;
adjust -= cb; DPrintf((DebugBuf, "Adjusting header RVAs by %#08lx\n", adjust)); for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++) { if (New.OptionalHeader.DataDirectory[i].VirtualAddress && New.OptionalHeader.DataDirectory[i].VirtualAddress < New.OptionalHeader.SizeOfHeaders) { DPrintf((DebugBuf, "Adjusting unit[%s] RVA from %#08lx to %#08lx\n", apszUnit[i], New.OptionalHeader.DataDirectory[i].VirtualAddress, New.OptionalHeader.DataDirectory[i].VirtualAddress + adjust)); New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust; } } New.OptionalHeader.SizeOfHeaders += adjust; } else if (adjust > 0) { int i;
//
// Loop over DataDirectory entries and look for any entries that point to
// information stored in the 'dead' space after the section table but before
// the SizeOfHeaders length.
//
DPrintf((DebugBuf, "Checking header RVAs for 'dead' space usage\n")); for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++) { if (New.OptionalHeader.DataDirectory[i].VirtualAddress && New.OptionalHeader.DataDirectory[i].VirtualAddress < Old.OptionalHeader.SizeOfHeaders) { DPrintf((DebugBuf, "Adjusting unit[%s] RVA from %#08lx to %#08lx\n", apszUnit[i], New.OptionalHeader.DataDirectory[i].VirtualAddress, New.OptionalHeader.DataDirectory[i].VirtualAddress + adjust)); New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust; } } } ibNewObjTabEnd += adjust;
/* Allocate storage for new section table */ cb = New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); pObjtblNew = (PIMAGE_SECTION_HEADER)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), (short)cb); if (pObjtblNew == NULL) { cb = ERROR_NOT_ENOUGH_MEMORY; goto AbortExit; } RtlZeroMemory((PVOID)pObjtblNew, cb); DPrintf((DebugBuf, "New section table: %#08lx bytes at %#08lx\n", cb, pObjtblNew)); pObjResourceNew = pObjtblNew + nObjResource;
/*
* copy old section table to new */ adjust = 0; /* adjustment to virtual address */ for (pObjOld=pObjtblOld,pObjNew=pObjtblNew ; pObjOld<pObjLast ; pObjOld++) { if (pObjOld == pObjResourceOldX) { if (nObjResourceX == -1) { // we have to move back all the other section.
// the .rsrc1 is bigger than what we need
// adjust must be a negative number
if (pObjOld+1 < pObjLast) { adjust -= (pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress; } } continue; } else if (pObjNew == pObjResourceNew) { DPrintf((DebugBuf, "Resource Section %i\n", nObjResource+1)); cb = ROUNDUP(cbNew, New.OptionalHeader.FileAlignment); if (pObjResourceOld == NULL) { adjust = ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment); RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER)); strcpy((char *)pObjNew->Name, ".rsrc"); pObjNew->VirtualAddress = pObjOld->VirtualAddress; pObjNew->PointerToRawData = pObjOld->PointerToRawData; pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; pObjNew->SizeOfRawData = cb; pObjNew->Misc.VirtualSize = cbNew; } else { *pObjNew = *pObjOld; /* copy obj table entry */ pObjNew->SizeOfRawData = cb; pObjNew->Misc.VirtualSize = cbNew; if (pObjNew->SizeOfRawData == pObjOld->SizeOfRawData) { adjust = 0; } else if (pObjNew->SizeOfRawData > pObjOld->SizeOfRawData) { adjust += ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment); if (pObjOld+1 < pObjLast) { // if there are more entries after pObjOld, shift those back as well
adjust -= ((pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress); } } else { /* is smaller, but pad so will be valid */ adjust = 0; pObjNew->SizeOfRawData = pObjResourceOld->SizeOfRawData; /* if legoized, the VS could be > RawSize !!! */ pObjNew->Misc.VirtualSize = pObjResourceOld->Misc.VirtualSize; cbMustPad = pObjResourceOld->SizeOfRawData; } } pObjNew++; if (pObjResourceOld == NULL) goto rest_of_table; } else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX) { DPrintf((DebugBuf, "Additional Resource Section %i\n", nObjResourceX+1)); RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER)); strcpy((char *)pObjNew->Name, ".rsrc1"); /*
* Before we copy the virtual address we have to move back the * .reloc * virtual address. Otherwise we will keep moving the * reloc VirtualAddress forward. * We will have to move back the address of .rsrc1 */ if (pObjResourceOldX == NULL) { // This is the first time we have a .rsrc1
pObjNew->VirtualAddress = pObjOld->VirtualAddress; pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjNew->VirtualAddress; DPrintf((DebugBuf, "Added .rsrc1. VirtualAddress %lu\t adjust: %lu\n", pObjNew->VirtualAddress, adjust )); } else { // we already have an .rsrc1 use the position of that and
// calculate the new adjust
pObjNew->VirtualAddress = pObjResourceOldX->VirtualAddress; pObjNew->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
DPrintf((DebugBuf, ".rsrc1 Keep old position.\t\tVirtualAddress %lu\t", pObjNew->VirtualAddress )); // Check if we have enough room in the old .rsrc1
// Include the full size of the section, data + roundup
if (cbResource - (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress) <= pObjOld->VirtualAddress - pObjNew->VirtualAddress ) { // we have to move back all the other section.
// the .rsrc1 is bigger than what we need
// adjust must be a negative number
// calc new adjust size
adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjOld->VirtualAddress; DPrintf((DebugBuf, "adjust: %ld\tsmall: New %lu\tOld %lu\n", adjust, cbResource - (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress), pObjOld->VirtualAddress - pObjNew->VirtualAddress)); } else { // we have to move the section again.
// The .rsrc1 is too small
adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjOld->VirtualAddress; DPrintf((DebugBuf, "adjust: %lu\tsmall: New %lu\tOld %lu\n", adjust, cbResource - (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress), pObjOld->VirtualAddress - pObjNew->VirtualAddress)); } } pObjNew++; goto rest_of_table; } else if (pObjNew < pObjResourceNew) { DPrintf((DebugBuf, "copying section table entry %i@%#08lx\n", pObjOld - pObjtblOld + 1, pObjNew)); *pObjNew++ = *pObjOld; /* copy obj table entry */ } else { rest_of_table: DPrintf((DebugBuf, "copying section table entry %i@%#08lx\n", pObjOld - pObjtblOld + 1, pObjNew)); DPrintf((DebugBuf, "adjusting VirtualAddress by %#08lx\n", adjust)); *pObjNew++ = *pObjOld; (pObjNew-1)->VirtualAddress += adjust; } }
pObjNew = pObjtblNew + New.FileHeader.NumberOfSections - 1; New.OptionalHeader.SizeOfImage = ROUNDUP(pObjNew->VirtualAddress + pObjNew->SizeOfRawData, New.OptionalHeader.SectionAlignment);
/* allocate room to build the resource directory/tables in */ pResTab = (PIMAGE_RESOURCE_DIRECTORY)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), cbRestab); if (pResTab == NULL) { cb = ERROR_NOT_ENOUGH_MEMORY; goto AbortExit; }
/* First, setup the "root" type directory table. It will be followed by */ /* Types directory entries. */
RtlZeroMemory((PVOID)pResTab, cbRestab); DPrintf((DebugBuf, "resource directory tables: %#08lx bytes at %#08lx(mem)\n", cbRestab, pResTab)); p = (PUCHAR)pResTab; SetRestab(pResTab, clock, (USHORT)cTypeStr, (USHORT)(cTypes - cTypeStr));
/* Calculate the start of the various parts of the resource table. */ /* We need the start of the Type/Name/Language directories as well */ /* as the start of the UNICODE strings and the actual data nodes. */
pResDirT = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTab + 1);
pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirT) + cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirN) + cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) + cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
pResData = (PIMAGE_RESOURCE_DATA_ENTRY)(((PUCHAR)pResDirL) + cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) + cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
pResStr = (PUSHORT)(((PUCHAR)pResData) + cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY));
pResStrEnd = (PUSHORT)(((PUCHAR)pResStr) + cbName + cbType);
/*
* Loop over type table, building the PE resource table. */
/*
* ***************************************************************** * This code doesn't sort the table - the TYPEINFO and RESINFO ** * insertion code in rcp.c (AddResType and SaveResFile) do the ** * insertion by ordinal type and name, so we don't have to sort ** * it at this point. ** * ***************************************************************** */ DPrintf((DebugBuf, "building resource directory\n"));
// First, add all the entries in the Types: Alpha list.
DPrintf((DebugBuf, "Walk the type: Alpha list\n")); pType = pUpdate->ResTypeHeadName; while (pType) { DPrintf((DebugBuf, "resource type ")); DPrintfu((pType->Type->szStr)); DPrintfn((DebugBuf, "\n"));
pResDirT->Name = (ULONG)((((PUCHAR)pResStr) - p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirT++;
*pResStr = pType->Type->cbsz; wcsncpy((WCHAR*)(pResStr+1), pType->Type->szStr, pType->Type->cbsz); pResStr += pType->Type->cbsz + 1;
pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN; SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID); pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
pPreviousName = NULL;
pRes = pType->NameHeadName; while (pRes) { DPrintf((DebugBuf, "resource ")); DPrintfu((pRes->Name->szStr)); DPrintfn((DebugBuf, "\n"));
if (pPreviousName == NULL || wcscmp(pPreviousName->szStr,pRes->Name->szStr) != 0) { // Setup a new name directory
pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
// Copy the alpha name to a string entry
*pResStr = pRes->Name->cbsz; wcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz); pResStr += pRes->Name->cbsz + 1;
pPreviousName = pRes->Name;
// Setup the Language table
pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL; SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages); pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1); }
// Setup a new Language directory
pResDirL->Name = pRes->LanguageId; pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p); pResDirL++;
// Setup a new resource data entry
SetResdata(pResData, pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress, pRes->DataSize); pResData++;
pRes = pRes->pnext; }
pPreviousName = NULL;
pRes = pType->NameHeadID; while (pRes) { DPrintf((DebugBuf, "resource %hu\n", pRes->Name->uu.Ordinal));
if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) { // Setup the name directory to point to the next language
// table
pResDirN->Name = pRes->Name->uu.Ordinal; pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
pPreviousName = pRes->Name;
// Init a new Language table
pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL; SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages); pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1); }
// Setup a new language directory entry to point to the next
// resource
pResDirL->Name = pRes->LanguageId; pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p); pResDirL++;
// Setup a new resource data entry
SetResdata(pResData, pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress, pRes->DataSize); pResData++;
pRes = pRes->pnext; }
pType = pType->pnext; }
// Do the same thing, but this time, use the Types: ID list.
DPrintf((DebugBuf, "Walk the type: ID list\n")); pType = pUpdate->ResTypeHeadID; while (pType) { DPrintf((DebugBuf, "resource type %hu\n", pType->Type->uu.Ordinal));
pResDirT->Name = (ULONG)pType->Type->uu.Ordinal; pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirT++;
pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN; SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID); pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
pPreviousName = NULL;
pRes = pType->NameHeadName; while (pRes) { DPrintf((DebugBuf, "resource ")); DPrintfu((pRes->Name->szStr)); DPrintfn((DebugBuf, "\n"));
if (pPreviousName == NULL || wcscmp(pPreviousName->szStr,pRes->Name->szStr) != 0) { // Setup a new name directory
pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
// Copy the alpha name to a string entry.
*pResStr = pRes->Name->cbsz; wcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz); pResStr += pRes->Name->cbsz + 1;
pPreviousName = pRes->Name;
// Setup the Language table
pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL; SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages); pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1); }
// Setup a new Language directory
pResDirL->Name = pRes->LanguageId; pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p); pResDirL++;
// Setup a new resource data entry
SetResdata(pResData, pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress, pRes->DataSize); pResData++;
pRes = pRes->pnext; }
pPreviousName = NULL;
pRes = pType->NameHeadID; while (pRes) { DPrintf((DebugBuf, "resource %hu\n", pRes->Name->uu.Ordinal));
if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal) { // Setup the name directory to point to the next language
// table
pResDirN->Name = pRes->Name->uu.Ordinal; pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
pPreviousName = pRes->Name;
// Init a new Language table
pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL; SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages); pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1); }
// Setup a new language directory entry to point to the next
// resource
pResDirL->Name = pRes->LanguageId; pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p); pResDirL++;
// Setup a new resource data entry
SetResdata(pResData, pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress, pRes->DataSize); pResData++;
pRes = pRes->pnext; }
pType = pType->pnext; } DPrintf((DebugBuf, "Zeroing %u bytes after strings at %#08lx(mem)\n", (pResStrEnd - pResStr) * sizeof(*pResStr), pResStr)); while (pResStr < pResStrEnd) { *pResStr++ = 0; }
#if DBG
{ USHORT j = 0; PUSHORT pus = (PUSHORT)pResTab;
while (pus < (PUSHORT)pResData) { DPrintf((DebugBuf, "%04x\t%04x %04x %04x %04x %04x %04x %04x %04x\n", j, *pus, *(pus + 1), *(pus + 2), *(pus + 3), *(pus + 4), *(pus + 5), *(pus + 6), *(pus + 7))); pus += 8; j += 16; } } #endif /* DBG */
/*
* copy the Old exe header and stub, and allocate room for the PE header. */ DPrintf((DebugBuf, "copying through PE header: %#08lx bytes @0x0\n", cbOldexe + sizeof(NT_HEADER_TYPE))); MuMoveFilePos(inpfh, 0L); MuCopy(inpfh, outfh, cbOldexe + sizeof(NT_HEADER_TYPE));
/*
* Copy rest of file header */ DPrintf((DebugBuf, "skipping section table: %#08lx bytes @%#08lx\n", New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), FilePos(outfh))); DPrintf((DebugBuf, "copying hdr data: %#08lx bytes @%#08lx ==> @%#08lx\n", Old.OptionalHeader.SizeOfHeaders - ibObjTabEnd, ibObjTabEnd, ibObjTabEnd + New.OptionalHeader.SizeOfHeaders - Old.OptionalHeader.SizeOfHeaders));
MuMoveFilePos(outfh, ibNewObjTabEnd + New.OptionalHeader.SizeOfHeaders - Old.OptionalHeader.SizeOfHeaders); MuMoveFilePos(inpfh, ibObjTabEnd); MuCopy(inpfh, outfh, Old.OptionalHeader.SizeOfHeaders - ibNewObjTabEnd);
/*
* copy existing image sections */
/* Align data sections on sector boundary */ cb = REMAINDER(New.OptionalHeader.SizeOfHeaders, New.OptionalHeader.FileAlignment); New.OptionalHeader.SizeOfHeaders += cb; DPrintf((DebugBuf, "padding header with %#08lx bytes @%#08lx\n", cb, FilePos(outfh))); while (cb >= cbPadMax) { MuWrite(outfh, pchZero, cbPadMax); cb -= cbPadMax; } MuWrite(outfh, pchZero, cb);
cb = ROUNDUP(Old.OptionalHeader.SizeOfHeaders, Old.OptionalHeader.FileAlignment); MuMoveFilePos(inpfh, cb);
/* copy one section at a time */ New.OptionalHeader.SizeOfInitializedData = 0; for (pObjOld = pObjtblOld , pObjNew = pObjtblNew ; pObjOld < pObjLast ; pObjNew++) { if (pObjOld == pObjResourceOldX) pObjOld++; if (pObjNew == pObjResourceNew) {
/* Write new resource section */ DPrintf((DebugBuf, "Primary resource section %i to %#08lx\n", nObjResource+1, FilePos(outfh)));
pObjNew->PointerToRawData = FilePos(outfh); New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = pObjResourceNew->VirtualAddress; New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = cbResource; ibSave = FilePos(outfh); DPrintf((DebugBuf, "writing resource header data: %#08lx bytes @%#08lx\n", cbRestab, ibSave)); MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
pResSave = WriteResSection(pUpdate, outfh, New.OptionalHeader.FileAlignment, pObjResourceNew->SizeOfRawData-cbRestab, NULL); cb = FilePos(outfh); DPrintf((DebugBuf, "wrote resource data: %#08lx bytes @%#08lx\n", cb - ibSave - cbRestab, ibSave + cbRestab)); if (cbMustPad != 0) { cbMustPad -= cb - ibSave; DPrintf((DebugBuf, "writing MUNGE pad: %#04lx bytes @%#08lx\n", cbMustPad, cb)); /* assumes that cbMustPad % cbpadMax == 0 */ while (cbMustPad > 0) { MuWrite(outfh, pchZero, cbPadMax); cbMustPad -= cbPadMax; } cb = FilePos(outfh); } if (nObjResourceX == -1) { MuMoveFilePos(outfh, ibSave); DPrintf((DebugBuf, "re-writing resource directory: %#08x bytes @%#08lx\n", cbRestab, ibSave)); MuWrite(outfh, (PUCHAR)pResTab, cbRestab); MuMoveFilePos(outfh, cb); cb = FilePos(inpfh); MuMoveFilePos(inpfh, cb+pObjOld->SizeOfRawData); } New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData; if (pObjResourceOld == NULL) { pObjNew++; goto next_section; } else pObjOld++; } else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX) {
/* Write new resource section */ DPrintf((DebugBuf, "Secondary resource section %i @%#08lx\n", nObjResourceX+1, FilePos(outfh)));
pObjNew->PointerToRawData = FilePos(outfh); (void)WriteResSection(pUpdate, outfh, New.OptionalHeader.FileAlignment, 0xffffffff, pResSave); cb = FilePos(outfh); pObjNew->SizeOfRawData = cb - pObjNew->PointerToRawData; pObjNew->Misc.VirtualSize = pObjNew->SizeOfRawData; DPrintf((DebugBuf, "wrote resource data: %#08lx bytes @%#08lx\n", pObjNew->SizeOfRawData, pObjNew->PointerToRawData)); MuMoveFilePos(outfh, ibSave); DPrintf((DebugBuf, "re-writing resource directory: %#08x bytes @%#08lx\n", cbRestab, ibSave)); MuWrite(outfh, (PUCHAR)pResTab, cbRestab); MuMoveFilePos(outfh, cb); New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData; pObjNew++; goto next_section; } else { if (pObjNew < pObjResourceNew && pObjOld->PointerToRawData != 0 && pObjOld->PointerToRawData != FilePos(outfh)) { MuMoveFilePos(outfh, pObjOld->PointerToRawData); } next_section: DPrintf((DebugBuf, "copying section %i @%#08lx\n", pObjNew-pObjtblNew+1, FilePos(outfh))); if (pObjOld->PointerToRawData != 0) { pObjNew->PointerToRawData = FilePos(outfh); MuMoveFilePos(inpfh, pObjOld->PointerToRawData); MuCopy(inpfh, outfh, pObjOld->SizeOfRawData); } if (pObjOld == pObjDebugDirOld) { pObjDebugDirNew = pObjNew; } if ((pObjNew->Characteristics&IMAGE_SCN_CNT_INITIALIZED_DATA) != 0) New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData; pObjOld++; } } if (pObjResourceOldX != NULL) New.OptionalHeader.SizeOfInitializedData -= pObjResourceOldX->SizeOfRawData;
/* Update the address of the relocation table */ pObjNew = FindSection(pObjtblNew, pObjtblNew+New.FileHeader.NumberOfSections, ".reloc"); if (pObjNew != NULL) { New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = pObjNew->VirtualAddress; }
/*
* Write new section table out. */ DPrintf((DebugBuf, "Writing new section table: %#08x bytes @%#08lx\n", New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), ibObjTab)); MuMoveFilePos(outfh, ibObjTab); MuWrite(outfh, (PUCHAR)pObjtblNew, New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
/* Seek to end of output file and issue truncating write */
adjust = _llseek(outfh, 0L, SEEK_END); MuWrite(outfh, NULL, 0); DPrintf((DebugBuf, "File size is: %#08lx\n", adjust));
/* If a debug section, fix up the debug table */
pObjNew = FindSection(pObjtblNew, pObjtblNew+New.FileHeader.NumberOfSections, ".debug"); cb = PatchDebug(inpfh, outfh, pObjDebug, pObjNew, pObjDebugDirOld, pObjDebugDirNew, &Old, &New, ibMaxDbgOffsetOld, &adjust);
if (cb == NO_ERROR) { if (pObjResourceOld == NULL) { cb = (LONG)pObjResourceNew->SizeOfRawData;
} else { cb = (LONG)pObjResourceOld->SizeOfRawData - (LONG)pObjResourceNew->SizeOfRawData; }
cb = PatchRVAs(inpfh, outfh, pObjtblNew, cb, &New, Old.OptionalHeader.SizeOfHeaders); }
/* copy NOTMAPPED debug info */
if ((pObjDebugDirOld != NULL) && (pObjDebug == NULL) && (New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)) {
ULONG ibt;
ibSave = _llseek(inpfh, 0L, SEEK_END); /* copy debug data */ ibt = _llseek(outfh, 0L, SEEK_END); /* to EOF */ if (New.FileHeader.PointerToSymbolTable != 0) { New.FileHeader.PointerToSymbolTable += ibt - adjust; }
MuMoveFilePos(inpfh, adjust); /* returned by PatchDebug */ DPrintf((DebugBuf, "Copying NOTMAPPED Debug Information, %#08lx bytes\n", ibSave-adjust)); MuCopy(inpfh, outfh, ibSave-adjust); }
//
// Write updated PE header.
//
MuMoveFilePos(outfh, cbOldexe); MuWrite(outfh, (char*)&New, sizeof(NT_HEADER_TYPE));
/* free up allocated memory */
RtlFreeHeap(RtlProcessHeap(), 0, pObjtblOld); RtlFreeHeap(RtlProcessHeap(), 0, pResTab);
AbortExit: RtlFreeHeap(RtlProcessHeap(), 0, pObjtblNew); return cb; }
|