Hi,
Is there a safe and anternative way to get the filename in PsSetLoadImageNotifyRoutine callback?
For most of dlls I get the correct name but, for e.g., when a usermode app loads a dll using the full path, I get something like this: C:\MyApp\Mydll.dllmydll. Like if the string were modified but the length not adjusted.
Regards,
Mauro.
Are you printing the string with %ws or %wZ? A UNICODE_STRING does not have to be NUL-terminated, so I guess it’s legal for somebody to simply adjust the length without inserting a NUL.
So it may be that the UNICODE_STRING is in fact correct, and could be safely passed to other routines that take UNICODE_STRING parameters.
Does the Length member appear to be correct?
Although cannot figure out why I saw wrong lengths (couldn’t reproduce), the other thing I see is, for e.g., \windows\system32\kernelbase.dll is loading. Fine but the device name is missing for several dlls.
Thanks Tomas.
By the way, do you know if it is safe to call FltSendMessage from this callback? I know, for registry callbacks, there is a global registry lock that might be active and can generate a deadlock if not handled with care but don’t know if there exists some global lock for a process initialization/image loading.
Regards,
Mauro.
For the name, use the ExtendedInfoPresent bit and call
FltGetFileNameInformationUnsafe on the resulting file object. This allows
you to get a canonical name for the file and not worry about dealing with
weird (or incomplete) paths.
The only thing to note is that this will get you *a* name for the image, not
necessarily the name that was used to open the image (e.g. a DLL might have
multiple hard links).
There are some restrictions around what you can do in this callback
described in the documentation:
https://msdn.microsoft.com/en-us/library/windows/hardware/mt764088(v=vs.85).aspx
-scott
OSR
@OSRDrivers
wrote in message news:xxxxx@ntdev…
Thanks Tomas.
By the way, do you know if it is safe to call FltSendMessage from this
callback? I know, for registry callbacks, there is a global registry lock
that might be active and can generate a deadlock if not handled with care
but don’t know if there exists some global lock for a process
initialization/image loading.
Regards,
Mauro.
I have the same issue.
FltGetFileNameInformationUnsafe() seems to deadlock.
Hi Scott,
Yes I know the limitations so I was planning to use IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION/PAGE_EXECUTE as an alternative for my needs but when a process is started, the section is created by the parent process.
But checking for the IMAGE_FILE_DLL flag in PE header, does not seems to be enough because, although not desirable, an exe can be loaded as a dll with LoadLibrary.
Is there any way to know if the image being mapped is for a new process or a dll?
Regards.
What’s the !thread output for the hanging thread?
-scott
OSR
@OSRDrivers
wrote in message news:xxxxx@ntdev…
I have the same issue.
FltGetFileNameInformationUnsafe() seems to deadlock.
I don’t think you can determine intent that early. Creating a process is
basically:
-
hFile = ZwCreateFile() => IRP_MJ_CREATE
-
hSection = ZwCreateSection(hFile) =>
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
-
Create process object => ObRegisterCallbacks for new process handle
-
Create thread object => ObRegisterCallbacks for new thread handle
-
PsSetCreateProcessNotifyRoutineEx called for new process creation
-
PsSetImageLoadNotify called for executable image (note that it’s mapped
earlier but the notification is delayed)
Loading a DLL is:
-
hFile = ZwCreateFile() => IRP_MJ_CREATE
-
hSection = ZwCreateSection(hFile) =>
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
-
dllMapping = ZwMapViewOfSection(hSection) => PsSetImageLoadNotify called
for executable mapping of a file
Differentiating the two based on the early steps would be difficult. The
process create notify routine is the only thing that is really definitive
-scott
OSR
@OSRDrivers
wrote in message news:xxxxx@ntdev…
Hi Scott,
Yes I know the limitations so I was planning to use
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION/PAGE_EXECUTE as an alternative
for my needs but when a process is started, the section is created by the
parent process.
But checking for the IMAGE_FILE_DLL flag in PE header, does not seems to be
enough because, although not desirable, an exe can be loaded as a dll with
LoadLibrary.
Is there any way to know if the image being mapped is for a new process or a
dll?
Regards.
A process PID is a HANDLE. So it is a 32 bits unsigned integer on X86 and a 64 bits unsigned integer on x64 or a ULONG_PTR in both cases.
It is a perfect candidate for indexing an AVL tree. You can maintain a collection of running processes with an AVL tree. So within a CreateProcess notify routine you add or remove nodes to the AVL tree while in the LoadImage notify routine, you maintain a list of loaded modules.
You can try to use ObQueryNameString (NTIFS.H) to obtain the full NT path of the loaded image when you have the FILE_OBJECT pointer. You will get a file path like:
\Device\Harddiskvolume2\Windows\System32\Kernell32.dll
Now remember that some images are not loaded with a file but from the section object directly either named (like \KnownDlls\Kernel32.DLL) or unnamed like NTDLL.DLL (nt!PspSystemDlls). Also, most of the libraries are loaded by the user-mode loader during process initialization, well before the main or WinMain function runs. So LoadLibrary is rarely used.
kd> !object (poi(poi(nt!PspSystemDlls)) & 0xFFFFFFFFFFFFFFF0)
Object: ffffd68190d1c290 Type: (ffff9a8aff52c910) Section
ObjectHeader: ffffd68190d1c260 (new version)
HandleCount: 0 PointerCount: 16
Directory Object: 00000000 Name: \Windows\System32\ntdll.dll
When the LoadImage is invoked for a newly created process, both the process image and NTDLL.DLL are actually already mapped. You can see this the !vad debugger extension when Windows Defender’s MpLoadImageNotifyRoutine is called:
kd> !vad
VAD Level Start End Commit
ffff9a8b0092e330 3 7ffe0 7ffe0 1 Private READONLY
ffff9a8b0092e280 2 7ffe1 7ffef -1 Private READONLY
ffff9a8b00932400 3 e170820 e17089f 6 Private READWRITE
ffff9a8b009328f0 1 e170a00 e170bff 3 Private READWRITE
ffff9a8b009325e0 2 25ebd210 25ebd22f 32 Private READWRITE
ffff9a8b009324b0 3 25ebd230 25ebd247 0 Mapped READONLY Pagefile section, shared commit 0
ffff9a8b00932a40 0 7df5ffbf0 7ff5ffbef 1 Mapped NO_ACCESS Pagefile section, shared commit 0
ffff9a8b00932940 2 7ff725440 7ff725462 0 Mapped READONLY Pagefile section, shared commit 0
ffff9a8b0091bc50 1 7ff725c90 7ff725cb4 2 Mapped Exe EXECUTE_WRITECOPY Windows\System32\smss.exe
ffff9a8b00932ae0 2 7ffdf32b0 7ffdf348a 12 Mapped Exe EXECUTE_WRITECOPY \Windows\System32\ntdll.dll
Total VADs: 10, average level: 2, maximum depth: 3
Total private commit: 0x39 pages (228 KB)
Total shared commit: 0 pages (0 KB)
kd> kb L1
RetAddr : Args to Child : Call Site
00 fffff8017fc436a7 : ffffb081
d3ce6840 fffff8017fb86e90 00000000
00000000 ffffb081`d3ce6890 : WdFilter!MpLoadImageNotifyRoutine
Thanks to all.
I’ll see how to deal with this.
Kind regards,
Mauro.