Skip to content

Commit 2117456

Browse files
committed
Add RemotePlayEnabler plugin
1 parent 61dfbfd commit 2117456

File tree

12 files changed

+379
-7
lines changed

12 files changed

+379
-7
lines changed

kernel/src/Plugins/PluginManager.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <Plugins/Substitute/Substitute.hpp>
1313
#include <Plugins/BrowserActivator/BrowserActivator.hpp>
1414
#include <Plugins/MorpheusEnabler/MorpheusEnabler.hpp>
15+
#include <Plugins/RemotePlayEnabler/RemotePlayEnabler.hpp>
1516
#include <Plugins/SyscallGuard/SyscallGuardPlugin.hpp>
1617
#include <Plugins/TTYRedirector/TTYRedirector.hpp>
1718

@@ -36,6 +37,7 @@ PluginManager::PluginManager() :
3637
m_Substitute(nullptr),
3738
m_BrowserActivator(nullptr),
3839
m_MorpheusEnabler(nullptr),
40+
m_RemotePlayEnabler(nullptr),
3941
m_SyscallGuard(nullptr)
4042
{
4143
// Hushes error: private field 'm_FileManager' is not used [-Werror,-Wunused-private-field]
@@ -138,6 +140,15 @@ bool PluginManager::OnLoad()
138140
break;
139141
}
140142

143+
// Initialize RemotePlayEnabler
144+
m_RemotePlayEnabler = new Mira::Plugins::RemotePlayEnabler();
145+
if (m_RemotePlayEnabler == nullptr)
146+
{
147+
WriteLog(LL_Error, "could not allocate remote play enabler.");
148+
s_Success = false;
149+
break;
150+
}
151+
141152
// Initialize TTYRedirector
142153
m_TTYRedirector = new Mira::Plugins::TTYRedirector();
143154
if (m_TTYRedirector == nullptr)
@@ -196,6 +207,12 @@ bool PluginManager::OnLoad()
196207
WriteLog(LL_Error, "could not load morpheus enabler.");
197208
}
198209

210+
if (m_RemotePlayEnabler)
211+
{
212+
if (!m_RemotePlayEnabler->OnLoad())
213+
WriteLog(LL_Error, "could not load remote play enabler.");
214+
}
215+
199216
if (m_TTYRedirector)
200217
{
201218
if (!m_TTYRedirector->OnLoad())
@@ -346,6 +363,18 @@ bool PluginManager::OnUnload()
346363
m_MorpheusEnabler = nullptr;
347364
}
348365

366+
// Delete RemotePlayEnabler
367+
if (m_RemotePlayEnabler)
368+
{
369+
WriteLog(LL_Debug, "unloading remote play enabler");
370+
if (!m_RemotePlayEnabler->OnUnload())
371+
WriteLog(LL_Error, "remote play enabler could not unload");
372+
373+
// Free RemotePlayEnabler
374+
delete m_RemotePlayEnabler;
375+
m_RemotePlayEnabler = nullptr;
376+
}
377+
349378
// Delete the debugger
350379
// NOTE: Don't unload before the debugger for catch error if something wrong
351380
if (m_Debugger)
@@ -446,6 +475,13 @@ bool PluginManager::OnSuspend()
446475
WriteLog(LL_Error, "morpheus enabler suspend failed");
447476
}
448477

478+
// Suspend RemotePlayEnabler (does nothing)
479+
if (m_RemotePlayEnabler)
480+
{
481+
if (!m_RemotePlayEnabler->OnSuspend())
482+
WriteLog(LL_Error, "remote play enabler suspend failed");
483+
}
484+
449485
// Nota: Don't suspend before the debugger for catch error if something when wrong
450486
if (m_Debugger)
451487
{
@@ -513,6 +549,13 @@ bool PluginManager::OnResume()
513549
WriteLog(LL_Error, "morpheus enabler resume failed");
514550
}
515551

