GUI: Implement MSELF extraction tool (#9909)

* MSELF: fix overflow

* GUI: Implement MSELF extraction tool

* VS: fix mself files in vcxproj

* fix

* Update mself.cpp

* fixed
This commit is contained in:
Eladash 2021-03-07 18:59:37 +02:00 committed by GitHub
parent 1b5cf118e7
commit 2afc7cbaaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 139 additions and 19 deletions

View File

@ -99,6 +99,7 @@ target_sources(rpcs3_emu PRIVATE
# Loader
target_sources(rpcs3_emu PRIVATE
../Loader/ELF.cpp
../Loader/mself.cpp
../Loader/PSF.cpp
../Loader/PUP.cpp
../Loader/TAR.cpp

77
rpcs3/Loader/mself.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "stdafx.h"
#include "Utilities/File.h"
#include "util/logs.hpp"
#include "Emu/VFS.h"
#include "mself.hpp"
LOG_CHANNEL(mself_log, "MSELF");
bool extract_mself(const std::string& file, const std::string& extract_to)
{
fs::file mself(file);
mself_log.notice("Extracting MSELF file '%s' to directory '%s'...", file, extract_to);
if (!mself)
{
mself_log.error("Error opening MSELF file '%s' (%s)", file, fs::g_tls_error);
return false;
}
mself_header hdr{};
if (!mself.read(hdr))
{
mself_log.error("Error reading MSELF header, file is too small. (size=0x%x)", mself.size());
return false;
}
const u64 mself_size = mself.size();
const u32 hdr_count = hdr.get_count(mself_size);
if (!hdr_count)
{
mself_log.error("Provided file is not an MSELF");
return false;
}
std::vector<mself_record> recs(hdr_count);
if (!mself.read(recs))
{
mself_log.error("Error extracting MSELF records");
return false;
}
std::vector<u8> buffer;
for (const mself_record& rec : recs)
{
const std::string name = vfs::escape(rec.name);
const u64 pos = rec.get_pos(mself_size);
if (!pos)
{
mself_log.error("Error extracting %s from MSELF", name);
return false;
}
buffer.resize(rec.size);
mself.seek(pos);
mself.read(buffer.data(), rec.size);
if (!fs::write_file(extract_to + name, fs::rewrite, buffer))
{
mself_log.error("Error creating %s (%s)", extract_to + name, fs::g_tls_error);
return false;
}
mself_log.success("Extracted '%s' to '%s'", name, extract_to + name);
}
mself_log.success("Extraction complete!");
return true;
}

View File

@ -3,6 +3,23 @@
#include "util/types.hpp"
#include "util/endian.hpp"
struct mself_record
{
char name[0x20];
be_t<u64> off;
be_t<u64> size;
u8 reserved[0x10];
u64 get_pos(u64 file_size) const
{
// Fast sanity check
if (off < file_size && file_size - off >= size) [[likely]]
return off;
return 0;
}
};
struct mself_header
{
nse_t<u32> magic; // "MSF\x00"
@ -12,10 +29,10 @@ struct mself_header
be_t<u32> header_size; // ???
u8 reserved[0x28];
u32 get_count(u64 file_size)
u32 get_count(u64 file_size) const
{
// Fast sanity check
if (magic != "MSF"_u32 || ver != u32{1} || this->size != file_size) [[unlikely]]
if (magic != "MSF"_u32 || ver != u32{1} || (file_size - sizeof(mself_header)) / sizeof(mself_record) < count || this->size != file_size) [[unlikely]]
return 0;
return count;
@ -24,21 +41,6 @@ struct mself_header
CHECK_SIZE(mself_header, 0x40);
struct mself_record
{
char name[0x20];
be_t<u64> off;
be_t<u64> size;
u8 reserved[0x10];
u64 get_pos(u64 file_size)
{
// Fast sanity check
if (off < file_size && off + size <= file_size) [[likely]]
return off;
return 0;
}
};
CHECK_SIZE(mself_record, 0x40);
bool extract_mself(const std::string& file, const std::string& extract_to);

View File

@ -422,6 +422,7 @@
<ClCompile Include="Loader\PSF.cpp" />
<ClCompile Include="Loader\PUP.cpp" />
<ClCompile Include="Loader\TAR.cpp" />
<ClCompile Include="Loader\mself.cpp" />
<ClCompile Include="Loader\TROPUSR.cpp" />
<ClCompile Include="Loader\TRP.cpp" />
<ClCompile Include="rpcs3_version.cpp" />
@ -483,6 +484,7 @@
<ClInclude Include="Emu\title.h" />
<ClInclude Include="Emu\system_config.h" />
<ClInclude Include="Emu\system_config_types.h" />
<ClInclude Include="Loader\mself.hpp" />
<ClInclude Include="util\atomic.hpp" />
<ClInclude Include="util\v128.hpp" />
<ClInclude Include="util\v128sse.hpp" />

View File

@ -776,6 +776,9 @@
<ClCompile Include="Loader\TAR.cpp">
<Filter>Loader</Filter>
</ClCompile>
<ClCompile Include="Loader\mself.cpp">
<Filter>Loader</Filter>
</ClCompile>
<ClCompile Include="Emu\GDB.cpp">
<Filter>Emu</Filter>
</ClCompile>
@ -1912,6 +1915,9 @@
<ClInclude Include="Emu\RSX\Common\texture_cache_types.h">
<Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude>
<ClInclude Include="Loader\mself.hpp">
<Filter>Loader</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Common\Interpreter\FragmentInterpreter.glsl">

View File

@ -129,6 +129,7 @@ namespace gui
const gui_save fd_decrypt_sprx = gui_save(main_window, "lastExplorePathSPRX", "");
const gui_save fd_cg_disasm = gui_save(main_window, "lastExplorePathCGD", "");
const gui_save fd_log_viewer = gui_save(main_window, "lastExplorePathLOG", "");
const gui_save fd_ext_mself = gui_save(main_window, "lastExplorePathExMSELF", "");
const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false);
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);

View File

@ -41,6 +41,7 @@
#include "rpcs3_version.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Emu/system_config.h"
#include "Crypto/unpkg.h"
@ -49,6 +50,7 @@
#include "Loader/PUP.h"
#include "Loader/TAR.h"
#include "Loader/mself.hpp"
#include "Utilities/Thread.h"
#include "util/sysinfo.hpp"
@ -769,6 +771,25 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
}
}
void main_window::ExtractMSELF()
{
const QString path_last_mself = m_gui_settings->GetValue(gui::fd_ext_mself).toString();
QString file_path = QFileDialog::getOpenFileName(this, tr("Select MSELF To extract"), path_last_mself, tr("All mself files (*.mself);;All files (*.*)"));
if (file_path.isEmpty())
{
return;
}
QString dir = QFileDialog::getExistingDirectory(this, tr("Extraction Directory"), QString{}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty())
{
m_gui_settings->SetValue(gui::fd_ext_mself, QFileInfo(file_path).path());
extract_mself(sstr(file_path), sstr(dir) + '/');
}
}
void main_window::InstallPup(QString file_path)
{
if (file_path.isEmpty())
@ -1919,6 +1940,8 @@ void main_window::CreateConnects()
connect(ui->toolsDecryptSprxLibsAct, &QAction::triggered, this, &main_window::DecryptSPRXLibraries);
connect(ui->toolsExtractMSELFAct, &QAction::triggered, this, &main_window::ExtractMSELF);
connect(ui->showDebuggerAct, &QAction::triggered, [this](bool checked)
{
checked ? m_debugger_frame->show() : m_debugger_frame->hide();

View File

@ -146,6 +146,8 @@ private:
void InstallPup(QString filePath = "");
void HandlePupInstallation(QString file_path = "");
void ExtractMSELF();
drop_type IsValidFile(const QMimeData& md, QStringList* drop_paths = nullptr);
void AddGamesFromDir(const QString& path);

View File

@ -256,6 +256,7 @@
<addaction name="toolsStringSearchAct"/>
<addaction name="separator"/>
<addaction name="toolsDecryptSprxLibsAct"/>
<addaction name="toolsExtractMSELFAct"/>
<addaction name="separator"/>
<addaction name="actionopen_rsx_capture"/>
<addaction name="separator"/>
@ -626,6 +627,11 @@
<string>Decrypt PS3 Binaries</string>
</property>
</action>
<action name="toolsExtractMSELFAct">
<property name="text">
<string>Extract MSELF</string>
</property>
</action>
<action name="showDebuggerAct">
<property name="checkable">
<bool>true</bool>