Skip to content

Commit

Permalink
Add RemotePlayEnabler plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Al-Azif committed Aug 9, 2020
1 parent 61dfbfd commit 2117456
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 7 deletions.
43 changes: 43 additions & 0 deletions kernel/src/Plugins/PluginManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <Plugins/Substitute/Substitute.hpp>
#include <Plugins/BrowserActivator/BrowserActivator.hpp>
#include <Plugins/MorpheusEnabler/MorpheusEnabler.hpp>
#include <Plugins/RemotePlayEnabler/RemotePlayEnabler.hpp>
#include <Plugins/SyscallGuard/SyscallGuardPlugin.hpp>
#include <Plugins/TTYRedirector/TTYRedirector.hpp>

Expand All @@ -36,6 +37,7 @@ PluginManager::PluginManager() :
m_Substitute(nullptr),
m_BrowserActivator(nullptr),
m_MorpheusEnabler(nullptr),
m_RemotePlayEnabler(nullptr),
m_SyscallGuard(nullptr)
{
// Hushes error: private field 'm_FileManager' is not used [-Werror,-Wunused-private-field]
Expand Down Expand Up @@ -138,6 +140,15 @@ bool PluginManager::OnLoad()
break;
}

// Initialize RemotePlayEnabler
m_RemotePlayEnabler = new Mira::Plugins::RemotePlayEnabler();
if (m_RemotePlayEnabler == nullptr)
{
WriteLog(LL_Error, "could not allocate remote play enabler.");
s_Success = false;
break;
}

// Initialize TTYRedirector
m_TTYRedirector = new Mira::Plugins::TTYRedirector();
if (m_TTYRedirector == nullptr)
Expand Down Expand Up @@ -196,6 +207,12 @@ bool PluginManager::OnLoad()
WriteLog(LL_Error, "could not load morpheus enabler.");
}

if (m_RemotePlayEnabler)
{
if (!m_RemotePlayEnabler->OnLoad())
WriteLog(LL_Error, "could not load remote play enabler.");
}

if (m_TTYRedirector)
{
if (!m_TTYRedirector->OnLoad())
Expand Down Expand Up @@ -346,6 +363,18 @@ bool PluginManager::OnUnload()
m_MorpheusEnabler = nullptr;
}

// Delete RemotePlayEnabler
if (m_RemotePlayEnabler)
{
WriteLog(LL_Debug, "unloading remote play enabler");
if (!m_RemotePlayEnabler->OnUnload())
WriteLog(LL_Error, "remote play enabler could not unload");

// Free RemotePlayEnabler
delete m_RemotePlayEnabler;
m_RemotePlayEnabler = nullptr;
}

// Delete the debugger
// NOTE: Don't unload before the debugger for catch error if something wrong
if (m_Debugger)
Expand Down Expand Up @@ -446,6 +475,13 @@ bool PluginManager::OnSuspend()
WriteLog(LL_Error, "morpheus enabler suspend failed");
}

// Suspend RemotePlayEnabler (does nothing)
if (m_RemotePlayEnabler)
{
if (!m_RemotePlayEnabler->OnSuspend())
WriteLog(LL_Error, "remote play enabler suspend failed");
}

// Nota: Don't suspend before the debugger for catch error if something when wrong
if (m_Debugger)
{
Expand Down Expand Up @@ -513,6 +549,13 @@ bool PluginManager::OnResume()
WriteLog(LL_Error, "morpheus enabler resume failed");
}

WriteLog(LL_Debug, "resuming remote play enabler");
if (m_RemotePlayEnabler)
{
if (!m_RemotePlayEnabler->OnResume())
WriteLog(LL_Error, "remote play enabler resume failed");
}

