Skip to content

Commit

Permalink
Fix inject problems (goatcorp#820)
Browse files Browse the repository at this point in the history
* CoreCLR: resolve and load nethost on demand instead of requiring it on load

* Remove nethost loading from C# side

* Added option to not chain Process.Dispose; see for last error only if result is empty
Soreepeong authored Apr 25, 2022
1 parent 5b4833a commit 9a38a94
Showing 15 changed files with 57 additions and 94 deletions.
4 changes: 0 additions & 4 deletions Dalamud.Boot/Dalamud.Boot.vcxproj
Original file line number Diff line number Diff line change
@@ -117,10 +117,6 @@
<ClInclude Include="pch.h" />
<ClInclude Include="veh.h" />
</ItemGroup>
<ItemGroup>
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib" />
<Library Include="..\lib\CoreCLR\nethost\nethost.lib" />
</ItemGroup>
<Target Name="RemoveExtraFiles" AfterTargets="PostBuildEvent">
<Delete Files="$(OutDir)$(TargetName).lib" />
<Delete Files="$(OutDir)$(TargetName).exp" />
12 changes: 0 additions & 12 deletions Dalamud.Boot/Dalamud.Boot.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Library Files">
<UniqueIdentifier>{18be40ac-9367-46ff-b848-4c528aa97a8d}</UniqueIdentifier>
<Extensions>lib</Extensions>
</Filter>
<Filter Include="CoreCLR">
<UniqueIdentifier>{dc468303-865e-43bd-908f-a3542c4bb669}</UniqueIdentifier>
</Filter>
@@ -56,12 +52,4 @@
<Filter>Dalamud.Boot DLL</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Library Include="..\lib\CoreCLR\nethost\nethost.lib">
<Filter>Library Files</Filter>
</Library>
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib">
<Filter>Library Files</Filter>
</Library>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions Dalamud.Boot/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam)

