Wrong names in PsSetLoadImageNotifyRoutine

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.

Have you seen the old threads from this forum? e.g.

http://www.osronline.com/showthread.cfm?link=253156
http://www.osronline.com/showthread.cfm?link=192593

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:

  1. hFile = ZwCreateFile() => IRP_MJ_CREATE

  2. hSection = ZwCreateSection(hFile) =>
    IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION

  3. Create process object => ObRegisterCallbacks for new process handle

  4. Create thread object => ObRegisterCallbacks for new thread handle

  5. PsSetCreateProcessNotifyRoutineEx called for new process creation

  6. PsSetImageLoadNotify called for executable image (note that it’s mapped
    earlier but the notification is delayed)

Loading a DLL is:

  1. hFile = ZwCreateFile() => IRP_MJ_CREATE

  2. hSection = ZwCreateSection(hFile) =>
    IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION

  3. 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 : ffffb081d3ce6840 fffff8017fb86e90 0000000000000000 ffffb081`d3ce6890 : WdFilter!MpLoadImageNotifyRoutine

Thanks to all.

I’ll see how to deal with this.

Kind regards,
Mauro.