{$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 (aSizeOf(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.