Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace
const DWORD XEXP_FINISH_EXECUTABLE_LOAD_RETAIL = 0x8007AF68;
const DWORD XEXP_FINISH_EXECUTABLE_LOAD_DEVKIT = 0x800A17C8;

// TODO: make this nicer
const DWORD IW4_MP_TU6_TIMESTAMP = 0x4BE22338;
const DWORD IW4_MP_TU6_EXECUTION_VERSION = 0x0000060A;
const DWORD IW4_MP_TU9_EXECUTION_VERSION = 0x0000090A;

PluginManager *g_plugin_manager = nullptr;
Detour g_xexp_finish_executable_load_detour;
bool g_title_terminate_registered = false;
Expand Down Expand Up @@ -44,6 +49,40 @@ DWORD ResolveCurrentTimeDateStamp()
return module != nullptr ? module->TimeDateStamp : 0;
}

bool SpoofCurrentTitleVersionIfNeeded(DWORD timestamp)
{
// Report MW2 TU6 as TU9 so spoof-enabled consoles can join each other on Xbox Live.
if (timestamp != IW4_MP_TU6_TIMESTAMP)
{
return false;
}

PXEX_EXECUTION_ID execution_id = nullptr;
const NTSTATUS status = XamGetExecutionId(&execution_id);
if (status != 0 || execution_id == nullptr)
{
return false;
}

if (!MmIsAddressValid(execution_id) || !MmIsAddressValid(&execution_id->Version))
{
return false;
}

if (execution_id->TitleID != TITLE_ID_IW4)
{
return false;
}

if (execution_id->Version != IW4_MP_TU6_EXECUTION_VERSION)
{
return false;
}

execution_id->Version = IW4_MP_TU9_EXECUTION_VERSION;
return true;
}

void XexpFinishExecutableLoad_Hook(PLDR_DATA_TABLE_ENTRY module, const char *commandLine)
{
if (g_plugin_manager != nullptr)
Expand All @@ -56,7 +95,12 @@ void XexpFinishExecutableLoad_Hook(PLDR_DATA_TABLE_ENTRY module, const char *com
if (g_plugin_manager != nullptr)
{
const DWORD timestamp = module != nullptr ? module->TimeDateStamp : 0;
const bool spoofed_title_version = SpoofCurrentTitleVersionIfNeeded(timestamp);
g_plugin_manager->OnExecutableLoaded(ResolveCurrentTitleId(), timestamp);
if (spoofed_title_version)
{
xbox::Notify("Title update spoofed: TU6 -> TU9");
}
}
}
} // namespace
Expand Down Expand Up @@ -86,6 +130,8 @@ bool DllMain(HANDLE hModule, DWORD reason, LPVOID lpvReserved)
return TRUE;
}

xbox::ApplySystemPatches();

ExRegisterTitleTerminateNotification(&g_title_terminate_registration, TRUE);
g_title_terminate_registered = true;

Expand Down
37 changes: 16 additions & 21 deletions src/plugin_manager.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
#include "pch.h"
#include "plugin_manager.h"

enum TitleID : DWORD
{
DASHBOARD = 0xFFFE07D1,
};

