Merge pull request #160 from Rodrigo-Todescatto/main

Added MMXboxDeviceEnumerator.
This commit is contained in:
Tyler Jaacks
2025-03-12 17:27:19 -05:00
committed by GitHub
9 changed files with 350 additions and 113 deletions

View File

@@ -0,0 +1,51 @@
#include "pch.h"
#include "MMXboxDeviceEnumeratorWrapper.h"
#include "MMDeviceEnumeratorWrapper.h"
HRESULT __stdcall MMDeviceEnumeratorWrapper::QueryInterface(REFIID riid, void** ppvObject)
{
if (riid == __uuidof(IMMXboxDeviceEnumerator))
{
*ppvObject = new MMXboxDeviceEnumerator(this);
this->AddRef();
return S_OK;
}
return m_realEnumerator->QueryInterface(riid, ppvObject);
}
ULONG __stdcall MMDeviceEnumeratorWrapper::AddRef(void)
{
return m_realEnumerator->AddRef();
}
ULONG __stdcall MMDeviceEnumeratorWrapper::Release(void)
{
return m_realEnumerator->Release();
}
HRESULT __stdcall MMDeviceEnumeratorWrapper::EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection** ppDevices)
{
return m_realEnumerator->EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices);
}
HRESULT __stdcall MMDeviceEnumeratorWrapper::GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice** ppEndpoint)
{
return m_realEnumerator->GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint);
}
HRESULT __stdcall MMDeviceEnumeratorWrapper::GetDevice(LPCWSTR pwstrId, IMMDevice** ppDevice)
{
return m_realEnumerator->GetDevice(pwstrId, ppDevice);
}
HRESULT __stdcall MMDeviceEnumeratorWrapper::RegisterEndpointNotificationCallback(IMMNotificationClient* pClient)
{
return m_realEnumerator->RegisterEndpointNotificationCallback(pClient);
}
HRESULT __stdcall MMDeviceEnumeratorWrapper::UnregisterEndpointNotificationCallback(IMMNotificationClient* pClient)
{
return m_realEnumerator->UnregisterEndpointNotificationCallback(pClient);
}

View File

@@ -0,0 +1,52 @@
#pragma once
#include <mmdeviceapi.h>
class MMDeviceEnumeratorWrapper : IMMDeviceEnumerator
{
public:
MMDeviceEnumeratorWrapper(IMMDeviceEnumerator* realEnumerator) : m_realEnumerator(realEnumerator)
{
}
HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef(void) override;
ULONG STDMETHODCALLTYPE Release(void) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ DWORD dwStateMask,
/* [annotation][out] */
_Out_ IMMDeviceCollection** ppDevices) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ ERole role,
/* [annotation][out] */
_Out_ IMMDevice** ppEndpoint) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDevice(
/* [annotation][in] */
_In_ LPCWSTR pwstrId,
/* [annotation][out] */
_Out_ IMMDevice** ppDevice) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient* pClient) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient* pClient) override;
IMMDeviceEnumerator* m_realEnumerator;
};

View File

@@ -0,0 +1,57 @@
#include "pch.h"
#include "MMXboxDeviceEnumeratorWrapper.h"
HRESULT __stdcall MMXboxDeviceEnumerator::QueryInterface(REFIID riid, void** ppvObject)
{
return m_realEnumerator->QueryInterface(riid, ppvObject);
}
ULONG __stdcall MMXboxDeviceEnumerator::AddRef(void)
{
return m_realEnumerator->AddRef();
}
ULONG __stdcall MMXboxDeviceEnumerator::Release(void)
{
return m_realEnumerator->Release();
}
HRESULT __stdcall MMXboxDeviceEnumerator::EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection** ppDevices)
{
return m_realEnumerator->EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices);
}
HRESULT __stdcall MMXboxDeviceEnumerator::GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice** ppEndpoint)
{
return m_realEnumerator->GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint);
}
HRESULT __stdcall MMXboxDeviceEnumerator::GetDevice(LPCWSTR pwstrId, IMMDevice** ppDevice)
{
return m_realEnumerator->GetDevice(pwstrId, ppDevice);
}
HRESULT __stdcall MMXboxDeviceEnumerator::RegisterEndpointNotificationCallback(IMMNotificationClient* pClient)
{
return m_realEnumerator->RegisterEndpointNotificationCallback(pClient);
}
HRESULT __stdcall MMXboxDeviceEnumerator::UnregisterEndpointNotificationCallback(IMMNotificationClient* pClient)
{
return m_realEnumerator->UnregisterEndpointNotificationCallback(pClient);
}
HRESULT __stdcall MMXboxDeviceEnumerator::GetHdAudioChannelCounts(unsigned int* pHdmiChannelCount, unsigned int* pSpdifChannelCount)
{
return E_NOTIMPL;
}
HRESULT __stdcall MMXboxDeviceEnumerator::RegisterChannelCountNotificationCallback(uint32_t* pClient)
{
return E_NOTIMPL;
}
HRESULT __stdcall MMXboxDeviceEnumerator::UnregisterChannelCountNotificationCallback(uint32_t* pClient)
{
return E_NOTIMPL;
}

