Delete the relocations from a PE file.

Post date: Mar 15, 2010 10:05:52 PM

This unit enables you to strip the table of the base relocations (Fix-Up Table) from EXE files and saves space, making them smaller. As a rule, there's no need for an EXE to have a base relocation table. This is because EXEs are the first thing loaded into an address space, and therefore are guaranteed to load at the preferred load address. It is recommend that you do not strip relocations from all EXEs you come across, because while this may save space, it may cause some executables not to work properly. If you take a look at Windows Notepad.exe the relocation table has been stripped.

Read more: http://en.wikipedia.org/wiki/Relocation_table

{

Unit: uStripRelocs

Author: steve10120

Description: Delete the relocations from a PE file.

Website: http://hackhound.org

History: First try

}

unit uStripRelocs;
interface
uses Windows;
function StripRelocations(szFilePath:string; szDestFile:string):Boolean;
type
  TByteArray = array of Byte;
implementation
function FileToBytes(sPath:string; var bFile:TByteArray):Boolean;
var
hFile:    THandle;
dSize:    DWORD;
dRead:    DWORD;
begin
  Result := FALSE;
  hFile := CreateFile(PChar(sPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if hFile <> 0 then
  begin
    dSize := GetFileSize(hFile, nil);
    SetFilePointer(hFile, 0, nil, FILE_BEGIN);
    SetLength(bFile, dSize);
    if ReadFile(hFile, bFile[0], dSize, dRead, nil) then
      Result := TRUE;
    CloseHandle(hFile);
  end;
end;
procedure BytesToFile(bData:TByteArray; sPath:string);
var
hFile:    THandle;
dWritten: DWORD;
begin
  hFile := CreateFile(PChar(sPath), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  if hFile <> 0 then
  begin
    SetFilePointer(hFile, 0, nil, FILE_BEGIN);
    WriteFile(hFile, bData[0],Length(bData), dWritten, nil);
    CloseHandle(hFile);
  end;
end;
function StripRelocations(szFilePath:string; szDestFile:string):Boolean;
var
  bFile:      TByteArray;
  IDH:        TImageDosHeader;
  INH:        TImageNtHeaders;
  ISH:        TImageSectionHeader;
  szSecName:  array[0..7] of Char;
begin
  Result := FALSE;
  if FileToBytes(szFilePath, bFile) then
  begin
    CopyMemory(@IDH, @bFile[0], 64);
    if IDH.e_magic = IMAGE_DOS_SIGNATURE then
    begin
      CopyMemory(@INH, @bFile[IDH._lfanew], 248);
      if INH.Signature = IMAGE_NT_SIGNATURE then
      begin
        if (INH.OptionalHeader.DataDirectory[5].VirtualAddress > 0) and (INH.OptionalHeader.DataDirectory[5].Size > 0) then
        begin
          CopyMemory(@ISH, @bFile[IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40], 40);
          CopyMemory(@szSecName[0], @ISH.Name[0], 8);
          if szSecName = '.reloc' then
          begin
            SetLength(bFile, Length(bFile) - ISH.SizeOfRawData);
            INH.OptionalHeader.DataDirectory[5].VirtualAddress := 0;
            INH.OptionalHeader.DataDirectory[5].Size := 0;
            FillChar(ISH, 40, #0);
            CopyMemory(@bFile[IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40], @ISH, 40);
            Dec(INH.FileHeader.NumberOfSections);
            CopyMemory(@ISH, @bFile[IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40], 40);
            INH.OptionalHeader.SizeOfImage := ISH.VirtualAddress + ISH.Misc.VirtualSize;
            CopyMemory(@bFile[IDH._lfanew], @INH, 248);
            BytesToFile(bFile, szDestFile);
            Result := TRUE;
          end;
        end;
      end;
    end;
  end;
end;
end.