1
votes

The phenomenon goes like this.

I'm trying to implement dll injection. My application create process in 'suspended' state, (Using CreateProcess with CREATE_SUSPENDED), wait for an important dll to be loaded(kernel32.dll of course), and then executes injection. The suspended process is resumed using ResumeThread after the injection.

I'm using suspended process creation in the hope that dll is injected prior to any other execution except dll load. But while executing this, I found something interesting.

I've simply tested this injection using notepad.exe and it worked just fine. But when I've duplicated the executable as notepad2.exe, my injection waits for infinite time. Kernel32.dll never loads up until the main thread of the process is resumed.

It seems there's some sort of 'authenticated' executable that modules are loaded beforehand (or maybe some security solutions installed in my computer that already uses dll injection might cause this different execution).

Does Anyone knows if there's any sort of thing that modules are loaded in different manner? (Frankly, I still don't understand the life cycle of windows process...)

1
In my experience only ntdll.dll is initially mapped, and an APC is queued to run when the thread resumes. This calls ntdll!LdrpInitializeProcess, which initializes the execution environment (e.g. language support, the heap, thread-local storage, the KnownDlls directory), loads kernel32.dll and gets the address of BaseThreadInitThunk, does static DLL imports, breaks for an attached debugger, and runs the init routines. Then execution jumps to ntdll!RtlUserThreadStart, which calls kernel32!BaseThreadInitThunk, which calls the EXE's entry point such as WinMainCRTStartup.Eryk Sun
I've seen DLL loading behave differently during process startup in seemingly random ways, even for the same executable. I suspect Windows attempts to optimize process startup based on undocumented heuristics - e.g., it may be "taking notes" each time a particular executable starts up, and using that information to try to start it faster the next time. Unfortunately the bottom line is probably that there is no reliable way to predict whether kernel32.dll (or any other system DLL) will be loaded before or after the process is resumed. (But I guess you could queue an APC?)Harry Johnston
@HarryJohnston, there are services such as prefetch/superfetch that work at the level of the memory manager to optimize which DLL and EXE pages are loaded system-wide to accelerate application loading. But I thought the work done by the initial APC queued that starts at ntdll!LdrInitializeThunk has been fairly consistent over the years. I always see the initialization steps and DLL load order in the following debug session: cdb -xe cpr -c "bp ntdll!LdrInitializeThunk; g" notepad. That said, it could be that NtCreateUserProcess is sometimes pre-mapping DLLs other than ntdll.dll.Eryk Sun
I guess I've got some hint. The security solution installed on my computer uses Detour to inject and hook windows API. And it seems that windows Detour enables you to inject DLL with CreateProcess suspended state. I'm guessing when I created process, after several time elapses, Detour loads the security solution dll, and before that, loads up the 'kernel32.dll'. Though I'm not confident on this assumption, several executables I've tested that successfully loads kernel32.dll before main thread resumes all yielded Detour Debug output viewd from DebugViewer (Solution makers left the message!)Sihu Song
@SihuSong, that sounds plausible. Why don't you write it up as answer?Eryk Sun

1 Answers

0
votes

I think I've found an answer. The answer is that though the process is in SUSPENDED state, and therefore main thread is stopped, when certain thread in that process tries to access to a module, then the required modules are loaded (Which means, that windows application seems to 'Lazy Load' require modules)

In the comment, I said that the process protected by certain security solution installed on my PC uses Detour to inject DLL, and therefore modules in certain Process loaded while the process is in SUSPENDED state. But that was not a specific case of Detour, but general issues on every processes.

I was stupid that the injection technique I used was, to list all the modules loaded in the target process, find kernel32.dll, calculate the offset of LoadLibraryW, and call that function using remote thread. In this technique, the injector enumerates all the modules BEFORE LoadLibrary functions are ever called, and therefore LazyLoading never happens, and therefore I can never see kernel32.dll loaded on the process.

When I used simple technique that use GetProcAddress from current process, get the address of LoadLibrary function, and remotely calling the process, kernel32.dll was successfully loaded and the injection succeeded.

In case of several applications protected through the 'security solutions using Detour', even though I suspended the process, the injection tries do happen, and that's why kernel32.dll was loaded on notepad.exe (which is in the list of the security solution), but not loaded on notepad2.exe (as image name differed, it is not in the list).

I was just stupid, trying to use more complicated methods for dll injection, and that's what caused all these problems.

And thanks a lot for the comments.