Change ImageBase of a PE File
Post date: Mar 13, 2010 11:01:08 PM
When a PE file is generated, it is not usually known where in memory it will be loaded. The virtual address where the first byte of the file will be loaded is called ImageBase address. Default for delphi files is 40000.
{
Unit: uRebase
Author: steve10120
Description: Change the ImageBase of a PE. Needs a relocation table!
Credits: Author of BTMemoryModule: PerformBaseRelocation().
Release Date: 27th August 2009
Website: hackhound.org
History: First try
}
unit uRebase;
interface
uses Windows;
function RebaseFile(szFilePath:string; szDestFile:string; dwNewImageBase:DWORD):Boolean;
type
PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
end;
implementation
function FileToMem(szFilePath:string; var pFile:Pointer; var dwSize:DWORD):Boolean;
var
hFile: DWORD;
dwNull: DWORD;
begin
Result := FALSE;
hFile := CreateFile(PChar(szFilePath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
dwSize := GetFileSize(hFile, nil);
if dwSize > 0 then
begin
GetMem(pFile, dwSize);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
ReadFile(hFile, pFile^, dwSize, dwNull, nil);
CloseHandle(hFile);
Result := TRUE;
end;
end;
end;
procedure MemToFile(pData:Pointer; sPath:string; dSize:DWORD);
var
hFile: THandle;
dWritten: DWORD;
begin
hFile := CreateFile(PChar(sPath), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
if hFile <> 0 then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, pData^, dSize, dWritten, nil);
FreeMem(pData, dSize);
CloseHandle(hFile);
end;
end;
procedure PerformBaseRelocation(f_module: Pointer; INH:PImageNtHeaders; f_delta: Cardinal); stdcall;
var
l_i: Cardinal;
l_codebase: Pointer;
l_relocation: PImageBaseRelocation;
l_dest: Pointer;
l_relInfo: ^Word;
l_patchAddrHL: ^DWord;
l_type, l_offset: integer;
begin
l_codebase := f_module;
if INH^.OptionalHeader.DataDirectory[5].Size > 0 then
begin
l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + INH^.OptionalHeader.DataDirectory[5].VirtualAddress);
while l_relocation.VirtualAddress > 0 do
begin
l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
l_relInfo := Pointer(Cardinal(l_relocation) + 8);
for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - 8) / 2)) - 1) do
begin
l_type := (l_relInfo^ shr 12);
l_offset := l_relInfo^ and $FFF;
if l_type = 3 then
begin
l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
end;
inc(l_relInfo);
end;
l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
end;
end;
end;
function AlignImage(pImage:Pointer):Pointer;
var
IDH: PImageDosHeader;
INH: PImageNtHeaders;
ISH: PImageSectionHeader;
i: WORD;
begin
IDH := pImage;
INH := Pointer(DWORD(pImage) + IDH^._lfanew);
GetMem(Result, INH^.OptionalHeader.SizeOfImage);
ZeroMemory(Result, INH^.OptionalHeader.SizeOfImage);
CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders);
for i := 0 to INH^.FileHeader.NumberOfSections - 1 do
begin
ISH := Pointer(DWORD(pImage) + IDH^._lfanew + 248 + i * 40);
CopyMemory(Pointer(DWORD(Result) + ISH^.VirtualAddress), Pointer(DWORD(pImage) + ISH^.PointerToRawData), ISH^.SizeOfRawData);
end;
end;
function RebuildImage(pImage:Pointer):Pointer;
var
IDH: PImageDosHeader;
INH: PImageNtHeaders;
ISH: PImageSectionHeader;
i: WORD;
begin
IDH := pImage;
INH := Pointer(DWORD(pImage) + IDH^._lfanew);
ISH := Pointer(DWORD(pImage) + IDH^._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40);
GetMem(Result, (ISH.PointerToRawData + ISH.SizeOfRawData));
ZeroMemory(Result, INH^.OptionalHeader.SizeOfHeaders);
CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders);
for i := 0 to INH^.FileHeader.NumberOfSections - 1 do
begin
ISH := Pointer(DWORD(pImage) + IDH^._lfanew + 248 + i * 40);
CopyMemory(Pointer(DWORD(Result) + ISH^.PointerToRawData), Pointer(DWORD(pImage) + ISH^.VirtualAddress), ISH^.SizeOfRawData);
end;
end;
function RebaseFile(szFilePath:string; szDestFile:string; dwNewImageBase:DWORD):Boolean;
var
pFile: Pointer;
dwSize: DWORD;
IDH: PImageDosHeader;
INH: PImageNtHeaders;
begin
Result := FALSE;
if FileToMem(szFilePath, pFile, dwSize) then
begin
IDH := pFile;
if IDH^.e_magic = IMAGE_DOS_SIGNATURE then
begin
INH := Pointer(DWORD(pFile) + IDH^._lfanew);
if INH^.Signature = IMAGE_NT_SIGNATURE then
begin
pFile := AlignImage(pFile);
if INH^.OptionalHeader.DataDirectory[5].Size > 0 then
begin
PerformBaseRelocation(pFile, INH, (dwNewImageBase - INH^.OptionalHeader.ImageBase));
INH^.OptionalHeader.ImageBase := dwNewImageBase;
CopyMemory(Pointer(DWORD(pFile) + IDH^._lfanew), INH, 248);
pFile := RebuildImage(pFile);
MemToFile(pFile, szDestFile, dwSize);
Result := TRUE;
end;
end;
end;
end;
end;
end.