void* entrypoint_vfn;
int result = InitializeClrAndGetEntryPoint(
g_hModule,
runtimeconfig_path,
module_path,
L"Dalamud.EntryPoint, Dalamud",
4 changes: 0 additions & 4 deletions Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj
Original file line number Diff line number Diff line change
@@ -99,10 +99,6 @@
<ClInclude Include="..\lib\CoreCLR\nethost\nethost.h" />
<ClInclude Include="..\lib\CoreCLR\pch.h" />
</ItemGroup>
<ItemGroup>
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib" />
<Library Include="..\lib\CoreCLR\nethost\nethost.lib" />
</ItemGroup>
<Target Name="RemoveExtraFiles" AfterTargets="PostBuildEvent">
<Delete Files="$(OutDir)$(TargetName).lib" />
<Delete Files="$(OutDir)$(TargetName).exp" />
11 changes: 0 additions & 11 deletions Dalamud.Injector.Boot/Dalamud.Injector.Boot.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -13,9 +13,6 @@
<UniqueIdentifier>{4faac519-3a73-4b2b-96e7-fb597f02c0be}</UniqueIdentifier>
<Extensions>ico;rc</Extensions>
</Filter>
<Filter Include="Library Files">
<UniqueIdentifier>{6aff1bed-6979-4bc9-94e8-ddafb626e6bf}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Image Include="dalamud.ico">
@@ -55,12 +52,4 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Library Include="..\lib\CoreCLR\nethost\nethost.lib">
<Filter>Library Files</Filter>
</Library>
<Library Include="..\lib\CoreCLR\nethost\libnethost.lib">
<Filter>Library Files</Filter>
</Library>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions Dalamud.Injector.Boot/main.cpp
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ int wmain(int argc, wchar_t** argv)

void* entrypoint_vfn;
int result = InitializeClrAndGetEntryPoint(
GetModuleHandleW(nullptr),
runtimeconfig_path,
module_path,
L"Dalamud.Injector.EntryPoint, Dalamud.Injector",
6 changes: 1 addition & 5 deletions Dalamud.Injector/EntryPoint.cs
Original file line number Diff line number Diff line change
@@ -634,17 +634,13 @@ private static DalamudStartInfo AdjustStartInfo(DalamudStartInfo startInfo, stri

private static void Inject(Process process, DalamudStartInfo startInfo)
{
var nethostName = "nethost.dll";
var bootName = "Dalamud.Boot.dll";

var nethostPath = Path.GetFullPath(nethostName);
var bootPath = Path.GetFullPath(bootName);

// ======================================================

using var injector = new Injector(process);
using var injector = new Injector(process, false);

injector.LoadLibrary(nethostPath, out _);
injector.LoadLibrary(bootPath, out var bootModule);

// ======================================================
22 changes: 9 additions & 13 deletions Dalamud.Injector/Injector.cs
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ namespace Dalamud.Injector
internal sealed class Injector : IDisposable
{
private readonly Process targetProcess;
private readonly bool disposeTargetProcess;
private readonly ExternalMemory extMemory;
private readonly CircularBuffer circularBuffer;
private readonly PrivateMemoryBuffer memoryBuffer;
@@ -41,9 +42,11 @@ internal sealed class Injector : IDisposable
/// Initializes a new instance of the <see cref="Injector"/> class.
/// </summary>
/// <param name="targetProcess">Process to inject.</param>
public Injector(Process targetProcess)
/// <param name="disposeTargetProcess">Dispose given process on disposing self.</param>
public Injector(Process targetProcess, bool disposeTargetProcess = true)
{
this.targetProcess = targetProcess;
this.disposeTargetProcess = disposeTargetProcess;

this.extMemory = new ExternalMemory(targetProcess);
this.circularBuffer = new CircularBuffer(4096, this.extMemory);
@@ -67,7 +70,8 @@ public void Dispose()
{
GC.SuppressFinalize(this);

this.targetProcess?.Dispose();
if (this.disposeTargetProcess)
this.targetProcess?.Dispose();
this.circularBuffer?.Dispose();
this.memoryBuffer?.Dispose();
}
@@ -85,14 +89,9 @@ public void LoadLibrary(string modulePath, out IntPtr address)
throw new Exception("Unable to allocate LoadLibraryW parameter");

this.CallRemoteFunction(this.loadLibraryShellPtr, lpParameter, out var err);

if (err != 0)
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: {new Win32Exception((int)err).Message} ({err})");

address = this.extMemory.Read<IntPtr>(this.loadLibraryRetPtr);

if (address == IntPtr.Zero)
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: Error code unavailable");
throw new Exception($"LoadLibraryW(\"{modulePath}\") failure: {new Win32Exception((int)err).Message} ({err})");
}

/// <summary>
@@ -110,12 +109,9 @@ public void GetFunctionAddress(IntPtr module, string functionName, out IntPtr ad
throw new Exception("Unable to allocate GetProcAddress parameter ptr");

this.CallRemoteFunction(this.getProcAddressShellPtr, lpParameter, out var err);
if (err != 0)
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: {new Win32Exception((int)err).Message} ({err})");

this.extMemory.Read(this.getProcAddressRetPtr, out address);
address = this.extMemory.Read<IntPtr>(this.getProcAddressRetPtr);
if (address == IntPtr.Zero)
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: Error code unavailable");
throw new Exception($"GetProcAddress(0x{module:X}, \"{functionName}\") failure: {new Win32Exception((int)err).Message} ({err})");
}

/// <summary>
40 changes: 33 additions & 7 deletions lib/CoreCLR/CoreCLR.cpp
Original file line number Diff line number Diff line change
@@ -2,12 +2,14 @@

#include "CoreCLR.h"
#include <Windows.h>
#include <filesystem>
#include <iostream>
#include "nethost/nethost.h"

#pragma comment(lib, "nethost/libnethost.lib")

CoreCLR::CoreCLR() {}
CoreCLR::CoreCLR(void* calling_module)
: m_calling_module(calling_module)
{
}

/* Core public functions */
int CoreCLR::load_hostfxr()
@@ -18,19 +20,43 @@ int CoreCLR::load_hostfxr()
int CoreCLR::load_hostfxr(const struct get_hostfxr_parameters* parameters)
{
// Get the path to CoreCLR's hostfxr
std::wstring calling_module_path(MAX_PATH, L'\0');

do
{
calling_module_path.resize(GetModuleFileNameW(static_cast<HMODULE>(m_calling_module), &calling_module_path[0], static_cast<DWORD>(calling_module_path.size())));
}
while (!calling_module_path.empty() && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
if (calling_module_path.empty())
return -1;

calling_module_path = (std::filesystem::path(calling_module_path).parent_path() / L"nethost.dll").wstring();

auto lib_nethost = reinterpret_cast<void*>(load_library(calling_module_path.c_str()));
if (!lib_nethost)
return -1;

auto get_hostfxr_path = reinterpret_cast<get_hostfxr_path_type>(
get_export(lib_nethost, "get_hostfxr_path"));
if (!get_hostfxr_path)
return -1;

wchar_t buffer[MAX_PATH]{};
size_t buffer_size = sizeof buffer / sizeof(wchar_t);
if (int rc = get_hostfxr_path(buffer, &buffer_size, parameters); rc != 0)
return rc;

// Load hostfxr and get desired exports
auto lib = reinterpret_cast<void*>(load_library(buffer));
auto lib_hostfxr = reinterpret_cast<void*>(load_library(buffer));
if (!lib_hostfxr)
return -1;

m_hostfxr_initialize_for_runtime_config_fptr = reinterpret_cast<hostfxr_initialize_for_runtime_config_fn>(
get_export(lib, "hostfxr_initialize_for_runtime_config"));
get_export(lib_hostfxr, "hostfxr_initialize_for_runtime_config"));
m_hostfxr_get_runtime_delegate_fptr = reinterpret_cast<hostfxr_get_runtime_delegate_fn>(
get_export(lib, "hostfxr_get_runtime_delegate"));
get_export(lib_hostfxr, "hostfxr_get_runtime_delegate"));
m_hostfxr_close_fptr = reinterpret_cast<hostfxr_close_fn>(
get_export(lib, "hostfxr_close"));
get_export(lib_hostfxr, "hostfxr_close"));

return m_hostfxr_initialize_for_runtime_config_fptr
&& m_hostfxr_get_runtime_delegate_fptr
8 changes: 5 additions & 3 deletions lib/CoreCLR/CoreCLR.h
Original file line number Diff line number Diff line change
@@ -5,8 +5,10 @@
#include "nethost/nethost.h"

class CoreCLR {
public:
explicit CoreCLR();
void* const m_calling_module;

public:
explicit CoreCLR(void* calling_module);
~CoreCLR() = default;

int load_hostfxr();
@@ -32,7 +34,7 @@ class CoreCLR {
void* reserved,
void** delegate) const;

private:
private:
/* HostFXR delegates. */
hostfxr_initialize_for_runtime_config_fn m_hostfxr_initialize_for_runtime_config_fptr{};
hostfxr_get_runtime_delegate_fn m_hostfxr_get_runtime_delegate_fptr{};
3 changes: 2 additions & 1 deletion lib/CoreCLR/boot.cpp
Original file line number Diff line number Diff line change
@@ -26,14 +26,15 @@ void ConsoleTeardown()
std::optional<CoreCLR> g_clr;

int InitializeClrAndGetEntryPoint(
void* calling_module,
std::wstring runtimeconfig_path,
std::wstring module_path,
std::wstring entrypoint_assembly_name,
std::wstring entrypoint_method_name,
std::wstring entrypoint_delegate_type_name,
void** entrypoint_fn)
{
g_clr = CoreCLR();
g_clr.emplace(calling_module);

int result;
SetEnvironmentVariable(L"DOTNET_MULTILEVEL_LOOKUP", L"0");
1 change: 1 addition & 0 deletions lib/CoreCLR/boot.h
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ void ConsoleSetup(const std::wstring console_name);
void ConsoleTeardown();

int InitializeClrAndGetEntryPoint(
void* calling_module,
std::wstring runtimeconfig_path,
std::wstring module_path,
std::wstring entrypoint_assembly_name,
Binary file removed lib/CoreCLR/nethost/libnethost.lib
Binary file not shown.
38 changes: 4 additions & 34 deletions lib/CoreCLR/nethost/nethost.h
Original file line number Diff line number Diff line change
@@ -6,36 +6,6 @@

#include <stddef.h>

#ifdef _WIN32
#ifdef NETHOST_EXPORT
#define NETHOST_API __declspec(dllexport)
#else
// Consuming the nethost as a static library
// Shouldn't export attempt to dllimport.
#ifdef NETHOST_USE_AS_STATIC
#define NETHOST_API
#else
#define NETHOST_API __declspec(dllimport)
#endif
#endif

#define NETHOST_CALLTYPE __stdcall
#ifdef _WCHAR_T_DEFINED
typedef wchar_t char_t;
#else
typedef unsigned short char_t;
#endif
#else
#ifdef NETHOST_EXPORT
#define NETHOST_API __attribute__((__visibility__("default")))
#else
#define NETHOST_API
#endif

#define NETHOST_CALLTYPE
typedef char char_t;
#endif

#ifdef __cplusplus
extern "C" {
#endif
@@ -87,10 +57,10 @@ struct get_hostfxr_parameters {
// The full search for the hostfxr library is done on every call. To minimize the need
// to call this function multiple times, pass a large buffer (e.g. PATH_MAX).
//
NETHOST_API int NETHOST_CALLTYPE get_hostfxr_path(
char_t * buffer,
size_t * buffer_size,
const struct get_hostfxr_parameters *parameters);
using get_hostfxr_path_type = int(__stdcall *)(
char_t* buffer,
size_t* buffer_size,
const struct get_hostfxr_parameters* parameters);

#ifdef __cplusplus
} // extern "C"
Binary file removed lib/CoreCLR/nethost/nethost.lib
Binary file not shown.

0 comments on commit 9a38a94

Please sign in to comment.