upload files
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.36422.26
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GTASPRXPS4", "GTASPRXPS4.vcxproj", "{82CE3C65-C144-4D91-8A5B-324A963546C3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ORBIS = Debug|ORBIS
|
||||
Release|ORBIS = Release|ORBIS
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{82CE3C65-C144-4D91-8A5B-324A963546C3}.Debug|ORBIS.ActiveCfg = Debug|ORBIS
|
||||
{82CE3C65-C144-4D91-8A5B-324A963546C3}.Debug|ORBIS.Build.0 = Debug|ORBIS
|
||||
{82CE3C65-C144-4D91-8A5B-324A963546C3}.Release|ORBIS.ActiveCfg = Release|ORBIS
|
||||
{82CE3C65-C144-4D91-8A5B-324A963546C3}.Release|ORBIS.Build.0 = Release|ORBIS
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2A7492B0-84F4-4E66-8BCA-1CF48EB16BC0}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ORBIS">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ORBIS</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ORBIS">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ORBIS</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{82ce3c65-c144-4d91-8a5b-324a963546c3}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup Condition="'$(DebuggerFlavor)'=='ORBISDebugger'" Label="OverrideDebuggerDefaults">
|
||||
<!--LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand-->
|
||||
<!--LocalDebuggerCommandArguments></LocalDebuggerCommandArguments-->
|
||||
<!--LocalDebuggerTarget></LocalDebuggerTarget-->
|
||||
<!--LocalDebuggerWorkingDirectory>$(ProjectDir)</LocalDebuggerWorkingDirectory-->
|
||||
<!--LocalRunCommandLine></LocalRunCommandLine-->
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Condition="Exists('$(VCTargetsPath)\BuildCustomizations\OrbisWavePsslc.props')" Project="$(VCTargetsPath)\BuildCustomizations\OrbisWavePsslc.props" />
|
||||
<Import Condition="Exists('$(VCTargetsPath)\BuildCustomizations\SCU.props')" Project="$(VCTargetsPath)\BuildCustomizations\SCU.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">
|
||||
<TargetName>GTAServer</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">
|
||||
<TargetName>GTAServer</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<Addressing>NonAslr</Addressing>
|
||||
<AdditionalDependencies>$(SCE_ORBIS_SDK_DIR)\target\lib\libSceImeDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSysmodule_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceMsgDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceCommonDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSystemService_stub.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSystemService_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libScePosix_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceNet_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceHttp_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libScePad_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceUserService_stub_weak.a;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>cd /d "$(TargetDir)"
|
||||
call "$(TargetDir)make_sprx.bat"
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<OptimizationLevel>Level2</OptimizationLevel>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd /d "$(TargetDir)"
|
||||
call "$(TargetDir)make_sprx.bat"
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(SCE_ORBIS_SDK_DIR)\target\lib\libSceImeDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSysmodule_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceMsgDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceCommonDialog_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSystemService_stub.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceSystemService_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libScePosix_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceNet_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceHttp_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libScePad_stub_weak.a;$(SCE_ORBIS_SDK_DIR)\target\lib\libSceUserService_stub_weak.a;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="prx.cpp" />
|
||||
<ClCompile Include="Syscall.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Syscall.h" />
|
||||
</ItemGroup>
|
||||
<Import Condition="'$(ConfigurationType)' == 'Makefile' and Exists('$(VCTargetsPath)\Platforms\$(Platform)\SCE.Makefile.$(Platform).targets')" Project="$(VCTargetsPath)\Platforms\$(Platform)\SCE.Makefile.$(Platform).targets" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Condition="Exists('$(VCTargetsPath)\BuildCustomizations\OrbisWavePsslc.targets')" Project="$(VCTargetsPath)\BuildCustomizations\OrbisWavePsslc.targets" />
|
||||
<Import Condition="Exists('$(VCTargetsPath)\BuildCustomizations\SCU.targets')" Project="$(VCTargetsPath)\BuildCustomizations\SCU.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;cc;s;asm</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;pssli</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Shader Files">
|
||||
<UniqueIdentifier>{5FAE8098-8EE5-44A0-ABB6-C797B807CDE6}</UniqueIdentifier>
|
||||
<Extensions>pssl;scu</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="prx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Syscall.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Syscall.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,30 @@
|
||||
prx.cpp
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(257,12): warning : unused variable 'g_user_logged_in' [-Wunused-variable]
|
||||
static int g_user_logged_in = 0;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(258,29): warning : unused variable 'g_user_id' [-Wunused-variable]
|
||||
static SceUserServiceUserId g_user_id = 1;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(259,12): warning : unused variable 'g_login_event_pending' [-Wunused-variable]
|
||||
static int g_login_event_pending = 1;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(260,12): warning : unused variable 'g_logout_event_pending' [-Wunused-variable]
|
||||
static int g_logout_event_pending = 0;
|
||||
^
|
||||
4 warnings generated.
|
||||
orbis-ld 4.50.0.4213 (rel,orbis,4.500 @342832 x64) C:\Program Files (x86)\SCE\ORBIS SDKs\4.500\host_tools\bin\orbis-ld.exe
|
||||
Command line : warning : L0474: The --addressing=<mode> option only applies to main modules and will be ignored
|
||||
GTASPRXPS4.vcxproj -> C:\Users\DontCry361x\Documents\GTASPRXPS4\ORBIS_Debug\GTAServer.prx
|
||||
[INFO] Running fself.py ...
|
||||
loading elf file: GTAServer.prx
|
||||
saving fake signed elf file: test.sprx
|
||||
processing segment #00...
|
||||
processing segment #01...
|
||||
processing segment #02...
|
||||
processing segment #07...
|
||||
processing segment #08...
|
||||
done
|
||||
[OK] SPRX created.
|
||||
[INFO] Uploading to PS4...
|
||||
Connecting to 192.168.137.241:2121 ...
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(148,5): warning MSB5021: Terminating the task executable "cmd" and its child processes because the build was canceled.
|
||||
@@ -0,0 +1,2 @@
|
||||
#TargetFrameworkVersion=v4.0:PlatformToolSet=Clang:EnableManagedIncrementalBuild=:VCToolArchitecture=:WindowsTargetPlatformVersion=
|
||||
Debug|ORBIS|C:\Users\DontCry361x\Documents\GTASPRXPS4\|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,816 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, struct, traceback
|
||||
import hashlib, hmac
|
||||
import argparse, re, string
|
||||
|
||||
def int_with_base_type(val):
|
||||
return int(val, 0)
|
||||
|
||||
def try_parse_int(x, base=0):
|
||||
try:
|
||||
return int(x, base) if isinstance(x, str) else int(x)
|
||||
except:
|
||||
return None
|
||||
|
||||
def align_up(x, alignment):
|
||||
return (x + (alignment - 1)) & ~(alignment - 1)
|
||||
|
||||
def align_down(x, alignment):
|
||||
return x & ~(alignment - 1)
|
||||
|
||||
def ilog2(x):
|
||||
if x <= 0:
|
||||
raise ValueError('math domain error')
|
||||
return len(bin(x)) - 3
|
||||
|
||||
def is_intervals_overlap(p1, p2):
|
||||
return p1[0] <= p2[1] and p1[1] <= p2[0]
|
||||
|
||||
def check_file_magic(f, expected_magic):
|
||||
old_offset = f.tell()
|
||||
try:
|
||||
magic = f.read(len(expected_magic))
|
||||
except:
|
||||
return False
|
||||
finally:
|
||||
f.seek(old_offset)
|
||||
return magic == expected_magic
|
||||
|
||||
def parse_version(version):
|
||||
major, minor, patch = (version >> 8) & 0xFF, version & 0xFF, 0 # FIXME
|
||||
major = 10 * (major >> 4) + (major & 0xF)
|
||||
minor = 10 * (minor >> 4) + (minor & 0xF)
|
||||
return '{0:d}.{1:02d}.{2:03d}'.format(major, minor, patch)
|
||||
|
||||
def sha256(data):
|
||||
return hashlib.sha256(data).digest()
|
||||
|
||||
def hmac_sha256(key, data):
|
||||
return hmac.new(key=key, msg=data, digestmod=hashlib.sha256).digest()
|
||||
|
||||
class ElfError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.msg)
|
||||
|
||||
class ElfEHdr(object):
|
||||
FMT = '<4s5B6xB'
|
||||
EX_FMT = '<2HI3QI6H'
|
||||
|
||||
MAGIC = '\x7FELF'
|
||||
CLASS64 = 0x2
|
||||
DATA2LSB = 0x1
|
||||
EM_X86_64 = 0x3E
|
||||
EV_CURRENT = 0x1
|
||||
|
||||
ET_EXEC = 0x2
|
||||
ET_SCE_EXEC = 0xFE00
|
||||
ET_SCE_EXEC_ASLR = 0xFE10
|
||||
ET_SCE_DYNAMIC = 0xFE18
|
||||
|
||||
def __init__(self):
|
||||
self.magic = None
|
||||
self.machine_class = None
|
||||
self.data_encoding = None
|
||||
self.version = None
|
||||
self.os_abi = None
|
||||
self.abi_version = None
|
||||
self.nident_size = None
|
||||
self.type = None
|
||||
self.machine = None
|
||||
self.version = None
|
||||
self.entry = None
|
||||
self.phoff = None
|
||||
self.shoff = None
|
||||
self.flags = None
|
||||
self.ehsize = None
|
||||
self.phentsize = None
|
||||
self.phnum = None
|
||||
self.shentsize = None
|
||||
self.shnum = None
|
||||
self.shstridx = None
|
||||
|
||||
def load(self, f):
|
||||
if not check_file_magic(f, ElfEHdr.MAGIC):
|
||||
raise ElfError('Invalid magic.')
|
||||
|
||||
self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size = struct.unpack(ElfEHdr.FMT, f.read(struct.calcsize(ElfEHdr.FMT)))
|
||||
if self.machine_class != ElfEHdr.CLASS64 or self.data_encoding != ElfEHdr.DATA2LSB:
|
||||
raise ElfError('Unsupported class or data encoding.')
|
||||
self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx = struct.unpack(ElfEHdr.EX_FMT, f.read(struct.calcsize(ElfEHdr.EX_FMT)))
|
||||
if self.machine != ElfEHdr.EM_X86_64 or self.version != ElfEHdr.EV_CURRENT:
|
||||
raise ElfError('Unsupported machine type or version.')
|
||||
if self.phentsize != struct.calcsize(ElfPHdr.FMT) or (self.shentsize > 0 and self.shentsize != struct.calcsize(ElfSHdr.FMT)):
|
||||
raise ElfError('Unsupported header entry size.')
|
||||
if self.type not in [ElfEHdr.ET_EXEC, ElfEHdr.ET_SCE_EXEC, ElfEHdr.ET_SCE_EXEC_ASLR, ElfEHdr.ET_SCE_DYNAMIC]:
|
||||
raise ElfError('Unsupported type.')
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfEHdr.FMT, self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size))
|
||||
f.write(struct.pack(ElfEHdr.EX_FMT, self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx))
|
||||
|
||||
def has_segments(self):
|
||||
return self.phentsize > 0 and self.phnum > 0
|
||||
|
||||
def has_sections(self):
|
||||
return self.shentsize > 0 and self.shnum > 0
|
||||
|
||||
class ElfPHdr(object):
|
||||
FMT = '<2I6Q'
|
||||
|
||||
PT_LOAD = 0x1
|
||||
PT_DYNAMIC = 0x2
|
||||
PT_INTERP = 0x3
|
||||
PT_TLS = 0x7
|
||||
PT_GNU_EH_FRAME = 0x6474E550
|
||||
PT_GNU_STACK = 0x6474E551
|
||||
PT_SCE_RELA = 0x60000000,
|
||||
PT_SCE_DYNLIBDATA = 0x61000000
|
||||
PT_SCE_PROCPARAM = 0x61000001
|
||||
PT_SCE_MODULE_PARAM = 0x61000002
|
||||
PT_SCE_RELRO = 0x61000010
|
||||
PT_SCE_COMMENT = 0x6FFFFF00
|
||||
PT_SCE_VERSION = 0x6FFFFF01
|
||||
|
||||
PF_EXEC = 0x1
|
||||
PF_WRITE = 0x2
|
||||
PF_READ = 0x4
|
||||
PF_READ_EXEC = PF_READ | PF_EXEC
|
||||
PF_READ_WRITE = PF_READ | PF_WRITE
|
||||
|
||||
def __init__(self, idx):
|
||||
self.idx = idx
|
||||
self.type = None
|
||||
self.flags = None
|
||||
self.offset = None
|
||||
self.vaddr = None
|
||||
self.paddr = None
|
||||
self.filesz = None
|
||||
self.memsz = None
|
||||
self.align = None
|
||||
|
||||
def load(self, f):
|
||||
self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align = struct.unpack(ElfPHdr.FMT, f.read(struct.calcsize(ElfPHdr.FMT)))
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfPHdr.FMT, self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align))
|
||||
|
||||
def name(self):
|
||||
if self.type == ElfPHdr.PT_LOAD:
|
||||
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
|
||||
return '.text'
|
||||
elif (self.flags & ElfPHdr.PF_READ_WRITE) == ElfPHdr.PF_READ_WRITE:
|
||||
return '.data'
|
||||
else:
|
||||
return '.load_{0:02}'.format(self.idx)
|
||||
else:
|
||||
return {
|
||||
ElfPHdr.PT_DYNAMIC: '.dynamic',
|
||||
ElfPHdr.PT_INTERP: '.interp',
|
||||
ElfPHdr.PT_TLS: '.tls',
|
||||
ElfPHdr.PT_GNU_EH_FRAME: '.eh_frame_hdr',
|
||||
ElfPHdr.PT_SCE_DYNLIBDATA: '.sce_dynlib_data',
|
||||
ElfPHdr.PT_SCE_PROCPARAM: '.sce_process_param',
|
||||
ElfPHdr.PT_SCE_MODULE_PARAM: '.sce_module_param',
|
||||
ElfPHdr.PT_SCE_COMMENT: '.sce_comment',
|
||||
}.get(self.type, None)
|
||||
|
||||
def class_name(self):
|
||||
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
|
||||
return 'CODE'
|
||||
else:
|
||||
return 'DATA'
|
||||
|
||||
class ElfSHdr(object):
|
||||
FMT = '<2I4Q2I2Q'
|
||||
|
||||
def __init__(self, idx):
|
||||
self.idx = idx
|
||||
self.name = None
|
||||
self.type = None
|
||||
self.flags = None
|
||||
self.addr = None
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.link = None
|
||||
self.info = None
|
||||
self.align = None
|
||||
self.entsize = None
|
||||
|
||||
def load(self, f):
|
||||
self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize = struct.unpack(ElfSHdr.FMT, f.read(struct.calcsize(ElfSHdr.FMT)))
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfSHdr.FMT, self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize))
|
||||
|
||||
class ElfFile(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.ehdr = None
|
||||
self.phdrs = None
|
||||
self.shdrs = None
|
||||
self.file_size = None
|
||||
self.digest = None
|
||||
self.segments = None
|
||||
self.sections = None
|
||||
self.ignore_shdrs = 'ignore_shdrs' in kwargs and kwargs['ignore_shdrs']
|
||||
|
||||
def load(self, f):
|
||||
start_offset = f.tell()
|
||||
data = f.read()
|
||||
self.file_size = len(data)
|
||||
self.digest = sha256(data)
|
||||
f.seek(start_offset)
|
||||
|
||||
self.ehdr = ElfEHdr()
|
||||
self.ehdr.load(f)
|
||||
|
||||
if self.ignore_shdrs:
|
||||
self.ehdr.shnum = 0
|
||||
|
||||
self.phdrs = []
|
||||
self.segments = []
|
||||
if self.ehdr.has_segments():
|
||||
for i in xrange(self.ehdr.phnum):
|
||||
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
|
||||
phdr = ElfPHdr(i)
|
||||
phdr.load(f)
|
||||
self.phdrs.append(phdr)
|
||||
if phdr.filesz > 0:
|
||||
f.seek(start_offset + phdr.offset)
|
||||
data = f.read(phdr.filesz)
|
||||
else:
|
||||
data = ''
|
||||
self.segments.append(data)
|
||||
|
||||
self.shdrs = []
|
||||
self.sections = []
|
||||
if self.ehdr.has_sections():
|
||||
for i in xrange(self.ehdr.shnum):
|
||||
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
|
||||
shdr = ElfSHdr(i)
|
||||
shdr.load(f)
|
||||
self.shdrs.append(shdr)
|
||||
if phdr.filesz > 0:
|
||||
f.seek(start_offset + shdr.offset)
|
||||
data = f.read(phdr.filesz)
|
||||
else:
|
||||
data = ''
|
||||
self.sections.append(data)
|
||||
|
||||
def save(self, f, no_sections=False):
|
||||
start_offset = f.tell()
|
||||
|
||||
self.ehdr.save(f)
|
||||
|
||||
if not no_sections:
|
||||
if self.ehdr.has_sections():
|
||||
for i in xrange(self.ehdr.shnum):
|
||||
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
|
||||
shdr = self.shdrs[i]
|
||||
shdr.save(f)
|
||||
|
||||
if self.ehdr.has_segments():
|
||||
for i in xrange(self.ehdr.phnum):
|
||||
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
|
||||
phdr = self.phdrs[i]
|
||||
phdr.save(f)
|
||||
|
||||
DIGEST_SIZE = 0x20
|
||||
SIGNATURE_SIZE = 0x100
|
||||
BLOCK_SIZE = 0x4000
|
||||
DEFAULT_BLOCK_SIZE = 0x1000
|
||||
|
||||
SELF_CONTROL_BLOCK_TYPE_NPDRM = 0x3
|
||||
SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE = 0x13
|
||||
SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE = 0xD
|
||||
|
||||
EMPTY_DIGEST = '\0' * DIGEST_SIZE
|
||||
EMPTY_SIGNATURE = '\0' * SIGNATURE_SIZE
|
||||
|
||||
class SignedElfEntry(object):
|
||||
FMT = '<4Q'
|
||||
|
||||
PROPS_ORDER_SHIFT = 0
|
||||
PROPS_ORDER_MASK = 0x1
|
||||
PROPS_ENCRYPTED_SHIFT = 1
|
||||
PROPS_ENCRYPTED_MASK = 0x1
|
||||
PROPS_SIGNED_SHIFT = 2
|
||||
PROPS_SIGNED_MASK = 0x1
|
||||
PROPS_COMPRESSED_SHIFT = 3
|
||||
PROPS_COMPRESSED_MASK = 0x1
|
||||
PROPS_WINDOW_BITS_SHIFT = 8
|
||||
PROPS_WINDOW_BITS_MASK = 0x7
|
||||
PROPS_HAS_BLOCKS_SHIFT = 11
|
||||
PROPS_HAS_BLOCKS_MASK = 0x1
|
||||
PROPS_BLOCK_SIZE_SHIFT = 12
|
||||
PROPS_BLOCK_SIZE_MASK = 0xF
|
||||
PROPS_HAS_DIGESTS_SHIFT = 16
|
||||
PROPS_HAS_DIGESTS_MASK = 0x1
|
||||
PROPS_HAS_EXTENTS_SHIFT = 17
|
||||
PROPS_HAS_EXTENTS_MASK = 0x1
|
||||
PROPS_HAS_META_SEGMENT_SHIFT = 20
|
||||
PROPS_HAS_META_SEGMENT_MASK = 0x1
|
||||
PROPS_SEGMENT_INDEX_SHIFT = 20
|
||||
PROPS_SEGMENT_INDEX_MASK = 0xFFFF
|
||||
PROPS_DEFAULT_BLOCK_SIZE = 0x1000
|
||||
PROPS_META_SEGMENT_MASK = 0xF0000
|
||||
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
|
||||
self.props = None
|
||||
self.offset = None
|
||||
self.filesz = None
|
||||
self.memsz = None
|
||||
|
||||
self.data = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfEntry.FMT, self.props, self.offset, self.filesz, self.memsz))
|
||||
|
||||
@property
|
||||
def order(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_ORDER_SHIFT) & SignedElfEntry.PROPS_ORDER_MASK
|
||||
|
||||
@order.setter
|
||||
def order(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_ORDER_MASK << SignedElfEntry.PROPS_ORDER_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_ORDER_MASK) << SignedElfEntry.PROPS_ORDER_SHIFT
|
||||
|
||||
@property
|
||||
def encrypted(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_ENCRYPTED_SHIFT) & SignedElfEntry.PROPS_ENCRYPTED_MASK) != 0
|
||||
|
||||
@encrypted.setter
|
||||
def encrypted(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT
|
||||
|
||||
@property
|
||||
def signed(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_SIGNED_SHIFT) & SignedElfEntry.PROPS_SIGNED_MASK) != 0
|
||||
|
||||
@signed.setter
|
||||
def signed(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT
|
||||
|
||||
@property
|
||||
def compressed(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_COMPRESSED_SHIFT) & SignedElfEntry.PROPS_COMPRESSED_MASK) != 0
|
||||
|
||||
@compressed.setter
|
||||
def compressed(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT
|
||||
|
||||
@property
|
||||
def has_blocks(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT) & SignedElfEntry.PROPS_HAS_BLOCKS_MASK) != 0
|
||||
|
||||
@has_blocks.setter
|
||||
def has_blocks(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT
|
||||
|
||||
@property
|
||||
def has_digests(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT) & SignedElfEntry.PROPS_HAS_DIGESTS_MASK) != 0
|
||||
|
||||
@has_digests.setter
|
||||
def has_digests(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT
|
||||
|
||||
@property
|
||||
def has_extents(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT) & SignedElfEntry.PROPS_HAS_EXTENTS_MASK) != 0
|
||||
|
||||
@has_extents.setter
|
||||
def has_extents(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT
|
||||
|
||||
@property
|
||||
def has_meta_segment(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT) & SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK) != 0
|
||||
|
||||
@has_meta_segment.setter
|
||||
def has_meta_segment(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT
|
||||
|
||||
@property
|
||||
def wbits(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_WINDOW_BITS_SHIFT) & SignedElfEntry.PROPS_WINDOW_BITS_MASK
|
||||
|
||||
@wbits.setter
|
||||
def wbits(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_WINDOW_BITS_MASK << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_WINDOW_BITS_MASK) << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT
|
||||
|
||||
@property
|
||||
def block_size(self):
|
||||
if self.has_blocks:
|
||||
return 1 << (12 + (self.props >> SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT) & SignedElfEntry.PROPS_BLOCK_SIZE_MASK)
|
||||
else:
|
||||
return DEFAULT_BLOCK_SIZE
|
||||
|
||||
@block_size.setter
|
||||
def block_size(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_BLOCK_SIZE_MASK << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT)
|
||||
if self.has_blocks:
|
||||
value = ilog2(value) - 12
|
||||
else:
|
||||
value = 0 # TODO: check
|
||||
self.props |= (value & SignedElfEntry.PROPS_BLOCK_SIZE_MASK) << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT
|
||||
|
||||
@property
|
||||
def segment_index(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT) & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK
|
||||
|
||||
@wbits.setter
|
||||
def segment_index(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_SEGMENT_INDEX_MASK << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK) << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT
|
||||
|
||||
def is_meta_segment(self): # TODO: check
|
||||
return (self.props & SignedElfEntry.PROPS_META_SEGMENT_MASK) != 0
|
||||
|
||||
def __repr__(self):
|
||||
return 'prs:0x{0:X} ofs:0x{1:X} fsz:0x{2:X} msz:0x{3:X}'.format(self.props, self.offset, self.filesz, self.memsz)
|
||||
|
||||
class SignedElfExInfo(object):
|
||||
FMT = '<4Q32s'
|
||||
|
||||
PTYPE_FAKE = 0x1
|
||||
PTYPE_NPDRM_EXEC = 0x4
|
||||
PTYPE_NPDRM_DYNLIB = 0x5
|
||||
PTYPE_SYSTEM_EXEC = 0x8
|
||||
PTYPE_SYSTEM_DYNLIB = 0x9 # including Mono binaries
|
||||
PTYPE_HOST_KERNEL = 0xC
|
||||
PTYPE_SECURE_MODULE = 0xE
|
||||
PTYPE_SECURE_KERNEL = 0xF
|
||||
|
||||
def __init__(self):
|
||||
self.paid = None
|
||||
self.ptype = None
|
||||
self.app_version = None
|
||||
self.fw_version = None
|
||||
self.digest = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfExInfo.FMT, self.paid, self.ptype, self.app_version, self.fw_version, self.digest))
|
||||
|
||||
class SignedElfNpdrmControlBlock(object):
|
||||
FMT = '<H14x19s13s'
|
||||
|
||||
def __init__(self):
|
||||
self.type = SELF_CONTROL_BLOCK_TYPE_NPDRM
|
||||
self.content_id = None
|
||||
self.random_pad = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfNpdrmControlBlock.FMT, self.type, self.content_id, self.random_pad))
|
||||
|
||||
class SignedElfMetaBlock(object):
|
||||
FMT = '<80x'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfMetaBlock.FMT))
|
||||
|
||||
class SignedElfMetaFooter(object):
|
||||
FMT = '<48xI28x'
|
||||
|
||||
def __init__(self):
|
||||
self.unk1 = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfMetaFooter.FMT, self.unk1))
|
||||
|
||||
class SignedElfFile(object):
|
||||
COMMON_HEADER_FMT = '<4s4B'
|
||||
EXT_HEADER_FMT = '<I2HQ2H4x'
|
||||
|
||||
MAGIC = '\x4F\x15\x3D\x1D'
|
||||
VERSION = 0x00
|
||||
MODE = 0x01
|
||||
ENDIAN = 0x01
|
||||
ATTRIBS = 0x12
|
||||
|
||||
KEY_TYPE = 0x101
|
||||
|
||||
FLAGS_SEGMENT_SIGNED_SHIFT = 4
|
||||
FLAGS_SEGMENT_SIGNED_MASK = 0x7
|
||||
|
||||
HAS_NPDRM = 1
|
||||
|
||||
def __init__(self, elf, **kwargs):
|
||||
self.elf = elf
|
||||
|
||||
self.magic = None
|
||||
self.version = None
|
||||
self.mode = None
|
||||
self.endian = None
|
||||
self.attribs = None
|
||||
self.key_type = None
|
||||
self.header_size = None
|
||||
self.meta_size = None
|
||||
self.file_size = None
|
||||
self.num_entries = None
|
||||
self.flags = None
|
||||
|
||||
self.entries = None
|
||||
self.ex_info = None
|
||||
self.npdrm_control_block = None
|
||||
self.meta_blocks = None
|
||||
self.meta_footer = None
|
||||
self.signature = None
|
||||
self.version_data = None
|
||||
|
||||
self.paid = kwargs['paid'] if 'paid' in kwargs and not kwargs['paid'] is None else 0x3100000000000002
|
||||
self.ptype = kwargs['ptype'] if 'ptype' in kwargs and not kwargs['ptype'] is None else SignedElfExInfo.PTYPE_FAKE
|
||||
self.app_version = kwargs['app_version'] if 'app_version' in kwargs and not kwargs['app_version'] is None else 0
|
||||
self.fw_version = kwargs['fw_version'] if 'fw_version' in kwargs and not kwargs['fw_version'] is None else 0
|
||||
self.auth_info = kwargs['auth_info'] if 'auth_info' in kwargs and not kwargs['auth_info'] is None else None
|
||||
|
||||
def _prepare(self):
|
||||
self.magic = SignedElfFile.MAGIC
|
||||
self.version = SignedElfFile.VERSION
|
||||
self.mode = SignedElfFile.MODE
|
||||
self.endian = SignedElfFile.ENDIAN
|
||||
self.attribs = SignedElfFile.ATTRIBS
|
||||
self.key_type = SignedElfFile.KEY_TYPE
|
||||
self.flags = 0x2
|
||||
|
||||
signed_block_count = 2
|
||||
self.flags |= (signed_block_count & SignedElfFile.FLAGS_SEGMENT_SIGNED_MASK) << SignedElfFile.FLAGS_SEGMENT_SIGNED_SHIFT
|
||||
|
||||
self.entries = []
|
||||
entry_idx = 0
|
||||
for i in xrange(self.elf.ehdr.phnum):
|
||||
phdr = self.elf.phdrs[i]
|
||||
if phdr.type == ElfPHdr.PT_SCE_VERSION:
|
||||
self.version_data = self.elf.segments[i]
|
||||
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
|
||||
continue
|
||||
meta_entry = SignedElfEntry(entry_idx)
|
||||
meta_entry.props = 0
|
||||
meta_entry.encrypted = False
|
||||
meta_entry.signed = True
|
||||
meta_entry.has_digests = True
|
||||
meta_entry.segment_index = entry_idx + 1
|
||||
self.entries.append(meta_entry)
|
||||
data_entry = SignedElfEntry(entry_idx + 1)
|
||||
data_entry.props = 0
|
||||
data_entry.encrypted = False
|
||||
data_entry.signed = True
|
||||
data_entry.has_blocks = True
|
||||
data_entry.block_size = BLOCK_SIZE
|
||||
data_entry.segment_index = i
|
||||
self.entries.append(data_entry)
|
||||
entry_idx += 2
|
||||
self.num_entries = len(self.entries)
|
||||
|
||||
self.ex_info = SignedElfExInfo()
|
||||
self.ex_info.paid = self.paid
|
||||
self.ex_info.ptype = self.ptype
|
||||
self.ex_info.app_version = self.app_version
|
||||
self.ex_info.fw_version = self.fw_version
|
||||
self.ex_info.digest = self.elf.digest
|
||||
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.npdrm_control_block = SignedElfNpdrmControlBlock()
|
||||
self.npdrm_control_block.content_id = '\0' * SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE
|
||||
self.npdrm_control_block.random_pad = '\0' * SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE
|
||||
|
||||
self.header_size = struct.calcsize(SignedElfFile.COMMON_HEADER_FMT) + struct.calcsize(SignedElfFile.EXT_HEADER_FMT)
|
||||
self.header_size += self.num_entries * struct.calcsize(SignedElfEntry.FMT)
|
||||
self.header_size += max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
|
||||
self.header_size = align_up(self.header_size, 16)
|
||||
self.header_size += struct.calcsize(SignedElfExInfo.FMT)
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.header_size += struct.calcsize(SignedElfNpdrmControlBlock.FMT)
|
||||
self.meta_size = self.num_entries * struct.calcsize(SignedElfMetaBlock.FMT) + struct.calcsize(SignedElfMetaFooter.FMT) + SIGNATURE_SIZE
|
||||
|
||||
self.meta_blocks = []
|
||||
for i in xrange(self.num_entries):
|
||||
meta_block = SignedElfMetaBlock()
|
||||
self.meta_blocks.append(meta_block)
|
||||
|
||||
self.meta_footer = SignedElfMetaFooter()
|
||||
self.meta_footer.unk1 = 0x10000
|
||||
|
||||
if not self.auth_info is None:
|
||||
self.signature = (struct.pack('<QQ', len(self.auth_info), self.ex_info.paid) + self.auth_info[8:]).ljust(SIGNATURE_SIZE, '\0')
|
||||
else:
|
||||
self.signature = EMPTY_SIGNATURE
|
||||
|
||||
entry_idx = 0
|
||||
offset = self.header_size + self.meta_size
|
||||
for i in xrange(self.elf.ehdr.phnum):
|
||||
phdr = self.elf.phdrs[i]
|
||||
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
|
||||
continue
|
||||
print('processing segment #{0:02}...'.format(i))
|
||||
|
||||
meta_entry, data_entry = self.entries[entry_idx], self.entries[entry_idx + 1]
|
||||
|
||||
num_blocks = align_up(phdr.filesz, BLOCK_SIZE) // BLOCK_SIZE
|
||||
meta_entry.data = EMPTY_DIGEST * num_blocks
|
||||
meta_entry.offset = offset
|
||||
meta_entry.memsz = meta_entry.filesz = len(meta_entry.data)
|
||||
offset += meta_entry.filesz
|
||||
offset = align_up(offset, 16)
|
||||
|
||||
data_entry.data = self.elf.segments[i]
|
||||
data_entry.offset = offset
|
||||
data_entry.memsz = data_entry.filesz = phdr.filesz
|
||||
offset += data_entry.filesz
|
||||
offset = align_up(offset, 16)
|
||||
|
||||
entry_idx += 2
|
||||
|
||||
self.file_size = offset
|
||||
|
||||
def save(self, f):
|
||||
start_offset = f.tell()
|
||||
|
||||
# calculate neccessary fields
|
||||
self._prepare()
|
||||
|
||||
# write common header
|
||||
f.write(struct.pack(SignedElfFile.COMMON_HEADER_FMT, self.magic, self.version, self.mode, self.endian, self.attribs))
|
||||
|
||||
# write extended header
|
||||
f.write(struct.pack(SignedElfFile.EXT_HEADER_FMT, self.key_type, self.header_size, self.meta_size, self.file_size, self.num_entries, self.flags))
|
||||
|
||||
# write entries
|
||||
for entry in self.entries:
|
||||
entry.save(f)
|
||||
|
||||
# write elf headers
|
||||
elf_offset = f.tell()
|
||||
elf_header_size = max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
|
||||
elf_header_size = align_up(elf_header_size, 16)
|
||||
self.elf.save(f, True)
|
||||
f.seek(elf_offset + elf_header_size)
|
||||
|
||||
# write extended info
|
||||
self.ex_info.save(f)
|
||||
|
||||
# write npdrm control block
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.npdrm_control_block.save(f)
|
||||
|
||||
# write meta blocks
|
||||
for meta_block in self.meta_blocks:
|
||||
meta_block.save(f)
|
||||
|
||||
# write meta footer
|
||||
self.meta_footer.save(f)
|
||||
|
||||
# write signature
|
||||
f.write(self.signature)
|
||||
|
||||
# write segments
|
||||
for entry in self.entries:
|
||||
f.seek(start_offset + entry.offset)
|
||||
f.write(entry.data)
|
||||
|
||||
# write version
|
||||
if not self.version_data is None:
|
||||
f.write(self.version_data)
|
||||
|
||||
def ensure_hex_string(val, **kwargs):
|
||||
exact_size = int(kwargs['exact_size']) if 'exact_size' in kwargs else None
|
||||
min_size = int(kwargs['min_size']) if 'min_size' in kwargs else None
|
||||
max_size = int(kwargs['max_size']) if 'max_size' in kwargs else None
|
||||
|
||||
val = re.sub('\s+', '', val)
|
||||
val_size = len(val)
|
||||
if val_size > 0:
|
||||
if val.startswith('0x') or val.startswith('0X'):
|
||||
val = val[2:]
|
||||
if len(val) % 2 != 0 or not all(x in string.hexdigits for x in val):
|
||||
return None
|
||||
val = val.decode('hex')
|
||||
val_size = len(val)
|
||||
|
||||
if not exact_size is None and val_size != exact_size:
|
||||
return None
|
||||
else:
|
||||
if not min_size is None and val_size < min_size:
|
||||
return None
|
||||
if not max_size is None and val_size > max_size:
|
||||
return None
|
||||
|
||||
return val
|
||||
|
||||
def input_file_type(val):
|
||||
if not os.access(val, os.F_OK | os.R_OK) or not os.path.isfile(val):
|
||||
raise argparse.ArgumentTypeError('invalid input file: {0}'.format(val))
|
||||
return val
|
||||
|
||||
def output_file_type(val):
|
||||
if os.access(val, os.F_OK) and (not os.path.isfile(val) or not os.access(val, os.F_OK | os.W_OK)):
|
||||
raise argparse.ArgumentTypeError('invalid output file: {0}'.format(val))
|
||||
return val
|
||||
|
||||
def auth_info_type(val):
|
||||
new_val = ensure_hex_string(val, exact_size=0x88)
|
||||
if new_val is None:
|
||||
raise argparse.ArgumentTypeError('invalid auth info: {0}'.format(val))
|
||||
return new_val
|
||||
|
||||
class MyParser(argparse.ArgumentParser):
|
||||
def error(self, message):
|
||||
self.print_help()
|
||||
sys.stderr.write('\nerror: {0}\n'.format(message))
|
||||
sys.exit(2)
|
||||
|
||||
parser = MyParser(description='fake signed elf maker')
|
||||
parser.add_argument('input', type=input_file_type, default=None, help='elf/prx file path')
|
||||
parser.add_argument('output', type=output_file_type, default=None, help='self/sprx file path')
|
||||
parser.add_argument('--paid', type=int_with_base_type, default=0x3100000000000002, help='program authentication id')
|
||||
parser.add_argument('--ptype', default=None, help='program type {fake, npdrm_exec, npdrm_dynlib, system_exec, system_dynlib, host_kernel, secure_module, secure_kernel}')
|
||||
parser.add_argument('--app-version', type=int_with_base_type, default=0, help='application version')
|
||||
parser.add_argument('--fw-version', type=int_with_base_type, default=0, help='firmware version')
|
||||
parser.add_argument('--auth-info', type=auth_info_type, default=None, help='authentication info')
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
paid = args.paid
|
||||
if not (0 <= paid <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid program authentication id: 0x{0:016X}'.format(paid))
|
||||
|
||||
ptype = SignedElfExInfo.PTYPE_FAKE
|
||||
if not args.ptype is None:
|
||||
ptype = {
|
||||
'fake': SignedElfExInfo.PTYPE_FAKE,
|
||||
'npdrm_exec': SignedElfExInfo.PTYPE_NPDRM_EXEC,
|
||||
'npdrm_dynlib': SignedElfExInfo.PTYPE_NPDRM_DYNLIB,
|
||||
'system_exec': SignedElfExInfo.PTYPE_SYSTEM_EXEC,
|
||||
'system_dynlib': SignedElfExInfo.PTYPE_SYSTEM_DYNLIB,
|
||||
'host_kernel': SignedElfExInfo.PTYPE_HOST_KERNEL,
|
||||
'secure_module': SignedElfExInfo.PTYPE_SECURE_MODULE,
|
||||
'secure_kernel': SignedElfExInfo.PTYPE_SECURE_KERNEL,
|
||||
}.get(args.ptype.strip().lower(), None)
|
||||
if ptype is None:
|
||||
ptype = try_parse_int(args.ptype)
|
||||
if ptype is None:
|
||||
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
|
||||
if not (0 <= ptype <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
|
||||
|
||||
app_version = args.app_version
|
||||
if not (0 <= app_version <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid application version: 0x{0:016X}'.format(app_version))
|
||||
|
||||
fw_version = args.fw_version
|
||||
if not (0 <= fw_version <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid firmware version: 0x{0:016X}'.format(fw_version))
|
||||
|
||||
auth_info = args.auth_info
|
||||
|
||||
elf_file_path = args.input
|
||||
fself_file_path = args.output
|
||||
|
||||
print('loading elf file: {0}'.format(elf_file_path))
|
||||
try:
|
||||
with open(elf_file_path, 'rb') as f:
|
||||
elf_file = ElfFile(ignore_shdrs=True)
|
||||
elf_file.load(f)
|
||||
except Exception as err:
|
||||
traceback.print_exc()
|
||||
print('')
|
||||
parser.error('unable to load elf file: {0} ({1})'.format(elf_file_path, err))
|
||||
|
||||
print('saving fake signed elf file: {0}'.format(fself_file_path))
|
||||
try:
|
||||
with open(fself_file_path, 'wb') as f:
|
||||
self_file = SignedElfFile(elf_file, paid=paid, ptype=ptype, app_version=app_version, fw_version=fw_version, auth_info=auth_info)
|
||||
self_file.save(f)
|
||||
except Exception as err:
|
||||
traceback.print_exc()
|
||||
print('')
|
||||
parser.error('unable to save fself file: {0} ({1})'.format(elf_file_path, err))
|
||||
|
||||
print('done')
|
||||
@@ -0,0 +1,46 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
REM ==============================
|
||||
REM RUN FSELF
|
||||
REM ==============================
|
||||
echo [INFO] Running fself.py ...
|
||||
C:\Python27\python.exe fself.py GTAServer.prx test.sprx
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] fself failed.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] SPRX created.
|
||||
|
||||
REM ==============================
|
||||
REM FTP UPLOAD (WinSCP)
|
||||
REM ==============================
|
||||
set WINSCP="C:\Program Files (x86)\WinSCP\winscp.com"
|
||||
set PS4_IP=192.168.137.241
|
||||
set PS4_PORT=2121
|
||||
set REMOTE_DIR=/data/GoldHEN/plugins
|
||||
set FILE=test.sprx
|
||||
|
||||
if not exist "%FILE%" (
|
||||
echo [ERROR] %FILE% not found.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [INFO] Uploading to PS4...
|
||||
|
||||
%WINSCP% ^
|
||||
/command ^
|
||||
"open ftp://anonymous@%PS4_IP%:%PS4_PORT%/" ^
|
||||
"cd %REMOTE_DIR%" ^
|
||||
"put %FILE%" ^
|
||||
"exit"
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] FTP upload failed.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] FTP upload successful.
|
||||
exit /b 0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
prx.cpp
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(257,12): warning : unused variable 'g_user_logged_in' [-Wunused-variable]
|
||||
static int g_user_logged_in = 0;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(258,29): warning : unused variable 'g_user_id' [-Wunused-variable]
|
||||
static SceUserServiceUserId g_user_id = 1;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(259,12): warning : unused variable 'g_login_event_pending' [-Wunused-variable]
|
||||
static int g_login_event_pending = 1;
|
||||
^
|
||||
C:\Users\DontCry361x\Documents\GTASPRXPS4\prx.cpp(260,12): warning : unused variable 'g_logout_event_pending' [-Wunused-variable]
|
||||
static int g_logout_event_pending = 0;
|
||||
^
|
||||
4 warnings generated.
|
||||
GTASPRXPS4.vcxproj -> C:\Users\DontCry361x\Documents\GTASPRXPS4\ORBIS_Release\GTAServer.prx
|
||||
'"C:\Users\DontCry361x\Documents\GTASPRXPS4\ORBIS_Release\make_sprx.bat"' is not recognized as an internal or external command,
|
||||
operable program or batch file.
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(148,5): error MSB3073: The command "cd /d "C:\Users\DontCry361x\Documents\GTASPRXPS4\ORBIS_Release\"
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(148,5): error MSB3073: call "C:\Users\DontCry361x\Documents\GTASPRXPS4\ORBIS_Release\make_sprx.bat"
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(148,5): error MSB3073:
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.CppCommon.targets(148,5): error MSB3073: :VCEnd" exited with code 1.
|
||||
@@ -0,0 +1,2 @@
|
||||
#TargetFrameworkVersion=v4.0:PlatformToolSet=Clang:EnableManagedIncrementalBuild=:VCToolArchitecture=:WindowsTargetPlatformVersion=
|
||||
Release|ORBIS|C:\Users\DontCry361x\Documents\GTASPRXPS4\|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
C:\Users\DontCry361x\source\repos\GTASPRXPS4\ORBIS_Release\GTAServer.prx
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,816 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, struct, traceback
|
||||
import hashlib, hmac
|
||||
import argparse, re, string
|
||||
|
||||
def int_with_base_type(val):
|
||||
return int(val, 0)
|
||||
|
||||
def try_parse_int(x, base=0):
|
||||
try:
|
||||
return int(x, base) if isinstance(x, str) else int(x)
|
||||
except:
|
||||
return None
|
||||
|
||||
def align_up(x, alignment):
|
||||
return (x + (alignment - 1)) & ~(alignment - 1)
|
||||
|
||||
def align_down(x, alignment):
|
||||
return x & ~(alignment - 1)
|
||||
|
||||
def ilog2(x):
|
||||
if x <= 0:
|
||||
raise ValueError('math domain error')
|
||||
return len(bin(x)) - 3
|
||||
|
||||
def is_intervals_overlap(p1, p2):
|
||||
return p1[0] <= p2[1] and p1[1] <= p2[0]
|
||||
|
||||
def check_file_magic(f, expected_magic):
|
||||
old_offset = f.tell()
|
||||
try:
|
||||
magic = f.read(len(expected_magic))
|
||||
except:
|
||||
return False
|
||||
finally:
|
||||
f.seek(old_offset)
|
||||
return magic == expected_magic
|
||||
|
||||
def parse_version(version):
|
||||
major, minor, patch = (version >> 8) & 0xFF, version & 0xFF, 0 # FIXME
|
||||
major = 10 * (major >> 4) + (major & 0xF)
|
||||
minor = 10 * (minor >> 4) + (minor & 0xF)
|
||||
return '{0:d}.{1:02d}.{2:03d}'.format(major, minor, patch)
|
||||
|
||||
def sha256(data):
|
||||
return hashlib.sha256(data).digest()
|
||||
|
||||
def hmac_sha256(key, data):
|
||||
return hmac.new(key=key, msg=data, digestmod=hashlib.sha256).digest()
|
||||
|
||||
class ElfError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.msg)
|
||||
|
||||
class ElfEHdr(object):
|
||||
FMT = '<4s5B6xB'
|
||||
EX_FMT = '<2HI3QI6H'
|
||||
|
||||
MAGIC = '\x7FELF'
|
||||
CLASS64 = 0x2
|
||||
DATA2LSB = 0x1
|
||||
EM_X86_64 = 0x3E
|
||||
EV_CURRENT = 0x1
|
||||
|
||||
ET_EXEC = 0x2
|
||||
ET_SCE_EXEC = 0xFE00
|
||||
ET_SCE_EXEC_ASLR = 0xFE10
|
||||
ET_SCE_DYNAMIC = 0xFE18
|
||||
|
||||
def __init__(self):
|
||||
self.magic = None
|
||||
self.machine_class = None
|
||||
self.data_encoding = None
|
||||
self.version = None
|
||||
self.os_abi = None
|
||||
self.abi_version = None
|
||||
self.nident_size = None
|
||||
self.type = None
|
||||
self.machine = None
|
||||
self.version = None
|
||||
self.entry = None
|
||||
self.phoff = None
|
||||
self.shoff = None
|
||||
self.flags = None
|
||||
self.ehsize = None
|
||||
self.phentsize = None
|
||||
self.phnum = None
|
||||
self.shentsize = None
|
||||
self.shnum = None
|
||||
self.shstridx = None
|
||||
|
||||
def load(self, f):
|
||||
if not check_file_magic(f, ElfEHdr.MAGIC):
|
||||
raise ElfError('Invalid magic.')
|
||||
|
||||
self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size = struct.unpack(ElfEHdr.FMT, f.read(struct.calcsize(ElfEHdr.FMT)))
|
||||
if self.machine_class != ElfEHdr.CLASS64 or self.data_encoding != ElfEHdr.DATA2LSB:
|
||||
raise ElfError('Unsupported class or data encoding.')
|
||||
self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx = struct.unpack(ElfEHdr.EX_FMT, f.read(struct.calcsize(ElfEHdr.EX_FMT)))
|
||||
if self.machine != ElfEHdr.EM_X86_64 or self.version != ElfEHdr.EV_CURRENT:
|
||||
raise ElfError('Unsupported machine type or version.')
|
||||
if self.phentsize != struct.calcsize(ElfPHdr.FMT) or (self.shentsize > 0 and self.shentsize != struct.calcsize(ElfSHdr.FMT)):
|
||||
raise ElfError('Unsupported header entry size.')
|
||||
if self.type not in [ElfEHdr.ET_EXEC, ElfEHdr.ET_SCE_EXEC, ElfEHdr.ET_SCE_EXEC_ASLR, ElfEHdr.ET_SCE_DYNAMIC]:
|
||||
raise ElfError('Unsupported type.')
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfEHdr.FMT, self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size))
|
||||
f.write(struct.pack(ElfEHdr.EX_FMT, self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx))
|
||||
|
||||
def has_segments(self):
|
||||
return self.phentsize > 0 and self.phnum > 0
|
||||
|
||||
def has_sections(self):
|
||||
return self.shentsize > 0 and self.shnum > 0
|
||||
|
||||
class ElfPHdr(object):
|
||||
FMT = '<2I6Q'
|
||||
|
||||
PT_LOAD = 0x1
|
||||
PT_DYNAMIC = 0x2
|
||||
PT_INTERP = 0x3
|
||||
PT_TLS = 0x7
|
||||
PT_GNU_EH_FRAME = 0x6474E550
|
||||
PT_GNU_STACK = 0x6474E551
|
||||
PT_SCE_RELA = 0x60000000,
|
||||
PT_SCE_DYNLIBDATA = 0x61000000
|
||||
PT_SCE_PROCPARAM = 0x61000001
|
||||
PT_SCE_MODULE_PARAM = 0x61000002
|
||||
PT_SCE_RELRO = 0x61000010
|
||||
PT_SCE_COMMENT = 0x6FFFFF00
|
||||
PT_SCE_VERSION = 0x6FFFFF01
|
||||
|
||||
PF_EXEC = 0x1
|
||||
PF_WRITE = 0x2
|
||||
PF_READ = 0x4
|
||||
PF_READ_EXEC = PF_READ | PF_EXEC
|
||||
PF_READ_WRITE = PF_READ | PF_WRITE
|
||||
|
||||
def __init__(self, idx):
|
||||
self.idx = idx
|
||||
self.type = None
|
||||
self.flags = None
|
||||
self.offset = None
|
||||
self.vaddr = None
|
||||
self.paddr = None
|
||||
self.filesz = None
|
||||
self.memsz = None
|
||||
self.align = None
|
||||
|
||||
def load(self, f):
|
||||
self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align = struct.unpack(ElfPHdr.FMT, f.read(struct.calcsize(ElfPHdr.FMT)))
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfPHdr.FMT, self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align))
|
||||
|
||||
def name(self):
|
||||
if self.type == ElfPHdr.PT_LOAD:
|
||||
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
|
||||
return '.text'
|
||||
elif (self.flags & ElfPHdr.PF_READ_WRITE) == ElfPHdr.PF_READ_WRITE:
|
||||
return '.data'
|
||||
else:
|
||||
return '.load_{0:02}'.format(self.idx)
|
||||
else:
|
||||
return {
|
||||
ElfPHdr.PT_DYNAMIC: '.dynamic',
|
||||
ElfPHdr.PT_INTERP: '.interp',
|
||||
ElfPHdr.PT_TLS: '.tls',
|
||||
ElfPHdr.PT_GNU_EH_FRAME: '.eh_frame_hdr',
|
||||
ElfPHdr.PT_SCE_DYNLIBDATA: '.sce_dynlib_data',
|
||||
ElfPHdr.PT_SCE_PROCPARAM: '.sce_process_param',
|
||||
ElfPHdr.PT_SCE_MODULE_PARAM: '.sce_module_param',
|
||||
ElfPHdr.PT_SCE_COMMENT: '.sce_comment',
|
||||
}.get(self.type, None)
|
||||
|
||||
def class_name(self):
|
||||
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
|
||||
return 'CODE'
|
||||
else:
|
||||
return 'DATA'
|
||||
|
||||
class ElfSHdr(object):
|
||||
FMT = '<2I4Q2I2Q'
|
||||
|
||||
def __init__(self, idx):
|
||||
self.idx = idx
|
||||
self.name = None
|
||||
self.type = None
|
||||
self.flags = None
|
||||
self.addr = None
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.link = None
|
||||
self.info = None
|
||||
self.align = None
|
||||
self.entsize = None
|
||||
|
||||
def load(self, f):
|
||||
self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize = struct.unpack(ElfSHdr.FMT, f.read(struct.calcsize(ElfSHdr.FMT)))
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(ElfSHdr.FMT, self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize))
|
||||
|
||||
class ElfFile(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.ehdr = None
|
||||
self.phdrs = None
|
||||
self.shdrs = None
|
||||
self.file_size = None
|
||||
self.digest = None
|
||||
self.segments = None
|
||||
self.sections = None
|
||||
self.ignore_shdrs = 'ignore_shdrs' in kwargs and kwargs['ignore_shdrs']
|
||||
|
||||
def load(self, f):
|
||||
start_offset = f.tell()
|
||||
data = f.read()
|
||||
self.file_size = len(data)
|
||||
self.digest = sha256(data)
|
||||
f.seek(start_offset)
|
||||
|
||||
self.ehdr = ElfEHdr()
|
||||
self.ehdr.load(f)
|
||||
|
||||
if self.ignore_shdrs:
|
||||
self.ehdr.shnum = 0
|
||||
|
||||
self.phdrs = []
|
||||
self.segments = []
|
||||
if self.ehdr.has_segments():
|
||||
for i in xrange(self.ehdr.phnum):
|
||||
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
|
||||
phdr = ElfPHdr(i)
|
||||
phdr.load(f)
|
||||
self.phdrs.append(phdr)
|
||||
if phdr.filesz > 0:
|
||||
f.seek(start_offset + phdr.offset)
|
||||
data = f.read(phdr.filesz)
|
||||
else:
|
||||
data = ''
|
||||
self.segments.append(data)
|
||||
|
||||
self.shdrs = []
|
||||
self.sections = []
|
||||
if self.ehdr.has_sections():
|
||||
for i in xrange(self.ehdr.shnum):
|
||||
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
|
||||
shdr = ElfSHdr(i)
|
||||
shdr.load(f)
|
||||
self.shdrs.append(shdr)
|
||||
if phdr.filesz > 0:
|
||||
f.seek(start_offset + shdr.offset)
|
||||
data = f.read(phdr.filesz)
|
||||
else:
|
||||
data = ''
|
||||
self.sections.append(data)
|
||||
|
||||
def save(self, f, no_sections=False):
|
||||
start_offset = f.tell()
|
||||
|
||||
self.ehdr.save(f)
|
||||
|
||||
if not no_sections:
|
||||
if self.ehdr.has_sections():
|
||||
for i in xrange(self.ehdr.shnum):
|
||||
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
|
||||
shdr = self.shdrs[i]
|
||||
shdr.save(f)
|
||||
|
||||
if self.ehdr.has_segments():
|
||||
for i in xrange(self.ehdr.phnum):
|
||||
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
|
||||
phdr = self.phdrs[i]
|
||||
phdr.save(f)
|
||||
|
||||
DIGEST_SIZE = 0x20
|
||||
SIGNATURE_SIZE = 0x100
|
||||
BLOCK_SIZE = 0x4000
|
||||
DEFAULT_BLOCK_SIZE = 0x1000
|
||||
|
||||
SELF_CONTROL_BLOCK_TYPE_NPDRM = 0x3
|
||||
SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE = 0x13
|
||||
SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE = 0xD
|
||||
|
||||
EMPTY_DIGEST = '\0' * DIGEST_SIZE
|
||||
EMPTY_SIGNATURE = '\0' * SIGNATURE_SIZE
|
||||
|
||||
class SignedElfEntry(object):
|
||||
FMT = '<4Q'
|
||||
|
||||
PROPS_ORDER_SHIFT = 0
|
||||
PROPS_ORDER_MASK = 0x1
|
||||
PROPS_ENCRYPTED_SHIFT = 1
|
||||
PROPS_ENCRYPTED_MASK = 0x1
|
||||
PROPS_SIGNED_SHIFT = 2
|
||||
PROPS_SIGNED_MASK = 0x1
|
||||
PROPS_COMPRESSED_SHIFT = 3
|
||||
PROPS_COMPRESSED_MASK = 0x1
|
||||
PROPS_WINDOW_BITS_SHIFT = 8
|
||||
PROPS_WINDOW_BITS_MASK = 0x7
|
||||
PROPS_HAS_BLOCKS_SHIFT = 11
|
||||
PROPS_HAS_BLOCKS_MASK = 0x1
|
||||
PROPS_BLOCK_SIZE_SHIFT = 12
|
||||
PROPS_BLOCK_SIZE_MASK = 0xF
|
||||
PROPS_HAS_DIGESTS_SHIFT = 16
|
||||
PROPS_HAS_DIGESTS_MASK = 0x1
|
||||
PROPS_HAS_EXTENTS_SHIFT = 17
|
||||
PROPS_HAS_EXTENTS_MASK = 0x1
|
||||
PROPS_HAS_META_SEGMENT_SHIFT = 20
|
||||
PROPS_HAS_META_SEGMENT_MASK = 0x1
|
||||
PROPS_SEGMENT_INDEX_SHIFT = 20
|
||||
PROPS_SEGMENT_INDEX_MASK = 0xFFFF
|
||||
PROPS_DEFAULT_BLOCK_SIZE = 0x1000
|
||||
PROPS_META_SEGMENT_MASK = 0xF0000
|
||||
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
|
||||
self.props = None
|
||||
self.offset = None
|
||||
self.filesz = None
|
||||
self.memsz = None
|
||||
|
||||
self.data = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfEntry.FMT, self.props, self.offset, self.filesz, self.memsz))
|
||||
|
||||
@property
|
||||
def order(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_ORDER_SHIFT) & SignedElfEntry.PROPS_ORDER_MASK
|
||||
|
||||
@order.setter
|
||||
def order(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_ORDER_MASK << SignedElfEntry.PROPS_ORDER_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_ORDER_MASK) << SignedElfEntry.PROPS_ORDER_SHIFT
|
||||
|
||||
@property
|
||||
def encrypted(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_ENCRYPTED_SHIFT) & SignedElfEntry.PROPS_ENCRYPTED_MASK) != 0
|
||||
|
||||
@encrypted.setter
|
||||
def encrypted(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT
|
||||
|
||||
@property
|
||||
def signed(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_SIGNED_SHIFT) & SignedElfEntry.PROPS_SIGNED_MASK) != 0
|
||||
|
||||
@signed.setter
|
||||
def signed(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT
|
||||
|
||||
@property
|
||||
def compressed(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_COMPRESSED_SHIFT) & SignedElfEntry.PROPS_COMPRESSED_MASK) != 0
|
||||
|
||||
@compressed.setter
|
||||
def compressed(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT
|
||||
|
||||
@property
|
||||
def has_blocks(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT) & SignedElfEntry.PROPS_HAS_BLOCKS_MASK) != 0
|
||||
|
||||
@has_blocks.setter
|
||||
def has_blocks(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT
|
||||
|
||||
@property
|
||||
def has_digests(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT) & SignedElfEntry.PROPS_HAS_DIGESTS_MASK) != 0
|
||||
|
||||
@has_digests.setter
|
||||
def has_digests(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT
|
||||
|
||||
@property
|
||||
def has_extents(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT) & SignedElfEntry.PROPS_HAS_EXTENTS_MASK) != 0
|
||||
|
||||
@has_extents.setter
|
||||
def has_extents(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT
|
||||
|
||||
@property
|
||||
def has_meta_segment(self):
|
||||
return ((self.props >> SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT) & SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK) != 0
|
||||
|
||||
@has_meta_segment.setter
|
||||
def has_meta_segment(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT)
|
||||
if value:
|
||||
self.props |= SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT
|
||||
|
||||
@property
|
||||
def wbits(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_WINDOW_BITS_SHIFT) & SignedElfEntry.PROPS_WINDOW_BITS_MASK
|
||||
|
||||
@wbits.setter
|
||||
def wbits(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_WINDOW_BITS_MASK << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_WINDOW_BITS_MASK) << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT
|
||||
|
||||
@property
|
||||
def block_size(self):
|
||||
if self.has_blocks:
|
||||
return 1 << (12 + (self.props >> SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT) & SignedElfEntry.PROPS_BLOCK_SIZE_MASK)
|
||||
else:
|
||||
return DEFAULT_BLOCK_SIZE
|
||||
|
||||
@block_size.setter
|
||||
def block_size(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_BLOCK_SIZE_MASK << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT)
|
||||
if self.has_blocks:
|
||||
value = ilog2(value) - 12
|
||||
else:
|
||||
value = 0 # TODO: check
|
||||
self.props |= (value & SignedElfEntry.PROPS_BLOCK_SIZE_MASK) << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT
|
||||
|
||||
@property
|
||||
def segment_index(self):
|
||||
return (self.props >> SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT) & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK
|
||||
|
||||
@wbits.setter
|
||||
def segment_index(self, value):
|
||||
self.props &= ~(SignedElfEntry.PROPS_SEGMENT_INDEX_MASK << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT)
|
||||
self.props |= (value & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK) << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT
|
||||
|
||||
def is_meta_segment(self): # TODO: check
|
||||
return (self.props & SignedElfEntry.PROPS_META_SEGMENT_MASK) != 0
|
||||
|
||||
def __repr__(self):
|
||||
return 'prs:0x{0:X} ofs:0x{1:X} fsz:0x{2:X} msz:0x{3:X}'.format(self.props, self.offset, self.filesz, self.memsz)
|
||||
|
||||
class SignedElfExInfo(object):
|
||||
FMT = '<4Q32s'
|
||||
|
||||
PTYPE_FAKE = 0x1
|
||||
PTYPE_NPDRM_EXEC = 0x4
|
||||
PTYPE_NPDRM_DYNLIB = 0x5
|
||||
PTYPE_SYSTEM_EXEC = 0x8
|
||||
PTYPE_SYSTEM_DYNLIB = 0x9 # including Mono binaries
|
||||
PTYPE_HOST_KERNEL = 0xC
|
||||
PTYPE_SECURE_MODULE = 0xE
|
||||
PTYPE_SECURE_KERNEL = 0xF
|
||||
|
||||
def __init__(self):
|
||||
self.paid = None
|
||||
self.ptype = None
|
||||
self.app_version = None
|
||||
self.fw_version = None
|
||||
self.digest = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfExInfo.FMT, self.paid, self.ptype, self.app_version, self.fw_version, self.digest))
|
||||
|
||||
class SignedElfNpdrmControlBlock(object):
|
||||
FMT = '<H14x19s13s'
|
||||
|
||||
def __init__(self):
|
||||
self.type = SELF_CONTROL_BLOCK_TYPE_NPDRM
|
||||
self.content_id = None
|
||||
self.random_pad = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfNpdrmControlBlock.FMT, self.type, self.content_id, self.random_pad))
|
||||
|
||||
class SignedElfMetaBlock(object):
|
||||
FMT = '<80x'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfMetaBlock.FMT))
|
||||
|
||||
class SignedElfMetaFooter(object):
|
||||
FMT = '<48xI28x'
|
||||
|
||||
def __init__(self):
|
||||
self.unk1 = None
|
||||
|
||||
def save(self, f):
|
||||
f.write(struct.pack(SignedElfMetaFooter.FMT, self.unk1))
|
||||
|
||||
class SignedElfFile(object):
|
||||
COMMON_HEADER_FMT = '<4s4B'
|
||||
EXT_HEADER_FMT = '<I2HQ2H4x'
|
||||
|
||||
MAGIC = '\x4F\x15\x3D\x1D'
|
||||
VERSION = 0x00
|
||||
MODE = 0x01
|
||||
ENDIAN = 0x01
|
||||
ATTRIBS = 0x12
|
||||
|
||||
KEY_TYPE = 0x101
|
||||
|
||||
FLAGS_SEGMENT_SIGNED_SHIFT = 4
|
||||
FLAGS_SEGMENT_SIGNED_MASK = 0x7
|
||||
|
||||
HAS_NPDRM = 1
|
||||
|
||||
def __init__(self, elf, **kwargs):
|
||||
self.elf = elf
|
||||
|
||||
self.magic = None
|
||||
self.version = None
|
||||
self.mode = None
|
||||
self.endian = None
|
||||
self.attribs = None
|
||||
self.key_type = None
|
||||
self.header_size = None
|
||||
self.meta_size = None
|
||||
self.file_size = None
|
||||
self.num_entries = None
|
||||
self.flags = None
|
||||
|
||||
self.entries = None
|
||||
self.ex_info = None
|
||||
self.npdrm_control_block = None
|
||||
self.meta_blocks = None
|
||||
self.meta_footer = None
|
||||
self.signature = None
|
||||
self.version_data = None
|
||||
|
||||
self.paid = kwargs['paid'] if 'paid' in kwargs and not kwargs['paid'] is None else 0x3100000000000002
|
||||
self.ptype = kwargs['ptype'] if 'ptype' in kwargs and not kwargs['ptype'] is None else SignedElfExInfo.PTYPE_FAKE
|
||||
self.app_version = kwargs['app_version'] if 'app_version' in kwargs and not kwargs['app_version'] is None else 0
|
||||
self.fw_version = kwargs['fw_version'] if 'fw_version' in kwargs and not kwargs['fw_version'] is None else 0
|
||||
self.auth_info = kwargs['auth_info'] if 'auth_info' in kwargs and not kwargs['auth_info'] is None else None
|
||||
|
||||
def _prepare(self):
|
||||
self.magic = SignedElfFile.MAGIC
|
||||
self.version = SignedElfFile.VERSION
|
||||
self.mode = SignedElfFile.MODE
|
||||
self.endian = SignedElfFile.ENDIAN
|
||||
self.attribs = SignedElfFile.ATTRIBS
|
||||
self.key_type = SignedElfFile.KEY_TYPE
|
||||
self.flags = 0x2
|
||||
|
||||
signed_block_count = 2
|
||||
self.flags |= (signed_block_count & SignedElfFile.FLAGS_SEGMENT_SIGNED_MASK) << SignedElfFile.FLAGS_SEGMENT_SIGNED_SHIFT
|
||||
|
||||
self.entries = []
|
||||
entry_idx = 0
|
||||
for i in xrange(self.elf.ehdr.phnum):
|
||||
phdr = self.elf.phdrs[i]
|
||||
if phdr.type == ElfPHdr.PT_SCE_VERSION:
|
||||
self.version_data = self.elf.segments[i]
|
||||
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
|
||||
continue
|
||||
meta_entry = SignedElfEntry(entry_idx)
|
||||
meta_entry.props = 0
|
||||
meta_entry.encrypted = False
|
||||
meta_entry.signed = True
|
||||
meta_entry.has_digests = True
|
||||
meta_entry.segment_index = entry_idx + 1
|
||||
self.entries.append(meta_entry)
|
||||
data_entry = SignedElfEntry(entry_idx + 1)
|
||||
data_entry.props = 0
|
||||
data_entry.encrypted = False
|
||||
data_entry.signed = True
|
||||
data_entry.has_blocks = True
|
||||
data_entry.block_size = BLOCK_SIZE
|
||||
data_entry.segment_index = i
|
||||
self.entries.append(data_entry)
|
||||
entry_idx += 2
|
||||
self.num_entries = len(self.entries)
|
||||
|
||||
self.ex_info = SignedElfExInfo()
|
||||
self.ex_info.paid = self.paid
|
||||
self.ex_info.ptype = self.ptype
|
||||
self.ex_info.app_version = self.app_version
|
||||
self.ex_info.fw_version = self.fw_version
|
||||
self.ex_info.digest = self.elf.digest
|
||||
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.npdrm_control_block = SignedElfNpdrmControlBlock()
|
||||
self.npdrm_control_block.content_id = '\0' * SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE
|
||||
self.npdrm_control_block.random_pad = '\0' * SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE
|
||||
|
||||
self.header_size = struct.calcsize(SignedElfFile.COMMON_HEADER_FMT) + struct.calcsize(SignedElfFile.EXT_HEADER_FMT)
|
||||
self.header_size += self.num_entries * struct.calcsize(SignedElfEntry.FMT)
|
||||
self.header_size += max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
|
||||
self.header_size = align_up(self.header_size, 16)
|
||||
self.header_size += struct.calcsize(SignedElfExInfo.FMT)
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.header_size += struct.calcsize(SignedElfNpdrmControlBlock.FMT)
|
||||
self.meta_size = self.num_entries * struct.calcsize(SignedElfMetaBlock.FMT) + struct.calcsize(SignedElfMetaFooter.FMT) + SIGNATURE_SIZE
|
||||
|
||||
self.meta_blocks = []
|
||||
for i in xrange(self.num_entries):
|
||||
meta_block = SignedElfMetaBlock()
|
||||
self.meta_blocks.append(meta_block)
|
||||
|
||||
self.meta_footer = SignedElfMetaFooter()
|
||||
self.meta_footer.unk1 = 0x10000
|
||||
|
||||
if not self.auth_info is None:
|
||||
self.signature = (struct.pack('<QQ', len(self.auth_info), self.ex_info.paid) + self.auth_info[8:]).ljust(SIGNATURE_SIZE, '\0')
|
||||
else:
|
||||
self.signature = EMPTY_SIGNATURE
|
||||
|
||||
entry_idx = 0
|
||||
offset = self.header_size + self.meta_size
|
||||
for i in xrange(self.elf.ehdr.phnum):
|
||||
phdr = self.elf.phdrs[i]
|
||||
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
|
||||
continue
|
||||
print('processing segment #{0:02}...'.format(i))
|
||||
|
||||
meta_entry, data_entry = self.entries[entry_idx], self.entries[entry_idx + 1]
|
||||
|
||||
num_blocks = align_up(phdr.filesz, BLOCK_SIZE) // BLOCK_SIZE
|
||||
meta_entry.data = EMPTY_DIGEST * num_blocks
|
||||
meta_entry.offset = offset
|
||||
meta_entry.memsz = meta_entry.filesz = len(meta_entry.data)
|
||||
offset += meta_entry.filesz
|
||||
offset = align_up(offset, 16)
|
||||
|
||||
data_entry.data = self.elf.segments[i]
|
||||
data_entry.offset = offset
|
||||
data_entry.memsz = data_entry.filesz = phdr.filesz
|
||||
offset += data_entry.filesz
|
||||
offset = align_up(offset, 16)
|
||||
|
||||
entry_idx += 2
|
||||
|
||||
self.file_size = offset
|
||||
|
||||
def save(self, f):
|
||||
start_offset = f.tell()
|
||||
|
||||
# calculate neccessary fields
|
||||
self._prepare()
|
||||
|
||||
# write common header
|
||||
f.write(struct.pack(SignedElfFile.COMMON_HEADER_FMT, self.magic, self.version, self.mode, self.endian, self.attribs))
|
||||
|
||||
# write extended header
|
||||
f.write(struct.pack(SignedElfFile.EXT_HEADER_FMT, self.key_type, self.header_size, self.meta_size, self.file_size, self.num_entries, self.flags))
|
||||
|
||||
# write entries
|
||||
for entry in self.entries:
|
||||
entry.save(f)
|
||||
|
||||
# write elf headers
|
||||
elf_offset = f.tell()
|
||||
elf_header_size = max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
|
||||
elf_header_size = align_up(elf_header_size, 16)
|
||||
self.elf.save(f, True)
|
||||
f.seek(elf_offset + elf_header_size)
|
||||
|
||||
# write extended info
|
||||
self.ex_info.save(f)
|
||||
|
||||
# write npdrm control block
|
||||
if SignedElfFile.HAS_NPDRM:
|
||||
self.npdrm_control_block.save(f)
|
||||
|
||||
# write meta blocks
|
||||
for meta_block in self.meta_blocks:
|
||||
meta_block.save(f)
|
||||
|
||||
# write meta footer
|
||||
self.meta_footer.save(f)
|
||||
|
||||
# write signature
|
||||
f.write(self.signature)
|
||||
|
||||
# write segments
|
||||
for entry in self.entries:
|
||||
f.seek(start_offset + entry.offset)
|
||||
f.write(entry.data)
|
||||
|
||||
# write version
|
||||
if not self.version_data is None:
|
||||
f.write(self.version_data)
|
||||
|
||||
def ensure_hex_string(val, **kwargs):
|
||||
exact_size = int(kwargs['exact_size']) if 'exact_size' in kwargs else None
|
||||
min_size = int(kwargs['min_size']) if 'min_size' in kwargs else None
|
||||
max_size = int(kwargs['max_size']) if 'max_size' in kwargs else None
|
||||
|
||||
val = re.sub('\s+', '', val)
|
||||
val_size = len(val)
|
||||
if val_size > 0:
|
||||
if val.startswith('0x') or val.startswith('0X'):
|
||||
val = val[2:]
|
||||
if len(val) % 2 != 0 or not all(x in string.hexdigits for x in val):
|
||||
return None
|
||||
val = val.decode('hex')
|
||||
val_size = len(val)
|
||||
|
||||
if not exact_size is None and val_size != exact_size:
|
||||
return None
|
||||
else:
|
||||
if not min_size is None and val_size < min_size:
|
||||
return None
|
||||
if not max_size is None and val_size > max_size:
|
||||
return None
|
||||
|
||||
return val
|
||||
|
||||
def input_file_type(val):
|
||||
if not os.access(val, os.F_OK | os.R_OK) or not os.path.isfile(val):
|
||||
raise argparse.ArgumentTypeError('invalid input file: {0}'.format(val))
|
||||
return val
|
||||
|
||||
def output_file_type(val):
|
||||
if os.access(val, os.F_OK) and (not os.path.isfile(val) or not os.access(val, os.F_OK | os.W_OK)):
|
||||
raise argparse.ArgumentTypeError('invalid output file: {0}'.format(val))
|
||||
return val
|
||||
|
||||
def auth_info_type(val):
|
||||
new_val = ensure_hex_string(val, exact_size=0x88)
|
||||
if new_val is None:
|
||||
raise argparse.ArgumentTypeError('invalid auth info: {0}'.format(val))
|
||||
return new_val
|
||||
|
||||
class MyParser(argparse.ArgumentParser):
|
||||
def error(self, message):
|
||||
self.print_help()
|
||||
sys.stderr.write('\nerror: {0}\n'.format(message))
|
||||
sys.exit(2)
|
||||
|
||||
parser = MyParser(description='fake signed elf maker')
|
||||
parser.add_argument('input', type=input_file_type, default=None, help='elf/prx file path')
|
||||
parser.add_argument('output', type=output_file_type, default=None, help='self/sprx file path')
|
||||
parser.add_argument('--paid', type=int_with_base_type, default=0x3100000000000002, help='program authentication id')
|
||||
parser.add_argument('--ptype', default=None, help='program type {fake, npdrm_exec, npdrm_dynlib, system_exec, system_dynlib, host_kernel, secure_module, secure_kernel}')
|
||||
parser.add_argument('--app-version', type=int_with_base_type, default=0, help='application version')
|
||||
parser.add_argument('--fw-version', type=int_with_base_type, default=0, help='firmware version')
|
||||
parser.add_argument('--auth-info', type=auth_info_type, default=None, help='authentication info')
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
paid = args.paid
|
||||
if not (0 <= paid <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid program authentication id: 0x{0:016X}'.format(paid))
|
||||
|
||||
ptype = SignedElfExInfo.PTYPE_FAKE
|
||||
if not args.ptype is None:
|
||||
ptype = {
|
||||
'fake': SignedElfExInfo.PTYPE_FAKE,
|
||||
'npdrm_exec': SignedElfExInfo.PTYPE_NPDRM_EXEC,
|
||||
'npdrm_dynlib': SignedElfExInfo.PTYPE_NPDRM_DYNLIB,
|
||||
'system_exec': SignedElfExInfo.PTYPE_SYSTEM_EXEC,
|
||||
'system_dynlib': SignedElfExInfo.PTYPE_SYSTEM_DYNLIB,
|
||||
'host_kernel': SignedElfExInfo.PTYPE_HOST_KERNEL,
|
||||
'secure_module': SignedElfExInfo.PTYPE_SECURE_MODULE,
|
||||
'secure_kernel': SignedElfExInfo.PTYPE_SECURE_KERNEL,
|
||||
}.get(args.ptype.strip().lower(), None)
|
||||
if ptype is None:
|
||||
ptype = try_parse_int(args.ptype)
|
||||
if ptype is None:
|
||||
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
|
||||
if not (0 <= ptype <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
|
||||
|
||||
app_version = args.app_version
|
||||
if not (0 <= app_version <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid application version: 0x{0:016X}'.format(app_version))
|
||||
|
||||
fw_version = args.fw_version
|
||||
if not (0 <= fw_version <= 0xFFFFFFFFFFFFFFFF):
|
||||
parser.error('invalid firmware version: 0x{0:016X}'.format(fw_version))
|
||||
|
||||
auth_info = args.auth_info
|
||||
|
||||
elf_file_path = args.input
|
||||
fself_file_path = args.output
|
||||
|
||||
print('loading elf file: {0}'.format(elf_file_path))
|
||||
try:
|
||||
with open(elf_file_path, 'rb') as f:
|
||||
elf_file = ElfFile(ignore_shdrs=True)
|
||||
elf_file.load(f)
|
||||
except Exception as err:
|
||||
traceback.print_exc()
|
||||
print('')
|
||||
parser.error('unable to load elf file: {0} ({1})'.format(elf_file_path, err))
|
||||
|
||||
print('saving fake signed elf file: {0}'.format(fself_file_path))
|
||||
try:
|
||||
with open(fself_file_path, 'wb') as f:
|
||||
self_file = SignedElfFile(elf_file, paid=paid, ptype=ptype, app_version=app_version, fw_version=fw_version, auth_info=auth_info)
|
||||
self_file.save(f)
|
||||
except Exception as err:
|
||||
traceback.print_exc()
|
||||
print('')
|
||||
parser.error('unable to save fself file: {0} ({1})'.format(elf_file_path, err))
|
||||
|
||||
print('done')
|
||||
Binary file not shown.
+18
@@ -0,0 +1,18 @@
|
||||
__asm__(
|
||||
".att_syntax prefix\n"
|
||||
".globl orbis_syscall\n"
|
||||
"orbis_syscall:\n"
|
||||
" movq $0, %rax\n"
|
||||
" movq %rcx, %r10\n"
|
||||
" syscall\n"
|
||||
" jb err\n"
|
||||
" retq\n"
|
||||
"err:\n"
|
||||
" pushq %rax\n"
|
||||
" callq __error\n"
|
||||
" popq %rcx\n"
|
||||
" movl %ecx, 0(%rax)\n"
|
||||
" movq $0xFFFFFFFFFFFFFFFF, %rax\n"
|
||||
" movq $0xFFFFFFFFFFFFFFFF, %rdx\n"
|
||||
" retq\n"
|
||||
);
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int orbis_syscall(int num, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user