template <typename T> std::unique_ptr<Plugin> CreatePlugin()
{
return make_unique<T>();
Expand Down Expand Up @@ -41,112 +36,111 @@ struct GameInfo

const GameInfo GAME_INFO[] = {
{
0x415607FF,
TITLE_ID_QOS,
0x49E8DEDE, // Fri Apr 17 20:56:14 2009
"default_mp.xex",
"",
"007: Quantum of Solace MP Title Update #2",
&CreatePlugin<qos::mp::QOS_MP_Plugin>,
},
{
0x415607FF,
TITLE_ID_QOS,
0x48D0C2CA, // Wed Sep 17 09:41:46 2008
"default.xex",
"",
"007: Quantum of Solace SP Title Update #2",
&CreatePlugin<qos::sp::QOS_SP_Plugin>,
},

{
0x415607D1,
TITLE_ID_IW2,
0x4456B8A3, // Tue May 2 02:40:51 2006
"default_mp.xex",
"",
"Call of Duty 2 MP Title Update #3",
&CreatePlugin<iw2::mp::IW2_MP_Plugin>,
},
{
0x415607D1,
TITLE_ID_IW2,
0x43E7A218, // Mon Feb 6 19:23:04 2006
"default.xex",
"",
"Call of Duty 2 SP Title Update #3",
&CreatePlugin<iw2::sp::IW2_SP_Plugin>,
},
{
0x415607E6,
TITLE_ID_IW3,
0x4A78A577, // Tue Aug 4 22:17:43 2009
"default_mp.xex",
"CoD4 MP 1.4 build 79 nightly Tue Aug 04 2009 01:51:14PM xenon",
"Call of Duty 4: Modern Warfare MP Title Update #4",
&CreatePlugin<iw3::mp::IW3_MP_Plugin>,
},
{
0x415607E6,
TITLE_ID_IW3,
0x46E1E82F, // Sat Sep 8 01:09:19 2007
"default.xex",
"CoD4 1.0 build 472 nightly Fri Sep 07 2007 04:59:49PM xenon",
"Call of Duty 4: Modern Warfare SP Title Update #4",
&CreatePlugin<iw3::sp::IW3_SP_Plugin>,
},
{
0x4156081C,
TITLE_ID_T4,
0x4AD7C0EE, // Fri Oct 16 01:40:14 2009
"default_mp.xex",
"Call of Duty Multiplayer COD_WaW MP build 5.5.51 CL(0) ZQABUILD1 Thu Oct 15 17:39:03 2009 xenon",
"Call of Duty: World at War MP Title Update #7",
&CreatePlugin<t4::mp::T4_MP_Plugin>,
},
{
0x4156081C,
TITLE_ID_T4,
0x4AD7C0DF, // Fri Oct 16 01:39:59 2009
"default.xex",
"",
"Call of Duty: World at War SP Title Update #7",
&CreatePlugin<t4::sp::T4_SP_Plugin>,
},
{
0x41560817,
TITLE_ID_IW4,
0x4BE22338, // Thu May 6 03:02:32 2010
"default_mp.xex",
"IW4 MP 1.4 build 669 latest Wed May 05 2010 06:55:32PM xenon",
"Call of Duty: Modern Warfare 2 MP Title Update #6",
&CreatePlugin<iw4::mp_tu6::IW4_MP_TU6_Plugin>,
},
{
0x41560817,
TITLE_ID_IW4,
0x5B11C269, // Fri Jun 1 23:02:17 2018
"default_mp.xex",
"IW4 MP 1.4 build 163842 Tue Feb 08 16:52:00 2011 xenon",
"Call of Duty: Modern Warfare 2 MP Title Update #9",
&CreatePlugin<iw4::mp::IW4_MP_Plugin>,
},
{
0x41560817,
TITLE_ID_IW4,
0x5074B056, // Wed Oct 10 00:16:38 2012
"default.xex",
"IW4 1.0 build 125545 Fri Sep 25 22:12:21 2009 xenon",
"Call of Duty: Modern Warfare 2 SP Title Update #9",
&CreatePlugin<iw4::sp::IW4_SP_Plugin>,
},
{
0x41560855,
TITLE_ID_T5,
0x4E542876, // Tue Aug 23 23:23:50 2011
"default_mp.xex",
"",
"Call of Duty: Black Ops MP Title Update #11",
&CreatePlugin<t5::mp::T5_MP_Plugin>,
},
{
0x41560855,
TITLE_ID_T5,
0x4E542875, // Tue Aug 23 23:23:49 2011
"default.xex",
"",
"Call of Duty: Black Ops SP Title Update #11",
&CreatePlugin<t5::sp::T5_SP_Plugin>,
},
{
0x415608CB,
TITLE_ID_IW5,
0x5B10A113, // Fri Jun 1 02:27:47 2018
"default_mp.xex",
"IW5 MP 1.8 build 388110 Fri Sep 14 00:04:28 2012 xenon",
Expand Down Expand Up @@ -224,7 +218,7 @@ void PluginManager::OnExecutableLoadStarted()

void PluginManager::OnExecutableLoaded(DWORD title_id, DWORD timestamp)
{
if (title_id == DASHBOARD)
if (title_id == TITLE_ID_DASHBOARD)
{
return;
}
Expand All @@ -238,6 +232,7 @@ void PluginManager::OnExecutableLoaded(DWORD title_id, DWORD timestamp)
}

DbgPrint("[codxe][PluginManager] Game detected: '%s'.\n", info->friendlyVersion);
xbox::Notify(info->friendlyVersion);
LoadPlugin(info);
}

Expand Down
12 changes: 12 additions & 0 deletions src/plugin_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

struct GameInfo;

enum TitleID : DWORD
{
TITLE_ID_DASHBOARD = 0xFFFE07D1,
TITLE_ID_IW2 = 0x415607D1,
TITLE_ID_IW3 = 0x415607E6,
TITLE_ID_IW4 = 0x41560817,
TITLE_ID_IW5 = 0x415608CB,
TITLE_ID_QOS = 0x415607FF,
TITLE_ID_T4 = 0x4156081C,
TITLE_ID_T5 = 0x41560855,
};

class PluginManager
{
public:
Expand Down
50 changes: 50 additions & 0 deletions src/xbox360.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ void *ResolveFunction(const char *moduleName, unsigned int ordinal)
return GetProcAddress(moduleHandle, reinterpret_cast<const char *>(ordinal));
}

enum XNotifyQueueUIType
{
XNOTIFYUI_TYPE_GENERIC = 3,
XNOTIFYUI_TYPE_EXCLAIM = 34,
};

typedef int (*XNotifyQueueUI_t)(XNotifyQueueUIType type, DWORD user_index, DWORD areas, const WCHAR *display_text,
void *context_data);
static XNotifyQueueUI_t XNotifyQueueUI = reinterpret_cast<XNotifyQueueUI_t>(ResolveFunction("xam.xex", 656));

const DWORD XNOTIFY_USER_INDEX_ANY = 0x000000FF;
const DWORD XNOTIFY_AREA_SYSTEM = 0x00000001;

/**
* Check if we are running in Xenia Canary.
*
Expand Down Expand Up @@ -41,6 +54,25 @@ Environment DetectEnvironment()

return DetectDevkit() ? ENVIRONMENT_XBOX_DEVKIT : ENVIRONMENT_XBOX_RETAIL;
}

void CopyAsciiToWide(const char *source, WCHAR *destination, size_t destination_count)
{
if (destination == nullptr || destination_count == 0)
{
return;
}

size_t i = 0;
if (source != nullptr)
{
for (; source[i] != '\0' && i + 1 < destination_count; i++)
{
destination[i] = static_cast<unsigned char>(source[i]);
}
}

destination[i] = L'\0';
}
} // namespace

Environment GetEnvironment()
Expand All @@ -65,4 +97,22 @@ const char *GetEnvironmentName(Environment environment)
}
}

void ApplySystemPatches()
{
// Allow XNotifyQueueUI to be called from system threads.
*(volatile uint16_t *)0x816A3158 = 0x4800;
}

void Notify(const char *message)
{
assert(message != nullptr);

char branded_message[160];
_snprintf_s(branded_message, sizeof(branded_message), _TRUNCATE, "CoD Xe: %s", message);

WCHAR display_text[160];
CopyAsciiToWide(branded_message, display_text, ARRAYSIZE(display_text));
XNotifyQueueUI(XNOTIFYUI_TYPE_EXCLAIM, XNOTIFY_USER_INDEX_ANY, XNOTIFY_AREA_SYSTEM, display_text, nullptr);
}

} // namespace xbox
2 changes: 2 additions & 0 deletions src/xbox360.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ enum Environment

Environment GetEnvironment();
const char *GetEnvironmentName(Environment environment);
void ApplySystemPatches();
void Notify(const char *message);

} // namespace xbox
Loading