/*++ Copyright (c) 1992 Microsoft Corporation Module Name: rebase.c Abstract: Source file for the REBASE utility that takes a group of image files and rebases them so they are packed as closely together in the virtual address space as possible. Author: Mark Lucovsky (markl) 30-Apr-1993 Revision History: --*/ #include #define ROUNDUP(x, y) ((x + (y-1)) & ~(y-1)) VOID RemoveRelocations( PCHAR ImageName ); #define REBASE_ERR 99 #define REBASE_OK 0 ULONG ReturnCode = REBASE_OK; #define ROUND_UP( Size, Amount ) (((ULONG)(Size) + ((Amount) - 1)) & ~((Amount) - 1)) BOOL fVerbose; BOOL fQuiet; BOOL fGoingDown; BOOL fSumOnly; BOOL fRebaseSysfileOk; BOOL fShowAllBases; BOOL fCoffBaseIncExt; FILE *CoffBaseDotTxt; FILE *BaseAddrFile; FILE *RebaseLog; ULONG SplitFlags; BOOL fRemoveRelocs; BOOL fUpdateSymbolsOnly; LPSTR BaseAddrFileName; BOOL ProcessGroupList( LPSTR ImagesRoot, LPSTR GroupListFName, BOOL fReBase, BOOL fOverlay ); BOOL FindInIgnoreList( LPSTR chName ); ULONG64 FindInBaseAddrFile( LPSTR Name, PULONG pulSize ); VOID ReBaseFile( LPSTR pstrName, BOOL fReBase ); VOID ParseSwitch( CHAR chSwitch, int *pArgc, char **pArgv[] ); VOID ShowUsage( VOID ); typedef struct _GROUPNODE { struct _GROUPNODE *pgnNext; PCHAR chName; } GROUPNODE, *PGROUPNODE; PGROUPNODE pgnIgnoreListHdr, pgnIgnoreListEnd; typedef BOOL (__stdcall *REBASEIMAGE64) ( IN PSTR CurrentImageName, IN PSTR SymbolPath, IN BOOL fReBase, // TRUE if actually rebasing, false if only summing IN BOOL fRebaseSysfileOk, // TRUE is system images s/b rebased IN BOOL fGoingDown, // TRUE if the image s/b rebased below the given base IN ULONG CheckImageSize, // Max size allowed (0 if don't care) OUT ULONG *OldImageSize, // Returned from the header OUT ULONG64 *OldImageBase, // Returned from the header OUT ULONG *NewImageSize, // Image size rounded to next separation boundary IN OUT ULONG64 *NewImageBase, // (in) Desired new address. // (out) Next address (actual if going down) IN ULONG TimeStamp // new timestamp for image, if non-zero ); REBASEIMAGE64 pReBaseImage64; UCHAR ImagesRoot[ MAX_PATH+1 ]; PCHAR SymbolPath; UCHAR DebugFilePath[ MAX_PATH+1 ]; ULONG64 OriginalImageBase; ULONG OriginalImageSize; ULONG64 NewImageBase; ULONG NewImageSize; ULONG64 InitialBase = 0; ULONG64 MinBase = (~((ULONG64)0)); ULONG64 TotalSize; ULONG SizeAdjustment; int __cdecl main( int argc, char *argv[], char *envp[] ) { char chChar, *pchChar; envp; _tzset(); pgnIgnoreListHdr = (PGROUPNODE) malloc( sizeof ( GROUPNODE ) ); pgnIgnoreListHdr->chName = NULL; pgnIgnoreListHdr->pgnNext = NULL; pgnIgnoreListEnd = pgnIgnoreListHdr; pReBaseImage64 = (REBASEIMAGE64) GetProcAddress(GetModuleHandle("imagehlp.dll"), "ReBaseImage64"); if (!pReBaseImage64) { puts("REBASE: Warning\n" "REBASE: Warning - unable to correctly rebase 64-bit images - update your imagehlp.dll\n" "REBASE: Warning"); pReBaseImage64 = (REBASEIMAGE64) GetProcAddress(GetModuleHandle("imagehlp.dll"), "ReBaseImage"); } fVerbose = FALSE; fQuiet = FALSE; fGoingDown = FALSE; fSumOnly = FALSE; fRebaseSysfileOk = FALSE; fShowAllBases = FALSE; ImagesRoot[ 0 ] = '\0'; if (argc <= 1) { ShowUsage(); } while (--argc) { pchChar = *++argv; if (*pchChar == '/' || *pchChar == '-') { while (chChar = *++pchChar) { ParseSwitch( chChar, &argc, &argv ); } } else { if (*pchChar == '@') { // Inline response file with a list of files to rebase. FILE *hFiles =fopen(pchChar+1, "rt"); int ScanRet; CHAR pchFileName[_MAX_PATH]; if (hFiles == NULL) { fprintf( stderr, "REBASE: fopen %s failed %d\n", pchChar+1, errno ); ExitProcess( REBASE_ERR ); } ScanRet = fscanf( hFiles, "%s", pchFileName ); while (ScanRet && ScanRet != EOF) { if ( !FindInIgnoreList( pchFileName ) ) { ReBaseFile( pchFileName, TRUE ); } ScanRet = fscanf( hFiles, "%s", pchFileName ); } fclose(hFiles); } else { if ( !FindInIgnoreList( pchChar ) ) { ReBaseFile( pchChar, TRUE ); } } } } if ( !fQuiet ) { if ( BaseAddrFile ) { InitialBase = MinBase; } if ( fGoingDown ) { TotalSize = InitialBase - NewImageBase; } else { TotalSize = NewImageBase - InitialBase; } fprintf( stdout, "\n" ); fprintf( stdout, "REBASE: Total Size of mapping 0x%016I64x\n", TotalSize ); fprintf( stdout, "REBASE: Range 0x%016I64x -0x%016I64x\n", min(NewImageBase, InitialBase), max(NewImageBase, InitialBase)); if (RebaseLog) { fprintf( RebaseLog, "\nTotal Size of mapping 0x%016I64x\n", TotalSize ); fprintf( RebaseLog, "Range 0x%016I64x -0x%016I64x\n\n", min(NewImageBase, InitialBase), max(NewImageBase, InitialBase)); } } if (RebaseLog) { fclose(RebaseLog); } if (BaseAddrFile){ fclose(BaseAddrFile); } if (CoffBaseDotTxt){ fclose(CoffBaseDotTxt); } return ReturnCode; } VOID ShowUsage( VOID ) { fputs( "usage: REBASE [switches]\n" " [-R image-root [-G filename] [-O filename] [-N filename]]\n" " image-names... \n" "\n" " One of -b and -i switches are mandatory.\n" "\n" " [-a] Does nothing\n" " [-b InitialBase] specify initial base address\n" " [-c coffbase_filename] generate coffbase.txt\n" " -C includes filename extensions, -c does not\n" " [-d] top down rebase\n" " [-e SizeAdjustment] specify extra size to allow for image growth\n" " [-f] Strip relocs after rebasing the image\n" " [-i coffbase_filename] get base addresses from coffbase_filename\n" " [-l logFilePath] write image bases to log file.\n" " [-p] Does nothing\n" " [-q] minimal output\n" " [-s] just sum image range\n" " [-u symbol_dir] Update debug info in .DBG along this path\n" " [-v] verbose output\n" " [-x symbol_dir] Same as -u\n" " [-z] allow system file rebasing\n" " [-?] display this message\n" "\n" " [-R image_root] set image root for use by -G, -O, -N\n" " [-G filename] group images together in address space\n" " [-O filename] overlay images in address space\n" " [-N filename] leave images at their origional address\n" " -G, -O, -N, may occur multiple times. File \"filename\"\n" " contains a list of files (relative to \"image-root\")\n" , stderr ); exit( REBASE_ERR ); } VOID ParseSwitch( CHAR chSwitch, int *pArgc, char **pArgv[] ) { switch (toupper( chSwitch )) { case '?': ShowUsage(); break; case 'A': break; case 'B': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; if (sscanf(**pArgv, "%I64x", &InitialBase) == 1) { NewImageBase = InitialBase; } break; case 'C': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; fCoffBaseIncExt = (chSwitch == 'C'); CoffBaseDotTxt = fopen( *(*pArgv), "at" ); if ( !CoffBaseDotTxt ) { fprintf( stderr, "REBASE: fopen %s failed %d\n", *(*pArgv), errno ); ExitProcess( REBASE_ERR ); } break; case 'D': fGoingDown = TRUE; break; case 'E': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; if (sscanf(**pArgv, "%x", &SizeAdjustment) != 1) { ShowUsage(); } break; case 'F': fRemoveRelocs = TRUE; break; case 'G': case 'O': case 'N': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; if (!ImagesRoot[0]) { fprintf( stderr, "REBASE: -R must preceed -%c\n", chSwitch ); exit( REBASE_ERR ); } ProcessGroupList( (PCHAR) ImagesRoot, *(*pArgv), toupper(chSwitch) != 'N', toupper(chSwitch) == 'O'); break; case 'I': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; BaseAddrFileName = *(*pArgv); BaseAddrFile = fopen( *(*pArgv), "rt" ); if ( !BaseAddrFile ) { fprintf( stderr, "REBASE: fopen %s failed %d\n", *(*pArgv), errno ); ExitProcess( REBASE_ERR ); } break; case 'L': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; RebaseLog = fopen( *(*pArgv), "at" ); if ( !RebaseLog ) { fprintf( stderr, "REBASE: fopen %s failed %d\n", *(*pArgv), errno ); ExitProcess( REBASE_ERR ); } break; case 'P': break; case 'Q': fQuiet = TRUE; break; case 'R': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; strcpy( (PCHAR) ImagesRoot, *(*pArgv) ); break; case 'S': fprintf(stdout,"\n"); fSumOnly = TRUE; break; case 'U': case 'X': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; fUpdateSymbolsOnly = TRUE; SymbolPath = **pArgv; break; case 'V': fVerbose = TRUE; break; case 'Z': fRebaseSysfileOk = TRUE; break; default: fprintf( stderr, "REBASE: Invalid switch - /%c\n", chSwitch ); ShowUsage(); break; } } BOOL ProcessGroupList( LPSTR ImagesRoot, LPSTR GroupListFName, BOOL fReBase, BOOL fOverlay ) { PGROUPNODE pgn; FILE *GroupList; CHAR chName[MAX_PATH+1]; int ateof; ULONG64 SavedImageBase; ULONG MaxImageSize=0; DWORD dw; CHAR Buffer[ MAX_PATH+1 ]; LPSTR FilePart; if (RebaseLog) { fprintf( RebaseLog, "*** %s\n", GroupListFName ); } GroupList = fopen( GroupListFName, "rt" ); if ( !GroupList ) { fprintf( stderr, "REBASE: fopen %s failed %d\n", GroupListFName, errno ); ExitProcess( REBASE_ERR ); } ateof = fscanf( GroupList, "%s", chName ); SavedImageBase = NewImageBase; while ( ateof && ateof != EOF ) { dw = SearchPath( ImagesRoot, chName, NULL, sizeof(Buffer), Buffer, &FilePart ); if ( dw == 0 || dw > sizeof( Buffer ) ) { if (!fQuiet) { fprintf( stderr, "REBASE: Could Not Find %s\\%s\n", ImagesRoot, chName ); } } else { _strlwr( Buffer ); // Lowercase for consistency when displayed. pgn = (PGROUPNODE) malloc( sizeof( GROUPNODE ) ); if ( NULL == pgn ) { fprintf( stderr, "REBASE: *** malloc failed.\n" ); ExitProcess( REBASE_ERR ); } pgn->chName = _strdup( Buffer ); if ( NULL == pgn->chName ) { fprintf( stderr, "REBASE: *** strdup failed (%s).\n", Buffer ); ExitProcess( REBASE_ERR ); } pgn->pgnNext = NULL; pgnIgnoreListEnd->pgnNext = pgn; pgnIgnoreListEnd = pgn; ReBaseFile( Buffer, fReBase ); if ( fOverlay ) { if ( MaxImageSize < NewImageSize ) { MaxImageSize = NewImageSize; } NewImageBase = SavedImageBase; } } ateof = fscanf( GroupList, "%s", chName ); } fclose( GroupList ); if ( fOverlay ) { if ( fGoingDown ) { NewImageBase -= ROUND_UP( MaxImageSize, IMAGE_SEPARATION ); } else { NewImageBase += ROUND_UP( MaxImageSize, IMAGE_SEPARATION ); } } if (RebaseLog) { fprintf( RebaseLog, "\n" ); } return TRUE; } BOOL FindInIgnoreList( LPSTR chName ) { PGROUPNODE pgn; DWORD dw; CHAR Buffer[ MAX_PATH+1 ]; LPSTR FilePart; dw = GetFullPathName( chName, sizeof(Buffer), Buffer, &FilePart ); if ( dw == 0 || dw > sizeof( Buffer ) ) { fprintf( stderr, "REBASE: *** GetFullPathName failed (%s).\n", chName ); ExitProcess( REBASE_ERR ); } for (pgn = pgnIgnoreListHdr->pgnNext; pgn != NULL; pgn = pgn->pgnNext) { if (!_stricmp( Buffer, pgn->chName ) ) { return TRUE; } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// /* ****************************************************************************** On a Hydra System, we don't want imaghlp.dll to load user32.dll since it prevents CSRSS from exiting when running a under a debugger. The following function has been copied from user32.dll so that we don't link to user32.dll. ****************************************************************************** */ ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// VOID ReBaseFile( LPSTR CurrentImageName, BOOL fReBase ) { DWORD dw; CHAR Buffer[ MAX_PATH+1 ]; CHAR Buffer2[ MAX_PATH+1 ]; LPSTR FilePart; LPSTR LocalSymbolPath; ULONG ThisImageExpectedSize = 0; ULONG64 ThisImageRequestedBase = NewImageBase; ULONG TimeStamp; static char LastName = '\0'; static ULONG LastTimeStamp = 0; BOOL FirstPass = TRUE; if ( !InitialBase && !BaseAddrFile ) { fprintf( stderr, "REBASE: -b switch must specify a non-zero base --or--\n" ); fprintf( stderr, " -i must specify a filename\n" ); exit( REBASE_ERR ); } if ( BaseAddrFile && ( InitialBase || fGoingDown || CoffBaseDotTxt ) ) { fprintf( stderr, "REBASE: -i is incompatible with -b, -d, and -c\n" ); exit( REBASE_ERR ); } dw = GetFullPathName( CurrentImageName, sizeof(Buffer), Buffer, &FilePart ); if ( dw == 0 || dw > sizeof(Buffer) ) { FilePart = CurrentImageName; } _strlwr( FilePart ); // Lowercase for consistency when displayed. if ( BaseAddrFile && !(NewImageBase = ThisImageRequestedBase = FindInBaseAddrFile( FilePart, &ThisImageExpectedSize )) ) { fprintf( stdout, "REBASE: %-16s Not listed in %s\n", FilePart, BaseAddrFileName ); } if (fUpdateSymbolsOnly) { // On update, the symbol path is a semi-colon delimited path. Find the one we want and // then fix the path for RebaseImage. HANDLE hDebugFile; CHAR Drive[_MAX_DRIVE]; CHAR Dir[_MAX_DIR]; PCHAR s; hDebugFile = FindDebugInfoFile(CurrentImageName, SymbolPath, DebugFilePath); if ( hDebugFile ) { CloseHandle(hDebugFile); _splitpath(DebugFilePath, Drive, Dir, NULL, NULL); _makepath(Buffer2, Drive, Dir, NULL, NULL); s = Buffer2 + strlen(Buffer2); s = CharPrev(Buffer2, s); if (*s == '\\') { *s = '\0'; } LocalSymbolPath = Buffer2; } else { LocalSymbolPath = NULL; } } else { LocalSymbolPath = SymbolPath; } NewImageSize = (ULONG) -1; // Hack so we can tell when system images are skipped. time( (time_t *) &TimeStamp ); // Ensure all images with the same first letter have unique timestamps. if (!LastTimeStamp) LastTimeStamp = TimeStamp; if (LastName == *FilePart) { TimeStamp = LastTimeStamp++; } else { LastTimeStamp = TimeStamp; LastName = *FilePart; } RebaseAgain: if (!(*pReBaseImage64)( CurrentImageName, (PCHAR) LocalSymbolPath, fReBase && !fSumOnly, fRebaseSysfileOk, fGoingDown, ThisImageExpectedSize, &OriginalImageSize, &OriginalImageBase, &NewImageSize, &ThisImageRequestedBase, TimeStamp ) ) { if (ThisImageRequestedBase == 0) { fprintf(stderr, "REBASE: %-16s ***Grew too large (Size=0x%x; ExpectedSize=0x%x)\n", FilePart, OriginalImageSize, ThisImageExpectedSize); } else { if (GetLastError() == ERROR_BAD_EXE_FORMAT) { if (fVerbose) { fprintf( stderr, "REBASE: %-16s DOS or OS/2 image ignored\n", FilePart ); } } else if (GetLastError() == ERROR_INVALID_ADDRESS) { fprintf( stderr, "REBASE: %-16s Rebase failed. Relocations are missing or new address is invalid\n", FilePart ); if (RebaseLog) { fprintf( RebaseLog, "%16s based at 0x%016I64x (size 0x%08x) Unable to rebase. (missing relocations or new address is invalid)\n", FilePart, OriginalImageBase, OriginalImageSize); } } else { fprintf( stderr, "REBASE: *** RelocateImage failed (%s). Image may be corrupted\n", FilePart ); } } ReturnCode = REBASE_ERR; return; } else { if (GetLastError() == ERROR_INVALID_DATA) { fprintf(stderr, "REBASE: Warning: DBG checksum did not match image.\n"); } } // Keep track of the lowest base address. if (MinBase > NewImageBase) { MinBase = NewImageBase; } if ( fSumOnly || !fReBase ) { if (!fQuiet) { fprintf( stdout, "REBASE: %16s mapped at %016I64x (size 0x%08x)\n", FilePart, OriginalImageBase, OriginalImageSize); } } else { if (SizeAdjustment && FirstPass && (NewImageSize != (ULONG) -1)) { if ((OriginalImageSize + SizeAdjustment) > NewImageSize) { // If we were to add SizeAdjustment to the image (say as a ServicePack or QFE fix), we'd blow // out our space. Make room so this isn't necessary. if (fGoingDown) { // Going down - the requested base is where we need our image // to end - adjust it down so we have room to grow and go again. FirstPass = FALSE; NewImageBase -= IMAGE_SEPARATION; ThisImageRequestedBase = NewImageBase; goto RebaseAgain; } else { // Going up. Move the next guy up so we can grow. ThisImageRequestedBase += IMAGE_SEPARATION; } } } if (RebaseLog) { fprintf( RebaseLog, "%16s rebased to 0x%016I64x (size 0x%08x)\n", FilePart, fGoingDown ? ThisImageRequestedBase : NewImageBase, NewImageSize); } if ((NewImageSize != (ULONG) -1) && (OriginalImageBase != (fGoingDown ? ThisImageRequestedBase : NewImageBase)) && ( fVerbose || fQuiet ) ) { if ( fVerbose ) { fprintf( stdout, "REBASE: %16s initial base at 0x%016I64x (size 0x%08x)\n", FilePart, OriginalImageBase, OriginalImageSize); } fprintf( stdout, "REBASE: %16s rebased to 0x%016I64x (size 0x%08x)\n", FilePart, fGoingDown ? ThisImageRequestedBase : NewImageBase, NewImageSize); if ( fVerbose && fUpdateSymbolsOnly && DebugFilePath[0]) { char szExt[_MAX_EXT]; _splitpath(DebugFilePath, NULL, NULL, NULL, szExt); if (_stricmp(szExt, ".pdb")) { fprintf( stdout, "REBASE: %16s updated image base in %s\n", FilePart, DebugFilePath ); } } } if (fRemoveRelocs) { RemoveRelocations(CurrentImageName); } } if ( CoffBaseDotTxt ) { if ( !fCoffBaseIncExt ) { char *n; if ( n = strrchr(FilePart,'.') ) { *n = '\0'; } } fprintf( CoffBaseDotTxt, "%-16s 0x%016I64x 0x%08x\n", FilePart, fSumOnly ? OriginalImageBase : (fGoingDown ? ThisImageRequestedBase : NewImageBase), NewImageSize); } NewImageBase = ThisImageRequestedBase; // Set up the next one... } ULONG64 FindInBaseAddrFile( LPSTR Name, PULONG pulSize ) { struct { CHAR Name[MAX_PATH+1]; ULONG64 Base; ULONG Size; } BAFileEntry; CHAR NameNoExt[MAX_PATH+1]; // PCHAR pchExt; int ateof; strcpy(NameNoExt,Name); // if (pchExt = strrchr(NameNoExt,'.')) { // *pchExt = '\0'; // } if (fseek(BaseAddrFile, 0, SEEK_SET)) { return 0; } ateof = fscanf(BaseAddrFile,"%s %I64x %x",BAFileEntry.Name,&BAFileEntry.Base,&BAFileEntry.Size); while ( ateof && ateof != EOF ) { if ( !_stricmp(NameNoExt,BAFileEntry.Name) ) { *pulSize = BAFileEntry.Size; return BAFileEntry.Base; } ateof = fscanf(BaseAddrFile,"%s %I64x %x",BAFileEntry.Name,&BAFileEntry.Base,&BAFileEntry.Size); } *pulSize = 0; return 0; } VOID RemoveRelocations( PCHAR ImageName ) { // UnSafe... LOADED_IMAGE li; IMAGE_SECTION_HEADER RelocSectionHdr, *Section, *pRelocSecHdr; PIMAGE_DEBUG_DIRECTORY DebugDirectory; ULONG DebugDirectorySize, i, RelocSecNum; PIMAGE_OPTIONAL_HEADER32 OptionalHeader32 = NULL; PIMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NULL; PIMAGE_FILE_HEADER FileHeader; if (!MapAndLoad(ImageName, NULL, &li, FALSE, FALSE)) { return; } FileHeader = &li.FileHeader->FileHeader; OptionalHeadersFromNtHeaders((PIMAGE_NT_HEADERS32)li.FileHeader, &OptionalHeader32, &OptionalHeader64); if (!OptionalHeader32 && !OptionalHeader64) return; // See if the image has already been stripped or there are no relocs. if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || (!OPTIONALHEADER(DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size))) { UnMapAndLoad(&li); return; } for (Section = li.Sections, i = 0; i < li.NumberOfSections; Section++, i++) { if (Section->PointerToRawData != 0) { if (!_stricmp( (char *) Section->Name, ".reloc" )) { RelocSectionHdr = *Section; pRelocSecHdr = Section; RelocSecNum = i + 1; } } } RelocSectionHdr.Misc.VirtualSize = ROUNDUP(RelocSectionHdr.Misc.VirtualSize, OPTIONALHEADER(SectionAlignment)); RelocSectionHdr.SizeOfRawData = ROUNDUP(RelocSectionHdr.SizeOfRawData, OPTIONALHEADER(FileAlignment)); if (RelocSecNum != li.NumberOfSections) { // Move everything else up and fixup old addresses. for (i = RelocSecNum - 1, Section = pRelocSecHdr;i < li.NumberOfSections - 1; Section++, i++) { *Section = *(Section + 1); Section->VirtualAddress -= RelocSectionHdr.Misc.VirtualSize; Section->PointerToRawData -= RelocSectionHdr.SizeOfRawData; } } // Zero out the last one. RtlZeroMemory(Section, sizeof(IMAGE_SECTION_HEADER)); // Reduce the section count. FileHeader->NumberOfSections--; // Set the strip bit in the header FileHeader->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; // If there's a pointer to the coff symbol table, move it back. if (FileHeader->PointerToSymbolTable) { FileHeader->PointerToSymbolTable -= RelocSectionHdr.SizeOfRawData; } // Clear out the base reloc entry in the data dir. OPTIONALHEADER_LV(DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) = 0; OPTIONALHEADER_LV(DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) = 0; // Reduce the Init Data size. OPTIONALHEADER_LV(SizeOfInitializedData) -= RelocSectionHdr.Misc.VirtualSize; // Reduce the image size. OPTIONALHEADER_LV(SizeOfImage) -= ((RelocSectionHdr.SizeOfRawData + (OPTIONALHEADER(SectionAlignment) - 1) ) & ~(OPTIONALHEADER(SectionAlignment) - 1)); // Move the debug info up (if there is any). DebugDirectory = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( li.MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugDirectorySize ); if (DebugDirectoryIsUseful(DebugDirectory, DebugDirectorySize)) { for (i = 0; i < (DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)); i++) { RtlMoveMemory(li.MappedAddress + DebugDirectory->PointerToRawData - RelocSectionHdr.SizeOfRawData, li.MappedAddress + DebugDirectory->PointerToRawData, DebugDirectory->SizeOfData); DebugDirectory->PointerToRawData -= RelocSectionHdr.SizeOfRawData; if (DebugDirectory->AddressOfRawData) { DebugDirectory->AddressOfRawData -= RelocSectionHdr.Misc.VirtualSize; } DebugDirectory++; } } // Truncate the image size li.SizeOfImage -= RelocSectionHdr.SizeOfRawData; // And we're done. UnMapAndLoad(&li); }