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 # Loader
target_sources(rpcs3_emu PRIVATE target_sources(rpcs3_emu PRIVATE
../Loader/ELF.cpp ../Loader/ELF.cpp
../Loader/mself.cpp
../Loader/PSF.cpp ../Loader/PSF.cpp
../Loader/PUP.cpp ../Loader/PUP.cpp
../Loader/TAR.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/types.hpp"
#include "util/endian.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 struct mself_header
{ {
nse_t<u32> magic; // "MSF\x00" nse_t<u32> magic; // "MSF\x00"
@ -12,10 +29,10 @@ struct mself_header
be_t<u32> header_size; // ??? be_t<u32> header_size; // ???
u8 reserved[0x28]; u8 reserved[0x28];
u32 get_count(u64 file_size) u32 get_count(u64 file_size) const
{ {
// Fast sanity check // 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 0;
return count; return count;
@ -24,21 +41,6 @@ struct mself_header
CHECK_SIZE(mself_header, 0x40); 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); 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\PSF.cpp" />
<ClCompile Include="Loader\PUP.cpp" /> <ClCompile Include="Loader\PUP.cpp" />
<ClCompile Include="Loader\TAR.cpp" /> <ClCompile Include="Loader\TAR.cpp" />
<ClCompile Include="Loader\mself.cpp" />
<ClCompile Include="Loader\TROPUSR.cpp" /> <ClCompile Include="Loader\TROPUSR.cpp" />
<ClCompile Include="Loader\TRP.cpp" /> <ClCompile Include="Loader\TRP.cpp" />
<ClCompile Include="rpcs3_version.cpp" /> <ClCompile Include="rpcs3_version.cpp" />
@ -483,6 +484,7 @@
<ClInclude Include="Emu\title.h" /> <ClInclude Include="Emu\title.h" />
<ClInclude Include="Emu\system_config.h" /> <ClInclude Include="Emu\system_config.h" />
<ClInclude Include="Emu\system_config_types.h" /> <ClInclude Include="Emu\system_config_types.h" />
<ClInclude Include="Loader\mself.hpp" />
<ClInclude Include="util\atomic.hpp" /> <ClInclude Include="util\atomic.hpp" />
<ClInclude Include="util\v128.hpp" /> <ClInclude Include="util\v128.hpp" />
<ClInclude Include="util\v128sse.hpp" /> <ClInclude Include="util\v128sse.hpp" />

View file

@ -776,6 +776,9 @@
<ClCompile Include="Loader\TAR.cpp"> <ClCompile Include="Loader\TAR.cpp">
<Filter>Loader</Filter> <Filter>Loader</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Loader\mself.cpp">
<Filter>Loader</Filter>
</ClCompile>
<ClCompile Include="Emu\GDB.cpp"> <ClCompile Include="Emu\GDB.cpp">
<Filter>Emu</Filter> <Filter>Emu</Filter>
</ClCompile> </ClCompile>
@ -1912,6 +1915,9 @@
<ClInclude Include="Emu\RSX\Common\texture_cache_types.h"> <ClInclude Include="Emu\RSX\Common\texture_cache_types.h">
<Filter>Emu\GPU\RSX\Common</Filter> <Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Loader\mself.hpp">
<Filter>Loader</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Emu\RSX\Common\Interpreter\FragmentInterpreter.glsl"> <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_decrypt_sprx = gui_save(main_window, "lastExplorePathSPRX", "");
const gui_save fd_cg_disasm = gui_save(main_window, "lastExplorePathCGD", ""); 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_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_debugger = gui_save(main_window, "debuggerVisible", false);
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true); const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);

View file

@ -41,6 +41,7 @@
#include "rpcs3_version.h" #include "rpcs3_version.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
#include "Crypto/unpkg.h" #include "Crypto/unpkg.h"
@ -49,6 +50,7 @@
#include "Loader/PUP.h" #include "Loader/PUP.h"
#include "Loader/TAR.h" #include "Loader/TAR.h"
#include "Loader/mself.hpp"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include "util/sysinfo.hpp" #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) void main_window::InstallPup(QString file_path)
{ {
if (file_path.isEmpty()) if (file_path.isEmpty())
@ -1919,6 +1940,8 @@ void main_window::CreateConnects()
connect(ui->toolsDecryptSprxLibsAct, &QAction::triggered, this, &main_window::DecryptSPRXLibraries); 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) connect(ui->showDebuggerAct, &QAction::triggered, [this](bool checked)
{ {
checked ? m_debugger_frame->show() : m_debugger_frame->hide(); checked ? m_debugger_frame->show() : m_debugger_frame->hide();

View file

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

View file

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