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.
 
 
 
 
 
 

1527 lines
57 KiB

/*++
(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;
}