mirror of https://github.com/red-prig/fpPS4.git
315 lines
6.8 KiB
Plaintext
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.
|
|
|