552+
WriteLog(LL_Debug, "resuming remote play enabler");
553+
if (m_RemotePlayEnabler)
554+
{
555+
if (!m_RemotePlayEnabler->OnResume())
556+
WriteLog(LL_Error, "remote play enabler resume failed");
557+
}
558+
516559
WriteLog(LL_Debug, "resuming tty redirector");
517560
if (m_TTYRedirector)
518561
{

kernel/src/Plugins/PluginManager.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace Mira
3535
Mira::Utils::IModule* m_Substitute;
3636
Mira::Utils::IModule* m_BrowserActivator;
3737
Mira::Utils::IModule* m_MorpheusEnabler;
38+
Mira::Utils::IModule* m_RemotePlayEnabler;
3839
Mira::Utils::IModule* m_SyscallGuard;
3940
Mira::Utils::IModule* m_TTYRedirector;
4041

@@ -45,6 +46,7 @@ namespace Mira
4546
Mira::Utils::IModule* GetSubstitute() { return m_Substitute; }
4647
Mira::Utils::IModule* GetBrowserActivator() { return m_BrowserActivator; }
4748
Mira::Utils::IModule* GetMorpheusEnabler() { return m_MorpheusEnabler; }
49+
Mira::Utils::IModule* GetRemotePlayEnabler() { return m_RemotePlayEnabler; }
4850
Mira::Utils::IModule* GetSyscallGuard() { return m_SyscallGuard; }
4951
};
5052
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
2+
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3+
4+
#include "RemotePlayEnabler.hpp"
5+
#include <Utils/Kdlsym.hpp>
6+
#include <Utils/Logger.hpp>
7+
8+
#include <OrbisOS/Utilities.hpp>
9+
10+
using namespace Mira::Plugins;
11+
using namespace Mira::OrbisOS;
12+
13+
extern "C"
14+
{
15+
#include <sys/mman.h>
16+
};
17+
18+
RemotePlayEnabler::RemotePlayEnabler()
19+
{
20+
21+
}
22+
23+
RemotePlayEnabler::~RemotePlayEnabler()
24+
{
25+
26+
}
27+
28+
bool RemotePlayEnabler::ShellUIPatch()
29+
{
30+
WriteLog(LL_Debug, "patching SceShellUI");
31+
32+
struct ::proc* s_Process = Utilities::FindProcessByName("SceShellUI");
33+
if (s_Process == nullptr)
34+
{
35+
WriteLog(LL_Error, "could not find SceShellUI");
36+
return false;
37+
}
38+
39+
ProcVmMapEntry* s_Entries = nullptr;
40+
size_t s_NumEntries = 0;
41+
auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
42+
if (s_Ret < 0)
43+
{
44+
WriteLog(LL_Error, "could not get vm map");
45+
return false;
46+
}
47+
48+
if (s_Entries == nullptr || s_NumEntries == 0)
49+
{
50+
WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
51+
return false;
52+
}
53+
54+
uint8_t* s_ShellUITextStart = nullptr;
55+
for (auto i = 0; i < s_NumEntries; ++i)
56+
{
57+
if (!memcmp(s_Entries[i].name, "executable", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
58+
{
59+
s_ShellUITextStart = (uint8_t*)s_Entries[i].start;
60+
break;
61+
}
62+
}
63+
64+
if (s_ShellUITextStart == nullptr)
65+
{
66+
WriteLog(LL_Error, "could not find SceShellUI text start");
67+
return false;
68+
}
69+
70+
WriteLog(LL_Debug, "SceShellUI .text: (%p)", s_ShellUITextStart);
71+
72+
uint8_t* s_ShellUIAppTextStart = nullptr;
73+
for (auto i = 0; i < s_NumEntries; ++i)
74+
{
75+
#if MIRA_PLATFORM < MIRA_PLATFORM_ORBIS_BSD_500
76+
if (!memcmp(s_Entries[i].name, "libSceVsh_aot.sprx", 18) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
77+
{
78+
s_ShellUIAppTextStart = (uint8_t*)s_Entries[i].start;
79+
break;
80+
}
81+
#else
82+
if (!memcmp(s_Entries[i].name, "app.exe.sprx", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
83+
{
84+
s_ShellUIAppTextStart = (uint8_t*)s_Entries[i].start;
85+
break;
86+
}
87+
#endif
88+
}
89+
90+
if (s_ShellUIAppTextStart == nullptr)
91+
{
92+
WriteLog(LL_Error, "could not find SceShellUI App text start");
93+
return false;
94+
}
95+
96+
WriteLog(LL_Debug, "SceShellUI App .text: (%p)", s_ShellUIAppTextStart);
97+
98+
// Free the entries we got returned
99+
delete [] s_Entries;
100+
s_Entries = nullptr;
101+
102+
// `/system_ex/app/NPXS20001/eboot.bin`
103+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUITextStart + ssu_CreateUserForIDU_patch), 4, (void*)"\x48\x31\xC0\xC3", nullptr, true);
104+
if (s_Ret < 0)
105+
{
106+
WriteLog(LL_Error, "ssu_CreateUserForIDU_patch");
107+
return false;
108+
}
109+
110+
#if MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_405
111+
// `/system_ex/app/NPXS20001/libSceVsh_aot.sprx`
112+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x64\x02\x00\x00", nullptr, true);
113+
#elif MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_455 && MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_474
114+
// `/system_ex/app/NPXS20001/libSceVsh_aot.sprx`
115+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x22\x02\x00\x00", nullptr, true);
116+
#elif MIRA_PLATFORM >= MIRA_PLATFORM_ORBIS_BSD_500 && MIRA_PLATFORM <= MIRA_PLATFORM_ORBIS_BSD_507
117+
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
118+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\x82\x02\x00\x00", nullptr, true);
119+
#elif MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_620
120+
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
121+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\xB8\x02\x00\x00", nullptr, true);
122+
#elif MIRA_PLATFORM == MIRA_PLATFORM_ORBIS_BSD_672
123+
// `/system_ex/app/NPXS20001/psm/Application/app.exe.sprx`
124+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_ShellUIAppTextStart + ssu_remote_play_menu_patch), 5, (void*)"\xE9\xBA\x02\x00\x00", nullptr, true);
125+
#else
126+
s_Ret = -1;
127+
#endif
128+
if (s_Ret < 0)
129+
{
130+
WriteLog(LL_Error, "ssu_remote_play_menu_patch");
131+
return false;
132+
}
133+
134+
WriteLog(LL_Debug, "SceShellUI successfully patched");
135+
136+
return true;
137+
}
138+
139+
bool RemotePlayEnabler::RemotePlayPatch()
140+
{
141+
WriteLog(LL_Debug, "patching SceRemotePlay");
142+
143+
struct ::proc* s_Process = Utilities::FindProcessByName("SceRemotePlay");
144+
if (s_Process == nullptr)
145+
{
146+
WriteLog(LL_Error, "could not find SceRemotePlay");
147+
return false;
148+
}
149+
150+
ProcVmMapEntry* s_Entries = nullptr;
151+
size_t s_NumEntries = 0;
152+
auto s_Ret = Utilities::GetProcessVmMap(s_Process, &s_Entries, &s_NumEntries);
153+
if (s_Ret < 0)
154+
{
155+
WriteLog(LL_Error, "could not get vm map");
156+
return false;
157+
}
158+
159+
if (s_Entries == nullptr || s_NumEntries == 0)
160+
{
161+
WriteLog(LL_Error, "invalid entries (%p) or numEntries (%d)", s_Entries, s_NumEntries);
162+
return false;
163+
}
164+
165+
uint8_t* s_RemotePlayTextStart = nullptr;
166+
for (auto i = 0; i < s_NumEntries; ++i)
167+
{
168+
if (!memcmp(s_Entries[i].name, "executable", 10) && s_Entries[i].prot >= (PROT_READ | PROT_EXEC))
169+
{
170+
s_RemotePlayTextStart = (uint8_t*)s_Entries[i].start;
171+
break;
172+
}
173+
}
174+
175+
if (s_RemotePlayTextStart == nullptr)
176+
{
177+
WriteLog(LL_Error, "could not find SceRemotePlay text start");
178+
return false;
179+
}
180+
181+
WriteLog(LL_Debug, "SceRemotePlay .text: (%p)", s_RemotePlayTextStart);
182+
183+
// Free the entries we got returned
184+
delete [] s_Entries;
185+
s_Entries = nullptr;
186+
187+
// `/system/vsh/app/NPXS21006/eboot.bin`
188+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_RemotePlayTextStart + srp_enabler_patchA), 1, (void*)"\x01", nullptr, true);
189+
if (s_Ret < 0)
190+
{
191+
WriteLog(LL_Error, "srp_enabler_patchA");
192+
return false;
193+
}
194+
195+
// `/system/vsh/app/NPXS21006/eboot.bin`
196+
s_Ret = Utilities::ProcessReadWriteMemory(s_Process, (void*)(s_RemotePlayTextStart + srp_enabler_patchB), 2, (void*)"\xEB\x1E", nullptr, true);
197+
if (s_Ret < 0)
198+
{
199+
WriteLog(LL_Error, "srp_enabler_patchB");
200+
return false;
201+
}
202+
203+
WriteLog(LL_Debug, "SceRemotePlay successfully patched");
204+
205+
return true;
206+
}
207+
208+
bool RemotePlayEnabler::OnLoad()
209+
{
210+
auto s_Ret = ShellUIPatch();
211+
if (s_Ret == false) {
212+
WriteLog(LL_Error, "could not patch SceShellUI");
213+
return false;
214+
}
215+
216+
s_Ret = RemotePlayPatch();
217+
if (s_Ret == false) {
218+
WriteLog(LL_Error, "could not patch SceRemotePlay");
219+
return false;
220+
}
221+
222+
return true;
223+
}
224+
225+
bool RemotePlayEnabler::OnUnload()
226+
{
227+
return true;
228+
}
229+
230+
bool RemotePlayEnabler::OnSuspend()
231+
{
232+
return true;
233+
}
234+
235+
bool RemotePlayEnabler::OnResume()
236+
{
237+
return true;
238+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
#include <Utils/IModule.hpp>
3+
#include <Utils/Types.hpp>
4+
5+
namespace Mira
6+
{
7+
namespace Plugins
8+
{
9+
class RemotePlayEnabler : public Mira::Utils::IModule
10+
{
11+
public:
12+
RemotePlayEnabler();
13+
virtual ~RemotePlayEnabler();
14+
15+
virtual const char* GetName() override { return "RemotePlayEnabler"; }
16+
virtual bool OnLoad() override;
17+
virtual bool OnUnload() override;
18+
virtual bool OnSuspend() override;
19+
virtual bool OnResume() override;
20+
21+
protected:
22+
static bool ShellUIPatch();
23+
static bool RemotePlayPatch();
24+
};
25+
}
26+
}

kernel/src/Utils/Kdlsym/Orbis405.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ for the platforms that do enable kernel ASLR (Address Space Layout Randomization
225225
#define ssu_sceSblRcMgrIsAllowDebugMenuForSettings_patch 0x000198C0
226226
#define ssu_sceSblRcMgrIsStoreMode_patch 0x00019BC0
227227

228+
// SceShellUI - remote play related patching
229+
#define ssu_CreateUserForIDU_patch 0x0017F330
230+
#define ssu_remote_play_menu_patch 0x011A8CF5
231+
232+
// SceRemotePlay - enabler patches
233+
#define srp_enabler_patchA 0x00065ED2
234+
#define srp_enabler_patchB 0x00065EED
235+
228236
// sceRegMgr
229237
#define kdlsym_addr_sceRegMgrGetInt 0x004CF9C0
230238
#define kdlsym_addr_sceRegMgrSetInt 0x004CEAB0

0 commit comments

Comments
 (0)