I'm trying to write an APC dll injection driver, I've found this example and thought to modify it to my needs.
After I understood the code, this is how I thought to modify it (and my question come from there).
In the code, the writer used PsLookupThreadByThreadId to receive a referenced pointer to the ETHREAD structure of the targeted process.
PsLookupThreadByThreadId(pSpi->Threads[0].ClientId.UniqueThread,&Thread)
but to get the SYSTEM_THREAD_INFORMATION for the UniqueThread handle, he used ZwQuerySystemInformation
I want to load my dll right after ntdll is loaded, so I want to use PsSetCreateProcessNotifyRoutineEx and save the UniqueThread from the PS_CREATE_NOTIFY_INFO I got when the callback is called for the process I'm targeting.
And after ntdll is loaded, which I'll know thanks to PsSetLoadImageNotifyRoutineEx I could inject my dll using his APC injection logic.
my goal is to inject my dll in the PloadImageNotifyRoutine callback, but don't use ZwQuerySystemInformation as he does to get the UniqueThread, but save it in the PcreateProcessNotifyRoutineEx callback.
So, my question is: Can I trust the UniqueThread I get from PS_CREATE_NOTIFY_INFO is the same during all the process loading time?
about
CreatingThreadId
fromPS_CREATE_NOTIFY_INFO
this id not for new created process/thread, but for creator. if you want inject self dll in the
PloadImageNotifyRoutine
callback - thePcreateProcessNotifyRoutineEx
is useless for you.the
PloadImageNotifyRoutine
called when image is mapped to target process - insideZwMapViewOfSection
. you need check thatProcessId
(second parameter ofPcreateProcessNotifyRoutineEx
- The process ID of the process where image is loaded) is equal toPsGetCurrentProcessId()
. this mean that image loaded to the current process and you can useKeGetCurrentThread()
- you not needPsLookupThreadByThreadId
at allat this moment any user mode structures in process yet not initialized. because it initialized by ntdll. as result - if you inject your apc and force execute it at this moment - you got crash of process. nothing more
i can advice you inject your dll when kernel32.dll is loaded. and here you need check that this is load as dll, not simply image mapping - check
ArbitraryUserPointer
in thread teb - are it point toL"*\\kernel32.dll"
: smss.exe map kernel32.dll during create\\KnownDlls
(ArbitraryUserPointer == 0
in this case), wow64 process several time map kernel32.dll (32 and 64 bit) withL"WOW64_IMAGE_SECTION"
orL"NOT_AN_IMAGE"
names inArbitraryUserPointer