LoadImageNotifyRoutine

I am using PsSetLoadImageNotifyRoutine for capturing all binary files which are loaded. I am able to get exe file successfully. But not able to get full path for dll files. Path name for this DLL files contains full path except volume/drive information. I was searching forum but got only queries not solution on it.

  1. Is there some alternative method for getting full path?
  2. I thought that pre create callback routine might be getting full name before load image is called, but i was able to get only some dll names not all before load Image is called.

FYI someone just asked this on NTDEV and there wasn’t a good answer there
either:

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

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntfsd…
> I am using PsSetLoadImageNotifyRoutine for capturing all binary files
> which are loaded. I am able to get exe file successfully. But not able to
> get full path for dll files. Path name for this DLL files contains full
> path except volume/drive information. I was searching forum but got only
> queries not solution on it.
> 1) Is there some alternative method for getting full path?
> 2) I thought that pre create callback routine might be getting full name
> before load image is called, but i was able to get only some dll names not
> all before load Image is called.
>
>
>

I believe you get something like:
\Program Files\My Company\My App\MyDll.dll
You could try prefixing that path with the volume devices that are currently
mounted and if you find the file to exist, then that might be the one :slight_smile:
But seriously.

You can check is ExtendedInfo is present

If the *ExtendedInfoPresent* flag is set, the IMAGE_INFO structure is part
of a larger, extended version of the image information structure. In this
case, the load-image notify routine can use the CONTAINING_RECORD macro in
the *Winnt.h* header file to obtain the base address of the following
structure:
If it is then you have file Object backing the image so it all comes down to
finding the the file object name or path, which is doable, or just get the
FileObject->DevicesObject name and prefix it to the module name you have
from the callback.

If extended info is not available, you can find out the module info from
user mode with
EnumProcessModules
GetModuleInformation or something to check the base address of the dll. If
it matches with the base address win the load image info then call
GetModuleFileName and get full path.

You can use a share event between user mode and your driver and use a
standard IPC mechanism to or Irp to communicate the PID and baseAddress of
module, then wait for the data.

Good luck.

On Wed, Jul 21, 2010 at 6:13 PM, Scott Noone wrote:

> FYI someone just asked this on NTDEV and there wasn’t a good answer there
> either:
>
> http://www.osronline.com/showthread.cfm?link=185940
>
> -scott
>
>
> –
> Scott Noone
> Consulting Associate
> OSR Open Systems Resources, Inc.
> http://www.osronline.com
>
>
> wrote in message news:xxxxx@ntfsd…
>
> I am using PsSetLoadImageNotifyRoutine for capturing all binary files
>> which are loaded. I am able to get exe file successfully. But not able to
>> get full path for dll files. Path name for this DLL files contains full path
>> except volume/drive information. I was searching forum but got only queries
>> not solution on it.
>> 1) Is there some alternative method for getting full path?
>> 2) I thought that pre create callback routine might be getting full name
>> before load image is called, but i was able to get only some dll names not
>> all before load Image is called.
>>
>>
>>
>>
> —
> NTFSD is sponsored by OSR
>
> For our schedule of debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Hi Gabriel & Other Device Driver Gurus,

The above approach of checking “ExtendedInfoPresent” works fine on Vista and above.

So what we did here is that if “ExtendedInfoPresent” field is set then we get hold of the IMAGE_INFO_EX structure. Which ultimately gives us access to the _FILE_OBJECT, which in turn has the DEVICE_OBJECT. By using the “IoGetDeviceProperty()” with “DevicePropertyPhysicalDeviceObjectName” device property we can get the Physical device name.
But unfortunately this “ExtendedInfoPresent” is only available for Vista and above operating systems. We are supposed to support XP SP3 and Windows 2003 Server for AE.

So what we did here is we just skipped the check for “ExtendedInfoPresent” flag. We just go ahead and use the CONTAINING_RECORD macro even on XP SP3 and Windows 2003 Server. And just carried out the above mentioned procedure. To our surprise we did always got the correct complete path for the DLL that is being loaded.

All I want to know from you guys is that is it safe to go ahead and use with this approach in the production code. Do you see any major pitfalls in here?
If you bless this approach then I will have some moral support to go ahead and implement it in the final code :wink:

Thanks in advance.
Regards,
~Semal

Are you sure that you actually tested this on XP/srv03? Those structure fields simply aren’t there on those platforms, you’re walking off the start of the structure if you access any of the IMAGE_INFO_EX fields preceding the IMAGE_INFO block.

Please do not attempt to do this on customer-facing code. This is certainly not safe, blessed, or recommended.

  • S (Msft)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, August 20, 2010 5:55 AM
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] LoadImageNotifyRoutine

Hi Gabriel & Other Device Driver Gurus,

The above approach of checking “ExtendedInfoPresent” works fine on Vista and above.

So what we did here is that if “ExtendedInfoPresent” field is set then we get hold of the IMAGE_INFO_EX structure. Which ultimately gives us access to the _FILE_OBJECT, which in turn has the DEVICE_OBJECT. By using the “IoGetDeviceProperty()” with “DevicePropertyPhysicalDeviceObjectName” device property we can get the Physical device name.
But unfortunately this “ExtendedInfoPresent” is only available for Vista and above operating systems. We are supposed to support XP SP3 and Windows 2003 Server for AE.

So what we did here is we just skipped the check for “ExtendedInfoPresent” flag. We just go ahead and use the CONTAINING_RECORD macro even on XP SP3 and Windows 2003 Server. And just carried out the above mentioned procedure. To our surprise we did always got the correct complete path for the DLL that is being loaded.

