-1

I have been playing around with writing a windows program that does DLL injection for my own education. My program is an x64 Visual C++ application I am running on windows 11. It injects the DLL into its victim by using CreateRemoteThread to execute a small piece of shell code that then executes the LoadLibraryA function. I did this in this fashion so if the LoadLibraryA function fails, I can retrieve the reason for the failure by using GetLastError. Here is the C++ version of that shell code:

struct DllLoaderThreadParam
{
    LoadLibraryA_t LoadLibraryA;
    GetLastError_t GetLastError;
    LPCSTR         injectedDllPath;
    HMODULE        injectedDllH;
    DWORD          lastError;
};

DWORD DllLoaderThread(PVOID pParam)
{
    DllLoaderThreadParam* p = (DllLoaderThreadParam*)pParam;
    p->injectedDllH = p->LoadLibraryA(p->injectedDllPath);
    if (!p->injectedDllH)
    {
        p->lastError = p->GetLastError();
    }
    return 0;
}

My injector allocates memory in the target process for the DllLoaderThreadParam, the DLL path name, and shell code; writes the necessary information to those memory locations; and then calls CreateRemoteThread to execute the shell code. This works fine for the most part. However, certain processes are unable to load the DLL for some unknown reason due to an "Access is denied" failure. Consider the following debug output:

PID 31876 redirected output to C:\Temp\31876_stdout.txt
PID 31876 is attaching DLL C:\Users\miked\Source\repos\InjectedDll\x64\Debug\InjectedDll.dll
PID 31876 set injection complete event
PID 31876 successfully attached DLL
Loaded injection DLL C:/Users/miked/Source/repos/InjectedDll/x64/Debug/InjectedDll.dll
Opened process 21180 for injection
Target Process Machine: 0, Host Process Machine: 0
Target Native Machine: 8664, Host Native Machine:  8664
Remote DLL loader thread 45620 created successfully!
Remote thread remote DLL loader thread terminated with exit code (0)
Remote ThreadMain thread 33604 created successfully!
Remote thread ThreadMain terminated with exit code (0)
PID 31876 is detaching DLL C:\Users\miked\Source\repos\InjectedDll\x64\Debug\InjectedDll.dll
InjectDLL rtn: 0
Selected file: C:/Users/miked/Source/repos/InjectedDll/x64/Debug/InjectedDll.dll
PID 31876 is redirecting output to file C:\Temp\31876
PID 31876 redirected output to C:\Temp\31876_stdout.txt
PID 31876 is attaching DLL C:\Users\miked\Source\repos\InjectedDll\x64\Debug\InjectedDll.dll
PID 31876 set injection complete event
PID 31876 successfully attached DLL
Loaded injection DLL C:/Users/miked/Source/repos/InjectedDll/x64/Debug/InjectedDll.dll
Opened process 25208 for injection
Target Process Machine: 0, Host Process Machine: 0
Target Native Machine: 8664, Host Native Machine:  8664
Remote DLL loader thread 49796 created successfully!
Remote thread remote DLL loader thread terminated with exit code (0)
**Remote DLL loader thread failed to load DLL, error: (5) - Access is denied.

PID 31876 is detaching DLL C:\Users\miked\Source\repos\InjectedDll\x64\Debug\InjectedDll.dll
InjectDLL rtn: 1

Both of these injections were made to processes running the msedge.exe executable. the first injection into process id 21180 worked flawlessly. My injector shell successfully loaded the DLL, and my injector program was subsequently able to run a program from that injected DLL also using CreateRemoteThread.

However, I tried to inject into another process running the same msedge.exe executable, but as you can see, my shell loader failed at the LoadLibraryA call with error 5 - Access is denied. Notice that I provide a fully qualified DLL path. I have also ensured (I believe) that the group Everyone should have access to it. I also use IsWow64Process2 to ensure the target process is running the same 64 bit architecture as my injector process, the results of which you can also see in the debug output.

FYI, I originally was using the classic DLL injection approach by directly executing only the LoadLibraryA function in the target, but because I was seeing this same issue using that approach, but couldn't know what the reason for the failure was (since the return code from the thread was the result of the LoadLibraryA call only) I decided to go the extra step of using the shell to retrieve the error code.

So this has me stumped. I am only marginally familiar with Windows security/privilege topics, and I did a ton of searching to discover if any privileges might prevent DLL access/loading exist, but came up empty. So I'd appreciate any clues as to why this might be happening. Thanks!

  • 1
    Edge/Chrome try to stop injections with process mitigations to stop spying and cookie/password stealing. – Anders Feb 22 '22 at 14:41
  • But some instances of edge allow the dll to load, while others don't. Any idea why this would this be the case? I've also seen this with other non-browser processes. Do you have any information about what mitigation techniques they use? – Mistah Mikey Feb 22 '22 at 15:43

1 Answers1

0

Edge is known to run in a sandbox mode, to protect your PC from websites. It appears the sandbox protection works both ways.

You mention "group Everyone", but that's just Role-Based Access Control. Sandboxing is intended to protect your files from your browser; user accounts do not matter there.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Why then would one instance of edge allow the DLL to load, while others don't? I have also seen this with other processes. Is there a way to determined if a process is using "Sandbox mode"? Is there a way around it so the inject can successfully load the DLL? – Mistah Mikey Feb 22 '22 at 15:38
  • 1
    IIRC, because Edge spawns a child process for each sandbox it creates. As for the "way around", don't bother. If such a way would be discovered, it would be fixed in the next security update. Don't try to fight security. CreateRemoteThread is for things like debuggers. – MSalters Feb 22 '22 at 15:58