mirror of https://github.com/red-prig/fpPS4.git
Added a utility that extracts the trophy key
This commit is contained in:
parent
67e7358dbc
commit
9d9edd79a1
|
@ -2282,6 +2282,12 @@ var
|
||||||
obj:elf_obj;
|
obj:elf_obj;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
DefaultSystemCodePage:=CP_UTF8;
|
||||||
|
DefaultUnicodeCodePage:=CP_UTF8;
|
||||||
|
DefaultFileSystemCodePage:=CP_UTF8;
|
||||||
|
DefaultRTLFileSystemCodePage:=CP_UTF8;
|
||||||
|
UTF8CompareLocale:=CP_UTF8;
|
||||||
|
|
||||||
parse_param;
|
parse_param;
|
||||||
|
|
||||||
if (ParamCount<=1) or (FileName='') then
|
if (ParamCount<=1) or (FileName='') then
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="12"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<MainUnitHasCreateFormStatements Value="False"/>
|
||||||
|
<MainUnitHasTitleStatement Value="False"/>
|
||||||
|
<MainUnitHasScaledStatement Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<Title Value="trophy_key_export"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
</General>
|
||||||
|
<BuildModes>
|
||||||
|
<Item Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<UseFileFilters Value="True"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<FormatVersion Value="2"/>
|
||||||
|
</RunParams>
|
||||||
|
<Units>
|
||||||
|
<Unit>
|
||||||
|
<Filename Value="trophy_key_export.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="trophy_key_export"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<DebugInfoType Value="dsDwarf3"/>
|
||||||
|
</Debugging>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions>
|
||||||
|
<Item>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
|
@ -0,0 +1,369 @@
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
sysutils,
|
||||||
|
elf64 in '..\..\sys\elf64.pas';
|
||||||
|
|
||||||
|
type
|
||||||
|
p_elf_obj=^elf_obj;
|
||||||
|
elf_obj=packed record
|
||||||
|
is_encrypted:Integer;
|
||||||
|
self:record
|
||||||
|
hdr :p_self_header;
|
||||||
|
segs :p_self_segment;
|
||||||
|
elf_hdr :p_elf64_hdr;
|
||||||
|
MinSeg :Int64;
|
||||||
|
MaxSeg :Int64;
|
||||||
|
end;
|
||||||
|
elf:record
|
||||||
|
hdr :p_elf64_hdr;
|
||||||
|
size:Int64;
|
||||||
|
end;
|
||||||
|
size:Int64;
|
||||||
|
//
|
||||||
|
min_offset:Int64;
|
||||||
|
max_offset:Int64;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure free_elf_obj(obj:p_elf_obj);
|
||||||
|
begin
|
||||||
|
if (obj=nil) then Exit;
|
||||||
|
FreeMem(obj^.self.hdr);
|
||||||
|
FreeMem(obj^.elf.hdr);
|
||||||
|
obj^:=Default(elf_obj);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_elf_phdr(elf_hdr:p_elf64_hdr):p_elf64_phdr;
|
||||||
|
begin
|
||||||
|
if (elf_hdr=nil) then Exit(nil);
|
||||||
|
if (elf_hdr^.e_phoff=0) then
|
||||||
|
begin
|
||||||
|
Result:=Pointer(elf_hdr+1);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Result:=Pointer(elf_hdr)+elf_hdr^.e_phoff;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function maxInt64(a,b:Int64):Int64; inline;
|
||||||
|
begin
|
||||||
|
if (a>b) then Result:=a else Result:=b;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function minInt64(a,b:Int64):Int64; inline;
|
||||||
|
begin
|
||||||
|
if (a<b) then Result:=a else Result:=b;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure fixup_offset_size(var offset,size:Int64;max:Int64);
|
||||||
|
var
|
||||||
|
s,e:Int64;
|
||||||
|
begin
|
||||||
|
s:=offset;
|
||||||
|
e:=s+size;
|
||||||
|
|
||||||
|
s:=MinInt64(s,max);
|
||||||
|
e:=MinInt64(e,max);
|
||||||
|
|
||||||
|
offset:=s;
|
||||||
|
size :=(e-s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function load_self(Const name:RawByteString;obj:p_elf_obj):Integer;
|
||||||
|
Var
|
||||||
|
F:THandle;
|
||||||
|
n,s:Int64;
|
||||||
|
Magic:DWORD;
|
||||||
|
i,count:Integer;
|
||||||
|
is_encrypted:Integer;
|
||||||
|
self_hdr :p_self_header;
|
||||||
|
self_segs:p_self_segment;
|
||||||
|
elf_hdr :p_elf64_hdr;
|
||||||
|
elf_phdr :p_elf64_phdr;
|
||||||
|
MinSeg :Int64;
|
||||||
|
MaxSeg :Int64;
|
||||||
|
src_ofs :Int64;
|
||||||
|
dst_ofs :Int64;
|
||||||
|
mem_size :Int64;
|
||||||
|
begin
|
||||||
|
Result:=0;
|
||||||
|
|
||||||
|
if (name='') or (obj=nil) then Exit(-1);
|
||||||
|
|
||||||
|
F:=FileOpen(name,fmOpenRead);
|
||||||
|
if (F=feInvalidHandle) then Exit(-2);
|
||||||
|
|
||||||
|
n:=FileRead(F,Magic,SizeOf(DWORD));
|
||||||
|
if (n<>SizeOf(DWORD)) then
|
||||||
|
begin
|
||||||
|
FileClose(F);
|
||||||
|
Exit(-3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
case Magic of
|
||||||
|
ELFMAG: //elf64
|
||||||
|
begin
|
||||||
|
obj^.size:=FileSeek(F,0,fsFromEnd);
|
||||||
|
|
||||||
|
if (obj^.size<=0) then
|
||||||
|
begin
|
||||||
|
FileClose(F);
|
||||||
|
Exit(-4);
|
||||||
|
end;
|
||||||
|
|
||||||
|
obj^.elf.hdr :=GetMem(obj^.size);
|
||||||
|
obj^.elf.size:=obj^.size;
|
||||||
|
|
||||||
|
FileSeek(F,0,fsFromBeginning);
|
||||||
|
n:=FileRead(F,obj^.elf.hdr^,obj^.size);
|
||||||
|
FileClose(F);
|
||||||
|
|
||||||
|
if (n<>obj^.size) then
|
||||||
|
begin
|
||||||
|
FreeMem(obj^.elf.hdr);
|
||||||
|
obj^.elf.hdr:=nil;
|
||||||
|
Exit(-5);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
SELF_MAGIC:
|
||||||
|
begin
|
||||||
|
obj^.size:=FileSeek(F,0,fsFromEnd);
|
||||||
|
|
||||||
|
if (obj^.size<=0) then
|
||||||
|
begin
|
||||||
|
FileClose(F);
|
||||||
|
Exit(-4);
|
||||||
|
end;
|
||||||
|
|
||||||
|
self_hdr:=GetMem(obj^.size);
|
||||||
|
obj^.self.hdr:=self_hdr;
|
||||||
|
|
||||||
|
FileSeek(F,0,fsFromBeginning);
|
||||||
|
n:=FileRead(F,self_hdr^,obj^.size);
|
||||||
|
FileClose(F);
|
||||||
|
|
||||||
|
if (n<>obj^.size) then
|
||||||
|
begin
|
||||||
|
FreeMem(obj^.self.hdr);
|
||||||
|
obj^.self.hdr:=nil;
|
||||||
|
Exit(-5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
count:=self_hdr^.Num_Segments;
|
||||||
|
|
||||||
|
self_segs:=Pointer(self_hdr+1);
|
||||||
|
obj^.self.segs:=self_segs;
|
||||||
|
|
||||||
|
is_encrypted:=0;
|
||||||
|
if (count<>0) then
|
||||||
|
For i:=0 to count-1 do
|
||||||
|
if ((self_segs[i].flags and (SELF_PROPS_ENCRYPTED or SELF_PROPS_COMPRESSED))<>0) then
|
||||||
|
begin
|
||||||
|
is_encrypted:=1;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
obj^.is_encrypted:=is_encrypted;
|
||||||
|
|
||||||
|
elf_hdr:=Pointer(self_segs)+(count*SizeOf(t_self_segment));
|
||||||
|
obj^.self.elf_hdr:=elf_hdr;
|
||||||
|
|
||||||
|
elf_phdr:=get_elf_phdr(elf_hdr);
|
||||||
|
|
||||||
|
MinSeg:=High(Int64);
|
||||||
|
MaxSeg:=0;
|
||||||
|
|
||||||
|
count:=self_hdr^.Num_Segments;
|
||||||
|
|
||||||
|
if (count<>0) then
|
||||||
|
For i:=0 to count-1 do
|
||||||
|
if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then
|
||||||
|
begin
|
||||||
|
s:=SELF_SEGMENT_INDEX(self_segs[i].flags);
|
||||||
|
s:=elf_phdr[s].p_offset;
|
||||||
|
MinSeg:=MinInt64(s,MinSeg);
|
||||||
|
s:=s+minInt64(self_segs[i].filesz,self_segs[i].filesz);
|
||||||
|
MaxSeg:=MaxInt64(s,MaxSeg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
obj^.self.MinSeg:=MinSeg;
|
||||||
|
obj^.self.MaxSeg:=MaxSeg;
|
||||||
|
|
||||||
|
if (is_encrypted=0) then //load elf
|
||||||
|
begin
|
||||||
|
obj^.elf.hdr :=AllocMem(MaxSeg);
|
||||||
|
obj^.elf.size:=MaxSeg;
|
||||||
|
|
||||||
|
//elf_hdr part
|
||||||
|
n:=ptruint(elf_hdr)-ptruint(self_hdr); //offset to hdr
|
||||||
|
s:=self_hdr^.Header_Size+self_hdr^.Meta_size; //offset to end
|
||||||
|
s:=MinInt64(obj^.size,s); //min size
|
||||||
|
s:=MaxInt64(s,n)-n; //get size
|
||||||
|
|
||||||
|
//first page
|
||||||
|
Move(elf_hdr^,obj^.elf.hdr^,s);
|
||||||
|
|
||||||
|
count:=self_hdr^.Num_Segments;
|
||||||
|
|
||||||
|
if (count<>0) then
|
||||||
|
For i:=0 to count-1 do
|
||||||
|
if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then
|
||||||
|
begin
|
||||||
|
s:=SELF_SEGMENT_INDEX(self_segs[i].flags);
|
||||||
|
|
||||||
|
mem_size:=minInt64(self_segs[i].filesz,self_segs[i].memsz);
|
||||||
|
|
||||||
|
src_ofs:=self_segs[i].offset; //start offset
|
||||||
|
dst_ofs:=elf_phdr[s].p_offset; //start offset
|
||||||
|
|
||||||
|
fixup_offset_size(src_ofs,mem_size,obj^.size);
|
||||||
|
fixup_offset_size(dst_ofs,mem_size,MaxSeg);
|
||||||
|
|
||||||
|
Move( (Pointer(self_hdr) +src_ofs)^, //src
|
||||||
|
(Pointer(obj^.elf.hdr)+dst_ofs)^, //dst
|
||||||
|
mem_size); //size
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FileClose(F);
|
||||||
|
Exit(-1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
Function get_bytes_str(p:PByte;size:Integer):RawByteString;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
while (size<>0) do
|
||||||
|
begin
|
||||||
|
Result:=Result+HexStr(P^,2);
|
||||||
|
Inc(P);
|
||||||
|
Dec(size);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
P_TROPHY_KEY_RECORD=^T_TROPHY_KEY_RECORD;
|
||||||
|
T_TROPHY_KEY_RECORD=packed record
|
||||||
|
str_ptr:QWORD; //"01","00"
|
||||||
|
key_val:Array[0..15] of Byte;
|
||||||
|
zero :QWORD;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//30h 0
|
||||||
|
//31h 1
|
||||||
|
//00h
|
||||||
|
//
|
||||||
|
//30h 0
|
||||||
|
//30h 0
|
||||||
|
//00h
|
||||||
|
|
||||||
|
procedure _search(obj:p_elf_obj);
|
||||||
|
var
|
||||||
|
base:Pointer;
|
||||||
|
size:QWORD;
|
||||||
|
curr_ptr :Pointer;
|
||||||
|
curr_size:QWORD;
|
||||||
|
//
|
||||||
|
offset :QWORD;
|
||||||
|
str_val:DWORD;
|
||||||
|
P_REC :P_TROPHY_KEY_RECORD;
|
||||||
|
begin
|
||||||
|
//
|
||||||
|
base:=obj^.elf.hdr;
|
||||||
|
size:=obj^.elf.size;
|
||||||
|
//
|
||||||
|
curr_ptr :=base;
|
||||||
|
curr_size:=size-SizeOf(T_TROPHY_KEY_RECORD)*2;
|
||||||
|
//
|
||||||
|
while (curr_size<>0) do
|
||||||
|
begin
|
||||||
|
offset:=PQWORD(curr_ptr)^;
|
||||||
|
offset:=offset+$4000;
|
||||||
|
|
||||||
|
if (offset<(size-8)) then
|
||||||
|
begin
|
||||||
|
str_val:=PDWORD(base+offset)^;
|
||||||
|
str_val:=str_val and $FFFFFF;
|
||||||
|
|
||||||
|
if (str_val=$003130) then //"01"
|
||||||
|
begin
|
||||||
|
P_REC:=curr_ptr;
|
||||||
|
|
||||||
|
offset:=P_REC[1].str_ptr;
|
||||||
|
offset:=offset+$4000;
|
||||||
|
|
||||||
|
if (offset<(size-8)) then
|
||||||
|
begin
|
||||||
|
str_val:=PDWORD(base+offset)^;
|
||||||
|
str_val:=str_val and $FFFFFF;
|
||||||
|
|
||||||
|
if (str_val=$003030) then //"00"
|
||||||
|
begin
|
||||||
|
Writeln('Trophy keys found!');
|
||||||
|
|
||||||
|
Writeln('(CEX) Release:',get_bytes_str(@P_REC[0].key_val,16));
|
||||||
|
Writeln('(DEX) Debug :',get_bytes_str(@P_REC[1].key_val,16));
|
||||||
|
|
||||||
|
Writeln;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
//
|
||||||
|
Inc(curr_ptr);
|
||||||
|
Dec(curr_size);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Writeln('Trophy keys NOT found!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
r:Integer;
|
||||||
|
obj:elf_obj;
|
||||||
|
|
||||||
|
FileName:RawByteString;
|
||||||
|
|
||||||
|
begin
|
||||||
|
DefaultSystemCodePage:=CP_UTF8;
|
||||||
|
DefaultUnicodeCodePage:=CP_UTF8;
|
||||||
|
DefaultFileSystemCodePage:=CP_UTF8;
|
||||||
|
DefaultRTLFileSystemCodePage:=CP_UTF8;
|
||||||
|
UTF8CompareLocale:=CP_UTF8;
|
||||||
|
|
||||||
|
if (ParamCount<=1) then
|
||||||
|
begin
|
||||||
|
Writeln('Usage: trophy_key_export elf/self-file (SceShellCore.elf)');
|
||||||
|
end;
|
||||||
|
|
||||||
|
FileName:=ParamStr(1);
|
||||||
|
|
||||||
|
r:=load_self(FileName,@obj);
|
||||||
|
|
||||||
|
if (r=0) then
|
||||||
|
begin
|
||||||
|
if (obj.is_encrypted<>0) then
|
||||||
|
begin
|
||||||
|
Writeln('Elf is_encrypted');
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
_search(@obj);
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Writeln('Error(',r,') load file:',FileName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
readln;
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue