unself: add some OOB checks

This commit is contained in:
Megamouse
2026-08-10 17:35:26 +02:00
parent d6d5c60823
commit 9af11f5cf1
2 changed files with 85 additions and 68 deletions
+70 -55
View File
@@ -90,7 +90,7 @@ inline void Write64(const fs::file& f, const be_t<u64> data)
f.write(&data, sizeof(data));
}
void WriteEhdr(const fs::file& f, Elf64_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, const Elf64_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -113,7 +113,7 @@ void WriteEhdr(const fs::file& f, Elf64_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, Elf64_Phdr& phdr)
void WritePhdr(const fs::file& f, const Elf64_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_flags);
@@ -125,7 +125,7 @@ void WritePhdr(const fs::file& f, Elf64_Phdr& phdr)
Write64(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, Elf64_Shdr& shdr)
void WriteShdr(const fs::file& f, const Elf64_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -139,7 +139,7 @@ void WriteShdr(const fs::file& f, Elf64_Shdr& shdr)
Write64(f, shdr.sh_entsize);
}
void WriteEhdr(const fs::file& f, Elf32_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, const Elf32_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -162,7 +162,7 @@ void WriteEhdr(const fs::file& f, Elf32_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, Elf32_Phdr& phdr)
void WritePhdr(const fs::file& f, const Elf32_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_offset);
@@ -174,7 +174,7 @@ void WritePhdr(const fs::file& f, Elf32_Phdr& phdr)
Write32(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, Elf32_Shdr& shdr)
void WriteShdr(const fs::file& f, const Elf32_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -674,7 +674,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
// Load the metadata section headers.
meta_shdr.clear();
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (u32 i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -699,9 +699,9 @@ bool SCEDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_length += ::narrow<u32>(hdr.data_size);
}
// Allocate a buffer to store decrypted data.
@@ -711,7 +711,7 @@ bool SCEDecrypter::DecryptData()
u32 data_buf_offset = 0;
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
@@ -719,43 +719,43 @@ bool SCEDecrypter::DecryptData()
u8 data_iv[0x10];
// Check if this is an encrypted section.
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
if ((hdr.key_idx <= meta_hdr.key_count - 1) && (hdr.iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
std::memcpy(data_key, data_keys.data() + hdr.key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + hdr.iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
auto buf = std::make_unique<u8[]>(hdr.data_size);
// Seek to the section data offset and read the encrypted data.
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.get(), hdr.data_size);
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
aes_crypt_ctr(&aes, hdr.data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
// Copy the decrypted data.
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), hdr.data_size);
}
}
else
{
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
auto buf = std::make_unique<u8[]>(hdr.data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.get(), hdr.data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), hdr.data_size);
}
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
return true;
@@ -770,9 +770,8 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
u32 data_buf_offset = 0;
// Write data.
for (u32 i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
const MetadataSectionHeader& hdr = meta_shdr[i];
const u8* src = data_buf.data() + data_buf_offset;
fs::file out_f = fs::make_stream<std::vector<u8>>();
@@ -851,13 +850,13 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
if (isElf32)
{
phdr32_arr.clear();
if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
if (elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
{
self_log.error("ELF program header offset is null!");
return false;
}
self_f.seek(m_ext_hdr.phdr_offset);
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
for (u32 i = 0; i < elf32_hdr.e_phnum; ++i)
{
phdr32_arr.emplace_back();
phdr32_arr.back().Load(self_f);
@@ -886,7 +885,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
m_seg_ext_hdr.clear();
self_f.seek(m_ext_hdr.segment_ext_hdr_offset);
for(u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
for (u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
{
if (self_f.pos() >= self_size)
{
@@ -952,7 +951,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
for (u32 i = 0; i < elf32_hdr.e_shnum; ++i)
{
shdr32_arr.emplace_back();
shdr32_arr.back().Load(self_f);
@@ -969,7 +968,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
for (u32 i = 0; i < elf64_hdr.e_shnum; ++i)
{
shdr64_arr.emplace_back();
shdr64_arr.back().Load(self_f);
@@ -1004,13 +1003,21 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("ELF program headers");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++)
isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show();
if (isElf32)
{
for (const Elf32_Phdr& hdr : phdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Phdr& hdr : phdr64_arr)
hdr.Show();
}
self_log.notice("----------------------------------------------------");
self_log.notice("Section info");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < m_seg_ext_hdr.size(); i++)
m_seg_ext_hdr[i].Show();
for (const segment_ext_header& hdr : m_seg_ext_hdr)
hdr.Show();
self_log.notice("----------------------------------------------------");
self_log.notice("SCE version info");
self_log.notice("----------------------------------------------------");
@@ -1018,13 +1025,21 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("Control info");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < m_supplemental_hdr_arr.size(); i++)
m_supplemental_hdr_arr[i].Show();
for (const supplemental_header& hdr : m_supplemental_hdr_arr)
hdr.Show();
self_log.notice("----------------------------------------------------");
self_log.notice("ELF section headers");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++)
isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show();
if (isElf32)
{
for (const Elf32_Shdr& hdr : shdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Shdr& hdr : shdr64_arr)
hdr.Show();
}
self_log.notice("----------------------------------------------------");
}
@@ -1162,7 +1177,7 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
// Load the metadata section headers.
meta_shdr.clear();
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (u32 i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -1187,12 +1202,12 @@ bool SELFDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
if ((hdr.key_idx <= meta_hdr.key_count - 1) && (hdr.iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(hdr.data_size);
}
}
@@ -1203,7 +1218,7 @@ bool SELFDecrypter::DecryptData()
u32 data_buf_offset = 0;
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
@@ -1211,34 +1226,34 @@ bool SELFDecrypter::DecryptData()
u8 data_iv[0x10];
// Check if this is an encrypted section.
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
if ((hdr.key_idx <= meta_hdr.key_count - 1) && (hdr.iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
std::memcpy(data_key, data_keys.data() + hdr.key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + hdr.iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
auto buf = std::make_unique<u8[]>(hdr.data_size);
// Seek to the section data offset and read the encrypted data.
self_f.seek(meta_shdr[i].data_offset);
self_f.read(buf.get(), meta_shdr[i].data_size);
self_f.seek(hdr.data_offset);
self_f.read(buf.get(), hdr.data_size);
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
aes_crypt_ctr(&aes, hdr.data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
// Copy the decrypted data.
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), hdr.data_size);
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
}
}
+15 -13
View File
@@ -482,7 +482,7 @@ public:
private:
template<typename EHdr, typename SHdr, typename PHdr>
void WriteElf(fs::file& e, EHdr ehdr, SHdr shdr, PHdr phdr)
void WriteElf(fs::file& e, EHdr ehdr, const std::vector<SHdr>& shdrs, const std::vector<PHdr>& phdrs)
{
// Set initial offset.
u32 data_buf_offset = 0;
@@ -491,20 +491,22 @@ private:
WriteEhdr(e, ehdr);
// Write program headers.
for (u32 i = 0; i < ehdr.e_phnum; ++i)
for (const PHdr& phdr : phdrs)
{
WritePhdr(e, phdr[i]);
WritePhdr(e, phdr);
}
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
// PHDR type.
if (meta_shdr[i].type == 2)
if (hdr.type == 2)
{
const PHdr& phdr = ::at32(phdrs, hdr.program_idx);
// Decompress if necessary.
if (meta_shdr[i].compressed == 2)
if (hdr.compressed == 2)
{
const auto filesz = phdr[meta_shdr[i].program_idx].p_filesz;
const auto filesz = phdr.p_filesz;
// Create a pointer to a buffer for decompression.
std::unique_ptr<u8[]> decomp_buf(new u8[filesz]);
@@ -528,18 +530,18 @@ private:
}
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.seek(phdr.p_offset);
e.write(decomp_buf.get(), filesz);
}
else
{
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf.data() + data_buf_offset, meta_shdr[i].data_size);
e.seek(phdr.p_offset);
e.write(data_buf.data() + data_buf_offset, hdr.data_size);
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
}
@@ -548,9 +550,9 @@ private:
{
e.seek(ehdr.e_shoff);
for (u32 i = 0; i < ehdr.e_shnum; ++i)
for (const SHdr& shdr : shdrs)
{
WriteShdr(e, shdr[i]);
WriteShdr(e, shdr);
}
}
}