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;
|
||||
|
||||
begin
|
||||
DefaultSystemCodePage:=CP_UTF8;
|
||||
DefaultUnicodeCodePage:=CP_UTF8;
|
||||
DefaultFileSystemCodePage:=CP_UTF8;
|
||||
DefaultRTLFileSystemCodePage:=CP_UTF8;
|
||||
UTF8CompareLocale:=CP_UTF8;
|
||||
|
||||
parse_param;
|
||||
|
||||
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