WriteLog(LL_Debug, "resuming tty redirector");
if (m_TTYRedirector)
{
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/Plugins/PluginManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace Mira
Mira::Utils::IModule* m_Substitute;
Mira::Utils::IModule* m_BrowserActivator;
Mira::Utils::IModule* m_MorpheusEnabler;
Mira::Utils::IModule* m_RemotePlayEnabler;
Mira::Utils::IModule* m_SyscallGuard;
Mira::Utils::IModule* m_TTYRedirector;

Expand All @@ -45,6 +46,7 @@ namespace Mira
Mira::Utils::IModule* GetSubstitute() { return m_Substitute; }
Mira::Utils::IModule* GetBrowserActivator() { return m_BrowserActivator; }
Mira::Utils::IModule* GetMorpheusEnabler() { return m_MorpheusEnabler; }
Mira::Utils::IModule* GetRemotePlayEnabler() { return m_RemotePlayEnabler; }
Mira::Utils::IModule* GetSyscallGuard() { return m_SyscallGuard; }
};
}
Expand Down
238 changes: 238 additions & 0 deletions kernel/src/Plugins/RemotePlayEnabler/RemotePlayEnabler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com

#include "RemotePlayEnabler.hpp"
#include <Utils/Kdlsym.hpp>
#include <Utils/Logger.hpp>

#include <OrbisOS/Utilities.hpp>

using namespace Mira::Plugins;
using namespace Mira::OrbisOS;

extern "C"
{
#include <sys/mman.h>
};

RemotePlayEnabler::RemotePlayEnabler()
{

}

RemotePlayEnabler::~RemotePlayEnabler()
{

}

