mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
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:
parent
1b5cf118e7
commit
2afc7cbaaa
@ -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
77
rpcs3/Loader/mself.cpp
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user