View File

@@ -0,0 +1,64 @@
#pragma once
#include <mmdeviceapi.h>
#include "MMDeviceEnumeratorWrapper.h"
MIDL_INTERFACE("8B557ADC-555E-47A0-B223-43477E481DAD")
IMMXboxDeviceEnumerator : public IMMDeviceEnumerator
{
public:
virtual HRESULT __stdcall GetHdAudioChannelCounts(unsigned int* pHdmiChannelCount, unsigned int* pSpdifChannelCount) = 0;
virtual HRESULT __stdcall RegisterChannelCountNotificationCallback(uint32_t* pClient) = 0; // IMMXboxNotificationClient
virtual HRESULT __stdcall UnregisterChannelCountNotificationCallback(uint32_t* pClient) = 0; // IMMXboxNotificationClient
};
class MMXboxDeviceEnumerator : IMMXboxDeviceEnumerator
{
public:
MMXboxDeviceEnumerator(IMMDeviceEnumerator* realEnumerator) : m_realEnumerator(realEnumerator)
{
}
HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef(void) override;
ULONG STDMETHODCALLTYPE Release(void) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ DWORD dwStateMask,
/* [annotation][out] */
_Out_ IMMDeviceCollection** ppDevices) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ ERole role,
/* [annotation][out] */
_Out_ IMMDevice** ppEndpoint) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDevice(
/* [annotation][in] */
_In_ LPCWSTR pwstrId,
/* [annotation][out] */
_Out_ IMMDevice** ppDevice) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient* pClient) override;
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient* pClient) override;
HRESULT __stdcall GetHdAudioChannelCounts(unsigned int* pHdmiChannelCount, unsigned int* pSpdifChannelCount) override;
HRESULT __stdcall RegisterChannelCountNotificationCallback(uint32_t* pClient) override; // IMMXboxNotificationClient
HRESULT __stdcall UnregisterChannelCountNotificationCallback(uint32_t* pClient) override; // IMMXboxNotificationClient
IMMDeviceEnumerator* m_realEnumerator;
};

View File

@@ -152,6 +152,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID reserved)
//DetourAttach(&reinterpret_cast<PVOID&>(TrueLoadLibraryExW), LoadLibraryExW_Hook);
DetourAttach(&reinterpret_cast<PVOID&>(TrueLoadLibraryW), LoadLibraryW_Hook);
DetourAttach(&reinterpret_cast<PVOID&>(TrueLoadLibraryExA), LoadLibraryExA_Hook);
DetourAttach(&reinterpret_cast<PVOID&>(TrueCoCreateInstance), CoCreateInstance_hook);
DetourTransactionCommit();
@@ -173,6 +174,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID reserved)
//DetourDetach(&reinterpret_cast<PVOID&>(TrueLoadLibraryExW), LoadLibraryExW_Hook);
DetourDetach(&reinterpret_cast<PVOID&>(TrueLoadLibraryW), LoadLibraryW_Hook);
DetourDetach(&reinterpret_cast<PVOID&>(TrueLoadLibraryExA), LoadLibraryExA_Hook);
DetourDetach(&reinterpret_cast<PVOID&>(TrueCoCreateInstance), CoCreateInstance_hook);
DetourTransactionCommit();

