Skip to content
Draft
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
4 changes: 4 additions & 0 deletions mhw-cs-plugin-loader.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
</Folder>
<Folder Name="/Native/">
<Project Path="dependencies/cimgui/cimgui.vcxproj" Id="56f04c3c-a690-34fc-a27a-995c51114a40" />
<Project Path="mhw-cs-plugin-loader/Launcher/Launcher.vcxproj" Id="1fa71114-1187-4059-9523-196a234c1b94">
<BuildType Solution="MinSizeRel|*" Project="Release" />
<BuildType Solution="RelWithDebInfo|*" Project="Debug" />
</Project>
<Project Path="mhw-cs-plugin-loader/mhw-cs-plugin-loader.vcxproj" Id="9267fd61-f5bf-4190-b327-8385f8576479">
<BuildType Solution="MinSizeRel|*" Project="Release" />
<BuildType Solution="RelWithDebInfo|*" Project="Release" />
Expand Down
94 changes: 94 additions & 0 deletions mhw-cs-plugin-loader/Launcher/Launcher.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// cl.exe Launcher.c kernel32.lib user32.lib /link /SUBSYSTEM:windows /NODEFAULTLIB /ENTRY:WinMainCRTStartup

#include <windows.h>
#include <tlhelp32.h>

#define TARGET_EXE "MonsterHunterWorld.exe"
#define TARGET_DLL "winmm.dll"

static DWORD (*K32GetModuleBaseNameA)(IN HANDLE hProcess, IN HMODULE hModule, OUT LPSTR lpBaseName, IN DWORD nSize);
static BOOL (*K32EnumProcessModules)(IN HANDLE hProcess, OUT HMODULE *lphModule, IN DWORD cb, OUT LPDWORD lpcbNeeded);

// MonsterHunterWorld.exe -> ntdll.dll -> KERNEL32.dll -> KERNELBASE.dll -> (apphelp.dll) -> TARGET_DLL + dependencies.
// () = Present on Windows and not Wine (Windows 11, Proton 11.0).
// Total modules varies between Windows and Wine, 64 is plenty in the case of MHW and likely most scenarios.
static HMODULE moduleHandles[64];
static CHAR moduleName[MAX_MODULE_NAME32 + 1];
static CHAR dllPath[MAX_PATH];

// https://git.musl-libc.org/cgit/musl/tree/src/string/strncmp.c
static int Strncmp(const char *_l, const char *_r, size_t n)
{
const unsigned char *l=(void *)_l, *r=(void *)_r;
if (!n--) return 0;
for (; *l && *r && n && *l == *r ; l++, r++, n--);
return *l - *r;
}

static BOOL DllWasInjected(HANDLE process)
{
DWORD cbNeeded;
if (K32EnumProcessModules(process, moduleHandles, sizeof(moduleHandles), &cbNeeded)) {
DWORD processCount = cbNeeded / sizeof(HMODULE);
for (DWORD i = 0; i < processCount; i++) {
K32GetModuleBaseNameA(process, moduleHandles[i], moduleName, sizeof(moduleName));
if (Strncmp(TARGET_DLL, moduleName, sizeof(TARGET_DLL)) == 0) {
return TRUE;
}
}
}
return FALSE;
}

void __stdcall WinMainCRTStartup()
{
HMODULE k32 = GetModuleHandleA("kernel32.dll");
LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(k32, "LoadLibraryA");
K32GetModuleBaseNameA = (LPVOID)GetProcAddress(k32, "K32GetModuleBaseNameA");
K32EnumProcessModules = (LPVOID)GetProcAddress(k32, "K32EnumProcessModules");

STARTUPINFOA si = { .cb = sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
if (CreateProcessA(NULL, TARGET_EXE, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi) == 0) {
MessageBoxA(NULL,
"Failed to create process. Is '" TARGET_EXE "' contained within this folder?",
"Launch Error",
MB_ICONERROR | MB_OK);
ExitProcess(1);
}

DWORD arglen = GetFullPathNameA(TARGET_DLL, sizeof(dllPath), dllPath, NULL);
LPVOID buf = VirtualAllocEx(pi.hProcess, NULL, arglen, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, buf, dllPath, arglen, NULL);

HANDLE hThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryAddr, buf, 0, NULL);
if (!hThread) {
MessageBoxA(NULL,
"Failed to CreateRemoteThread(), make sure the architecture of this exe matches " TARGET_EXE ".",
"Injection Failed",
MB_ICONWARNING | MB_OK);
} else {
WaitForSingleObject(hThread, INFINITE);
// The value of GetExitCodeThread() isn't usable, so try to manually check
// if the DLL got loaded (LoadLibrary() succeeded).
if (!DllWasInjected(pi.hProcess)) {
MessageBoxA(NULL,
"Failed to inject DLL. Is '" TARGET_DLL "' contained within this folder?",
"Injection Failed",
MB_ICONWARNING | MB_OK);
}
CloseHandle(hThread);
}

VirtualFreeEx(pi.hProcess, buf, 0, MEM_RELEASE);

ResumeThread(pi.hThread);

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

FreeLibrary(k32);

ExitProcess(0);
}
Binary file added mhw-cs-plugin-loader/Launcher/Launcher.ico
Binary file not shown.
Binary file added mhw-cs-plugin-loader/Launcher/Launcher.rc
Binary file not shown.
100 changes: 100 additions & 0 deletions mhw-cs-plugin-loader/Launcher/Launcher.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{1fa71114-1187-4059-9523-196a234c1b94}</ProjectGuid>
<RootNamespace>Launcher</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>SPLLauncher</TargetName>
<EmbedManifest>false</EmbedManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>SPLLauncher</TargetName>
<EmbedManifest>false</EmbedManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions);WIN32_LEAN_AND_MEAN</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<BufferSecurityCheck>false</BufferSecurityCheck>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>Yes</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions);WIN32_LEAN_AND_MEAN</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>Yes</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Launcher.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Launcher.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="Launcher.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
33 changes: 33 additions & 0 deletions mhw-cs-plugin-loader/Launcher/Launcher.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Launcher.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Image Include="Launcher.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Launcher.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions mhw-cs-plugin-loader/Launcher/create_icon.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#! /usr/bin/env sh
# -define icon:auto-resize=256,128,96,64,48,32,16
magick -density 512 -define icon:auto-resize=32 -background none ../../docs/images/SPL.svg Launcher.ico
16 changes: 16 additions & 0 deletions mhw-cs-plugin-loader/Launcher/resource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Launcher.rc
//
#define IDI_ICON1 101

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Loading