mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 23:11:25 +12:00
508 lines
12 KiB
C++
508 lines
12 KiB
C++
#pragma once
|
|
#include "aes.h"
|
|
#include "sha1.h"
|
|
#include "key_vault.h"
|
|
#include "Loader/ELF.h"
|
|
#include "Loader/SELF.h"
|
|
#include <wx/mstream.h>
|
|
#include <wx/zstream.h>
|
|
|
|
struct AppInfo
|
|
{
|
|
u64 authid;
|
|
u32 vendor_id;
|
|
u32 self_type;
|
|
u64 version;
|
|
u64 padding;
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
authid = Read64(f);
|
|
vendor_id = Read32(f);
|
|
self_type = Read32(f);
|
|
version = Read64(f);
|
|
padding = Read64(f);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("AuthID: 0x%llx", authid);
|
|
ConLog.Write("VendorID: 0x%08x", vendor_id);
|
|
ConLog.Write("SELF type: 0x%08x", self_type);
|
|
ConLog.Write("Version: 0x%llx", version);
|
|
}
|
|
};
|
|
|
|
struct SectionInfo
|
|
{
|
|
u64 offset;
|
|
u64 size;
|
|
u32 compressed;
|
|
u32 unknown1;
|
|
u32 unknown2;
|
|
u32 encrypted;
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
offset = Read64(f);
|
|
size = Read64(f);
|
|
compressed = Read32(f);
|
|
unknown1 = Read32(f);
|
|
unknown2 = Read32(f);
|
|
encrypted = Read32(f);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("Offset: 0x%llx", offset);
|
|
ConLog.Write("Size: 0x%llx", size);
|
|
ConLog.Write("Compressed: 0x%08x", compressed);
|
|
ConLog.Write("Unknown1: 0x%08x", unknown1);
|
|
ConLog.Write("Unknown2: 0x%08x", unknown2);
|
|
ConLog.Write("Encrypted: 0x%08x", encrypted);
|
|
}
|
|
};
|
|
|
|
struct SCEVersionInfo
|
|
{
|
|
u32 subheader_type;
|
|
u32 present;
|
|
u32 size;
|
|
u32 unknown;
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
subheader_type = Read32(f);
|
|
present = Read32(f);
|
|
size = Read32(f);
|
|
unknown = Read32(f);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("Sub-header type: 0x%08x", subheader_type);
|
|
ConLog.Write("Present: 0x%08x", present);
|
|
ConLog.Write("Size: 0x%08x", size);
|
|
ConLog.Write("Unknown: 0x%08x", unknown);
|
|
}
|
|
};
|
|
|
|
struct ControlInfo
|
|
{
|
|
u32 type;
|
|
u32 size;
|
|
u64 next;
|
|
|
|
union {
|
|
// type 1 0x30 bytes
|
|
struct {
|
|
u32 ctrl_flag1;
|
|
u32 unknown1;
|
|
u32 unknown2;
|
|
u32 unknown3;
|
|
u32 unknown4;
|
|
u32 unknown5;
|
|
u32 unknown6;
|
|
u32 unknown7;
|
|
} control_flags;
|
|
|
|
// type 2 0x30 bytes
|
|
struct {
|
|
u8 digest[20];
|
|
u64 unknown;
|
|
} file_digest_30;
|
|
|
|
// type 2 0x40 bytes
|
|
struct {
|
|
u8 digest1[20];
|
|
u8 digest2[20];
|
|
u64 unknown;
|
|
} file_digest_40;
|
|
|
|
// type 3 0x90 bytes
|
|
struct {
|
|
u32 magic;
|
|
u32 unknown1;
|
|
u32 license;
|
|
u32 type;
|
|
u8 content_id[48];
|
|
u8 digest[16];
|
|
u8 invdigest[16];
|
|
u8 xordigest[16];
|
|
u64 unknown2;
|
|
u64 unknown3;
|
|
} npdrm;
|
|
};
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
type = Read32(f);
|
|
size = Read32(f);
|
|
next = Read64(f);
|
|
|
|
if (type == 1)
|
|
{
|
|
control_flags.ctrl_flag1 = Read32(f);
|
|
control_flags.unknown1 = Read32(f);
|
|
control_flags.unknown2 = Read32(f);
|
|
control_flags.unknown3 = Read32(f);
|
|
control_flags.unknown4 = Read32(f);
|
|
control_flags.unknown5 = Read32(f);
|
|
control_flags.unknown6 = Read32(f);
|
|
control_flags.unknown7 = Read32(f);
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
if (size == 0x30)
|
|
{
|
|
f.Read(file_digest_30.digest, 20);
|
|
file_digest_30.unknown = Read64(f);
|
|
}
|
|
else if (size == 0x40)
|
|
{
|
|
f.Read(file_digest_40.digest1, 20);
|
|
f.Read(file_digest_40.digest2, 20);
|
|
file_digest_40.unknown = Read64(f);
|
|
}
|
|
}
|
|
else if (type == 3)
|
|
{
|
|
npdrm.magic = Read32(f);
|
|
npdrm.unknown1 = Read32(f);
|
|
npdrm.license = Read32(f);
|
|
npdrm.type = Read32(f);
|
|
f.Read(npdrm.content_id, 48);
|
|
f.Read(npdrm.digest, 16);
|
|
f.Read(npdrm.invdigest, 16);
|
|
f.Read(npdrm.xordigest, 16);
|
|
npdrm.unknown2 = Read64(f);
|
|
npdrm.unknown3 = Read64(f);
|
|
}
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("Type: 0x%08x", type);
|
|
ConLog.Write("Size: 0x%08x", size);
|
|
ConLog.Write("Next: 0x%llx", next);
|
|
|
|
if (type == 1)
|
|
{
|
|
ConLog.Write("Control flag 1: 0x%08x", control_flags.ctrl_flag1);
|
|
ConLog.Write("Unknown1: 0x%08x", control_flags.unknown1);
|
|
ConLog.Write("Unknown2: 0x%08x", control_flags.unknown2);
|
|
ConLog.Write("Unknown3: 0x%08x", control_flags.unknown3);
|
|
ConLog.Write("Unknown4: 0x%08x", control_flags.unknown4);
|
|
ConLog.Write("Unknown5: 0x%08x", control_flags.unknown5);
|
|
ConLog.Write("Unknown6: 0x%08x", control_flags.unknown6);
|
|
ConLog.Write("Unknown7: 0x%08x", control_flags.unknown7);
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
if (size == 0x30)
|
|
{
|
|
wxString digest_str;
|
|
for (int i = 0; i < 20; i++)
|
|
digest_str += wxString::Format("%02x", file_digest_30.digest[i]);
|
|
|
|
ConLog.Write("Digest: %s", digest_str.wc_str());
|
|
ConLog.Write("Unknown: 0x%llx", file_digest_30.unknown);
|
|
}
|
|
else if (size == 0x40)
|
|
{
|
|
wxString digest_str1;
|
|
wxString digest_str2;
|
|
for (int i = 0; i < 20; i++)
|
|
{
|
|
digest_str1 += wxString::Format("%02x", file_digest_40.digest1[i]);
|
|
digest_str2 += wxString::Format("%02x", file_digest_40.digest2[i]);
|
|
}
|
|
|
|
ConLog.Write("Digest1: %s", digest_str1.wc_str());
|
|
ConLog.Write("Digest2: %s", digest_str2.wc_str());
|
|
ConLog.Write("Unknown: 0x%llx", file_digest_40.unknown);
|
|
}
|
|
}
|
|
else if (type == 3)
|
|
{
|
|
wxString contentid_str;
|
|
wxString digest_str;
|
|
wxString invdigest_str;
|
|
wxString xordigest_str;
|
|
for (int i = 0; i < 48; i++)
|
|
contentid_str += wxString::Format("%02x", npdrm.content_id[i]);
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
digest_str += wxString::Format("%02x", npdrm.digest[i]);
|
|
invdigest_str += wxString::Format("%02x", npdrm.invdigest[i]);
|
|
xordigest_str += wxString::Format("%02x", npdrm.xordigest[i]);
|
|
}
|
|
|
|
ConLog.Write("Magic: 0x%08x", npdrm.magic);
|
|
ConLog.Write("Unknown1: 0x%08x", npdrm.unknown1);
|
|
ConLog.Write("License: 0x%08x", npdrm.license);
|
|
ConLog.Write("Type: 0x%08x", npdrm.type);
|
|
ConLog.Write("ContentID: %s", contentid_str.wc_str());
|
|
ConLog.Write("Digest: %s", digest_str.wc_str());
|
|
ConLog.Write("Inverse digest: %s", invdigest_str.wc_str());
|
|
ConLog.Write("XOR digest: %s", xordigest_str.wc_str());
|
|
ConLog.Write("Unknown2: 0x%llx", npdrm.unknown2);
|
|
ConLog.Write("Unknown3: 0x%llx", npdrm.unknown3);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
struct MetadataInfo
|
|
{
|
|
u8 key[0x10];
|
|
u8 key_pad[0x10];
|
|
u8 iv[0x10];
|
|
u8 iv_pad[0x10];
|
|
|
|
void Load(u8* in)
|
|
{
|
|
memcpy(key, in, 0x10);
|
|
memcpy(key_pad, in + 0x10, 0x10);
|
|
memcpy(iv, in + 0x20, 0x10);
|
|
memcpy(iv_pad, in + 0x30, 0x10);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
wxString key_str;
|
|
wxString key_pad_str;
|
|
wxString iv_str;
|
|
wxString iv_pad_str;
|
|
for (int i = 0; i < 0x10; i++)
|
|
{
|
|
key_str += wxString::Format("%02x", key[i]);
|
|
key_pad_str += wxString::Format("%02x", key_pad[i]);
|
|
iv_str += wxString::Format("%02x", iv[i]);
|
|
iv_pad_str += wxString::Format("%02x", iv_pad[i]);
|
|
}
|
|
|
|
ConLog.Write("Key: %s", key_str.wc_str());
|
|
ConLog.Write("Key pad: %s", key_pad_str.wc_str());
|
|
ConLog.Write("IV: %s", iv_str.wc_str());
|
|
ConLog.Write("IV pad: %s", iv_pad_str.wc_str());
|
|
}
|
|
};
|
|
|
|
struct MetadataHeader
|
|
{
|
|
u64 signature_input_length;
|
|
u32 unknown1;
|
|
u32 section_count;
|
|
u32 key_count;
|
|
u32 opt_header_size;
|
|
u32 unknown2;
|
|
u32 unknown3;
|
|
|
|
void Load(u8* in)
|
|
{
|
|
memcpy(&signature_input_length, in, 8);
|
|
memcpy(&unknown1, in + 8, 4);
|
|
memcpy(§ion_count, in + 12, 4);
|
|
memcpy(&key_count, in + 16, 4);
|
|
memcpy(&opt_header_size, in + 20, 4);
|
|
memcpy(&unknown2, in + 24, 4);
|
|
memcpy(&unknown3, in + 28, 4);
|
|
|
|
// Endian swap.
|
|
signature_input_length = swap64(signature_input_length);
|
|
unknown1 = swap32(unknown1);
|
|
section_count = swap32(section_count);
|
|
key_count = swap32(key_count);
|
|
opt_header_size = swap32(opt_header_size);
|
|
unknown2 = swap32(unknown2);
|
|
unknown3 = swap32(unknown3);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("Signature input length: 0x%llx", signature_input_length);
|
|
ConLog.Write("Unknown1: 0x%08x", unknown1);
|
|
ConLog.Write("Section count: 0x%08x", section_count);
|
|
ConLog.Write("Key count: 0x%08x", key_count);
|
|
ConLog.Write("Optional header size: 0x%08x", opt_header_size);
|
|
ConLog.Write("Unknown2: 0x%08x", unknown2);
|
|
ConLog.Write("Unknown3: 0x%08x", unknown3);
|
|
}
|
|
};
|
|
|
|
struct MetadataSectionHeader
|
|
{
|
|
u64 data_offset;
|
|
u64 data_size;
|
|
u32 type;
|
|
u32 program_idx;
|
|
u32 hashed;
|
|
u32 sha1_idx;
|
|
u32 encrypted;
|
|
u32 key_idx;
|
|
u32 iv_idx;
|
|
u32 compressed;
|
|
|
|
void Load(u8* in)
|
|
{
|
|
memcpy(&data_offset, in, 8);
|
|
memcpy(&data_size, in + 8, 8);
|
|
memcpy(&type, in + 16, 4);
|
|
memcpy(&program_idx, in + 20, 4);
|
|
memcpy(&hashed, in + 24, 4);
|
|
memcpy(&sha1_idx, in + 28, 4);
|
|
memcpy(&encrypted, in + 32, 4);
|
|
memcpy(&key_idx, in + 36, 4);
|
|
memcpy(&iv_idx, in + 40, 4);
|
|
memcpy(&compressed, in + 44, 4);
|
|
|
|
// Endian swap.
|
|
data_offset = swap64(data_offset);
|
|
data_size = swap64(data_size);
|
|
type = swap32(type);
|
|
program_idx = swap32(program_idx);
|
|
hashed = swap32(hashed);
|
|
sha1_idx = swap32(sha1_idx);
|
|
encrypted = swap32(encrypted);
|
|
key_idx = swap32(key_idx);
|
|
iv_idx = swap32(iv_idx);
|
|
compressed = swap32(compressed);
|
|
}
|
|
|
|
void Show()
|
|
{
|
|
ConLog.Write("Data offset: 0x%llx", data_offset);
|
|
ConLog.Write("Data size: 0x%llx", data_size);
|
|
ConLog.Write("Type: 0x%08x", type);
|
|
ConLog.Write("Program index: 0x%08x", program_idx);
|
|
ConLog.Write("Hashed: 0x%08x", hashed);
|
|
ConLog.Write("SHA1 index: 0x%08x", sha1_idx);
|
|
ConLog.Write("Encrypted: 0x%08x", encrypted);
|
|
ConLog.Write("Key index: 0x%08x", key_idx);
|
|
ConLog.Write("IV index: 0x%08x", iv_idx);
|
|
ConLog.Write("Compressed: 0x%08x", compressed);
|
|
}
|
|
};
|
|
|
|
struct SectionHash {
|
|
u8 sha1[20];
|
|
u8 padding[12];
|
|
u8 hmac_key[64];
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
f.Read(sha1, 20);
|
|
f.Read(padding, 12);
|
|
f.Read(hmac_key, 64);
|
|
}
|
|
};
|
|
|
|
struct CapabilitiesInfo
|
|
{
|
|
u32 type;
|
|
u32 capabilities_size;
|
|
u32 next;
|
|
u32 unknown1;
|
|
u64 unknown2;
|
|
u64 unknown3;
|
|
u64 flags;
|
|
u32 unknown4;
|
|
u32 unknown5;
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
type = Read32(f);
|
|
capabilities_size = Read32(f);
|
|
next = Read32(f);
|
|
unknown1 = Read32(f);
|
|
unknown2 = Read64(f);
|
|
unknown3 = Read64(f);
|
|
flags = Read64(f);
|
|
unknown4 = Read32(f);
|
|
unknown5 = Read32(f);
|
|
}
|
|
};
|
|
|
|
struct Signature
|
|
{
|
|
u8 r[21];
|
|
u8 s[21];
|
|
u8 padding[6];
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
f.Read(r, 21);
|
|
f.Read(s, 21);
|
|
f.Read(padding, 6);
|
|
}
|
|
};
|
|
|
|
struct SelfSection
|
|
{
|
|
u8 *data;
|
|
u64 size;
|
|
u64 offset;
|
|
|
|
void Load(vfsStream& f)
|
|
{
|
|
*data = Read32(f);
|
|
size = Read64(f);
|
|
offset = Read64(f);
|
|
}
|
|
};
|
|
|
|
class SELFDecrypter
|
|
{
|
|
// Main SELF file stream.
|
|
vfsStream& self_f;
|
|
|
|
// SCE, SELF and APP headers.
|
|
SceHeader sce_hdr;
|
|
SelfHeader self_hdr;
|
|
AppInfo app_info;
|
|
|
|
// ELF64 header and program header/section header arrays.
|
|
Elf64_Ehdr elf64_hdr;
|
|
Array<Elf64_Shdr> shdr64_arr;
|
|
Array<Elf64_Phdr> phdr64_arr;
|
|
|
|
// ELF32 header and program header/section header arrays.
|
|
Elf32_Ehdr elf32_hdr;
|
|
Array<Elf32_Shdr> shdr32_arr;
|
|
Array<Elf32_Phdr> phdr32_arr;
|
|
|
|
// Decryption info structs.
|
|
Array<SectionInfo> secinfo_arr;
|
|
SCEVersionInfo scev_info;
|
|
Array<ControlInfo> ctrlinfo_arr;
|
|
|
|
// Metadata structs.
|
|
MetadataInfo meta_info;
|
|
MetadataHeader meta_hdr;
|
|
Array<MetadataSectionHeader> meta_shdr;
|
|
|
|
// Internal data buffers.
|
|
u8 *data_keys;
|
|
u32 data_keys_length;
|
|
u8 *data_buf;
|
|
u32 data_buf_length;
|
|
|
|
// Main key vault instance.
|
|
KeyVault key_v;
|
|
|
|
public:
|
|
SELFDecrypter(vfsStream& s);
|
|
bool MakeElf(const std::string& elf, bool isElf32);
|
|
bool LoadHeaders(bool isElf32);
|
|
void ShowHeaders(bool isElf32);
|
|
bool LoadMetadata();
|
|
bool DecryptData();
|
|
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
|
bool GetKeyFromRap(u8 *content_id, u8 *npdrm_key);
|
|
};
|
|
|
|
extern bool IsSelf(const std::string& path);
|
|
extern bool IsSelfElf32(const std::string& path);
|
|
extern bool CheckDebugSelf(const std::string& self, const std::string& elf);
|
|
extern bool DecryptSelf(const std::string& elf, const std::string& self);
|