FPPS4/tools/fp_rebase/fp_rebase.lpr

315 lines
6.8 KiB
Plaintext

{$mode ObjFPC}{$H+}
Uses
SysUtils,
coff64,
fpdwarf;
var
IMAGE_COFF64:TIMAGE_COFF64;
var
DwarfDebugFile:TDwarfDebugFile;
function GetSectionByName(const name:RawByteString):TDwarfSectionInfo;
var
section:PIMAGE_SECTION_HEADER;
begin
Result:=Default(TDwarfSectionInfo);
section:=IMAGE_COFF64.GetSectionByName(name);
if (section=nil) then Exit;
Result.RawData:=IMAGE_COFF64.RawToPtr(section^.PointerToRawData);
Result.RawSize:=section^.SizeOfRawData;
end;
Procedure PrintSections(const IMAGE_COFF64:TIMAGE_COFF64);
var
STR_TABLE:PAnsiChar;
Name:PAnsiChar;
NumberOfSections:DWORD;
i:DWORD;
O:DWORD;
begin
Writeln('[Sections]');
STR_TABLE:=IMAGE_COFF64.STR_TABLE;
NumberOfSections:=IMAGE_COFF64.NT_HEADERS^.FileHeader.NumberOfSections;
if (NumberOfSections<>0) then
For i:=0 to NumberOfSections-1 do
begin
if (IMAGE_COFF64.SECTION_HEADER[i].Name[0]='/') then
begin
Name:=@IMAGE_COFF64.SECTION_HEADER[i].Name[1];
O:=StrToDWordDef(Name,0);
Name:=@STR_TABLE[O];
end else
begin
Name:=@IMAGE_COFF64.SECTION_HEADER[i].Name;
end;
Writeln(i:2,' ',Name);
end;
end;
Procedure PrintDirectotys(Base:Pointer;DataDirectory:PIMAGE_DATA_DIRECTORY;NumberOfRvaAndSizes:DWORD);
var
i:DWORD;
begin
Writeln('[DataDirectory]');
if (NumberOfRvaAndSizes<>0) then
For i:=0 to NumberOfRvaAndSizes-1 do
begin
Writeln(i,' ',HexStr(PtrUint(@DataDirectory[i])-PtrUint(Base),8),' ',HexStr(DataDirectory[i].VirtualAddress,8),' ',HexStr(DataDirectory[i].Size,8));
end;
end;
Procedure PrintRelocs(VirtualAddress:DWORD;RELOC:PRELOC;Count:DWORD);
var
i:DWORD;
RawAddress:DWORD;
VAddr:DWORD;
RAddr:DWORD;
Value:QWORD;
begin
Writeln('[Relocs:',Count,']');
RawAddress:=IMAGE_COFF64.VirtualToRaw(VirtualAddress);
if (Count<>0) then
For i:=0 to Count-1 do
begin
VAddr:=VirtualAddress+RELOC[i].ROffset;
RAddr:=RawAddress +RELOC[i].ROffset;
Value:=0;
case RELOC[i].RType of
IMAGE_REL_BASED_DIR64:
begin
Value:=PQWORD(IMAGE_COFF64.RawToPtr(RAddr))^;
end;
else;
end;
Writeln(i:3,' 0x',HexStr(PWORD(RELOC)[i],4),' ',RELOC[i].RType:2,' ',HexStr(VAddr,8),' ',HexStr(RAddr,8),' ',HexStr(Value,16));
end;
end;
Procedure PrintBaseRelocs(BASE_REL:PIMAGE_BASE_RELOCATION;Size:DWORD);
begin
while (Size>=SizeOf(TIMAGE_BASE_RELOCATION)) do
begin
Writeln('BASE_REL.VirtualAddress:0x',HexStr(BASE_REL^.VirtualAddress,8));
Writeln('BASE_REL.SizeOfBlock :0x',HexStr(BASE_REL^.SizeOfBlock,8));
PrintRelocs(BASE_REL^.VirtualAddress,Pointer(BASE_REL+1),(BASE_REL^.SizeOfBlock-SizeOf(TIMAGE_BASE_RELOCATION)) div 2);
if (Size>BASE_REL^.SizeOfBlock) then
begin
Size:=Size-BASE_REL^.SizeOfBlock;
end else
begin
Size:=0;
end;
BASE_REL:=Pointer(BASE_REL)+BASE_REL^.SizeOfBlock;
end;
end;
////
type
TCodePatcher=object
ExeFilename : RawByteString;
OutFilename : RawByteString;
NewImageBase: QWORD;
RebaseDwarf : Boolean;
//
ImageBase: QWORD;
ImageSize: QWORD;
Procedure Callback(P:PQWORD);
end;
Procedure TCodePatcher.Callback(P:PQWORD);
Var
Value:QWORD;
begin
Value:=P^;
if (Value>=ImageBase) and
(Value<(ImageBase+ImageSize)) then
begin
Value:=Value-ImageBase+NewImageBase;
//Writeln('=0x',HexStr(Value,16));
//save
P^:=Value;
end;
end;
var
CodePatcher:TCodePatcher;
////
function ParseCmd:Boolean;
var
i,n:Integer;
s:RawByteString;
label
promo;
begin
if (ParamCount=0) then
begin
promo:
Writeln('[fp_rebase]');
Writeln('Copyright (c) 2024 by red-prig');
Writeln('Utility designed to rebase COFF64 executable files compiled on Free pascal');
Writeln(' Parameters:');
Writeln(' fp_rebase -rebase 0xADDR file [-dwarf] [-out file]');
Writeln(' -rebase 0xADDR //set new image base addres (required)');
Writeln(' file //load file name (required)');
Writeln(' -dwarf //rebase DWARF info (optional)');
Writeln(' -out file //save file name (optional)');
Exit(False);
end;
CodePatcher:=Default(TCodePatcher);
n:=-1;
For i:=1 to ParamCount do
begin
case LowerCase(ParamStr(i)) of
'-rebase':n:=0;
'-dwarf':CodePatcher.RebaseDwarf:=True;
'-out':n:=1;
else
begin
Case n of
-1:CodePatcher.ExeFilename:=ParamStr(i); //[ExeFilename]
0:
begin
s:=ParamStr(i);
if (Lowercase(copy(s,1,2))='0x') then
begin
s:='$'+copy(s,3);
end;
CodePatcher.NewImageBase:=StrToQWordDef(s,0);
end;
1:CodePatcher.OutFilename:=ParamStr(i);//[-out]
end;
n:=-1;
end;
end;
end;
if (CodePatcher.ExeFilename='') or
(CodePatcher.NewImageBase=0) then
begin
goto promo;
end;
if (CodePatcher.OutFilename='') then
begin
CodePatcher.OutFilename:=CodePatcher.ExeFilename;
end;
Result:=True;
end;
var
retry:Integer;
begin
DefaultSystemCodePage:=CP_UTF8;
DefaultUnicodeCodePage:=CP_UTF8;
DefaultFileSystemCodePage:=CP_UTF8;
DefaultRTLFileSystemCodePage:=CP_UTF8;
UTF8CompareLocale:=CP_UTF8;
if not ParseCmd then Exit;
IMAGE_COFF64:=Default(TIMAGE_COFF64);
retry:=0;
repeat
if IMAGE_COFF64.LoadFile(CodePatcher.ExeFilename) then
begin
Break;
end else
begin
Inc(retry);
if (retry>3) then
begin
Writeln(stderr,'Error load file:',CodePatcher.ExeFilename);
Exit;
end else
begin
Sleep(100);
end;
end;
until false;
if not IMAGE_COFF64.Init then Exit;
CodePatcher.ImageBase:=IMAGE_COFF64.NT_HEADERS^.OptionalHeader.ImageBase;
CodePatcher.ImageSize:=IMAGE_COFF64.NT_HEADERS^.OptionalHeader.SizeOfImage;
//Writeln('REL_RAW:0x',HexStr(IMAGE_COFF64.REL_RAW,8));
//Writeln('TLS_RAW:0x',HexStr(IMAGE_COFF64.TLS_RAW,8));
//PrintBaseRelocs(IMAGE_COFF64.BASE_REL,IMAGE_COFF64.REL_DIRECTORY.Size);
//PrintDirectotys(IMAGE_COFF64.DOS_HEADER,@IMAGE_COFF64.NT_HEADERS^.OptionalHeader.DataDirectory,IMAGE_COFF64.NT_HEADERS^.OptionalHeader.NumberOfRvaAndSizes);
PrintSections(IMAGE_COFF64);
IMAGE_COFF64.Calc(@CodePatcher.Callback);
if CodePatcher.RebaseDwarf then
begin
DwarfDebugFile:=TDwarfDebugFile.Create;
DwarfDebugFile.cb:=@CodePatcher.Callback;
DwarfDebugFile.debug_abbrev :=GetSectionByName('.debug_abbrev');
DwarfDebugFile.debug_info :=GetSectionByName('.debug_info');
DwarfDebugFile.debug_str :=GetSectionByName('.debug_str');
DwarfDebugFile.debug_line :=GetSectionByName('.debug_line');
DwarfDebugFile.debug_aranges:=GetSectionByName('.debug_aranges');
DwarfDebugFile.LoadCompilationUnits();
DwarfDebugFile.LoadArangesUnits();
end;
retry:=0;
repeat
if IMAGE_COFF64.SaveFile(CodePatcher.OutFilename) then
begin
Break;
end else
begin
Inc(retry);
if (retry>3) then
begin
Writeln(stderr,'Error save file:',CodePatcher.OutFilename);
Exit;
end else
begin
Sleep(100);
end;
end;
until false;
Writeln(stderr,'Saved:',CodePatcher.OutFilename);
end.