|
|
/****************************************************************************
PROGRAM: updr16.cpp
PURPOSE: Contains API Entry points and routines for updating resource sections in exe/dll FUNCTIONS:
EndUpdateResource(HANDLE, BOOL) - end update, write changes UpdateResource(HANDLE, LPSTR, LPSTR, WORD, PVOID) - update individual resource BeginUpdateResource(LPSTR) - begin update
16 Bit version to update win32 binaries [alessanm] - 26/07/1993
Changed Rtl* fns to use combination of far & huge heap. Added mem-use reporting fns; grep MEM_STATISTICS. [MikeCo] - 8/17/1994 Port to 32-bit and used for Win95 IME Generator, ouput as an .OBJ - v-guanx 8/15/1995 delete HUGE & far HPUCHAR ==> BYTE * *******************************************************************************/
//#include <afxwin.h>
#include <windows.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
//#include "iodll.h"
#include "upimeres.h"
//#include "..\nls\nls16.h" V-GUANX 95/8/15
long error; #define cbPadMax 16L
static char *pchPad = "PADDINGXXPADDING"; static char *pchZero = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
#ifndef _X86_
#define HEAP_ZERO_MEMORY 0
#endif
DWORD gdwLastError = 0L; // we will have a global variable to remember the last error
//extern UINT _MBSTOWCS( WCHAR * pwszOut, CHAR * pszIn, UINT nLength);
//extern UINT _WCSTOMBS( CHAR * pszOut, WCHAR * pwszIn, UINT nOutLength, UINT nInLength = -1);
//v-guanx static UINT CopyFile( char * pszfilein, char * pszfileout );
//#define MEM_STATISTICS
#ifdef MEM_STATISTICS
static void RtlRecordAlloc(DWORD cb); static void RtlRecordFree(); static void RtlInitStatistics(); static void RtlReportStatistics(); #endif
static BOOL gbReportDupRes; // whether to report duplicate resources
/****************************************************************************
** ** API entry points ** ****************************************************************************/
/****************************************************************************
BeginUpdateResourceW:
This is a reduced version of the original NT API.
We accept only a call with the parameter bDeleteExistingResource==TRUE. We force this parameter to be TRUE so we haven't to call the LoadLibrary API. We don't want call this API to alowed the succesfull update of loaded modules
****************************************************************************/ HANDLE BeginUpdateResourceEx( LPCTSTR pwch, BOOL bDeleteExistingResources ) { PUPDATEDATA pUpdate; HANDLE hUpdate; LPTSTR pFileName; HMODULE hModule; #ifdef MEM_STATISTICS
RtlInitStatistics(); #endif
gbReportDupRes = TRUE;
SetLastError(0); hUpdate = GlobalAlloc(GHND, sizeof(UPDATEDATA)); if (hUpdate == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } pUpdate = (PUPDATEDATA)GlobalLock(hUpdate); if (pUpdate == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; }
pUpdate->hFileName = GlobalAlloc(GHND, strlen(pwch)+1); if (pUpdate->hFileName == NULL) { GlobalUnlock(hUpdate); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } pFileName = (LPTSTR)GlobalLock(pUpdate->hFileName); if (pFileName == NULL) { GlobalUnlock(hUpdate); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } strcpy(pFileName, pwch); GlobalUnlock(pUpdate->hFileName);
if (bDeleteExistingResources) pUpdate->Status = NO_ERROR; else { if (pwch != NULL) hModule = LoadLibrary(pwch); else hModule = NULL; error = GetLastError(); if (pwch != NULL && hModule == NULL) { GlobalUnlock(hUpdate); GlobalFree(hUpdate); return NULL; } else EnumResourceTypes(hModule, (ENUMRESTYPEPROC)EnumTypesFunc, (LONG)pUpdate); FreeLibrary(hModule); //v-guanx pUpdate->Status = ERROR_NOT_IMPLEMENTED;
} if (pUpdate->Status != NO_ERROR) { GlobalUnlock(hUpdate); GlobalFree(hUpdate); return NULL; }
GlobalUnlock(hUpdate); return hUpdate; }
BOOL UpdateResourceEx( HANDLE hUpdate, LPCTSTR lpType, LPCTSTR lpName, WORD language, LPVOID lpData, ULONG cb ) { PUPDATEDATA pUpdate; PSDATA Type; PSDATA Name; PVOID lpCopy; LONG fRet;
SetLastError(0); pUpdate = (PUPDATEDATA)GlobalLock(hUpdate); Name = AddStringOrID(lpName, pUpdate); if (Name == NULL) { pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY; GlobalUnlock(hUpdate); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } Type = AddStringOrID(lpType, pUpdate); if (Type == NULL) { pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY; GlobalUnlock(hUpdate); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } //v-guanx lpCopy = RtlAllocateHeap(RtlProcessHeap(), 0, cb);
lpCopy = malloc(cb); if (lpCopy == NULL) { pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY; GlobalUnlock(hUpdate); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } memset(lpCopy, 0, cb); memcpy(lpCopy, lpData, cb); fRet = AddResource(Type, Name, language, pUpdate, lpCopy, cb); GlobalUnlock(hUpdate); if (fRet == NO_ERROR) return TRUE; else { SetLastError(fRet); //v-guanx RtlFreeHeap(RtlProcessHeap(), 0, lpData);
if(lpCopy!=NULL) free(lpCopy); return FALSE; } }
BOOL EndUpdateResourceEx( HANDLE hUpdate, BOOL fDiscard ) { LPTSTR pFileName; PUPDATEDATA pUpdate; static char pTempFileName[_MAX_PATH]; int cch; LPSTR p; LONG rc;
SetLastError(0); pUpdate = (PUPDATEDATA)GlobalLock(hUpdate); if (fDiscard) { rc = NO_ERROR; } else { pFileName = (LPTSTR)GlobalLock(pUpdate->hFileName); // convert back to ANSI
strcpy(pTempFileName, pFileName); //v-guanx change back to wcscpy _WCSTOMBS( pTempFileName, pFileName, wcslen(pFileName)+1);
cch = strlen(pTempFileName); p = pTempFileName + cch; //v-guanx while (*p != L'\\' && p >= pTempFileName)
while (*p != '\\' && p >= pTempFileName) p--; *(p+1) = 0; rc = GetTempFileName( pTempFileName, "RCX", 0, pTempFileName); if (rc == 0) { rc = GetLastError(); } else { rc = WriteResFile(hUpdate, pTempFileName); if (rc == NO_ERROR) { DeleteFile(pFileName); if(!MoveFile(pTempFileName, pFileName)){ SetLastError(ERROR_FILE_NOT_FOUND); } } else { SetLastError(rc); DeleteFile(pTempFileName); } } GlobalUnlock(pUpdate->hFileName); GlobalFree(pUpdate->hFileName); }
#ifdef MEM_STATISTICS
RtlReportStatistics(); #endif
FreeData(pUpdate); GlobalUnlock(hUpdate); GlobalFree(hUpdate); return rc?FALSE:TRUE;
}
/* v-guanx
extern "C" void APIENTRY SetLastError( DWORD fdwError ) { gdwLastError = fdwError; }
extern "C" DWORD APIENTRY GetLastError( void ) { return gdwLastError; } */ /****************************************************************************
** ** Helper functions ** ****************************************************************************/
//-------------------------------------------------------------
// Helper for ReportDuplicateResource().
//-------------------------------------------------------------
/*LPSTR PrintablePSDATA(PSDATA x)
{ char work[70]; int i; if (x->discriminant == IS_ID) { // Format as hex
sprintf(work, "0x%x", x->uu.Ordinal); for (i=2; work[i] != 0; i++) { work[i] = toupper(work[i]); } return (LPSTR) work; } else { work[0] = '"'; strcpy(&work[1],x->szStr); strcat(work, "\""); return (LPSTR)work; } } */ //-------------------------------------------------------------
// Alerts user that a duplicate Type,Name pair was given to
// AddResource().
//-------------------------------------------------------------
//v-guanx rewrite this function as a C and use Windows API
/*void ReportDuplicateResource(PSDATA Type, PSDATA Name)
{ if (gbReportDupRes) { char work[200]; int uiStatus; sprintf(work, "WARNING: Duplicate resource id.\n\nType=%s; Name=%s.\n\n" "Report all problems of this kind?", (LPSTR)PrintablePSDATA(Type), (LPSTR)PrintablePSDATA(Name)); //V-GUANX UINT uiStatus = AfxMessageBox(work, MB_ICONEXCLAMATION | MB_YESNO);
uiStatus = MessageBox(NULL,work, "Warning", MB_YESNO); if (uiStatus == IDNO) { gbReportDupRes = FALSE; } } } */
LONG AddResource( PSDATA Type, PSDATA Name, WORD Language, PUPDATEDATA pupd, PVOID lpData, ULONG cb ) { PRESTYPE pType; PPRESTYPE ppType; PRESNAME pName; PRESNAME pNameT; PRESNAME pNameM; PPRESNAME ppName = NULL; BOOL fTypeID=(Type->discriminant == IS_ID); BOOL fNameID=(Name->discriminant == IS_ID); BOOL fSame=FALSE;
//
// figure out which list to store it in
//
ppType = fTypeID ? &pupd->ResTypeHeadID : &pupd->ResTypeHeadName;
//
// Try to find the Type in the list
//
// We only have new types
while ((pType=*ppType) != NULL) { if (pType->Type->uu.Ordinal == Type->uu.Ordinal) { ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName; break; } if (fTypeID) { if (Type->uu.Ordinal < pType->Type->uu.Ordinal) break; } else { if (memcmp(Type->szStr, pType->Type->szStr, Type->cbsz*sizeof(WCHAR)) < 0) break; } ppType = &(pType->pnext); } //
// Create a new type if needed
//
if (ppName == NULL) { pType = malloc(sizeof(RESTYPE)); if (pType == NULL) return ERROR_NOT_ENOUGH_MEMORY; memset((PVOID)pType,0, sizeof(RESTYPE)); pType->pnext = *ppType; *ppType = pType; pType->Type = Type; ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName; }
//
// Find proper place for name
//
// We only have new resources
while ( (pName = *ppName) != NULL) { if (fNameID) { if (Name->uu.Ordinal == pName->Name->uu.Ordinal) { fSame = TRUE; break; } if (Name->uu.Ordinal < pName->Name->uu.Ordinal) break; } else { if (memcmp(Name->szStr, pName->Name->szStr, Name->cbsz*sizeof(WCHAR)) == 0) { fSame = TRUE; break; } if (memcmp(Name->szStr, pName->Name->szStr, Name->cbsz*sizeof(WCHAR)) < 0) break; } ppName = &(pName->pnext); } //
// check for delete/modify
//
if (fSame) { /* same name, new language */ ppName = &pName->pnextRes;
// ReportDuplicateResource(Type, Name);
if (pName->pnextRes == NULL) { /* only one language currently ? */ // if (Language == pName->LanguageId) { /* REPLACE */
pName->DataSize = cb; if (cb == 0) { return ERROR_BAD_FORMAT; } pName->OffsetToDataEntry = (ULONG)lpData; return NO_ERROR; // }
} else { /* many languages currently */ pNameT = NULL; pNameM = pName; while ( (pName = *ppName) != NULL) { if (Language >= pName->LanguageId) break; pNameT = pName; ppName = &(pName->pnext); } if (lpData == NULL) { /* delete language */ if (Language != pName->LanguageId) return ERROR_INVALID_PARAMETER;
pName->NumberOfLanguages--; free((PVOID)pName->OffsetToDataEntry); if (pNameT == NULL) { /* first? */ pNameT = pName->pnext; if (pNameT == NULL) { /* nothing left? */ if (fNameID) { pType->NameHeadID = NULL; pType->NumberOfNamesID = 0; } else { pType->NameHeadName = NULL; pType->NumberOfNamesName = 0; } } else { /* set new head of list */ pNameT->NumberOfLanguages = pName->NumberOfLanguages-1; if (fNameID) { pType->NameHeadID = pNameT; pType->NumberOfNamesID -= 1; } else { pType->NameHeadName = pNameT; pType->NumberOfNamesName -= 1; } } } else { pNameT->pnext = pName->pnext; }
free(pName); return NO_ERROR; } else { /* add new language */ pNameM->NumberOfLanguages++; } } } else { /* unique name */ if (lpData == NULL) { /* can't delete new name */ return ERROR_INVALID_PARAMETER; } }
//
// add new name/language
//
if (!fSame) { if (fNameID) pType->NumberOfNamesID++; else pType->NumberOfNamesName++; }
pName = (PRESNAME)malloc(sizeof(RESNAME)); if (pName == NULL) return ERROR_NOT_ENOUGH_MEMORY;
memset((PVOID)pName,0, sizeof(RESNAME)); pName->pnext = *ppName; *ppName = pName; pName->Name = Name; pName->Type = Type; pName->NumberOfLanguages = 1; pName->LanguageId = Language; pName->DataSize = cb; pName->OffsetToDataEntry = (ULONG)lpData;
return NO_ERROR; }
/****************************************************************************
** ** Memory Helper functions ** ****************************************************************************/
size_t wcslen( WCHAR const * lpwszIn ) { UINT n = 0; while( *(lpwszIn+n)!=0x0000 ) { n++; } return( n ); }
WCHAR* wcsncpy( WCHAR* lpwszOut, WCHAR const * lpwszIn, size_t n ) { return (WCHAR*)memcpy( lpwszOut, lpwszIn, n*sizeof(WORD) ); }
WCHAR* wcscpy( WCHAR* lpwszOut, WCHAR const * lpwszIn ) { UINT n = wcslen( lpwszIn )+1; return (WCHAR*)memcpy( lpwszOut, lpwszIn, n*sizeof(WORD) ); }
int wcsncmp( WCHAR const * lpszw1, WCHAR const * lpszw2, size_t cb) { return memcmp( lpszw1, lpszw2, cb*sizeof(WORD)); }
//
// Resources are DWORD aligned and may be in any order.
//
#define TABLE_ALIGN 4
#define DATA_ALIGN 4L
PSDATA AddStringOrID( LPCTSTR lp, PUPDATEDATA pupd ) { USHORT cb; PSDATA pstring; PPSDATA ppstring;
if (((ULONG)lp & 0xFFFF0000) == 0) { //
// an ID
//
pstring = malloc(sizeof(SDATA)); if (pstring == NULL) return NULL; memset((PVOID)pstring,0, sizeof(SDATA)); pstring->discriminant = IS_ID;
pstring->uu.Ordinal = (WORD)((ULONG)lp & 0x0000ffff); } else { //
// a string
//
LPWSTR wlp; int i;
cb = strlen(lp)+1; wlp = malloc(cb*sizeof(WCHAR)); memset(wlp, 0, sizeof(wlp)); for(i=0;i<cb;i++) wlp[i]=lp[i];
ppstring = &pupd->StringHead;
while ((pstring = *ppstring) != NULL) { if (!memcmp(pstring->szStr, wlp, cb*sizeof(WCHAR))) break; ppstring = &(pstring->uu.ss.pnext); }
if (!pstring) {
//
// allocate a new one
//
pstring = malloc(sizeof(SDATA)); if (pstring == NULL) return NULL; memset((PVOID)pstring,0, sizeof(SDATA));
pstring->szStr = (WCHAR*)malloc(cb*sizeof(WCHAR)); if (pstring->szStr == NULL) { free(pstring); return NULL; } pstring->discriminant = IS_STRING; pstring->OffsetToString = pupd->cbStringTable;
pstring->cbData = sizeof(pstring->cbsz) + cb*sizeof(WCHAR); pstring->cbsz = (cb - 1); /* don't include zero terminator */ memcpy(pstring->szStr, (char *)wlp, cb*sizeof(WCHAR));
pupd->cbStringTable += pstring->cbData;
pstring->uu.ss.pnext=NULL; *ppstring=pstring; } }
return(pstring); }
// Fake the Rtl function
//LPHVOID
//RtlCopyMemory( LPHVOID lpTgt, LPHVOID lpSrc, DWORD cb)
//{
// hmemcpy(lpTargt, lpSrc, cb);
// return lpTgt;
//}
//v-guanx
//LPHVOID
//RtlAllocateHeap( DWORD dwUnused, int c, DWORD dwcbRequested )
//{
// LPHVOID lphAllocated;
// lphAllocated = malloc(dwcbRequested);
//if (lphAllocated != NULL)
// {
// return memset(lphAllocated, c, dwcbRequested);
// }
// return lphAllocated;
//}
//void
//RtlFreeHeap( DWORD dwUnused, int c, LPHVOID lpData)
//{
// free(lpData);
//}
//DWORD
//RtlProcessHeap( void )
//{
// return 0L;
//}
VOID FreeOne( PRESNAME pRes ) { // RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pRes->OffsetToDataEntry);
// RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pRes);
free((PVOID)pRes->OffsetToDataEntry); free((PVOID)pRes); }
VOID FreeData( PUPDATEDATA pUpd ) { PRESTYPE pType; PRESNAME pRes; PSDATA pstring, pStringTmp;
for (pType=pUpd->ResTypeHeadID ; pUpd->ResTypeHeadID ; pType=pUpd->ResTypeHeadID) { pUpd->ResTypeHeadID = pUpd->ResTypeHeadID->pnext;
for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID ) { pType->NameHeadID = pType->NameHeadID->pnext; FreeOne(pRes); }
for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName ) { pType->NameHeadName = pType->NameHeadName->pnext; FreeOne(pRes); }
// RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pType);
free((PVOID)pType); }
for (pType=pUpd->ResTypeHeadName ; pUpd->ResTypeHeadName ; pType=pUpd->ResTypeHeadName) { pUpd->ResTypeHeadName = pUpd->ResTypeHeadName->pnext;
for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID ) { pType->NameHeadID = pType->NameHeadID->pnext; FreeOne(pRes); }
for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName ) { pType->NameHeadName = pType->NameHeadName->pnext; FreeOne(pRes); }
}
pstring = pUpd->StringHead; while (pstring != NULL) { pStringTmp = pstring->uu.ss.pnext; if (pstring->discriminant == IS_STRING) free((PVOID)pstring->szStr); free((PVOID)pstring); pstring = pStringTmp; } return; }
/*
void DeleteFile( LPTSTR pFileName) { OFSTRUCT of; OpenFile( pFileName, &of, OF_DELETE); }
BOOL MoveFile( char * pTempFileName, LPTSTR pFileName) { //
// BUG: 409
// We will rename if on the same drive. Otherwise copy it
//
BOOL rc = FALSE; if (strncmp( pTempFileName, pFileName, 1 )) { // TRACE2("\t\tCopyFile:\tpTempFileName: %s\tpName: %s\n", pTempFileName, pFileName );
rc = CopyFile( pTempFileName, pFileName, TRUE ); // TRACE1("\t\tCopyFile: %ld\n", rc);
// Delete the temporary file name
DeleteFile( pTempFileName ); } else { // TRACE2("\t\tMoveFile:\tpTempFileName: %s\tpName: %s\n", pTempFileName, pFileName );
if(rename( pTempFileName, pFileName )==0) rc=TRUE; // TRACE1("\t\tMoveFile: %ld", rc);
} return rc; } */ /*
* Utility routines */
ULONG FilePos(int fh) {
return _llseek(fh, 0L, SEEK_CUR); }
ULONG MoveFilePos( INT fh, ULONG pos ) { return _llseek( fh, pos, SEEK_SET ); }
ULONG MyWrite( INT fh, UCHAR*p, ULONG n ) { ULONG n1;
if ((n1 = _hwrite(fh, (LPCSTR)p, n)) != n) { return n1; } else return 0; }
ULONG MyRead(INT fh, UCHAR*p, ULONG n ) { ULONG n1;
if ((n1 = _hread( fh, p, n )) != n) { return n1; } else return 0; }
BOOL MyCopy( INT srcfh, INT dstfh, ULONG nbytes ) { ULONG n; ULONG cb=0L; PUCHAR pb;
pb = (PUCHAR)malloc(BUFSIZE); if (pb == NULL) return 0; memset(pb, 0, BUFSIZE); while (nbytes) { if (nbytes <= BUFSIZE) n = nbytes; else n = BUFSIZE; nbytes -= n;
if (!MyRead( srcfh, pb, n )) { cb += n; MyWrite( dstfh, pb, n ); } else { free(pb); return (BOOL)cb; } } free(pb); return (BOOL)cb; }
VOID SetResdata( PIMAGE_RESOURCE_DATA_ENTRY pResData, ULONG offset, ULONG size) { pResData->OffsetToData = offset; pResData->Size = size; pResData->CodePage = DEFAULT_CODEPAGE; pResData->Reserved = 0L; }
VOID SetRestab( PIMAGE_RESOURCE_DIRECTORY pRestab, LONG time, WORD cNamed, WORD cId) { pRestab->Characteristics = 0L; pRestab->TimeDateStamp = time; pRestab->MajorVersion = MAJOR_RESOURCE_VERSION; pRestab->MinorVersion = MINOR_RESOURCE_VERSION; pRestab->NumberOfNamedEntries = cNamed; pRestab->NumberOfIdEntries = cId; }
PIMAGE_SECTION_HEADER FindSection( PIMAGE_SECTION_HEADER pObjBottom, PIMAGE_SECTION_HEADER pObjTop, LPSTR pName ) {
while (pObjBottom < pObjTop) { if (strcmp((char*)pObjBottom->Name, pName) == 0) return pObjBottom; pObjBottom++; }
return NULL; }
ULONG AssignResourceToSection( PRESNAME *ppRes, /* resource to assign */ ULONG ExtraSectionOffset, /* offset between .rsrc and .rsrc1 */ ULONG Offset, /* next available offset in section */ LONG Size, /* Maximum size of .rsrc */ PLONG pSizeRsrc1 ) { ULONG cb;
/* Assign this res to this section */ cb = ROUNDUP((*ppRes)->DataSize, CBLONG); if (Offset < ExtraSectionOffset && Offset + cb > (ULONG)Size) { *pSizeRsrc1 = Offset; Offset = ExtraSectionOffset; //DPrintf((DebugBuf, "<<< Secondary resource section @%#08lx >>>\n", Offset));
} (*ppRes)->OffsetToData = Offset; *ppRes = (*ppRes)->pnext; //DPrintf((DebugBuf, " --> %#08lx bytes at %#08lx\n", cb, Offset));
return Offset + cb; }
//
// adjust debug directory table
//
/* */ LONG PatchDebug(int inpfh, int outfh, PIMAGE_SECTION_HEADER pDebugOld, PIMAGE_SECTION_HEADER pDebugNew, PIMAGE_SECTION_HEADER pDebugDirOld, PIMAGE_SECTION_HEADER pDebugDirNew, PIMAGE_NT_HEADERS pOld, PIMAGE_NT_HEADERS 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) return NO_ERROR;
pDbgSave = pDbg = (PIMAGE_DEBUG_DIRECTORY)malloc(pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size); if (pDbg == NULL) return ERROR_NOT_ENOUGH_MEMORY; memset(pDbgSave, 0, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
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; MoveFilePos(inpfh, pDebugDirOld->PointerToRawData+ib); pDbgLast = pDbg + (pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size)/sizeof(IMAGE_DEBUG_DIRECTORY); MyRead(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; *pPointerToRawData = ibNew; /* return old */ 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));
} }
MoveFilePos(outfh, pDebugDirNew->PointerToRawData+ib); MyWrite(outfh, (PUCHAR)pDbgSave, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size); free(pDbgSave);
return NO_ERROR; }
//
// This routine patches various RVAs in the file to compensate
// for extra section table entries.
//
LONG PatchRVAs(int inpfh, int outfh, PIMAGE_SECTION_HEADER po32, ULONG pagedelta, PIMAGE_NT_HEADERS 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 { MoveFilePos(inpfh, offset - hdrdelta); MyRead(inpfh, (PUCHAR) &Exp, sizeof(Exp)); Exp.Name += hdrdelta; Exp.AddressOfFunctions += (ULONG)hdrdelta; Exp.AddressOfNames += (ULONG)hdrdelta; Exp.AddressOfNameOrdinals += (ULONG)hdrdelta; MoveFilePos(outfh, offset); MyWrite(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++) { MoveFilePos(inpfh, offset + cmod * sizeof(Imp) - hdrdelta); MyRead(inpfh, (PUCHAR) &Imp, sizeof(Imp)); if (Imp.FirstThunk == 0) { break; } Imp.Name += hdrdelta; MoveFilePos(outfh, offset + cmod * sizeof(Imp)); MyWrite(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));
MoveFilePos(inpfh, offiat - pagedelta); MoveFilePos(outfh, offiat); for (;;) { MyRead(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++; } MyWrite(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;
}
/***************************** Main Worker Function ***************************
* LONG PEWriteResFile * * This function writes the resources to the named executable file. * It assumes that resources have no fixups (even any existing resources * that it removes from the executable.) It places all the resources into * one or two sections. The resources are packed tightly into the section, * being aligned on dword boundaries. Each section is padded to a file * sector size (no invalid or zero-filled pages), and each * resource is padded to the afore-mentioned dword boundary. This * function uses the capabilities of the NT system to enable it to easily * manipulate the data: to wit, it assumes that the system can allocate * any sized piece of data, in particular the section and resource tables. * If it did not, it might have to deal with temporary files (the system * may have to grow the swap file, but that's what the system is for.) * * Return values are: * TRUE - file was written succesfully. * FALSE - file was not written succesfully. * * Effects: * * History: * Thur Apr 27, 1989 by Floyd Rogers [floydr] * Created. * 12/8/89 sanfords Added multiple section support. * 12/11/90 floydr Modified for new (NT) Linear Exe format * 1/18/92 vich Modified for new (NT) Portable Exe format * 5/8/92 bryant General cleanup so resonexe can work with unicode * 6/9/92 floydr incorporate bryan's changes * 6/15/92 floydr debug section separate from debug table * 9/25/92 floydr account for .rsrc not being last-1 * 9/28/92 floydr account for adding lots of resources by adding * a second .rsrc section. * 7/27/93 alessanm ported to win16 for Chicago \****************************************************************************/
/* */
/* This is a BIG function - disable warning about 'can't optimize' */ /* MHotchin Apr 1994 */ #pragma warning (disable : 4703)
LONG PEWriteResFile( INT inpfh, INT outfh, ULONG cbOldexe, PUPDATEDATA pUpdate ) { IMAGE_NT_HEADERS Old; /* original header */ IMAGE_NT_HEADERS New; /* working header */ PRESNAME pRes; PRESNAME pResSave; PRESTYPE pType; ULONG clock = GetTickCount(); /* current time */ 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 ibSave; //ULONG adjust=0;
LONG adjust=0; PIMAGE_SECTION_HEADER pObjtblOld, pObjtblNew, pObjDebug, pObjResourceOld, pObjResourceNew, pObjResourceOldX, pObjDebugDirOld, pObjDebugDirNew, pObjNew, pObjOld, pObjLast; BYTE *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 cbMustPadX = 0; ULONG ibMaxDbgOffsetOld;
MoveFilePos(inpfh, cbOldexe); MyRead(inpfh, (PUCHAR)&Old, sizeof(IMAGE_NT_HEADERS)); ibObjTab = FilePos(inpfh); ibObjTabEnd = ibObjTab + Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (*(PUSHORT)&Old.Signature != IMAGE_NT_SIGNATURE) return ERROR_INVALID_EXE_SIGNATURE;
if ((Old.FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) { return ERROR_EXE_MARKED_INVALID; } //TRACE(("\n"));
/* New header is like old one. */ memcpy(&New, &Old, sizeof(IMAGE_NT_HEADERS));
/* Read section table */ pObjtblOld = (PIMAGE_SECTION_HEADER)malloc(Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); if (pObjtblOld == NULL) { cb = ERROR_NOT_ENOUGH_MEMORY; goto AbortExit; } memset((PVOID)pObjtblOld, 0, Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER)); /*
TRACE2("old section table: %#08lx bytes at %#08lx(mem)\n", Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER), DPrintfpObjtblOld); */ MyRead(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++; cbName += (pRes->Name->cbsz + 1) * sizeof(WCHAR); cNameStr++; if (pPreviousName == NULL || memcmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz*sizeof(WCHAR)) != 0) 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++; cbName += (pRes->Name->cbsz + 1) * sizeof(WORD); cNameStr++; if (pPreviousName == NULL || memcmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz*sizeof(WCHAR)) != 0) 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; } 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"); if (pObjResourceOld == NULL) { cb = 0x7fffffff; /* can fill forever */ } else if (pObjResourceOld + 1 == pObjResourceOldX) { nObjResource = 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 { nObjResource = pObjResourceOld - pObjtblOld; //DPrintf((DebugBuf,"Old Resource section #%lu\n", nObjResource+1));
cb = (pObjResourceOld+1)->VirtualAddress - pObjResourceOld->VirtualAddress; 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!!! */ pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
if (pObjResourceOld != NULL && cbResource > (ULONG)cb) { if (pObjResourceOld != NULL && 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 = pObjOld - pObjtblOld; adjust = pObjOld->VirtualAddress - pObjResourceOld->VirtualAddress; } else { /* have already merged .rsrc & .rsrc1, if possible */ /*
* We are fine we have to calculate the place in which the old * .rsrc1 was. * Later we have to check if the .rsrc1 that we had was big enough or * if we have to move the .reloc section. * We will keep the .rsrc1 section in the position it is. * There is no need to push it forward to the .reloc section */ nObjResourceX = pObjResourceOldX - pObjtblOld; adjust = pObjResourceOldX->VirtualAddress - pObjResourceOld ->VirtualAddress; /*
adjust = pObjOld->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 = pObjOld - pObjtblOld; else if (pObjDebug != NULL) nObjResource = pObjDebug - pObjtblOld; else nObjResource = New.FileHeader.NumberOfSections; New.FileHeader.NumberOfSections++; } //DPrintf((DebugBuf, "resources assigned to section #%lu\n", nObjResource+1));
if (nObjResourceX != -1) { /* we have already a .rsrc1 section */ if (pObjResourceOldX != NULL) { nObjResourceX = pObjResourceOldX - pObjtblOld; New.FileHeader.NumberOfSections--; } else if (pObjOld != NULL) nObjResourceX = pObjOld - pObjtblOld; else if (pObjDebug != NULL) nObjResourceX = 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) // Check if we are reducing the number of section because removing the .rsrc1
New.FileHeader.NumberOfSections--;
/*
* 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(IMAGE_NT_HEADERS) + cbOldexe ); if (adjust > 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; }
/* Allocate storage for new section table */ cb = New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); pObjtblNew = (PIMAGE_SECTION_HEADER)malloc((short)cb); if (pObjtblNew == NULL) { cb = ERROR_NOT_ENOUGH_MEMORY; goto AbortExit; } memset((PVOID)pObjtblNew,0, 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) { 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); //v-guanx RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
memset(pObjNew,0, 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_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; pObjNew->SizeOfRawData = cb; pObjNew->Misc.VirtualSize = ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment); } else { *pObjNew = *pObjOld; /* copy obj table entry */ pObjNew->SizeOfRawData = cb; pObjNew->Misc.VirtualSize = ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment); if (pObjNew->SizeOfRawData == pObjOld->SizeOfRawData) { adjust = 0; } else if (pObjNew->SizeOfRawData > pObjOld->SizeOfRawData) { adjust += ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment) - ((pObjOld+1)->VirtualAddress-pObjOld->VirtualAddress); } else { /* is smaller, but pad so will be valid */ adjust = 0; pObjNew->SizeOfRawData = pObjResourceOld->SizeOfRawData; 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));
//v-guanx RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
memset(pObjNew,0, 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_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) + pObjResourceNew->VirtualAddress - pObjNew->VirtualAddress; // TRACE2("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_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; // TRACE1(".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; // subtract old size
//adjust -= pObjOld->VirtualAddress - pObjNew->VirtualAddress;
// TRACE3("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; // TRACE3("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) { /*
* There is no need for us to do anything. We have just to copy the * old section. There is no adjust we need to do */ //DPrintf((DebugBuf, "copying section table entry %i@%#08lx\n",
// pObjOld - pObjtblOld + 1, pObjNew));
*pObjNew++ = *pObjOld; /* copy obj table entry */ // TRACE3("Before .reloc, Just copy.\t\t %s\tVA: %lu\t adj: %ld\n",
// (pObjNew-1)->Name,
// (pObjNew-1)->VirtualAddress,
// adjust);
} 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; // TRACE3("After .reloc, might get moved.\t\t%s\tVA: %lu\t adj: %ld\n",
// (pObjNew-1)->Name,
// (pObjNew-1)->VirtualAddress,
// adjust);
} }
// TRACE1("Number of section: %u\n", New.FileHeader.NumberOfSections);
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)malloc(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. */
//v-guanx RtlZeroMemory((PVOID)pResTab, cbRestab);
memset((PVOID)pResTab,0, cbRestab); //DPrintf((DebugBuf, "resource directory tables: %#08lx bytes at %#08lx(mem)\n", cbRestab, pResTab));
p = (PUCHAR)pResTab; pResTab->Characteristics = 0L; pResTab->TimeDateStamp = clock; pResTab->MajorVersion = MAJOR_RESOURCE_VERSION; pResTab->MinorVersion = MINOR_RESOURCE_VERSION; pResTab->NumberOfNamedEntries = (USHORT)cTypeStr; pResTab->NumberOfIdEntries = (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)((((BYTE *)pResStr) - p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirT->OffsetToData = (ULONG)((((BYTE *)pResDirN) - p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirT++;
*pResStr = pType->Type->cbsz; memcpy((WCHAR*)(pResStr+1), pType->Type->szStr, pType->Type->cbsz*sizeof(WCHAR)); 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 || memcmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz*sizeof(WCHAR)) != 0) { // Setup a new name directory
pResDirN->Name = (ULONG)((((BYTE *)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirN->OffsetToData = (ULONG)((((BYTE *)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
// Copy the alpha name to a string entry
*pResStr = pRes->Name->cbsz; memcpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz*sizeof(WCHAR)); 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)(((BYTE *)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)((((BYTE *)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)(((BYTE *)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)((((BYTE *)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 || memcmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz*sizeof(WCHAR)) != 0) { // Setup a new name directory
pResDirN->Name = (ULONG)((((BYTE *)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING); pResDirN->OffsetToData = (ULONG)((((BYTE *)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY); pResDirN++;
// Copy the alpha name to a string entry.
*pResStr = pRes->Name->cbsz; memcpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz*sizeof(WCHAR)); 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)(((BYTE *)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)((((BYTE *)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)(((BYTE *)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(IMAGE_NT_HEADERS)));
MoveFilePos(inpfh, 0L); MyCopy(inpfh, outfh, cbOldexe + sizeof(IMAGE_NT_HEADERS));
/*
* 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));
MoveFilePos(outfh, ibObjTabEnd + New.OptionalHeader.SizeOfHeaders - Old.OptionalHeader.SizeOfHeaders); MoveFilePos(inpfh, ibObjTabEnd); MyCopy(inpfh, outfh, Old.OptionalHeader.SizeOfHeaders - ibObjTabEnd);
/*
* 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) { MyWrite(outfh, (PUCHAR)pchZero, cbPadMax); cb -= cbPadMax; } MyWrite(outfh, (PUCHAR)pchZero, cb);
cb = ROUNDUP(Old.OptionalHeader.SizeOfHeaders, Old.OptionalHeader.FileAlignment); MoveFilePos(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));
MyWrite(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) { MyWrite(outfh, (PUCHAR)pchPad, cbPadMax); cbMustPad -= cbPadMax; } cb = FilePos(outfh); } if (nObjResourceX == -1) { MoveFilePos(outfh, ibSave); //DPrintf((DebugBuf,
// "re-writing resource directory: %#08x bytes @%#08lx\n",
// cbRestab, ibSave));
MyWrite(outfh, (PUCHAR)pResTab, cbRestab); MoveFilePos(outfh, cb); cb = FilePos(inpfh); MoveFilePos(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; //DPrintf((DebugBuf, "wrote resource data: %#08lx bytes @%#08lx\n",
// pObjNew->SizeOfRawData, pObjNew->PointerToRawData));
MoveFilePos(outfh, ibSave); //DPrintf((DebugBuf,
// "re-writing resource directory: %#08x bytes @%#08lx\n",
// cbRestab, ibSave));
MyWrite(outfh, (PUCHAR)pResTab, cbRestab); MoveFilePos(outfh, cb); New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData; pObjNew++; goto next_section; } else { if (pObjNew < pObjResourceNew && pObjOld->PointerToRawData != 0 && pObjOld->PointerToRawData != FilePos(outfh)) { MoveFilePos(outfh, pObjOld->PointerToRawData); } next_section: if ((Old.OptionalHeader.BaseOfCode == 0x400) && (Old.FileHeader.Machine == IMAGE_FILE_MACHINE_R3000 || Old.FileHeader.Machine == IMAGE_FILE_MACHINE_R4000 ) && (pObjOld->PointerToRawData != 0) && (pObjOld->VirtualAddress != New.OptionalHeader.BaseOfCode) && ((pObjOld->Characteristics&IMAGE_SCN_CNT_CODE) != 0) ) { cb = FilePos(outfh) & 0xFFF; if (cb != 0) { cb = (cb ^ 0xFFF) + 1; //DPrintf((DebugBuf, "padding driver code section %#08lx bytes @%#08lx\n", cb, FilePos(outfh)));
while (cb >= cbPadMax) { MyWrite(outfh, (PUCHAR)pchZero, cbPadMax); cb -= cbPadMax; } MyWrite(outfh, (PUCHAR)pchZero, cb); } }
//DPrintf((DebugBuf, "copying section %i @%#08lx\n",
// pObjNew-pObjtblNew+1, FilePos(outfh)));
if (pObjOld->PointerToRawData != 0) { pObjNew->PointerToRawData = FilePos(outfh); MoveFilePos(inpfh, pObjOld->PointerToRawData); MyCopy(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));
MoveFilePos(outfh, ibObjTab); MyWrite(outfh, (PUCHAR)pObjtblNew, New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
/*
* Write updated PE header */ //DPrintf((DebugBuf, "writing updated file header: %#08x bytes @%#08lx\n",
// sizeof(IMAGE_NT_HEADERS),
// cbOldexe));
MoveFilePos(outfh, (long)cbOldexe); MyWrite(outfh, (PUCHAR)&New, sizeof(IMAGE_NT_HEADERS));
/* Seek to end of output file and issue truncating write */ adjust = _llseek(outfh, 0L, SEEK_END); MyWrite(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, (ULONG*)&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) { ibSave = _llseek(inpfh, 0L, SEEK_END); /* copy debug data */ _llseek(outfh, 0L, SEEK_END); /* to EOF */ MoveFilePos(inpfh, adjust); /* returned by PatchDebug */ //DPrintf((DebugBuf, "Copying NOTMAPPED Debug Information, %#08lx bytes\n", ibSave-adjust));
MyCopy(inpfh, outfh, ibSave-adjust); }
_lclose(outfh); //DPrintf((DebugBuf, "files closed\n"));
/* free up allocated memory */
//DPrintf((DebugBuf, "freeing old section table: %#08lx(mem)\n", pObjtblOld));
free(pObjtblOld); //DPrintf((DebugBuf, "freeing resource directory: %#08lx(mem)\n", pResTab));
free(pResTab);
AbortExit: //DPrintf((DebugBuf, "freeing new section table: %#08lx(mem)\n", pObjtblNew));
free(pObjtblNew); return cb; }
/***************************************************************************
* WriteResSection * * This routine writes out the resources asked for into the current section. * It pads resources to dword (4-byte) boundaries. **************************************************************************/
PRESNAME WriteResSection( PUPDATEDATA pUpdate, INT outfh, ULONG align, ULONG cbLeft, PRESNAME pResSave ) { ULONG cbB=0; /* bytes in current section */ ULONG cbT; /* bytes in current section */ ULONG size; PRESNAME pRes; PRESTYPE pType; BOOL fName; PVOID lpData;
/* Output contents associated with each resource */ pType = pUpdate->ResTypeHeadName; while (pType) { pRes = pType->NameHeadName; fName = TRUE; loop1: for ( ; pRes ; pRes = pRes->pnext) { if (pResSave != NULL && pRes != pResSave) continue; pResSave = NULL; #if DBG
if (pType->Type->discriminant == IS_STRING) { //DPrintf((DebugBuf, " "));
//DPrintfu((pType->Type->szStr));
//DPrintfn((DebugBuf, "."));
} else { //DPrintf(( DebugBuf, " %d.", pType->Type->uu.Ordinal ));
} if (pRes->Name->discriminant == IS_STRING) { //DPrintfu((pRes->Name->szStr));
} else { //DPrintfn(( DebugBuf, "%d", pRes->Name->uu.Ordinal ));
} #endif
lpData = (PVOID)pRes->OffsetToDataEntry; //DPrintfn((DebugBuf, "\n"));
/* if there is room in the current section, write it there */ size = pRes->DataSize; if (cbLeft != 0 && cbLeft >= size) { /* resource fits? */ //DPrintf((DebugBuf,
// "writing resource: %#04lx bytes @%#08lx\n",
// size, FilePos(outfh)));
MyWrite(outfh, (PUCHAR)lpData, size); /* pad resource */ cbT = REMAINDER(size, CBLONG); #ifdef DBG
if (cbT != 0) //DPrintf((DebugBuf,
// "writing small pad: %#04lx bytes @%#08lx\n",
// cbT, FilePos(outfh)));
#endif
MyWrite(outfh, (PUCHAR)pchPad, cbT); /* dword */ cbB += size + cbT; cbLeft -= size + cbT; /* less left */ continue; /* next resource */ } else { /* will fill up section */ //DPrintf((DebugBuf, "Done with .rsrc section\n"));
goto write_pad; } } if (fName) { fName = FALSE; pRes = pType->NameHeadID; goto loop1; } pType = pType->pnext; }
pType = pUpdate->ResTypeHeadID; while (pType) { pRes = pType->NameHeadName; fName = TRUE; loop2: for ( ; pRes ; pRes = pRes->pnext) { if (pResSave != NULL && pRes != pResSave) continue; pResSave = NULL; #if DBG
if (pType->Type->discriminant == IS_STRING) { //DPrintf((DebugBuf, " "));
//DPrintfu((pType->Type->szStr));
//DPrintfn((DebugBuf, "."));
} else { //DPrintf(( DebugBuf, " %d.", pType->Type->uu.Ordinal ));
} if (pRes->Name->discriminant == IS_STRING) { //DPrintfu((pRes->Name->szStr));
} else { //DPrintfn(( DebugBuf, "%d", pRes->Name->uu.Ordinal ));
} #endif
lpData = (PVOID)pRes->OffsetToDataEntry; //DPrintfn((DebugBuf, "\n"));
/* if there is room in the current section, write it there */ size = pRes->DataSize; if (cbLeft != 0 && cbLeft >= size) { /* resource fits? */ //DPrintf((DebugBuf,
// "writing resource: %#04lx bytes @%#08lx\n",
// size, FilePos(outfh)));
MyWrite(outfh, (PUCHAR)lpData, size); /* pad resource */ cbT = REMAINDER(size, CBLONG); #ifdef DBG
if (cbT != 0) //DPrintf((DebugBuf,
// "writing small pad: %#04lx bytes @%#08lx\n",
// cbT, FilePos(outfh)));
#endif
MyWrite(outfh, (PUCHAR)pchPad, cbT); /* dword */ cbB += size + cbT; cbLeft -= size + cbT; /* less left */ continue; /* next resource */ } else { /* will fill up section */ //DPrintf((DebugBuf, "Done with .rsrc section\n"));
goto write_pad; } } if (fName) { fName = FALSE; pRes = pType->NameHeadID; goto loop2; } pType = pType->pnext; } pRes = NULL;
write_pad: /* pad to alignment boundary */ cbB = FilePos(outfh); cbT = ROUNDUP(cbB, align); cbLeft = cbT - cbB; //DPrintf((DebugBuf, "writing file sector pad: %#04lx bytes @%#08lx\n",
// cbLeft, FilePos(outfh)));
if (cbLeft != 0) { while (cbLeft >= cbPadMax) { MyWrite(outfh, (PUCHAR)pchPad, cbPadMax); cbLeft -= cbPadMax; } MyWrite(outfh, (PUCHAR)pchPad, cbLeft); } return pRes; }
/*---------------------------------------------------------------------------*/ /* */ /* WriteResFile() - */ /* */ /*---------------------------------------------------------------------------*/
LONG WriteResFile( HANDLE hUpdate, char *pDstname) { INT inpfh; INT outfh; ULONG onewexe; IMAGE_DOS_HEADER oldexe; PUPDATEDATA pUpdate; LONG rc; LPTSTR pFilename; static char pSrcname[_MAX_PATH]; OFSTRUCT OpenBuf;
pUpdate = (PUPDATEDATA)GlobalLock(hUpdate); pFilename = (LPTSTR)GlobalLock(pUpdate->hFileName); memcpy(pSrcname, pFilename, strlen(pFilename));
/* open the original exe file */ //inpfh = (INT)CreateFileW(pFilename, GENERIC_READ,
// 0 /*exclusive access*/, NULL /* security attr */,
// OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
inpfh = (int)OpenFile( pSrcname, &OpenBuf, OF_READWRITE | OF_SHARE_EXCLUSIVE); GlobalUnlock(pUpdate->hFileName); if (inpfh == -1) { GlobalUnlock(hUpdate); return ERROR_OPEN_FAILED; }
/* read the old format EXE header */ rc = _lread(inpfh, (char*)&oldexe, sizeof(oldexe)); if (rc != sizeof(oldexe)) { _lclose(inpfh); GlobalUnlock(hUpdate); return ERROR_READ_FAULT; }
/* make sure its really an EXE file */ if (oldexe.e_magic != IMAGE_DOS_SIGNATURE) { _lclose(inpfh); GlobalUnlock(hUpdate); return ERROR_INVALID_EXE_SIGNATURE; }
/* make sure theres a new EXE header floating around somewhere */ if (!(onewexe = oldexe.e_lfanew)) { _lclose(inpfh); GlobalUnlock(hUpdate); return ERROR_BAD_EXE_FORMAT; } //outfh = (INT)CreateFileW(pDstname, GENERIC_READ|GENERIC_WRITE,
// 0 /*exclusive access*/, NULL /* security attr */,
// CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
outfh = (int)OpenFile( pDstname, &OpenBuf, OF_SHARE_EXCLUSIVE | OF_READWRITE ); if (outfh != -1) { rc = PEWriteResFile(inpfh, outfh, onewexe, pUpdate); _lclose(outfh); } _lclose(inpfh); GlobalUnlock(hUpdate); return rc; }
//v-guanx rewrite this function from C++ to Windows API
/*
static UINT CopyFile( char * pszfilein, char * pszfileout ) { CFile filein; CFile fileout; if (!filein.Open(pszfilein, CFile::modeRead | CFile::typeBinary)) return ERROR_FILE_OPEN; if (!fileout.Open(pszfileout, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary)) return ERROR_FILE_CREATE; LONG lLeft = filein.GetLength(); WORD wRead = 0; DWORD dwOffset = 0; BYTE far * pBuf = (BYTE far *) new BYTE[32739]; if(!pBuf) return ERROR_NEW_FAILED; while(lLeft>0){ wRead =(WORD) (32738ul < lLeft ? 32738: lLeft); if (wRead!= filein.Read( pBuf, wRead)) return ERROR_FILE_READ; fileout.Write( pBuf, wRead ); lLeft -= wRead; dwOffset += wRead; } delete []pBuf; } */
BOOL EnumTypesFunc( HANDLE hModule, LPTSTR lpType, LONG lParam ) {
EnumResourceNames(hModule, lpType, (ENUMRESNAMEPROC)EnumNamesFunc, lParam);
return TRUE; }
BOOL EnumNamesFunc( HANDLE hModule, LPTSTR lpType, LPTSTR lpName, LONG lParam ) { EnumResourceLanguages(hModule, lpType, lpName, (ENUMRESLANGPROC)EnumLangsFunc, lParam); return TRUE; }
BOOL EnumLangsFunc( HANDLE hModule, LPTSTR lpType, LPTSTR lpName, WORD language, LONG lParam ) { HANDLE hResInfo; LONG fError; PSDATA Type; PSDATA Name; ULONG cb; PVOID lpData; HANDLE hResource; PVOID lpResource;
hResInfo = FindResourceEx(hModule, lpType, lpName, language); if (hResInfo == NULL) { return FALSE; } else { Type = AddStringOrID(lpType, (PUPDATEDATA)lParam); if (Type == NULL) { ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY; return FALSE; } Name = AddStringOrID(lpName, (PUPDATEDATA)lParam); if (Name == NULL) { ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY; return FALSE; }
cb = SizeofResource(hModule, hResInfo); if (cb == 0) { return FALSE; } lpData = malloc(cb); if (lpData == NULL) { return FALSE; } memset(lpData,0, cb);
hResource = LoadResource(hModule, hResInfo); if (hResource == NULL) { free(lpData); return FALSE; }
lpResource = (PVOID)LockResource(hResource); if (lpResource == NULL) { free(lpData); return FALSE; }
memcpy(lpData, lpResource, cb); (VOID)UnlockResource(hResource); (VOID)FreeResource(hResource);
fError = AddResource(Type, Name, language, (PUPDATEDATA)lParam, lpData, cb); if (fError != NO_ERROR) { ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY; return FALSE; } }
return TRUE; }
|