3

I want to use DXVK in GTA 5 on Windows 11. Using the needed .dlls (d3d11.dll and dxgi.dll) and launching the game comes with this error

enter image description here

Using Process Explorer (while the error message is displayed) you can see that only dxgi.dll from the Windows directory is loaded, the one that i copied from DXVK is never loaded enter image description here

Using an injector does not work since loaders/injectors relay/defer the "injection" part until their DlllMain() has completed execution.

So how can i inject the custom dxgi.dll before the executable starts?

3 Answers3

2

Sometimes creating a file file.exe.local next to file.exe is enough to make it load DLLs from the same directory but it may not work if the program applied DLL sideloading mitigations or loads the DLL manually from the system directory using absolute path.

Igor Skochinsky
  • 36,553
  • 7
  • 65
  • 115
2

Two aspects weren't mentioned, so I wanted to add them. Igor's approach would be the least invasive, if it works.

  1. the first way to get around this would be a launcher. It is possible to create a process with the main thread suspended (CREATE_SUSPENDED in CreateProcess()). This way you can inject shell code before the program gets to start. However, this won't work with static imports (delay loads are yet another thing not subject to the same limitation). One convenient way to create a launcher is by setting the launcher as debugger to a given binary (full path or base name) using Image File Execution Options (GFlagsX has a graphical way of manipulating this stuff). It should be noted that this is what Process Explorer does when you tell it to "replace" the task manager.
  2. known DLLs have to be taken into account. Your d3d11.dll and dxgi.dll are not known DLLs (configured via HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs) on a vanilla Windows, but they could have been configured to be preloaded (unlikely though). These DLLs are preloaded by the system and have names in the object directories \KnownDlls and \KnownDlls32 respectively (use a tool like WinObj or WinDbg to inspect the object manager namespace). The objects therein are section objects (kernel mode lingo for memory mapped files), which take precedence whenever you attempt to load something, e.g. via DLL placement attack. This means even though you can coerce a program to load your placed DLL if it's not a known DLL, this won't work with known DLLs. The workaround is a highly privileged agent (usually a service) which would be able to tamper with the currently preloaded DLLs. This requires NT native APIs, though, because almost all functionality related to the object manager is hidden away from Win32 developers.

Suppose you have written a launcher, it may still not work, simply on account of the DLLs getting imported statically. The notion of a static import means that the statically imported DLLs get resolved and the imported functions resolved before your application entry point executes. This means you cannot do anything but manipulate the application or attempt a DLL placement attack in such a scenario. The launcher won't work (although it could provide ways to manipulate the running process early on and hook into the facilities used to load the DLL).

The message box you showed, however, suggests that your import happens at runtime (this is not the usual message box you would get to see when the image loader fails). This could suggest that inside your program someone/something sets the DLL search order. But it could just as well be a hardcoded full DLL path passed to LoadLibrary() et. al. One way of diagnosing this other than with a debugger would be ProcMon from Sysinternals/Microsoft. It has the ability to capture process events such as attempting to load a DLL.

Edit: There is one other option I am aware of that requires some agent running in the TCB, e.g. a service, and a kernel driver watching out for events like image loading and thread/process creation. The driver then subscribes to some notification scheme implemented between driver and service and performs the necessary steps from user mode early on before the process or most of its statically imported DLLs get to run any code.

0xC0000022L
  • 10,908
  • 9
  • 41
  • 79
0

Hook loadlibrary and see what it gets called with, this will pick up ntdll loading as well as anything done manually by the app. If you're using x64dbg you can make the breakpoint log out each call and then just look at the logs after it crashes out