Reloaded.Injector icon indicating copy to clipboard operation
Reloaded.Injector copied to clipboard

Allow creating process with injected DLL

Open chyyran opened this issue 3 years ago • 2 comments

I am trying to hook Vulkan in an application, and due to how the Vulkan loader works, it doesn't seem possible to hook after the application calls vkCreateInstance.

[X64.Function(X64.CallingConventions.Microsoft)]
[X86.Function(X86.CallingConventions.Stdcall)]
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
public unsafe delegate Result vkQueuePresentKHR(Queue queue, PresentInfoKHR* pPresentInfo);```

...

var handle = Kernel32.GetModuleHandle("vulkan-1");

// QueuePresentKHRFn is never called.
this.VkQueuePresentKHRHook  = ReloadedHooks.Instance.CreateHook<vkQueuePresentKHR>(QueuePresentKHRFn, (long)handle.GetProcAddress("vkQueuePresentKHR")).Activate();

I realize that the canonical way of doing Vulkan hooking is via layers, but doing it via a validation layer complicates .NET interop, so if possible it would be nice to do it the 'traditional' way.

To be able to hook Vulkan properly, I need to be able to obtain a handle to the created VkInstance, and thereafter I can use vkGetInstanceProcAddr. vkCreateInstance is called directly via vulkan-1.dll exports, so if I can hook the process before the target application creates its instance, I can obtain a handle to the VkInstance and resolve the other functions via vkInstanceGetProcAddr.

Detours provides DetourCreateProcessWithDllEx which does injection before the process is fully loaded, so I can hook vkCreateInstance as early as possible. I was wondering if this functionality could also be provided in Reloaded.Injector.

Alternatively maybe I'm doing things completely wrong and there's a much easier way to hook Vulkan calls without needing early-hooking, in which case I would be happy to do instead.

chyyran avatar Feb 16 '22 08:02 chyyran

A few ways to approach this.

One that doesn't involve modifying the target folder whatsoever is as follows:

  • Launch the Process Suspended (CreateProcessW + CREATE_SUSPENDED).
  • Inject your DLLs.
  • Resume the primary thread to start the process. (procInfo.hThread).

Only problem is this approach deadlocks during one of the initialisation steps with this specific library, so I wound up creating a simpler injector for another project that needed this sort of behaviour.

Was something related to grabbing the address of kernel32 IIRC.

Sewer56 avatar Feb 16 '22 09:02 Sewer56

I tried creating the process suspended and indeed ran into the deadlocking issues mentioned.

Rather than having to create another injector library, for my use case specifically I can probably 'inject' my CLR loader as a Vulkan layer and just pass in pfnNextGetInstanceProcAddr to the entry point, then do hooking as usual. Theoretically I think that should work though I haven't tried it out yet. Just a bit disappointing that I can't do it the same way as the other graphics APIs.

chyyran avatar Feb 16 '22 18:02 chyyran