mirror of https://github.com/red-prig/fpPS4.git
419 lines
9.8 KiB
Plaintext
419 lines
9.8 KiB
Plaintext
unit coff64;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
const
|
|
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
|
|
IMAGE_SIZEOF_SHORT_NAME = 8;
|
|
|
|
IMAGE_DIRECTORY_ENTRY_BASERELOC=5;
|
|
IMAGE_DIRECTORY_ENTRY_TLS =9;
|
|
|
|
type
|
|
PIMAGE_DOS_HEADER = ^TIMAGE_DOS_HEADER;
|
|
TIMAGE_DOS_HEADER = packed record
|
|
e_magic : WORD;
|
|
e_cblp : WORD;
|
|
e_cp : WORD;
|
|
e_crlc : WORD;
|
|
e_cparhdr : WORD;
|
|
e_minalloc : WORD;
|
|
e_maxalloc : WORD;
|
|
e_ss : WORD;
|
|
e_sp : WORD;
|
|
e_csum : WORD;
|
|
e_ip : WORD;
|
|
e_cs : WORD;
|
|
e_lfarlc : WORD;
|
|
e_ovno : WORD;
|
|
e_res : array[0..3] of WORD;
|
|
e_oemid : WORD;
|
|
e_oeminfo : WORD;
|
|
e_res2 : array[0..9] of WORD;
|
|
case boolean of
|
|
true : (e_lfanew : longint);
|
|
false: (_lfanew : longint); // delphi naming
|
|
end;
|
|
|
|
PIMAGE_FILE_HEADER = ^TIMAGE_FILE_HEADER;
|
|
TIMAGE_FILE_HEADER = packed record
|
|
Machine: WORD;
|
|
NumberOfSections: WORD;
|
|
TimeDateStamp: DWORD;
|
|
PointerToSymbolTable: DWORD;
|
|
NumberOfSymbols: DWORD;
|
|
SizeOfOptionalHeader: WORD;
|
|
Characteristics: WORD;
|
|
end;
|
|
|
|
PIMAGE_DATA_DIRECTORY = ^TIMAGE_DATA_DIRECTORY;
|
|
TIMAGE_DATA_DIRECTORY = packed record
|
|
VirtualAddress: DWORD;
|
|
Size: DWORD;
|
|
end;
|
|
|
|
PIMAGE_OPTIONAL_HEADER64 = ^TIMAGE_OPTIONAL_HEADER64;
|
|
TIMAGE_OPTIONAL_HEADER64 = packed record
|
|
Magic: Word;
|
|
MajorLinkerVersion: Byte;
|
|
MinorLinkerVersion: Byte;
|
|
SizeOfCode: DWORD;
|
|
SizeOfInitializedData: DWORD;
|
|
SizeOfUninitializedData: DWORD;
|
|
AddressOfEntryPoint: DWORD;
|
|
BaseOfCode: DWORD;
|
|
ImageBase: Int64;
|
|
SectionAlignment: DWORD;
|
|
FileAlignment: DWORD;
|
|
MajorOperatingSystemVersion: Word;
|
|
MinorOperatingSystemVersion: Word;
|
|
MajorImageVersion: Word;
|
|
MinorImageVersion: Word;
|
|
MajorSubsystemVersion: Word;
|
|
MinorSubsystemVersion: Word;
|
|
Win32VersionValue: DWORD;
|
|
SizeOfImage: DWORD;
|
|
SizeOfHeaders: DWORD;
|
|
CheckSum: DWORD;
|
|
Subsystem: Word;
|
|
DllCharacteristics: Word;
|
|
SizeOfStackReserve: Int64;
|
|
SizeOfStackCommit: Int64;
|
|
SizeOfHeapReserve: Int64;
|
|
SizeOfHeapCommit: Int64;
|
|
LoaderFlags: DWORD;
|
|
NumberOfRvaAndSizes: DWORD;
|
|
DataDirectory: array [0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TIMAGE_DATA_DIRECTORY;
|
|
end;
|
|
|
|
PIMAGE_NT_HEADERS64 = ^TIMAGE_NT_HEADERS64;
|
|
TIMAGE_NT_HEADERS64 = packed record
|
|
Signature: DWORD;
|
|
FileHeader: TIMAGE_FILE_HEADER;
|
|
OptionalHeader: TIMAGE_OPTIONAL_HEADER64;
|
|
end;
|
|
|
|
TImage_Section_SubHeader =packed record
|
|
case longint of
|
|
0 : ( PhysicalAddress : DWORD );
|
|
1 : ( VirtualSize : DWORD );
|
|
end;
|
|
|
|
PIMAGE_SECTION_HEADER = ^TIMAGE_SECTION_HEADER;
|
|
TIMAGE_SECTION_HEADER = packed record
|
|
Name : array[0..(IMAGE_SIZEOF_SHORT_NAME)-1] of ANSICHAR;
|
|
Misc : TImage_Section_SubHeader;
|
|
VirtualAddress : DWORD;
|
|
SizeOfRawData : DWORD;
|
|
PointerToRawData : DWORD;
|
|
PointerToRelocations : DWORD;
|
|
PointerToLinenumbers : DWORD;
|
|
NumberOfRelocations : WORD;
|
|
NumberOfLinenumbers : WORD;
|
|
Characteristics : DWORD;
|
|
end;
|
|
|
|
PIMAGE_TLS_DIRECTORY64 = ^TIMAGE_TLS_DIRECTORY64;
|
|
TIMAGE_TLS_DIRECTORY64 = packed record
|
|
StartAddressOfRawData : QWORD;
|
|
EndAddressOfRawData : QWORD;
|
|
AddressOfIndex : QWORD; { PDWORD }
|
|
AddressOfCallBacks : QWORD; { PIMAGE_TLS_CALLBACK *; }
|
|
SizeOfZeroFill : DWORD;
|
|
case longint of
|
|
0 : ( Characteristics : DWORD );
|
|
1 : ( CharacteristicsFields: bitpacked record
|
|
Reserved0 : 0..$FFFFF; // 5 nibbles=20 bits
|
|
Alignment : 0..$F; // 4 bits
|
|
Reserved1 : 0..$FF; // 8 bits
|
|
end );
|
|
end;
|
|
|
|
PIMAGE_BASE_RELOCATION = ^TIMAGE_BASE_RELOCATION;
|
|
TIMAGE_BASE_RELOCATION = packed record
|
|
VirtualAddress: DWORD;
|
|
SizeOfBlock: DWORD;
|
|
end;
|
|
|
|
PSYMENT = ^TSYMENT;
|
|
TSYMENT = packed record
|
|
n_name : array[0..7] of AnsiChar; // Symbol Name
|
|
n_value : DWORD; // Value of Symbol
|
|
n_scnum : WORD; // Section Number
|
|
n_type : WORD; // Symbol Type
|
|
n_sclass: BYTE; // Storage Class
|
|
n_numaux: BYTE; // Auxiliary Count
|
|
end;
|
|
|
|
type
|
|
PRELOC = ^TRELOC;
|
|
TRELOC = bitpacked record
|
|
ROffset:0..4095;
|
|
RType :0..15;
|
|
end;
|
|
|
|
const
|
|
IMAGE_REL_BASED_ABSOLUTE=0; //SKIP
|
|
IMAGE_REL_BASED_HIGH =1; //HIWORD
|
|
IMAGE_REL_BASED_LOW =2; //LOWORD
|
|
IMAGE_REL_BASED_HIGHLOW =3; //DWORD
|
|
IMAGE_REL_BASED_DIR64 =10; //QWORD
|
|
|
|
type
|
|
TOnAdd64Link=procedure(P:PQWORD) of object;
|
|
|
|
TIMAGE_COFF64=object
|
|
DOS_HEADER :PIMAGE_DOS_HEADER;
|
|
FILE_SIZE :PTRUINT;
|
|
NT_HEADERS :PIMAGE_NT_HEADERS64;
|
|
SECTION_HEADER:PIMAGE_SECTION_HEADER;
|
|
REL_DIRECTORY :TIMAGE_DATA_DIRECTORY;
|
|
TLS_DIRECTORY :TIMAGE_DATA_DIRECTORY;
|
|
STR_TABLE :PAnsiChar;
|
|
BASE_REL :PIMAGE_BASE_RELOCATION;
|
|
BASE_TLS :PIMAGE_TLS_DIRECTORY64;
|
|
STR_RAW :DWORD;
|
|
REL_RAW :DWORD;
|
|
TLS_RAW :DWORD;
|
|
Procedure FreeFile;
|
|
function LoadFile(const Filename:RawByteString):Boolean;
|
|
function SaveFile(const Filename:RawByteString):Boolean;
|
|
Function Init:Boolean;
|
|
Function RawToPtr(Raw:QWORD):Pointer;
|
|
Function VirtualToRaw(VirtualAddress:DWORD):DWORD;
|
|
Function GetSectionByName(const name:RawByteString):PIMAGE_SECTION_HEADER;
|
|
Procedure CalcRelocs(cb:TOnAdd64Link;VirtualAddress:DWORD;RELOC:PRELOC;Count:DWORD);
|
|
Procedure CalcBaseRelocs(cb:TOnAdd64Link);
|
|
Procedure Calc(cb:TOnAdd64Link);
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
Procedure TIMAGE_COFF64.FreeFile;
|
|
begin
|
|
if (DOS_HEADER<>nil) then
|
|
begin
|
|
FreeMem(DOS_HEADER);
|
|
DOS_HEADER:=nil;
|
|
end;
|
|
end;
|
|
|
|
function TIMAGE_COFF64.LoadFile(const Filename:RawByteString):Boolean;
|
|
var
|
|
F:THandle;
|
|
begin
|
|
Result:=False;
|
|
if not FileExists(Filename) then Exit;
|
|
|
|
F:=FileOpen(Filename,fmOpenRead);
|
|
if (F=feInvalidHandle) then Exit;
|
|
|
|
FILE_SIZE:=FileSeek(F,0,fsFromEnd);
|
|
FileSeek(F,0,fsFromBeginning);
|
|
|
|
DOS_HEADER:=GetMem(FILE_SIZE);
|
|
|
|
Result:=FileRead(F,DOS_HEADER^,FILE_SIZE)=FILE_SIZE;
|
|
|
|
FileClose(F);
|
|
end;
|
|
|
|
function TIMAGE_COFF64.SaveFile(const Filename:RawByteString):Boolean;
|
|
var
|
|
F:THandle;
|
|
begin
|
|
Result:=False;
|
|
|
|
F:=FileCreate(Filename);
|
|
if (F=feInvalidHandle) then Exit;
|
|
|
|
Result:=FileWrite(F,DOS_HEADER^,FILE_SIZE)=FILE_SIZE;
|
|
|
|
FileClose(F);
|
|
end;
|
|
|
|
Function TIMAGE_COFF64.Init:Boolean;
|
|
begin
|
|
Result:=False;
|
|
|
|
if (DOS_HEADER^.e_magic<>$5a4d) then
|
|
begin
|
|
Writeln(StdErr,'Wrong DOS.e_magic:0x',HexStr(DOS_HEADER^.e_magic,4));
|
|
Exit;
|
|
end;
|
|
|
|
NT_HEADERS:=RawToPtr(DOS_HEADER^.e_lfanew);
|
|
|
|
if (NT_HEADERS^.Signature<>$4550) then
|
|
begin
|
|
Writeln(StdErr,'Wrong NT.Signature:0x',HexStr(NT_HEADERS^.Signature,8));
|
|
Exit;
|
|
end;
|
|
|
|
if (NT_HEADERS^.FileHeader.Machine<>$8664) then
|
|
begin
|
|
Writeln(StdErr,'Wrong NT.FileHeader.Machine:0x',HexStr(NT_HEADERS^.FileHeader.Machine,4));
|
|
Exit;
|
|
end;
|
|
|
|
if (NT_HEADERS^.OptionalHeader.Magic<>$020B) then
|
|
begin
|
|
Writeln(StdErr,'Wrong NT.OptionalHeader.Magic:0x',HexStr(NT_HEADERS^.OptionalHeader.Magic,4));
|
|
Exit;
|
|
end;
|
|
|
|
REL_DIRECTORY:=NT_HEADERS^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
TLS_DIRECTORY:=NT_HEADERS^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
|
|
|
|
SECTION_HEADER:=Pointer(@NT_HEADERS^.OptionalHeader)+NT_HEADERS^.FileHeader.SizeOfOptionalHeader;
|
|
|
|
STR_RAW:=NT_HEADERS^.FileHeader.PointerToSymbolTable + NT_HEADERS^.FileHeader.NumberOfSymbols*SizeOf(TSYMENT);
|
|
|
|
STR_TABLE:=RawToPtr(STR_RAW);
|
|
|
|
REL_RAW:=VirtualToRaw(REL_DIRECTORY.VirtualAddress);
|
|
TLS_RAW:=VirtualToRaw(TLS_DIRECTORY.VirtualAddress);
|
|
|
|
BASE_REL:=RawToPtr(REL_RAW);
|
|
BASE_TLS:=RawToPtr(TLS_RAW);
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
Function TIMAGE_COFF64.RawToPtr(Raw:QWORD):Pointer;
|
|
begin
|
|
Result:=Pointer(DOS_HEADER)+Raw;
|
|
end;
|
|
|
|
Function TIMAGE_COFF64.VirtualToRaw(VirtualAddress:DWORD):DWORD;
|
|
var
|
|
NumberOfSections:DWORD;
|
|
i:DWORD;
|
|
D:DWORD;
|
|
begin
|
|
Result:=0;
|
|
NumberOfSections:=NT_HEADERS^.FileHeader.NumberOfSections;
|
|
if (NumberOfSections<>0) then
|
|
For i:=0 to NumberOfSections-1 do
|
|
begin
|
|
if (VirtualAddress>=SECTION_HEADER[i].VirtualAddress) and
|
|
(VirtualAddress<SECTION_HEADER[i].VirtualAddress+SECTION_HEADER[i].SizeOfRawData) then
|
|
begin
|
|
D:=VirtualAddress-SECTION_HEADER[i].VirtualAddress;
|
|
Exit(SECTION_HEADER[i].PointerToRawData+D);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Function TIMAGE_COFF64.GetSectionByName(const name:RawByteString):PIMAGE_SECTION_HEADER;
|
|
var
|
|
SName:PAnsiChar;
|
|
NumberOfSections:DWORD;
|
|
i:DWORD;
|
|
O:DWORD;
|
|
begin
|
|
NumberOfSections:=NT_HEADERS^.FileHeader.NumberOfSections;
|
|
if (NumberOfSections<>0) then
|
|
For i:=0 to NumberOfSections-1 do
|
|
begin
|
|
if (SECTION_HEADER[i].Name[0]='/') then
|
|
begin
|
|
SName:=@SECTION_HEADER[i].Name[1];
|
|
O:=StrToDWordDef(SName,0);
|
|
SName:=@STR_TABLE[O];
|
|
end else
|
|
begin
|
|
SName:=@SECTION_HEADER[i].Name;
|
|
end;
|
|
|
|
if (SName=name) then
|
|
begin
|
|
Exit(@SECTION_HEADER[i]);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
Procedure TIMAGE_COFF64.CalcRelocs(cb:TOnAdd64Link;VirtualAddress:DWORD;RELOC:PRELOC;Count:DWORD);
|
|
var
|
|
i:DWORD;
|
|
RawAddress:DWORD;
|
|
RAddr:DWORD;
|
|
begin
|
|
if (cb=nil) then Exit;
|
|
RawAddress:=VirtualToRaw(VirtualAddress);
|
|
if (Count<>0) then
|
|
For i:=0 to Count-1 do
|
|
begin
|
|
|
|
case RELOC[i].RType of
|
|
IMAGE_REL_BASED_DIR64:
|
|
begin
|
|
RAddr:=RawAddress+RELOC[i].ROffset;
|
|
//
|
|
cb(RawToPtr(RAddr));
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
Procedure TIMAGE_COFF64.CalcBaseRelocs(cb:TOnAdd64Link);
|
|
var
|
|
i,Size:DWORD;
|
|
REL:PIMAGE_BASE_RELOCATION;
|
|
begin
|
|
if (cb=nil) then Exit;
|
|
if (BASE_REL=nil) then Exit;
|
|
Size:=REL_DIRECTORY.Size;
|
|
REL:=BASE_REL;
|
|
while (Size>=SizeOf(TIMAGE_BASE_RELOCATION)) do
|
|
begin
|
|
|
|
if (Size>=REL^.SizeOfBlock) then
|
|
begin
|
|
i:=REL^.SizeOfBlock;
|
|
end else
|
|
begin
|
|
i:=Size;
|
|
end;
|
|
|
|
if (i>SizeOf(TIMAGE_BASE_RELOCATION)) then
|
|
begin
|
|
CalcRelocs(cb,REL^.VirtualAddress,Pointer(REL+1),(i-SizeOf(TIMAGE_BASE_RELOCATION)) div 2);
|
|
end;
|
|
|
|
Size:=Size-i;
|
|
|
|
REL:=Pointer(REL)+i;
|
|
end;
|
|
end;
|
|
|
|
Procedure TIMAGE_COFF64.Calc(cb:TOnAdd64Link);
|
|
begin
|
|
if (cb=nil) then Exit;
|
|
if (NT_HEADERS=nil) then Exit;
|
|
|
|
cb(@NT_HEADERS^.OptionalHeader.ImageBase);
|
|
|
|
if (BASE_TLS<>nil) then
|
|
begin
|
|
cb(@BASE_TLS^.StartAddressOfRawData);
|
|
cb(@BASE_TLS^.EndAddressOfRawData );
|
|
cb(@BASE_TLS^.AddressOfIndex );
|
|
cb(@BASE_TLS^.AddressOfCallBacks );
|
|
end;
|
|
|
|
CalcBaseRelocs(cb);
|
|
end;
|
|
|
|
end.
|
|
|