View File

@@ -6,6 +6,7 @@
#include <windows.applicationmodel.core.h>
#include "CurrentAppWrapper.hpp"
#include "MMDeviceEnumeratorWrapper.h"
#define RETURN_HR(hr) return hr
#define RETURN_LAST_ERROR_IF(cond) if (cond) return HRESULT_FROM_WIN32(GetLastError())
@@ -79,6 +80,31 @@ HRESULT(STDMETHODCALLTYPE* TrueGetLicenseInformation)(
ABI::Windows::ApplicationModel::Store::ILicenseInformation** value
) = nullptr;
HRESULT(WINAPI* TrueCoCreateInstance)(_In_ REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter,
_In_ DWORD dwClsContext,
_In_ REFIID riid,
_COM_Outptr_ _At_(*ppv, _Post_readable_size_(_Inexpressible_(varies))) LPVOID FAR* ppv) = CoCreateInstance;
HRESULT __stdcall CoCreateInstance_hook(
_In_ REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter,
_In_ DWORD dwClsContext,
_In_ REFIID riid,
_COM_Outptr_ _At_(*ppv, _Post_readable_size_(_Inexpressible_(varies))) LPVOID FAR* ppv
)
{
HRESULT hr = TrueCoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
if (riid == __uuidof(IMMDeviceEnumerator))
{
*ppv = new MMDeviceEnumeratorWrapper(static_cast<IMMDeviceEnumerator*>(*ppv));
}
return hr;
}
HRESULT XWineGetImport(_In_opt_ HMODULE Module, _In_ HMODULE ImportModule, _In_ LPCSTR Import, _Out_ PIMAGE_THUNK_DATA* pThunk)
{
if (ImportModule == nullptr)

View File

@@ -241,89 +241,22 @@ CONSOLE_TYPE GetConsoleType_X() {
return CONSOLE_TYPE::CONSOLE_TYPE_XBOX_ONE_X_DEVKIT;
}
PVOID __fastcall XMemAllocDefault_X(SIZE_T dwSize, uint64_t flags)
{
if (dwSize == 0) {
return NULL;
PVOID XMemAllocDefault_X(SIZE_T dwSize, uint64_t flags) {
PVOID ptr = nullptr;
// Example flag usage: we assume if the highest bit of flags is set, we zero the memory.
bool shouldZeroMemory = (flags & (1ULL << 63)) != 0;
// Allocate memory
ptr = malloc(dwSize);
// Optionally zero out the memory if the flag is set
if (ptr && shouldZeroMemory) {
memset(ptr, 0, dwSize);
}
SIZE_T regionSize = dwSize;
PVOID baseAddress = NULL;
unsigned int allocType;
HANDLE titleHeap;
ULONG protectFlags;
int allocationFlags;
// Determine heap index
unsigned int heapIndex = (flags >> 29) & 0xF;
if (!XmpHeapPageTypes[heapIndex]) {
return NULL;
}
// Check allocation type
if (XmpHeapAllocationTypes[heapIndex] != 0x10000000) {
unsigned int heapFlags = flags >> 24;
if ((flags & 0x1F) <= 4) {
allocType = 32; // Standard heap allocation
if ((flags & 0xC000) == 0) {
goto allocate_heap;
}
}
allocType = 33; // Virtual memory allocation
}
else {
allocType = heapIndex;
if ((flags & 0xC000) < 0x4000) {
flags |= 0x4000;
}
unsigned int flagBits = flags & 0x1F;
if (flagBits > 0x10 || dwSize > 0x20000) {
allocType = 33; // Virtual allocation
}
else if (flagBits > 0xC || dwSize > 0xF00) {
allocType |= 0x10;
}
}
allocate_heap:
if (allocType == 32) { // Heap allocation
titleHeap = HeapCreate(0, 0, 0x80002u);
return titleHeap ? HeapAlloc(titleHeap, 0, regionSize) : NULL;
}
if (allocType == 33) { // Virtual memory allocation
int memFlag = MEM_COMMIT | MEM_RESERVE;
switch (flags >> 14) {
case 1: memFlag = MEM_LARGE_PAGES; break;
case 2: memFlag = MEM_PHYSICAL; break;
}
allocationFlags = XmpHeapAllocationTypes[heapIndex] | memFlag;
protectFlags = XmpHeapPageTypes[heapIndex];
if (allocationFlags & 0x400000) {
allocationFlags &= ~0x400000;
if (!(flags >> 14)) {
allocationFlags |= MEM_TOP_DOWN;
}
}
baseAddress = VirtualAlloc(NULL, regionSize, allocationFlags, protectFlags);
if (baseAddress != NULL) {
return baseAddress;
}
}
HANDLE heapHandle = XmpHeaps[allocType];
if (!heapHandle) {
heapHandle = (HANDLE)HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
XmpHeaps[allocType] = heapHandle;
}
return heapHandle ? HeapAlloc(heapHandle, 0, regionSize) : NULL;
return ptr;
}
BOOLEAN __stdcall XMemFreeDefault_X(PVOID pAddress, uint64_t dwAllocAttributes) {
if (!pAddress) {
return FALSE; // Avoid processing NULL pointers
@@ -414,6 +347,37 @@ NTSTATUS __fastcall XMemSetAllocationHooks_X(PVOID(__fastcall* XMemAlloc)(SIZE_T
#define PROTECT_FLAGS_MASK (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_GUARD | PAGE_NOCACHE)
#define ALLOCATION_FLAGS_MASK (MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_LARGE_PAGES | MEM_PHYSICAL | MEM_TOP_DOWN | MEM_WRITE_WATCH)
LPVOID VirtualAllocEx_X(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
)
{
flProtect &= PROTECT_FLAGS_MASK;
flAllocationType &= ALLOCATION_FLAGS_MASK;
LPVOID ret = VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
// backup plan in the case that VirtualAlloc fails despite the flags being masked away
if (ret == nullptr)
{
//printf("VirtualAlloc failed with %i, using backup...\n", GetLastError());
if ((flAllocationType & 0x2000) != 0)
{
flAllocationType = 0x2000;
}
if ((flAllocationType & 0x1000) != 0)
{
flAllocationType = 0x1000;
}
ret = VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
}
return ret;
}
LPVOID VirtualAlloc_X(
LPVOID lpAddress,
SIZE_T dwSize,
@@ -421,22 +385,9 @@ LPVOID VirtualAlloc_X(
DWORD flProtect
)
{
flProtect &= PROTECT_FLAGS_MASK;
flAllocationType &= ALLOCATION_FLAGS_MASK;
LPVOID ret = VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
// backup plan in the case that VirtualAlloc fails despite the flags being masked away
if (ret == nullptr)
{
printf("VirtualAlloc failed with %i, using backup...\n", GetLastError());
ret = VirtualAlloc(lpAddress, dwSize, MEM_COMMIT, flProtect);
}
assert(ret != nullptr && "VirtualAlloc should not fail, check proper handling of xbox-one specific memory protection constants.");
return ret;
return VirtualAllocEx_X(GetCurrentProcess(), lpAddress, dwSize, flAllocationType, flProtect);
}
BOOL ToolingMemoryStatus_X(LPTOOLINGMEMORYSTATUS buffer)
{
DEBUG_PRINT();
@@ -462,35 +413,47 @@ BOOL ToolingMemoryStatus_X(LPTOOLINGMEMORYSTATUS buffer)
return TRUE;
}
//Vodka Doc: 1 to 1 copy from the original function
BOOL __stdcall TitleMemoryStatus_X(PTITLEMEMORYSTATUS Buffer) {
DEBUG_PRINT();
if (!Buffer || Buffer->dwLength != sizeof(TITLEMEMORYSTATUS)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
BOOL TitleMemoryStatus_X(LPTITLEMEMORYSTATUS Buffer)
{
__int64 ProcessInformation[10]; // [rsp+30h] [rbp-68h] BYREF
if (Buffer->dwLength != 80)
{
SetLastError(0x57u);
return false;
}
NTSTATUS status;
DWORDLONG ProcessInformation[7] = { 0 };
status = NtQueryInformationProcess(
GetCurrentProcess(),
NTSTATUS Status = NtQueryInformationProcess(
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
(PROCESSINFOCLASS)(0x3A | 0x3A),
&ProcessInformation,
sizeof(ProcessInformation),
NULL);
ProcessInformation,
0x48u,
0i64);
if (status < 0) {
RtlSetLastWin32ErrorAndNtStatusFromNtStatus(status);
if (!NT_SUCCESS(Status))
{
SetLastError(Status);
return FALSE;
}
Buffer->ullTotalMem = ProcessInformation[0];
Buffer->ullAvailMem = ProcessInformation[0] - ProcessInformation[1];
Buffer->ullLegacyUsed = ProcessInformation[2];
Buffer->ullLegacyAvail = ProcessInformation[4] - ProcessInformation[2];
Buffer->ullLegacyPeak = ProcessInformation[3];
Buffer->ullAvailMem = ProcessInformation[4] - ProcessInformation[2];
Buffer->ullTitleUsed = ProcessInformation[5];
Buffer->ullTitleAvail = ProcessInformation[6] - ProcessInformation[5];
Buffer->ullTitleUsed = ProcessInformation[5] - ProcessInformation[6];
//// @Patoke todo: what is this doing? it's writing outside the bounds of TITLEMEMORYSTATUS
//*(DWORD*)((uint8_t*)Buffer + 64) = ProcessInformation[7];
//*(DWORD*)((uint8_t*)Buffer + 72) = ProcessInformation[8];
// equivalent to the previous code
auto* nextBuffer = Buffer++;
nextBuffer->dwLength = ProcessInformation[7];
nextBuffer->dwReserved = ProcessInformation[8];
return TRUE;
}

View File

@@ -110,6 +110,8 @@
<ClInclude Include="ICoreApplicationX.h" />
<ClInclude Include="ICoreWindowX.h" />
<ClInclude Include="kernelx.h" />
<ClInclude Include="MMDeviceEnumeratorWrapper.h" />
<ClInclude Include="MMXboxDeviceEnumeratorWrapper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="utils.h" />
</ItemGroup>
@@ -121,6 +123,8 @@
<ClCompile Include="FrameworkViewSourceWrapper.cpp" />
<ClCompile Include="FrameworkViewWrapper.cpp" />
<ClCompile Include="kernelx.cpp" />
<ClCompile Include="MMDeviceEnumeratorWrapper.cpp" />
<ClCompile Include="MMXboxDeviceEnumeratorWrapper.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>

View File

@@ -19,6 +19,12 @@
<ClCompile Include="CurrentAppWrapper.cpp">
<Filter>Windows.ApplicationModel.Store\CurrentApp</Filter>
</ClCompile>
<ClCompile Include="MMXboxDeviceEnumeratorWrapper.cpp">
<Filter>MMDeviceEnumerator\Xbox</Filter>
</ClCompile>
<ClCompile Include="MMDeviceEnumeratorWrapper.cpp">
<Filter>MMDeviceEnumerator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
@@ -53,6 +59,12 @@
<ClInclude Include="ICoreApplicationGpuPolicy.h">
<Filter>Windows.ApplicationModel.Core</Filter>
</ClInclude>
<ClInclude Include="MMXboxDeviceEnumeratorWrapper.h">
<Filter>MMDeviceEnumerator\Xbox</Filter>
</ClInclude>
<ClInclude Include="MMDeviceEnumeratorWrapper.h">
<Filter>MMDeviceEnumerator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Exports.def" />
@@ -84,5 +96,11 @@
<Filter Include="Windows.ApplicationModel.Store\CurrentApp">
<UniqueIdentifier>{19e1cefa-5dbe-43ed-a9ad-b22278e05c1a}</UniqueIdentifier>
</Filter>
<Filter Include="MMDeviceEnumerator">
<UniqueIdentifier>{28b69cd1-c8f0-4a87-991d-b7cc93451aa7}</UniqueIdentifier>
</Filter>
<Filter Include="MMDeviceEnumerator\Xbox">
<UniqueIdentifier>{58f8ec7f-d4c1-43e8-a2a9-81a75350ae82}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>