3
votes
  • Copy kernel32.dll from System32 (or SysWOW64 if you're testing with a 32-bit application) to the directory containing your EXE file
  • Run the EXE file
  • Process Monitor shows it doesn't even bother to check the local folder for kernel32.dll first

This seems to contradict what I've always thought is the default behaviour of DLLs, that is to load from the local application directory first and if it's not there load from the PATH environment variable. However, for certain DLLs like ntdll or kernel32, Windows always seems to check System32 first. Is this expected behaviour? Can it be overridden?

(I'm aware that overriding this would be bad practice, but want to know if it's actually possible, for science!)

2
32-bit apps actually have system32 redirect to the 32-bit counterpart, so it doesn't even try to load a 64-bit DLL as the first choice.Paul Stelian
And those DLLs are pretty much already cached, and loading from another place is not nice. System critical DLLs will always be injected from the default path.Paul Stelian
I am aware that Windows redirects System32 to SysWOW64 if necessary, that's not what I'm asking. I am also aware it's bad practice to override these DLLs, but I'd still like to know if it's possible. Upon further research it seems I should be adding a .local file to the directory, but this still has no effect.tomysshadow
Then I think they can't be overridden due to Windows' caching behavior (the DLLs only live once in actual RAM, not once for every single process)Paul Stelian
This is the known dll support in windows.josh poley

2 Answers

2
votes

The KnownDLLs feature in Windows is supposed to help loading common DLLs faster but it also forces all DLLs on the list to load from system32.

On top of this, kernel32.dll and ntdll.dll are given special treatment in most versions of Windows and are loaded early inside CreateProcess because the real entry point of a usermode process is in one of those modules.

You can use .local and manifest redirection to override some of these.

1
votes

After more research, I found that the reason certain DLLs such as kernel32.dll or user32.dll cannot be overridden normally is because they are Known DLLs - Windows has a list of commonly used DLLs like these which automatically default to the System32 versions, rather than the default behaviour of checking the folder of the application first.

If you want to work around this, for example to make a proxy DLL, you need to include two files in the application directory: applicationName.exe.local and applicationName.exe.manifest where applicationName is the name of your EXE file.

These need to be the contents of the manifest file:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0" name="redirector" type="win32" />
    <file name="kernel32.dll" />
</assembly>

The assemblyIdentity tag is intended to give information about your application's version number and name, but we can basically just ignore it. The important part is the file tag which specifies a file to load locally. Replace kernel32.dll with DLL you'd like to load locally.

Also, Windows only refreshes the contents of .manifest files either upon restart, or when the EXE file is modified, so you could just open the EXE file in some hex editor, erase the first character and add it back and save... etc. to refresh the manifest file. Do this if you manifest file seems to be ignored.

  • On Windows 2000 and below, adding a .local file will be enough to convince it to load the local version of kernel32.dll .
  • On Windows XP and above, you need to use the .manifest file.
  • It's possible for an application to have a .manifest file embedded within it. In this case, you can delete the resource with a tool like Stud_PE.