/*++ (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 FreeStrings( PUPDATEDATA pUpd ); VOID FreeData( PUPDATEDATA pUpd ); PRESNAME WriteResSection( PUPDATEDATA pUpdate, INT outfh, ULONG align, ULONG cbLeft, PRESNAME pResSave ); // // Template for patch debug information function. // template 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 ; pDbgPointerToRawData >= ibMaxDbgOffsetOld && pDbg->PointerToRawData < ibNew ) ibNew = pDbg->PointerToRawData; if (ibNew != 0xffffffff) *pPointerToRawData = ibNew; else *pPointerToRawData = _llseek(inpfh, 0L, SEEK_END); for (pDbg=pDbgSave ; pDbgPointerToRawData)); if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld) pDbg->PointerToRawData += adjust - ibNew; DPrintf((DebugBuf, "New debug file offset: %#08lx\n", pDbg->PointerToRawData)); } } else { for ( ; pDbgAddressOfRawData, 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 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 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; LONG VaAdjust=0; PIMAGE_SECTION_HEADER pObjtblOld, pObjtblNew = NULL, 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 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 ; pObjOldPointerToRawData > 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= 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 */ VaAdjust = 0; /* adjustment to virtual address */ for (pObjOld=pObjtblOld,pObjNew=pObjtblNew ; pObjOldVirtualAddress - pObjOld->VirtualAddress; } } continue; } else if (pObjNew == pObjResourceNew) { DPrintf((DebugBuf, "Resource Section %i\n", nObjResource+1)); cb = ROUNDUP(cbNew, New.OptionalHeader.FileAlignment); if (pObjResourceOld == NULL) { VaAdjust = 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) { VaAdjust = 0; } else { /* Adjust VA accordingly */ VaAdjust += ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment); if (pObjOld+1 < pObjLast) { // if there are more entries after pObjOld, shift those back as well VaAdjust -= ((pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress); } } } 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; VaAdjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjNew->VirtualAddress; DPrintf((DebugBuf, "Added .rsrc1. VirtualAddress %lu\t adjust: %lu\n", pObjNew->VirtualAddress, VaAdjust )); } 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 VaAdjust = 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 VaAdjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjOld->VirtualAddress; DPrintf((DebugBuf, "adjust: %lu\tsmall: New %lu\tOld %lu\n", VaAdjust, 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", VaAdjust)); *pObjNew++ = *pObjOld; (pObjNew-1)->VirtualAddress += VaAdjust; } } 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 (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: if (pObjtblNew) { RtlFreeHeap(RtlProcessHeap(), 0, pObjtblNew); } return cb; }