Realign PE

posted 28 Jun 2010, 20:03 by Delphi Basics
After adding a section, you could use this unit, written by steve10120 of ic0de.org to realign your PE file to make it smaller. The unit also rebuilds section headers.

{ uReAlignPE

Author: steve10120
Description: Realign last section and rebuild section headers.
Website: http://www.ic0de.org
History: First try
Thanks: Cobein - mRealignPE.
CFF Explorer - I ripped(or tried to) your Realign PE Headers :P.

Todo:
Tidy RealignPEFromBytes
Total custom section realignment

}

unit uReAlignPE;

interface

uses Windows, SysUtils;
function RealignPEFromFile(sFile:string; sDestFile:string):Boolean;

implementation

type
TByteArray = array of Byte;

procedure Move(Destination, Source: Pointer; dLength:DWORD);
begin
CopyMemory(Destination, Source, dLength);
end;

function Align(dwValue:DWORD; dwAlign:DWORD):DWORD;
begin
if dwAlign <> 0 then
begin
if dwValue mod dwAlign <> 0 then
begin
Result := (dwValue + dwAlign) - (dwValue mod dwAlign);
Exit;
end;
end;
Result := dwValue;
end;

function RebuildHeaders(bFile:TByteArray):Boolean;
var
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
i: integer;
ImageSize: DWORD;
SecName: array[0..7] of Char;
begin
Result := FALSE;
try
Move(@IDH, @bFile[0], 64);
if IDH.e_magic = IMAGE_DOS_SIGNATURE then
begin
Move(@INH, @bFile[IDH._lfanew], 248);
if INH.Signature = IMAGE_NT_SIGNATURE then
begin
Move(@ISH, @bFile[IDH._lfanew + 248], 40);
ImageSize := ISH.VirtualAddress;
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
Move(@ISH, @bFile[IDH._lfanew + 248 + (i * 40)], 40);
if i < INH.FileHeader.NumberOfSections - 1 then
begin
Move(@SecName[0], @ISH.Name[0], 8);
ISH.Misc.VirtualSize := Align(ISH.Misc.VirtualSize, INH.OptionalHeader.SectionAlignment);
ISH.SizeOfRawData := Align(ISH.SizeOfRawData, INH.OptionalHeader.FileAlignment);
if (SecName <> '.tls') and (SecName <> 'BSS') then
begin
if ISH.SizeOfRawData = 0 then
ISH.SizeOfRawData := ISH.Misc.VirtualSize;
if ISH.PointerToRawData = 0 then
ISH.PointerToRawData := ISH.VirtualAddress;
end;
end;
ImageSize := ImageSize + ISH.Misc.VirtualSize;
Move(@bFile[IDH._lfanew + 248 + (i * 40)], @ISH, 40);
end;
INH.OptionalHeader.SizeOfImage := ImageSize;
Move(@bFile[IDH._lfanew], @INH, 248);
Result := TRUE;
end;
end;
except
on E: Exception do
MessageBox(0, PChar('Error: ' + E.ClassName + #13#10#13#10'Message: ' + E.Message), PChar('Error'), MB_ICONHAND or MB_ICONSTOP or MB_ICONERROR);
end;
end;

function RealignPEFromBytes(bFile: TByteArray; var bResult:TByteArray):Boolean;
var
dSize: DWORD;
dLastSectPos: DWORD;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
dDataSize: DWORD;
dAlign: DWORD;
bExtraData: TByteArray;
begin
Result := FALSE;
try
Move(@IDH, @bFile[0], 64);
if IDH.e_magic = IMAGE_DOS_SIGNATURE then
begin
Move(@INH, @bFile[IDH._lfanew], 248);
if INH.Signature = IMAGE_NT_SIGNATURE then
begin
dLastSectPos := IDH._lfanew + 248 + ((INH.FileHeader.NumberOfSections - 1) * 40);
Move(@ISH, @bFile[dLastSectPos], 40);
dSize := ISH.SizeOfRawData;
dDataSize := Length(bFile) - ISH.SizeOfRawData - ISH.PointerToRawData;
if (dSize + dDataSize) mod INH.OptionalHeader.SectionAlignment = 0 then
begin
ISH.SizeOfRawData := ISH.SizeOfRawData + dSize;
Move(@bFile[dLastSectPos], @ISH, 40);
end
else
begin
SetLength(bExtraData, dDataSize);
Move(@bExtraData[0], @bFile[Length(bFile) - dDataSize], dDataSize);
SetLength(bFile, Length(bFile) - dDataSize);
dAlign := Align(dDataSize, INH.OptionalHeader.SectionAlignment);
SetLength(bFile, Length(bFile) + dAlign);
Move(@bFile[Length(bFile) - dDataSize], @bExtraData[0], dDataSize);
ISH.Misc.VirtualSize := ISH.Misc.VirtualSize + dAlign;
ISH.SizeOfRawData := ISH.SizeOfRawData + dAlign;
Move(@bFile[dLastSectPos], @ISH, 40);
Result := TRUE;
end;
RebuildHeaders(bFile);
bResult := bFile;
SetLength(bFile, 0);
end;
end;
except
on E: Exception do
MessageBox(0, PChar('Error: ' + E.ClassName + #13#10#13#10'Message: ' + E.Message), PChar('Error'), MB_ICONHAND or MB_ICONSTOP or MB_ICONERROR);
end;
end;

function RealignPEFromFile(sFile:string; sDestFile:string):Boolean;
var
bFile: TByteArray;
hFile: THandle;
dSize: DWORD;
dRead: DWORD;
dWritten: DWORD;
bResult: TByteArray;
begin
Result := FALSE;
hFile := CreateFile(PChar(sFile), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
dSize := GetFileSize(hFile, nil);
SetLength(bFile, dSize);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
ReadFile(hFile, bFile[0], dSize, dRead, nil);
CloseHandle(hFile);

if RealignPEFromBytes(bFile, bResult) then
begin
if sDestFile = '' then
sDestFile := sFile;
hFile := CreateFile(PChar(sDestFile), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bResult[0], Length(bResult), dWritten, nil);
CloseHandle(hFile);
Result := TRUE;
end;
end;
end;
end;

end.

Comments