bool RemotePlayEnabler::ShellUIPatch()
{
WriteLog(LL_Debug, "patching SceShellUI");

struct ::proc* s_Process = Utilities::FindProcessByName("SceShellUI");
if (s_Process == nullptr)
{
WriteLog(LL_Error, "could not find SceShellUI");
return false;
}

ProcVmMapEntry* s_Entries = nullptr;
size_t s_NumEntries = 0;
auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
if (s_Ret < 0)
{
WriteLog(LL_Error, "could not get vm map");
return false;
}

if (s_Entries == nullptr || s_NumEntries == 0)
{
WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
return false;
}

uint8_t* s_ShellUITextStart = nullptr;
for (auto i = 0; i < s_NumEntries; ++i)
{
if (!memcmp(s_Entries[i].name, "executable", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
{
s_ShellUITextStart = (uint8_t*)s_Entries[i].start;
break;
}
}

if (s_ShellUITextStart == nullptr)
{
WriteLog(LL_Error, "could not find SceShellUI text start");
return false;
}

WriteLog(LL_Debug, "SceShellUI .text: (%p)", s_ShellUITextStart);

uint8_t* s_ShellUIAppTextStart = nullptr;
for (auto i = 0; i < s_NumEntries; ++i)
{
#if MIRA_PLATFORM < MIRA_PLATFORM_ORBIS_BSD_500
if (!memcmp(s_Entries[i].name, "libSceVsh_aot.sprx", 18) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
{
s_ShellUIAppTextStart = (uint8_t*)s_Entries[i].start;
break;
}
#else
if (!memcmp(s_Entries[i].name, "app.exe.sprx", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
{
s_ShellUIAppTextStart = (uint8_t*)s_Entries[i].start;
break;
}
#endif
}

if (s_ShellUIAppTextStart == nullptr)
{
WriteLog(LL_Error, "could not find SceShellUI App text start");
return false;
}

WriteLog(LL_Debug, "SceShellUI App .text: (%p)", s_ShellUIAppTextStart);

// Free the entries we got returned
delete [] s_Entries;
s_Entries = nullptr;

// `/system_ex/app/NPXS20001/eboot.bin`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUITextStart + ssu_CreateUserForIDU_patch), 4, (void*)"\x48\x31\xC0\xC3", nullptr, true);
if (s_Ret < 0)
{
WriteLog(LL_Error, "ssu_CreateUserForIDU_patch");
return false;
}

#if MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_405
// `/system_ex/app/NPXS20001/libSceVsh_aot.sprx`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x64\x02\x00\x00", nullptr, true);
#elif MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_455 && MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_474
// `/system_ex/app/NPXS20001/libSceVsh_aot.sprx`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x22\x02\x00\x00", nullptr, true);
#elif MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_500 && MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_507
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x82\x02\x00\x00", nullptr, true);
#elif MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_620
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\xB8\x02\x00\x00", nullptr, true);
#elif MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_672
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\xBA\x02\x00\x00", nullptr, true);
#else
s_Ret = -1;
#endif
if (s_Ret < 0)
{
WriteLog(LL_Error, "ssu_remote_play_menu_patch");
return false;
}

WriteLog(LL_Debug, "SceShellUI successfully patched");

return true;
}

bool RemotePlayEnabler::RemotePlayPatch()
{
WriteLog(LL_Debug, "patching SceRemotePlay");

struct ::proc* s_Process = Utilities::FindProcessByName("SceRemotePlay");
if (s_Process == nullptr)
{
WriteLog(LL_Error, "could not find SceRemotePlay");
return false;
}

ProcVmMapEntry* s_Entries = nullptr;
size_t s_NumEntries = 0;
auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
if (s_Ret < 0)
{
WriteLog(LL_Error, "could not get vm map");
return false;
}

if (s_Entries == nullptr || s_NumEntries == 0)
{
WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
return false;
}

uint8_t* s_RemotePlayTextStart = nullptr;
for (auto i = 0; i < s_NumEntries; ++i)
{
if (!memcmp(s_Entries[i].name, "executable", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
{
s_RemotePlayTextStart = (uint8_t*)s_Entries[i].start;
break;
}
}

if (s_RemotePlayTextStart == nullptr)
{
WriteLog(LL_Error, "could not find SceRemotePlay text start");
return false;
}

WriteLog(LL_Debug, "SceRemotePlay .text: (%p)", s_RemotePlayTextStart);

// Free the entries we got returned
delete [] s_Entries;
s_Entries = nullptr;

// `/system/vsh/app/NPXS21006/eboot.bin`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_RemotePlayTextStart + srp_enabler_patchA), 1, (void*)"\x01", nullptr, true);
if (s_Ret < 0)
{
WriteLog(LL_Error, "srp_enabler_patchA");
return false;
}

// `/system/vsh/app/NPXS21006/eboot.bin`
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_RemotePlayTextStart + srp_enabler_patchB), 2, (void*)"\xEB\x1E", nullptr, true);
if (s_Ret < 0)
{
WriteLog(LL_Error, "srp_enabler_patchB");
return false;
}

WriteLog(LL_Debug, "SceRemotePlay successfully patched");

return true;
}

bool RemotePlayEnabler::OnLoad()
{
auto s_Ret = ShellUIPatch();
if (s_Ret == false) {
WriteLog(LL_Error, "could not patch SceShellUI");
return false;
}

s_Ret = RemotePlayPatch();
if (s_Ret == false) {
WriteLog(LL_Error, "could not patch SceRemotePlay");
return false;
}

return true;
}

bool RemotePlayEnabler::OnUnload()
{
return true;
}

bool RemotePlayEnabler::OnSuspend()
{
return true;
}

bool RemotePlayEnabler::OnResume()
{
return true;
}
26 changes: 26 additions & 0 deletions kernel/src/Plugins/RemotePlayEnabler/RemotePlayEnabler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once
#include <Utils/IModule.hpp>
#include <Utils/Types.hpp>

namespace Mira
{
namespace Plugins
{
class RemotePlayEnabler : public Mira::Utils::IModule
{
public:
RemotePlayEnabler();
virtual ~RemotePlayEnabler();

virtual const char* GetName() override { return "RemotePlayEnabler"; }
virtual bool OnLoad() override;
virtual bool OnUnload() override;
virtual bool OnSuspend() override;
virtual bool OnResume() override;

protected:
static bool ShellUIPatch();
static bool RemotePlayPatch();
};
}
}
8 changes: 8 additions & 0 deletions kernel/src/Utils/Kdlsym/Orbis405.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ for the platforms that do enable kernel ASLR (Address Space Layout Randomization
#define ssu_sceSblRcMgrIsAllowDebugMenuForSettings_patch 0x000198C0
#define ssu_sceSblRcMgrIsStoreMode_patch 0x00019BC0

// SceShellUI - remote play related patching
#define ssu_CreateUserForIDU_patch 0x0017F330
#define ssu_remote_play_menu_patch 0x011A8CF5

// SceRemotePlay - enabler patches
#define srp_enabler_patchA 0x00065ED2
#define srp_enabler_patchB 0x00065EED

// sceRegMgr
#define kdlsym_addr_sceRegMgrGetInt 0x004CF9C0
#define kdlsym_addr_sceRegMgrSetInt 0x004CEAB0
Expand Down
Loading

0 comments on commit 2117456

Please sign in to comment.