From 1361e81b9b4562c3c004ff07d7c76dcfeb2ac772 Mon Sep 17 00:00:00 2001 From: Pavel <68122101+red-prig@users.noreply.github.com> Date: Sat, 1 Jul 2023 20:49:32 +0300 Subject: [PATCH] + --- .gitignore | 3 + tools/readself/elf64.pas | 718 ++++++++++++++++++++++++++++++++++ tools/readself/readself.lpi | 63 +++ tools/readself/readself.lpr | 746 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1530 insertions(+) create mode 100644 tools/readself/elf64.pas create mode 100644 tools/readself/readself.lpi create mode 100644 tools/readself/readself.lpr diff --git a/.gitignore b/.gitignore index 296797ca..a08ef334 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ *.bat *.prx *.sprx +*.bin +*.elf +*.self *.dump *.h link.res diff --git a/tools/readself/elf64.pas b/tools/readself/elf64.pas new file mode 100644 index 00000000..e113b49b --- /dev/null +++ b/tools/readself/elf64.pas @@ -0,0 +1,718 @@ +unit elf64; + +{$mode objfpc}{$H+} + +interface + +uses ctypes; + +{ + /--------------------------------------\--\ + |SELF Header Structure(t_self_header) | | + +--------------------------------------+--|-\ + |SELF Segment Structure(t_self_segment)| | | <- t_self_header.Num_Segments * SizeOf(t_self_segment) + +--------------------------------------+--|-/ + |ELF Segment Structure(elf64_hdr) | | + +--------------------------------------+--|-\ + |ELF Program header(elf64_phdr) | | | <- elf64_hdr.e_phnum * SizeOf(elf64_phdr) + +--------------------------------------+--|-/ + |Align(addr,16) | | + +--------------------------------------+ | + |SELF authinfo(t_self_authinfo) | | <- t_self_header.Header_Size + +--------------------------------------+ | + |Content_ID/Digest_SHA_256 | | + +--------------------------------------+-/--\ + |Metadata/Segment Certification | | <- t_self_header.Meta_size + +--------------------------------------+----/ + |ELF segments data | + \--------------------------------------/ +} + +Const + ET_NONE =0; + ET_REL =1; + ET_EXEC =2; + ET_DYN =3; + ET_CORE =4; + ET_SCE_EXEC =$FE00; + ET_SCE_REPLAY_EXEC=$FE01; + ET_SCE_RELEXEC =$FE04; + ET_SCE_STUBLIB =$FE0C; + ET_SCE_DYNEXEC =$FE10; + ET_SCE_DYNAMIC =$FE18; + + EI_MAG0 = 0; // e_ident[] indexes + EI_MAG1 = 1; + EI_MAG2 = 2; + EI_MAG3 = 3; + EI_CLASS = 4; + EI_DATA = 5; + EI_VERSION = 6; + EI_OSABI = 7; + EI_ABIVERSION = 8; + + EI_NIDENT=16; + + ELFMAG =$464C457F; + SELFMAG=4; + + EM_NONE =0; + EM_X86_64 =62; // AMD x86-64 + + PT_NULL = 0; + PT_LOAD = 1; + PT_DYNAMIC = 2; + PT_INTERP = 3; + PT_NOTE = 4; + PT_SHLIB = 5; + PT_PHDR = 6; + PT_TLS = 7; // Thread local storage segment + PT_SCE_RELA = $60000000; + PT_SCE_DYNLIBDATA = $61000000; + PT_SCE_PROCPARAM = $61000001; + PT_SCE_MODULE_PARAM = $61000002; + PT_SCE_RELRO = $61000010; + PT_GNU_EH_FRAME = $6474e550; + PT_GNU_STACK = $6474E551; + PT_SCE_COMMENT = $6FFFFF00; + PT_SCE_VERSION = $6FFFFF01; + PT_SCE_SEGSYM = $700000A8; + + // This is the info that is needed to parse the dynamic section of the file + DT_NULL = 0; + DT_NEEDED = 1; + DT_PLTRELSZ = 2; + DT_PLTGOT = 3; + DT_HASH = 4; + DT_STRTAB = 5; + DT_SYMTAB = 6; + DT_RELA = 7; + DT_RELASZ = 8; + DT_RELAENT = 9; + DT_STRSZ =10; + DT_SYMENT =11; + DT_INIT =12; + DT_FINI =13; + DT_SONAME =14; + DT_RPATH =15; + DT_SYMBOLIC =16; + DT_REL =17; + DT_RELSZ =18; + DT_RELENT =19; + DT_PLTREL =20; + DT_DEBUG =21; + DT_TEXTREL =22; + DT_JMPREL =23; + DT_BIND_NOW =24; + DT_INIT_ARRAY =25; + DT_FINI_ARRAY =26; + DT_INIT_ARRAYSZ =27; + DT_FINI_ARRAYSZ =28; + DT_RUNPATH =29; + DT_FLAGS =30; + DT_ENCODING =31; + DT_PREINIT_ARRAY =32; + DT_PREINIT_ARRAYSZ =33; + + // Dynamic Section Types + DT_SCE_IDTABENTSZ =$61000005; + DT_SCE_FINGERPRINT =$61000007; + DT_SCE_ORIGINAL_FILENAME =$61000009; + DT_SCE_MODULE_INFO =$6100000D; + DT_SCE_NEEDED_MODULE =$6100000F; + DT_SCE_MODULE_ATTR =$61000011; + DT_SCE_EXPORT_LIB =$61000013; + DT_SCE_IMPORT_LIB =$61000015; + DT_SCE_EXPORT_LIB_ATTR =$61000017; + DT_SCE_IMPORT_LIB_ATTR =$61000019; + DT_SCE_STUB_MODULE_NAME =$6100001D; + DT_SCE_STUB_MODULE_VERSION =$6100001F; + DT_SCE_STUB_LIBRARY_NAME =$61000021; + DT_SCE_STUB_LIBRARY_VERSION =$61000023; + DT_SCE_HASH =$61000025; + DT_SCE_PLTGOT =$61000027; + DT_SCE_JMPREL =$61000029; + DT_SCE_PLTREL =$6100002B; + DT_SCE_PLTRELSZ =$6100002D; + DT_SCE_RELA =$6100002F; + DT_SCE_RELASZ =$61000031; + DT_SCE_RELAENT =$61000033; + DT_SCE_STRTAB =$61000035; + DT_SCE_STRSZ =$61000037; + DT_SCE_SYMTAB =$61000039; + DT_SCE_SYMENT =$6100003B; + DT_SCE_HASHSZ =$6100003D; + DT_SCE_SYMTABSZ =$6100003F; + DT_SCE_HIOS =$6FFFF000; + DT_GNU_HASH =$6ffffef5; + DT_VERSYM =$6ffffff0; + DT_RELACOUNT =$6ffffff9; + DT_RELCOUNT =$6ffffffa; + DT_FLAGS_1 =$6ffffffb; + DT_VERDEF =$6ffffffc; + DT_VERDEFNUM =$6ffffffd; + + DF_ORIGIN =$1; + DF_SYMBOLIC =$2; + DF_TEXTREL =$4; + DF_BIND_NOW =$8; + DF_STATIC_TLS=$10; + + SHT_SYMTAB=2; + SHT_STRTAB=3; + + // Relocation types for AMD x86-64 architecture + R_X86_64_NONE = 0; // No reloc + R_X86_64_64 = 1; // Direct 64 bit + R_X86_64_PC32 = 2; // PC relative 32 bit signed + R_X86_64_GOT32 = 3; // 32 bit GOT entry + R_X86_64_PLT32 = 4; // 32 bit PLT address + R_X86_64_COPY = 5; // Copy symbol at runtime + R_X86_64_GLOB_DAT = 6; // Create GOT entry + R_X86_64_JUMP_SLOT = 7; // Create PLT entry + R_X86_64_RELATIVE = 8; // Adjust by program base + R_X86_64_GOTPCREL = 9; // 32 bit signed pc relative offset to GOT + R_X86_64_32 =10; // Direct 32 bit zero extended + R_X86_64_32S =11; // Direct 32 bit sign extended + R_X86_64_16 =12; // Direct 16 bit zero extended + R_X86_64_PC16 =13; // 16 bit sign extended pc relative + R_X86_64_8 =14; // Direct 8 bit sign extended + R_X86_64_PC8 =15; // 8 bit sign extended pc relative + R_X86_64_DTPMOD64 =16; // ID of module containing symbol + R_X86_64_DTPOFF64 =17; // Offset in module's TLS block + R_X86_64_TPOFF64 =18; // Offset in initial TLS block + R_X86_64_TLSGD =19; // 32 bit signed PC relative offset to two GOT entries for GD symbol + R_X86_64_TLSLD =20; // 32 bit signed PC relative offset to two GOT entries for LD symbol + R_X86_64_DTPOFF32 =21; // Offset in TLS block + R_X86_64_GOTTPOFF =22; // 32 bit signed PC relative offset to GOT entry for IE symbol + R_X86_64_TPOFF32 =23; // Offset in initial TLS block + R_X86_64_PC64 =24; // PC relative 64 bit + R_X86_64_GOTOFF64 =25; // 64 bit offset to GOT + R_X86_64_GOTPC32 =26; // 32 bit signed pc relative offset to GOT + R_X86_64_GOT64 =27; // 64-bit GOT entry offset + R_X86_64_GOTPCREL64 =28; // 64-bit PC relative offset to GOT entry + R_X86_64_GOTPC64 =29; // 64-bit PC relative offset to GOT + R_X86_64_GOTPLT64 =30; // like GOT64, says PLT entry needed + R_X86_64_PLTOFF64 =31; // 64-bit GOT relative offset to PLT entry + R_X86_64_SIZE32 =32; // Size of symbol plus 32-bit addend + R_X86_64_SIZE64 =33; // Size of symbol plus 64-bit addend + R_X86_64_GOTPC32_TLSDESC =34; // GOT offset for TLS descriptor + R_X86_64_TLSDESC_CALL =35; // Marker for call through TLS descriptor + R_X86_64_TLSDESC =36; // TLS descriptor + R_X86_64_IRELATIVE =37; // Adjust indirectly by program base + R_X86_64_RELATIVE64 =38; // 64bit adjust by program base + R_X86_64_ORBIS_GOTPCREL_LOAD =40; + + STB_LOCAL =0; + STB_GLOBAL=1; + STB_WEAK =2; + + STT_NOTYPE = 0; //module_start/module_stop + STT_OBJECT = 1; + STT_FUN = 2; + STT_SECTION = 3; + STT_FILE = 4; + STT_COMMON = 5; + STT_TLS = 6; + STT_LOOS =10; + STT_SCE =11; //module_start/module_stop + + //ST_LOCAL_NONE = 0x00 + //ST_LOCAL_OBJECT = 0x01 + //ST_LOCAL_FUNCTION = 0x02 + //ST_LOCAL_SECTION = 0x03 + //ST_LOCAL_FILE = 0x04 + //ST_LOCAL_COMMON = 0x05 + //ST_LOCAL_TLS = 0x06 + //ST_LOCAL_SCE = 0x0B + //ST_GLOBAL_NONE = 0x10 + //ST_GLOBAL_OBJECT = 0x11 + //ST_GLOBAL_FUNCTION = 0x12 + //ST_GLOBAL_SECTION = 0x13 + //ST_GLOBAL_FILE = 0x14 + //ST_GLOBAL_COMMON = 0x15 + //ST_GLOBAL_TLS = 0x16 + //ST_GLOBAL_SCE = 0x1B + //ST_WEAK_NONE = 0x20 + //ST_WEAK_OBJECT = 0x21 + //ST_WEAK_FUNCTION = 0x22 + //ST_WEAK_SECTION = 0x23 + //ST_WEAK_FILE = 0x24 + //ST_WEAK_COMMON = 0x25 + //ST_WEAK_TLS = 0x26 + //ST_WEAK_SCE = 0x2B + + STV_DEFAULT =0; + STV_INTERNAL =1; + STV_HIDDEN =2; + STV_PROTECTED =3; + + SHN_UNDEF=0; + + PF_X=$1; + PF_W=$2; + PF_R=$4; + +type + Elf64_Addr =cuint64; + Elf64_Half =cuint16; + Elf64_SHalf =cint64 ; + Elf64_Off =cuint64; + Elf64_Sword =cint32 ; + Elf64_Word =cuint32; + Elf64_Xword =cuint64; + Elf64_Sxword=cint64 ; + + p_elf64_hdr=^elf64_hdr; + elf64_hdr=packed record + e_ident:Array[0..EI_NIDENT-1] of Byte; // ELF "magic number" + e_type :Elf64_Half; + e_machine :Elf64_Half; + e_version :Elf64_Word; + e_entry :Elf64_Addr; // Entry point virtual address from where the process starts executing. + e_phoff :Elf64_Off ; // Program header table file offset + e_shoff :Elf64_Off ; // Section header table file offset + e_flags :Elf64_Word; + e_ehsize :Elf64_Half; + e_phentsize:Elf64_Half; + e_phnum :Elf64_Half; + e_shentsize:Elf64_Half; + e_shnum :Elf64_Half; + e_shstrndx :Elf64_Half; + end; + + p_elf64_phdr=^elf64_phdr; + elf64_phdr=packed record + p_type :Elf64_Word ; + p_flags :Elf64_Word ; + p_offset:Elf64_Off ; // Segment file offset + p_vaddr :Elf64_Addr ; // Segment virtual address + p_paddr :Elf64_Addr ; // Segment physical address + p_filesz:Elf64_Xword; // Segment size in file + p_memsz :Elf64_Xword; // Segment size in memory + p_align :Elf64_Xword; // Segment alignment, file & memory + end; + + p_elf64_shdr=^elf64_shdr; + elf64_shdr=packed record + sh_name :Elf64_Word ; // Section name, index in string tbl + sh_type :Elf64_Word ; // Type of section + sh_flags :Elf64_Xword; // Miscellaneous section attributes + sh_addr :Elf64_Addr ; // Section virtual addr at execution + sh_offset :Elf64_Off ; // Section file offset + sh_size :Elf64_Xword; // Size of section in bytes + sh_link :Elf64_Word ; // Index of another section + sh_info :Elf64_Word ; // Additional section information + sh_addralign:Elf64_Xword; // Section alignment + sh_entsize :Elf64_Xword; // Entry size if section holds table + end; + + p_elf64_dyn=^elf64_dyn; + elf64_dyn=packed record + d_tag:Elf64_Sxword; // entry tag value + d_un :packed record + Case Byte of + 0:(d_val:Elf64_Xword); + 1:(d_ptr:Elf64_Addr); + end; + end; + + p_elf64_rela=^elf64_rela; + elf64_rela=packed record + r_offset:Elf64_Addr; // Location at which to apply the action + r_info :Elf64_Xword; // index and type of relocation + r_addend:Elf64_Sxword; // Constant addend used to compute value + end; + + p_elf64_sym=^elf64_sym; + elf64_sym=packed record + st_name :Elf64_Word; // Symbol name, index in string tbl + st_info :Byte; // Type and binding attributes + st_other:Byte; // No defined meaning, 0 + st_shndx:Elf64_Half; // Associated section index + st_value:Elf64_Addr; // Value of the symbol + st_size :Elf64_Xword; // Associated symbol size + end; + +const + SELF_MAGIC =$1D3D154F; + SELF_VERSION =$0; + SELF_MODE =$1; + SELF_ENDIANNESS=$1; + + SELF_AUTH_INFO_SIZE =$88; + SELF_KEY_SIZE =$10; + SELF_DIGEST_SIZE =$20; + SELF_SEGMENT_BLOCK_ALIGNMENT=$10; + +type + p_self_header=^t_self_header; + t_self_header=packed record + Magic :DWORD; //Magic 4F 15 3D 1D + Version :Byte; //0 + Mode :Byte; //1 + Endian :Byte; //1 + Attr :Byte; // + Content_Type:Byte; //Content Type 1 on Self, 4 on PUP Entry + Program_Type:Byte; //Program Type + Padding :Word; //Padding + Header_Size :Word; //Header Size + Meta_size :Word; //Signature Size Metadata Size? + File_size :QWORD; //Size of SELF + Num_Segments:Word; //Number of Segments + Flags :Word; // + reserved :DWORD; // + end; + +const + SELF_PROPS_ORDERED = $00000001; + SELF_PROPS_ENCRYPTED = $00000002; + SELF_PROPS_SIGNED = $00000004; + SELF_PROPS_COMPRESSED = $00000008; + SELF_PROPS_WINDOW = $00000700; + SELF_PROPS_BLOCKED = $00000800; + SELF_PROPS_BLOCK_SIZE = $0000F000; + SELF_PROPS_HAS_DIGESTS = $00010000; + SELF_PROPS_HAS_EXTENTS = $00020000; + SELF_PROPS_SEGMENT_INDEX = $7FF00000; + + SELF_PROPS_WINDOW_OFFSET=8; + SELF_PROPS_WINDOW_MASK =7; + + SELF_PROPS_BLOCK_SIZE_OFFSET=12; + SELF_PROPS_BLOCK_SIZE_MASK =$F; + + SELF_PROPS_SEGMENT_INDEX_OFFSET=20; + SELF_PROPS_SEGMENT_INDEX_MASK =$7FF; + + SELF_PT_FAKE =$1; + SELF_PT_NPDRM_EXEC =$4; + SELF_PT_NPDRM_DYNLIB =$5; + SELF_PT_SYSTEM_EXEC =$8; + SELF_PT_SYSTEM_DYNLIB=$9; + SELF_PT_HOST_KERNEL =$C; + SELF_PT_SECURE_MODULE=$E; + SELF_PT_SECURE_KERNEL=$F; + +type + p_self_segment=^t_self_segment; + t_self_segment=packed record + flags :QWORD; + offset:QWORD; + filesz:QWORD; + memsz :QWORD; + end; + + p_self_authinfo=^t_self_authinfo; + t_self_authinfo=packed record + AuthorityID :QWORD; + Program_Type :QWORD; + Program_Version:QWORD; + System_Version :QWORD; + //Content_ID :array[0..31] of Byte; //Optional + Digest_SHA_256 :array[0..31] of Byte; + end; + + p_eh_frame_hdr=^eh_frame_hdr; + eh_frame_hdr=packed record + version :Byte; + eh_frame_ptr_enc:Byte; + fde_count_enc :Byte; + table_enc :Byte; + encoded:record end; + //encoded eh_frame_ptr + //encoded fde_count + end; + +const + DW_EH_PE_omit =$ff; // no data follows + + DW_EH_PE_absptr =$00; + DW_EH_PE_pcrel =$10; + DW_EH_PE_datarel=$30; + + DW_EH_PE_uleb128=$01; + DW_EH_PE_udata2 =$02; + DW_EH_PE_udata4 =$03; + DW_EH_PE_udata8 =$04; + DW_EH_PE_sleb128=$09; + DW_EH_PE_sdata2 =$0A; + DW_EH_PE_sdata4 =$0B; + DW_EH_PE_sdata8 =$0C; + +type + TModuleValue=packed record + case Byte of + 0:(value:Int64); + 1:(name_offset:DWORD; + version_minor:Byte; + version_major:Byte; + id:Word); + end; + + TLibraryValue=packed record + case Byte of + 0:(value:Int64); + 1:(name_offset:DWORD; + version_minor:Byte; + version_major:Byte; + id:Word); + end; + + PTLS_index=^TLS_index; + TLS_index=packed record + ti_moduleid :QWORD; + ti_tlsoffset:QWORD; + end; + + PPS4StartupParams=^TPS4StartupParams; + TPS4StartupParams=packed record + argc:Integer; + align:Integer; + argv:array[0..2] of Pointer; + //envrion = argv + argc + 1 + end; + +type + t_user_malloc_init =function():Integer; SysV_ABI_CDecl; + t_user_malloc_finalize =function():Integer; SysV_ABI_CDecl; + t_user_malloc =function(size:qword):Pointer; SysV_ABI_CDecl; + t_user_free =procedure(ptr:Pointer); SysV_ABI_CDecl; + t_user_calloc =function(nelem,count:qword):Pointer; SysV_ABI_CDecl; + t_user_realloc =function(ptr:Pointer;size:qword):Pointer; SysV_ABI_CDecl; + t_user_memalign =function(align,size:qword):Pointer; SysV_ABI_CDecl; + t_user_reallocalign =function(ptr:Pointer;size,align:qword):Pointer; SysV_ABI_CDecl; + t_user_posix_memalign =function(ptr:PPointer;align,size:qword):Integer; SysV_ABI_CDecl; + t_user_malloc_stats =function(mmsize:Pointer):Integer; SysV_ABI_CDecl; + t_user_malloc_stats_fast =function(mmsize:Pointer):Integer; SysV_ABI_CDecl; + t_user_malloc_usable_size=function(ptr:Pointer):qword; SysV_ABI_CDecl; + + PsceLibcMallocReplace=^TsceLibcMallocReplace; + TsceLibcMallocReplace=packed record + Size:QWORD; + Unknown1:QWORD; //00000001 + user_malloc_init :t_user_malloc_init; + user_malloc_finalize :t_user_malloc_finalize; + user_malloc :t_user_malloc; + user_free :t_user_free; + user_calloc :t_user_calloc; + user_realloc :t_user_realloc; + user_memalign :t_user_memalign; + user_reallocalign :t_user_reallocalign; + user_posix_memalign :t_user_posix_memalign; + user_malloc_stats :t_user_malloc_stats; + user_malloc_stats_fast :t_user_malloc_stats_fast; + user_malloc_usable_size:t_user_malloc_usable_size; + end; + + t_user_new_1 =function(size:qword):Pointer; SysV_ABI_CDecl; + t_user_new_2 =function(size:qword;throw:Pointer):Pointer; SysV_ABI_CDecl; + t_user_new_array_1 =function(size:qword):Pointer; SysV_ABI_CDecl; + t_user_new_array_2 =function(size:qword;throw:Pointer):Pointer; SysV_ABI_CDecl; + t_user_delete_1 =procedure(ptr:Pointer); SysV_ABI_CDecl; + t_user_delete_2 =procedure(ptr:Pointer;throw:Pointer); SysV_ABI_CDecl; + t_user_delete_array_1=procedure(ptr:Pointer); SysV_ABI_CDecl; + t_user_delete_array_2=procedure(ptr:Pointer;throw:Pointer); SysV_ABI_CDecl; + t_user_delete_3 =procedure(ptr:Pointer;size:qword); SysV_ABI_CDecl; + t_user_delete_4 =procedure(ptr:Pointer;size:qword;throw:Pointer); SysV_ABI_CDecl; + t_user_delete_array_3=procedure(ptr:Pointer;size:qword); SysV_ABI_CDecl; + t_user_delete_array_4=procedure(ptr:Pointer;size:qword;throw:Pointer); SysV_ABI_CDecl; + + PsceLibcNewReplace=^TsceLibcNewReplace; + TsceLibcNewReplace=packed record + Size:QWORD; + Unknown1:QWORD; //00000002 + user_new_1 :t_user_new_1; + user_new_2 :t_user_new_2; + user_new_array_1 :t_user_new_array_1; + user_new_array_2 :t_user_new_array_2; + user_delete_1 :t_user_delete_1; + user_delete_2 :t_user_delete_2; + user_delete_array_1:t_user_delete_array_1; + user_delete_array_2:t_user_delete_array_2; + user_delete_3 :t_user_delete_3; + user_delete_4 :t_user_delete_4; + user_delete_array_3:t_user_delete_array_3; + user_delete_array_4:t_user_delete_array_4; + end; + + t_user_malloc_init_for_tls =function():Integer; SysV_ABI_CDecl; + t_user_malloc_fini_for_tls =function():Integer; SysV_ABI_CDecl; + t_user_malloc_for_tls =function(size:qword):Pointer; SysV_ABI_CDecl; + t_user_posix_memalign_for_tls=function(ptr:PPointer;align,size:qword):Integer; SysV_ABI_CDecl; + t_user_free_for_tls =procedure(ptr:Pointer); SysV_ABI_CDecl; + + PsceLibcMallocReplaceForTls=^TsceLibcMallocReplaceForTls; + TsceLibcMallocReplaceForTls=packed record + Size:QWORD; + Unknown1:QWORD; //00000001 + user_malloc_init_for_tls :t_user_malloc_init_for_tls; + user_malloc_fini_for_tls :t_user_malloc_fini_for_tls; + user_malloc_for_tls :t_user_malloc_for_tls; + user_posix_memalign_for_tls:t_user_posix_memalign_for_tls; + user_free_for_tls :t_user_free_for_tls; + end; + + PSceLibcParam=^TSceLibcParam; + TSceLibcParam=packed record + Size:QWORD; + entry_count:DWORD; + SceLibcInternalHeap :DWORD; //1 //(entry_count > 1) + sceLibcHeapSize :PDWORD; + sceLibcHeapDelayedAlloc :PDWORD; + sceLibcHeapExtendedAlloc :PDWORD; + sceLibcHeapInitialSize :PDWORD; + _sceLibcMallocReplace :PsceLibcMallocReplace; + _sceLibcNewReplace :PsceLibcNewReplace; + sceLibcHeapHighAddressAlloc :PQWORD; //(entry_count > 2) + Need_sceLibc :PDWORD; + sceLibcHeapMemoryLock :PQWORD; //(entry_count > 4) + sceKernelInternalMemorySize :PQWORD; + _sceLibcMallocReplaceForTls :PsceLibcMallocReplaceForTls; + //The maximum amount of the memory areas for the mspace. min:0x1000000 + sceLibcMaxSystemSize :PQWORD; //(entry_count > 7) + sceLibcHeapDebugFlags :PQWORD; //(entry_count > 8) + sceLibcStdThreadStackSize :PDWORD; + Unknown3:QWORD; + sceKernelInternalMemoryDebugFlags:PDWORD; + sceLibcWorkerThreadNum :PDWORD; + sceLibcWorkerThreadPriority :PDWORD; + sceLibcThreadUnnamedObjects :PDWORD; + end; + + PSceKernelMemParam=^TSceKernelMemParam; + TSceKernelMemParam=packed record + Size:QWORD; + sceKernelExtendedPageTable :PQWORD; + sceKernelFlexibleMemorySize :PQWORD; + sceKernelExtendedMemory1 :PQWORD; + sceKernelExtendedGpuPageTable:PQWORD; + sceKernelExtendedMemory2 :PQWORD; + sceKernelExtendedCpuPageTable:PQWORD; + end; + + PSceKernelFsParam=^TSceKernelFsParam; + TSceKernelFsParam=packed record + Size:QWORD; + sceKernelFsDupDent:PQWORD; + end; + + PSceProcParam=^TSceProcParam; + TSceProcParam=packed record + Size :QWORD; //0x50 + Magic :DWORD; //"ORBI" //0x4942524F + Entry_count :DWORD; //>=1 + SDK_version :QWORD; //0x4508101 + sceProcessName :PChar; + sceUserMainThreadName :PChar; + sceUserMainThreadPriority :PDWORD; + sceUserMainThreadStackSize:PDWORD; + _sceLibcParam :PSceLibcParam; + _sceKernelMemParam :PSceKernelMemParam; + _sceKernelFsParam :PSceKernelFsParam; + sceProcessPreloadEnabled :PDWORD; + end; + + PsceModuleParam=^TsceModuleParam; + TsceModuleParam=packed record + Size :QWORD; + Magic :QWORD; + SDK_version:QWORD; + end; + +function SELF_WINDOW(i:Int64):Integer; inline; +function SELF_BLOCK_SIZE(i:Int64):Int64; inline; +function SELF_SEGMENT_INDEX(i:Int64):Integer; inline; + +function ELF64_R_SYM(i:QWORD):DWORD; inline; +function ELF64_R_TYPE(i:QWORD):DWORD; inline; +function ELF64_ST_BIND(i:Byte):Byte; inline; +function ELF64_ST_TYPE(i:Byte):Byte; inline; +function ELF64_ST_VISIBILITY(i:Byte):Byte; inline; + +function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline; +function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline; +function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline; +function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline; +function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline; +function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline; + +implementation + +function SELF_WINDOW(i:Int64):Integer; inline; +begin + Result:=(i shr SELF_PROPS_WINDOW_OFFSET) and SELF_PROPS_WINDOW_MASK; +end; + +function SELF_BLOCK_SIZE(i:Int64):Int64; inline; +begin + Result:=(i shr SELF_PROPS_BLOCK_SIZE_OFFSET) and SELF_PROPS_BLOCK_SIZE_MASK; + Result:=1 shl (Result+12) +end; + +function SELF_SEGMENT_INDEX(i:Int64):Integer; inline; +begin + Result:=(i shr SELF_PROPS_SEGMENT_INDEX_OFFSET) and SELF_PROPS_SEGMENT_INDEX_MASK; +end; + +function ELF64_R_SYM(i:QWORD):DWORD; inline; +begin + Result:=i shr 32; +end; + +function ELF64_R_TYPE(i:QWORD):DWORD; inline; +begin + Result:=i and $ffffffff; +end; + +function ELF64_ST_BIND(i:Byte):Byte; inline; +begin + Result:=i shr 4; +end; + +function ELF64_ST_TYPE(i:Byte):Byte; inline; +begin + Result:=i and $f; +end; + +function ELF64_ST_VISIBILITY(i:Byte):Byte; inline; +begin + Result:=i and 3; +end; + +function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline; +var + tmp:PtrUInt; +begin + if (alignment=0) then Exit(addr); + tmp:=addr+PtrUInt(alignment-1); + Result:=tmp-(tmp mod alignment) +end; + +function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline; +begin + Result:=Pointer(Align(PtrUInt(addr),alignment)); +end; + +function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline; +begin + Result:=addr-(addr mod alignment); +end; + +function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline; +begin + Result:=Pointer(AlignDw(PtrUInt(addr),alignment)); +end; + +function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline; +begin + Result:=(PtrUInt(addr) mod alignment)=0; +end; + +function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline; +begin + Result:=(addr mod alignment)=0; +end; + +end. + diff --git a/tools/readself/readself.lpi b/tools/readself/readself.lpi new file mode 100644 index 00000000..799f3465 --- /dev/null +++ b/tools/readself/readself.lpi @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + <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="readself.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="readself"/> + </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> diff --git a/tools/readself/readself.lpr b/tools/readself/readself.lpr new file mode 100644 index 00000000..ca47573d --- /dev/null +++ b/tools/readself/readself.lpr @@ -0,0 +1,746 @@ +program readself; + +uses + sysutils, + elf64; + +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; + 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 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 get_elf_phdr_offset(elf_hdr:p_elf64_hdr):Int64; +begin + if (elf_hdr=nil) then Exit(0); + if (elf_hdr^.e_phoff=0) then + begin + Result:=SizeOf(elf64_hdr); + end else + begin + Result:=elf_hdr^.e_phoff; + end; +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_s:Int64; + dst_ofs_s:Int64; + src_ofs_e:Int64; + dst_ofs_e: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:=elf_hdr^.e_phnum; + + if (count<>0) then + For i:=0 to count-1 do + begin + s:=elf_phdr[i].p_offset; + if (s<>0) then + begin + MinSeg:=MinInt64(s,MinSeg); + end; + s:=s+elf_phdr[i].p_filesz; + MaxSeg:=MaxInt64(s,MaxSeg); + end; + + n:=ptruint(elf_hdr)-ptruint(self_hdr); //offset to hdr + s:=MaxInt64(obj^.size,n)-n; //get size + + MinSeg:=MinInt64(MinSeg,s); + MaxSeg:=MinInt64(MaxSeg,s); + + 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_s:=self_segs[i].offset; //start offset + dst_ofs_s:=elf_phdr[s].p_offset; //start offset + + src_ofs_e:=src_ofs_s+mem_size; //end offset + dst_ofs_e:=dst_ofs_s+mem_size; //end offset + + src_ofs_s:=MinInt64(src_ofs_s,obj^.size); //bound self + src_ofs_e:=MinInt64(src_ofs_s,obj^.size); //bound self + + dst_ofs_s:=MinInt64(dst_ofs_s,obj^.elf.size); //bound elf + dst_ofs_e:=MinInt64(dst_ofs_s,obj^.elf.size); //bound elf + + mem_size:=minInt64(src_ofs_e-src_ofs_s,dst_ofs_e-dst_ofs_s); //min of two size + + Move( (Pointer(self_hdr) +src_ofs_s)^, //src + (Pointer(obj^.elf.hdr)+dst_ofs_s)^, //dst + mem_size); //size + end; + end; + + end; + else + begin + FileClose(F); + Exit(-1); + end; + end; + +end; + +procedure print_file_size(obj:p_elf_obj); +begin + Writeln('FILE Size:',obj^.size); + Writeln(); +end; + +procedure print_self_header(obj:p_elf_obj); +var + s,e:ptruint; +begin + if (obj^.self.hdr<>nil) then + begin + s:=0; + e:=obj^.self.hdr^.Header_Size+obj^.self.hdr^.Meta_size; + + Writeln('SELF Header:0x',HexStr(s,8),'..0x',HexStr(e,8),':',e); + + Writeln(' Magic :0x',HexStr(obj^.self.hdr^.Magic,8)); + Writeln(' Version :',obj^.self.hdr^.Version ); + Writeln(' Mode :',obj^.self.hdr^.Mode ); + Writeln(' Endian :',obj^.self.hdr^.Endian ); + Writeln(' Attr :',obj^.self.hdr^.Attr ); + Writeln(' Content_Type:',obj^.self.hdr^.Content_Type); + Writeln(' Program_Type:0x',HexStr(obj^.self.hdr^.Program_Type,2)); + Writeln(' Header_Size :',obj^.self.hdr^.Header_Size ); + Writeln(' Meta_size :',obj^.self.hdr^.Meta_size ); + Writeln(' File_size :',obj^.self.hdr^.File_size ); + Writeln(' Num_Segments:',obj^.self.hdr^.Num_Segments); + Writeln(' Flags :0x',HexStr(obj^.self.hdr^.Flags,4)); + Writeln(' MinSeg :0x',HexStr(obj^.self.MinSeg,8)); + Writeln(' MaxSeg :0x',HexStr(obj^.self.MaxSeg,8)); + end else + begin + Writeln('SELF Header:','not exist'); + end; + Writeln(); +end; + +procedure print_bytes(p:PByte;size:Integer); +begin + while (size<>0) do + begin + Write(HexStr(P^,2)); + Inc(P); + Dec(size); + end; +end; + +function get_program_type_str(pt:Byte):RawByteString; +begin + Result:=''; + Case pt of + SELF_PT_FAKE :Result:='(FAKE)'; + SELF_PT_NPDRM_EXEC :Result:='(NPDRM_EXEC)'; + SELF_PT_NPDRM_DYNLIB :Result:='(NPDRM_DYNLIB)'; + SELF_PT_SYSTEM_EXEC :Result:='(SYSTEM_EXEC)'; + SELF_PT_SYSTEM_DYNLIB:Result:='(SYSTEM_DYNLIB)'; + SELF_PT_HOST_KERNEL :Result:='(HOST_KERNEL)'; + SELF_PT_SECURE_MODULE:Result:='(SECURE_MODULE)'; + SELF_PT_SECURE_KERNEL:Result:='(SECURE_KERNEL)'; + else; + end; +end; + +procedure print_self_authinfo(obj:p_elf_obj); +label + _not_exist; +var + s,e,len:ptruint; + elf_hdr:p_elf64_hdr; + authinfo:p_self_authinfo; +begin + if (obj^.self.hdr<>nil) then + begin + elf_hdr:=obj^.self.elf_hdr; + s:=SizeOf(t_self_header); + s:=s+(obj^.self.hdr^.Num_Segments*SizeOf(t_self_segment)); + s:=s+get_elf_phdr_offset(elf_hdr); + s:=s+(elf_hdr^.e_phnum*SizeOf(elf64_phdr)); + s:=AlignUp(s,SELF_SEGMENT_BLOCK_ALIGNMENT); + + e:=obj^.self.hdr^.Header_Size; + + if (s>=e) then goto _not_exist; + + len:=(e-s); + + if (len<SizeOf(t_self_authinfo)) then goto _not_exist; + + Writeln('SELF authinfo:0x',HexStr(s,8),'..0x',HexStr(e,8),':',len); + + authinfo:=Pointer(Pointer(obj^.self.hdr)+s); + + Writeln(' AuthorityID :0x',HexStr(authinfo^.AuthorityID,16)); + Writeln(' Program_Type :0x',HexStr(authinfo^.Program_Type,2),' ',get_program_type_str(authinfo^.Program_Type)); + Writeln(' Program_Version:0x',HexStr(authinfo^.Program_Version,16)); + Writeln(' System_Version :0x',HexStr(authinfo^.System_Version,16)); + + Write (' Digest_SHA_256 :'); + print_bytes(@authinfo^.Digest_SHA_256,32); + Writeln; + + end else + begin + _not_exist: + Writeln('SELF authinfo:','not exist'); + end; + Writeln(); +end; + +procedure print_self_metadata(obj:p_elf_obj); +label + _not_exist; +var + s,e:ptruint; + m:PBYTE; +begin + if (obj^.self.hdr<>nil) then + begin + s:=obj^.self.hdr^.Header_Size; + e:=s+obj^.self.hdr^.Meta_size; + + if (s>=e) then goto _not_exist; + + Writeln('SELF Metadata:0x',HexStr(s,8),'..0x',HexStr(e,8),':',(e-s)); + + m:=Pointer(Pointer(obj^.self.hdr)+s); + + Writeln(' Offset(h)|00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F'); + Write (' ---------+-----------------------------------------------'); + + for s:=s to e-1 do + begin + if ((s mod 16)=0) then + begin + Writeln(); + Write(' 0x',HexStr(s-(s mod 16),7),'|'); + end; + Write(HexStr(m^,2),' '); + Inc(m); + end; + + Writeln; + end else + begin + _not_exist: + Writeln('SELF Metadata:','not exist'); + end; + Writeln; +end; + +function get_seg_flags_str(flags:QWORD):RawByteString; +begin + Result:='_______'; + + if ((flags and SELF_PROPS_ORDERED )<>0) then Result[1]:='O'; + if ((flags and SELF_PROPS_ENCRYPTED )<>0) then Result[2]:='E'; + if ((flags and SELF_PROPS_SIGNED )<>0) then Result[3]:='S'; + if ((flags and SELF_PROPS_COMPRESSED )<>0) then Result[4]:='C'; + if ((flags and SELF_PROPS_BLOCKED )<>0) then Result[5]:='B'; + if ((flags and SELF_PROPS_HAS_DIGESTS)<>0) then Result[6]:='D'; + if ((flags and SELF_PROPS_HAS_EXTENTS)<>0) then Result[7]:='E'; +end; + +procedure print_self_segs(obj:p_elf_obj); +label + _not_exist; +var + i,count:Integer; + seg:p_self_segment; + s,e:ptruint; +begin + if (obj^.self.segs<>nil) then + begin + count:=obj^.self.hdr^.Num_Segments; + + if (count=0) then goto _not_exist; + + s:=ptruint(obj^.self.segs)-ptruint(obj^.self.hdr); + e:=s+(count*SizeOf(t_self_segment)); + + Writeln('SELF Segments Headers:0x',HexStr(s,8),'..0x',HexStr(e,8),':',(e-s)); + + seg:=obj^.self.segs; + + Writeln(' Num Flags W BlockSize SEGID Offset Filesz Memsz'); + + For i:=0 to count-1 do + begin + Write(' ',i:3,' '); + Write(get_seg_flags_str(seg^.flags) ,' '); + Write(SELF_WINDOW(seg^.flags) ,' '); + Write('0x',HexStr(SELF_BLOCK_SIZE(seg^.flags),8),' '); + Write(SELF_SEGMENT_INDEX(seg^.flags):5,' '); + + Write('0x',HexStr(seg^.offset,8),' '); + Write('0x',HexStr(seg^.filesz,8),' '); + Write('0x',HexStr(seg^.memsz ,8),' '); + + Writeln(); + Inc(seg); + end; + end else + begin + _not_exist: + Writeln('SELF Segments Headers:','not exist'); + end; + Writeln(); +end; + +function get_elf_hdr_offset(obj:p_elf_obj):Int64; +begin + if (obj^.self.hdr<>nil) then + begin + Result:=obj^.self.hdr^.Num_Segments*SizeOf(t_self_segment); + end else + begin + Result:=0; + end; +end; + +function get_e_class_str(e_class:Byte):RawByteString; +begin + Result:=''; + Case e_class of + 0:Result:='(SNONE)'; + 1:Result:='(S32)'; + 2:Result:='(S64)'; + else; + end; +end; + +function get_e_data_str(e_data:Byte):RawByteString; +begin + Result:=''; + Case e_data of + 0:Result:='(NONE)'; + 1:Result:='(2LSB)'; + 2:Result:='(2MSB)'; + else; + end; +end; + +function get_e_type_str(e_type:Word):RawByteString; +begin + Result:=''; + Case e_type of + ET_NONE :Result:='(NONE)'; + ET_REL :Result:='(REL)'; + ET_EXEC :Result:='(EXEC)'; + ET_DYN :Result:='(DYN)'; + ET_CORE :Result:='(CORE)'; + ET_SCE_EXEC :Result:='(SCE_EXEC)'; + ET_SCE_REPLAY_EXEC:Result:='(SCE_REPLAY_EXEC)'; + ET_SCE_RELEXEC :Result:='(SCE_RELEXEC)'; + ET_SCE_STUBLIB :Result:='(SCE_STUBLIB)'; + ET_SCE_DYNEXEC :Result:='(SCE_DYNEXEC)'; + ET_SCE_DYNAMIC :Result:='(SCE_DYNAMIC)'; + else; + end; +end; + +function get_e_machine_str(e_machine:Word):RawByteString; +begin + Result:=''; + Case e_machine of + EM_NONE :Result:='(NONE)'; + EM_X86_64:Result:='(X86_64)'; + else; + end; +end; + +function get_osabi_name(e_machine:Word):RawByteString; +begin + Result:=''; + Case e_machine of + 0:Result:='(NONE)'; + 3:Result:='(LINUX)'; + 9:Result:='(FREEBSD)'; + else; + end; +end; + +procedure print_elf_header(obj:p_elf_obj); +var + s,e:ptruint; + elf_hdr:p_elf64_hdr; +begin + if (obj^.is_encrypted<>0) then + begin + Writeln('ELF Header:','is_encrypted'); + Exit; + end; + + if (obj^.elf.hdr<>nil) then + begin + elf_hdr:=obj^.elf.hdr; + s:=get_elf_hdr_offset(obj); + e:=s+SizeOf(elf64_hdr); + + Writeln('ELF Header:0x',HexStr(s,8),'..0x',HexStr(e,8),':',(e-s)); + + Writeln(' Magic :0x',HexStr(PDWORD(@elf_hdr^.e_ident)^,8)); + Writeln(' Class: :',elf_hdr^.e_ident[EI_CLASS],' ',get_e_class_str(elf_hdr^.e_ident[EI_CLASS])); + Writeln(' Data: :',elf_hdr^.e_ident[EI_DATA],' ',get_e_data_str(elf_hdr^.e_ident[EI_DATA])); + Writeln(' Version: :',elf_hdr^.e_ident[EI_VERSION]); + Writeln(' OS/ABI: :',elf_hdr^.e_ident[EI_OSABI],' ',get_osabi_name(elf_hdr^.e_ident[EI_OSABI])); + Writeln(' ABI Version:',elf_hdr^.e_ident[EI_ABIVERSION]); + + Writeln(' e_type :0x',HexStr(elf_hdr^.e_type,4),' ',get_e_type_str(elf_hdr^.e_type)); + Writeln(' e_machine :',elf_hdr^.e_machine,' ',get_e_machine_str(elf_hdr^.e_machine)); + Writeln(' e_version :',elf_hdr^.e_version ); + Writeln(' e_entry :0x',HexStr(elf_hdr^.e_entry,8)); + Writeln(' e_phoff :0x',HexStr(elf_hdr^.e_phoff,8)); + Writeln(' e_shoff :0x',HexStr(elf_hdr^.e_shoff,8)); + Writeln(' e_flags :0x',HexStr(elf_hdr^.e_flags,8)); + Writeln(' e_ehsize :',elf_hdr^.e_ehsize ); + Writeln(' e_phentsize:',elf_hdr^.e_phentsize); + Writeln(' e_phnum :',elf_hdr^.e_phnum ); + Writeln(' e_shentsize:',elf_hdr^.e_shentsize); + Writeln(' e_shnum :',elf_hdr^.e_shnum ); + Writeln(' e_shstrndx :',elf_hdr^.e_shstrndx ); + + end else + begin + Writeln('ELF Header:','not exist'); + end; + Writeln(); +end; + +function get_pt_name(p_type:DWORD):RawByteString; +begin + Result:=''; + Case p_type of + PT_NULL :Result:='NULL'; + PT_LOAD :Result:='LOAD'; + PT_DYNAMIC :Result:='DYNAMIC'; + PT_INTERP :Result:='INTERP'; + PT_NOTE :Result:='NOTE'; + PT_SHLIB :Result:='SHLIB'; + PT_PHDR :Result:='PHDR'; + PT_TLS :Result:='TLS'; + PT_SCE_RELA :Result:='SCE_RELA'; + PT_SCE_DYNLIBDATA :Result:='SCE_DYNLIBDATA'; + PT_SCE_PROCPARAM :Result:='SCE_PROCPARAM'; + PT_SCE_MODULE_PARAM:Result:='SCE_MODULE_PARAM'; + PT_SCE_RELRO :Result:='SCE_RELRO'; + PT_GNU_EH_FRAME :Result:='GNU_EH_FRAME'; + PT_GNU_STACK :Result:='GNU_STACK'; + PT_SCE_COMMENT :Result:='SCE_COMMENT'; + PT_SCE_VERSION :Result:='SCE_VERSION'; + PT_SCE_SEGSYM :Result:='SCE_SEGSYM'; + else Result:='0x'+HexStr(p_type,8); + end; +end; + +function get_p_flags_str(flags:DWORD):RawByteString; +begin + Result:='___'; + + if ((flags and PF_X)<>0) then Result[1]:='X'; + if ((flags and PF_W)<>0) then Result[2]:='W'; + if ((flags and PF_R)<>0) then Result[3]:='R'; +end; + +procedure print_elf_phdr(obj:p_elf_obj); +var + s,e:ptruint; + elf_hdr :p_elf64_hdr; + elf_phdr:p_elf64_phdr; + i,count:Integer; + str:RawByteString; +begin + if (obj^.is_encrypted<>0) then + begin + Writeln('ELF Header:','is_encrypted'); + Exit; + end; + + if (obj^.elf.hdr<>nil) then + begin + elf_hdr :=obj^.elf.hdr; + elf_phdr:=get_elf_phdr(elf_hdr); + count:=elf_hdr^.e_phnum; + + s:=get_elf_hdr_offset(obj); + s:=s+get_elf_phdr_offset(elf_hdr); + e:=s+count*SizeOf(elf64_phdr); + + Writeln('Program Headers:0x',HexStr(s,8),'..0x',HexStr(e,8),':',(e-s)); + + Writeln(' Type Flags Offset VirtAddr PhysAddr FileSize MemSize Align'); + if (count<>0) then + For i:=0 to count-1 do + begin + + str:=get_pt_name(elf_phdr^.p_type); + str:=str+space(16-Length(str)); + + Write(' ',str,' '); + + Write(get_p_flags_str(elf_phdr^.p_flags),' '); + + Write('0x'+HexStr(elf_phdr^.p_offset,8),' '); + Write('0x'+HexStr(elf_phdr^.p_vaddr ,8),' '); + Write('0x'+HexStr(elf_phdr^.p_paddr ,8),' '); + Write('0x'+HexStr(elf_phdr^.p_filesz,8),' '); + Write('0x'+HexStr(elf_phdr^.p_memsz ,8),' '); + Write('0x'+HexStr(elf_phdr^.p_align ,8),' '); + + Writeln; + + Inc(elf_phdr); + end; + + end else + begin + Writeln('Program Headers:','not exist'); + end; + Writeln(); +end; + +type + t_print_param=( + pp_file_size, + pp_self_header, + pp_self_segs, + pp_self_authinfo, + pp_self_metadata, + pp_file_header, + pp_program_headers + ); + t_print_param_set=Set of t_print_param; + +var + print_param:t_print_param_set=[]; + FileName:RawByteString; + +procedure parse_param; +var + i:Integer; + S:RawByteString; +begin + print_param:=[]; + For i:=1 to ParamCount do + begin + S:=Trim(ParamStr(i)); + case S of + '-a','-all' :print_param:=[pp_file_size, + pp_self_header, + pp_self_segs, + pp_self_authinfo, + pp_self_metadata, + pp_file_header, + pp_program_headers]; + + '-F','--file_size' :print_param:=print_param+[pp_file_size ]; + '-H','--self_header' :print_param:=print_param+[pp_self_header ]; + '-S','--self_segs' :print_param:=print_param+[pp_self_segs ]; + '-A','--self_authinfo' :print_param:=print_param+[pp_self_authinfo ]; + '-M','--self_metadata' :print_param:=print_param+[pp_self_metadata ]; + '-h','--file-header' :print_param:=print_param+[pp_file_header ]; + '-l','--program-headers':print_param:=print_param+[pp_program_headers]; + else + FileName:=S; + end; + end; +end; + +var + r:Integer; + obj:elf_obj; + +begin + parse_param; + + r:=load_self(FileName,@obj); + + if (r=0) then + begin + if (pp_file_size in print_param) then print_file_size (@obj); + if (pp_self_header in print_param) then print_self_header (@obj); + if (pp_self_segs in print_param) then print_self_segs (@obj); + if (pp_self_authinfo in print_param) then print_self_authinfo(@obj); + if (pp_self_metadata in print_param) then print_self_metadata(@obj); + if (pp_file_header in print_param) then print_elf_header (@obj); + if (pp_program_headers in print_param) then print_elf_phdr (@obj); + end else + begin + Writeln('Error(',r,') load file:',FileName); + end; + + free_elf_obj(@obj); + + readln; +end. +