All I want to know from you guys is that is it safe to go ahead and use with this approach in the production code. Do you see any major pitfalls in here?
If you bless this approach then I will have some moral support to go ahead and implement it in the final code :wink:

Thanks in advance.
Regards,
~Semal


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars (including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi Ken,
Thanks a lot for your feedback.

I think you might have mis-understood what we are doing here.
I am not reading any fields that are not present in the definition of the IMAGE_INFO structure for these platforms. In fact I am not at all using the IMAGE_INFO structure and that is what makes it more shady and hence I am super suscipicious about this code.
Please have a look at the following function; we pass in the “FullImageName” that we get from the LoadImageNotifyRoutineCallback to this function as the input, i_pUsImageName. And directly call CONTAINING_RECORD(i_pUsImageName,FILE_OBJECT,FileName); on that.

I tried to load a DLL located on C:\ABC\XYZ.DLL and also d:\ABC\XYZ.DLL, in both cases I got the correct HardDisc and Volume. And we had tested it on Windows XP SP3 and Windows 2003 Server and it actually seems to work.

This may be a total fluke, So I am ready to take up any flak :wink:
Any comments / suggestions and criticism are welcome.

By the way I had originally posted my problem in the past here but never got any response;
http://www.osronline.com/showthread.cfm?link=185940

Do you have any advice or suggestions for me here? Is it really IMPOSSIBLE to get the complete path of a DLL that is getting loaded?

Thanks in Advance,
Regards,
~Semal

BOOLEAN GetFullyQualifiedObjectName(IN PUNICODE_STRING i_pUsImageName,OUT PUNICODE_STRING o_pUsFullImageName)
{
PFILE_OBJECT pFileObject = NULL;
PDEVICE_OBJECT pDeviceObject = NULL;
WCHAR wstrDeviceName[50+(sizeof(UNICODE_STRING)/sizeof(WCHAR))+1] = {0};
ULONG ResultLength = 0;
ULONG BufferLength = 0;
UNICODE_STRING usDeviceName;
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = g_FilterCDO->DeviceExtension;

if(!i_pUsImageName || !o_pUsFullImageName)
return FALSE;

//Retrive File Object structure
pFileObject = CONTAINING_RECORD(i_pUsImageName,FILE_OBJECT,FileName);
if(!pFileObject)
return FALSE;

//Retrive Device Object structure
pDeviceObject = pFileObject->DeviceObject;
if(!pDeviceObject)
return FALSE;

//Leave Dlls which are not from File Disk or Network.
if( FILE_DEVICE_DISK != pDeviceObject->DeviceType &&
FILE_DEVICE_NETWORK_FILE_SYSTEM != pDeviceObject->DeviceType
)
return FALSE;

//Retrive Device name for File Disk Dlls.
if(FILE_DEVICE_DISK == pDeviceObject->DeviceType)
{
BufferLength = 50+(sizeof(UNICODE_STRING)/sizeof(WCHAR))+1;
Status = IoGetDeviceProperty( pDeviceObject,
DevicePropertyPhysicalDeviceObjectName ,
BufferLength,
wstrDeviceName,
&ResultLength);
if(STATUS_SUCCESS != Status)
return FALSE;

RtlInitUnicodeString(&usDeviceName,wstrDeviceName);
}
//Retrive Device name for Networks Dlls.
else if(FILE_DEVICE_NETWORK_FILE_SYSTEM == pDeviceObject->DeviceType)
{
if( deviceExtension->OsType == WINDOWS_VISTA || deviceExtension->OsType == WINDOWS_SERVER_2008 || deviceExtension->OsType == WINDOWS_7)
RtlInitUnicodeString(&usDeviceName, L"\Device\Mup");
else
RtlInitUnicodeString(&usDeviceName, L"\Device\LanmanRedirector");
}

//Prefix Device name to FullImage path.
//Path convert from Relative to Full.
o_pUsFullImageName->Length = usDeviceName.Length;
RtlCopyUnicodeString(o_pUsFullImageName,&usDeviceName);
RtlAppendUnicodeStringToString(o_pUsFullImageName,i_pUsImageName);

return TRUE;
}

Assuming that the address of the UNICODE_STRING object being passed to your image load callback is part of a FILE_OBJECT strikes me as unwise. This method relies entirely on non documented/published implementation details - something that can most certainly change.

If you have a file system filter, you could capture the paths of images as they’re loaded by using FsRtlRegisterFileSystemFilterCallbacks(), watching for FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION. Or, better yet if you have FS MiniFilter, filter the equivalent IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION pseudo-IRP.

Good luck!

-D

“we pass in the “FullImageName” that we get from the LoadImageNotifyRoutineCallback to this function as the input, i_pUsImageName. And directly call CONTAINING_RECORD(i_pUsImageName,FILE_OBJECT,FileName); on that.”

Hi Buke & others,

I certainly agree with you that the assumption “that the address of the UNICODE_STRING object being passed to your image load callback is part of a FILE_OBJECT” is not recommended as it is something that can most certainly change.

The thing is that, on Vista and above we are already using the “ExtendedInfoPresent” field and the IMAGE_INFO_EX. So we are using the proper documented way here.

Its only the XP SP3 and Windows Server 2003 that is problematic. Our experiments so far have suggested that the above approach seems to ALWAYS work.
I am assuming that there will not be any more Service Packs for XP that can possibly cause this Lucky coincidental behavior to break.
So what do you guys have to say, is it safe enough to assume so and go ahead with this code and incorporate it in the final production code?

Regards,
~Semal