GetModuleFileName() question

It is an user mode question but it is related to OS behaviour so it isn’t hopefully much OT. My coworker asked me about following scenario:

  1. a process has loaded a DLL using LoadLibrary()
  2. the DLL is renamed/moved to the different directory
  3. new DLL with the same name is copied to the original directory

Now, the process calls LoadLibrary() for the same DLL name again. LoadLibrary internally increments the count of loaded original DLL and returns its handle. That’s all expected but he’d like to distinguish this case from the case when point #1 wasn’t performed and the new DLL is loaded, instead.

Please note it is simplified scenario and obvious approaches can’t be used (installer is involved and so on). It’d be sufficient if he can find LoadLibrary() returns the handle of a DLL from different directory than caller asked. I recommended him to try GetModuleFileName() but I’m affraid it’ll return the original name of the DLL. Using GetModuleHandle() to find if module was loaded before can’t be used because it is allowed case; process can already have new DLL loaded or no executed points #2 and #3. We’d just need a way how to find current name of loaded DLL after its move or rename.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

Michal Vodicka wrote:

It is an user mode question but it is related to OS behaviour so it isn’t hopefully much OT. My coworker asked me about following scenario:

  1. a process has loaded a DLL using LoadLibrary()
  2. the DLL is renamed/moved to the different directory
  3. new DLL with the same name is copied to the original directory

Now, the process calls LoadLibrary() for the same DLL name again. LoadLibrary internally increments the count of loaded original DLL and returns its handle. That’s all expected but he’d like to distinguish this case from the case when point #1 wasn’t performed and the new DLL is loaded, instead.

Please note it is simplified scenario and obvious approaches can’t be used (installer is involved and so on). It’d be sufficient if he can find LoadLibrary() returns the handle of a DLL from different directory than caller asked. I recommended him to try GetModuleFileName() but I’m affraid it’ll return the original name of the DLL.

Yes, it does. I just tried it.

Using GetModuleHandle() to find if module was loaded before can’t be used because it is allowed case; process can already have new DLL loaded or no executed points #2 and #3. We’d just need a way how to find current name of loaded DLL after its move or rename.

I believe this is impossible. Even if you ignore the DLL portion of
this and think about the simpler case of having a handle to an open
file, I don’t believe you could do it. The mapping of file name to file
handle is one-way; a file handle just doesn’t know the current path name
of the file it is referring to, if any. In fact, what with symbolic
links, hard links, and reparse points, it is possible that there might
be zero, one, or even multiple file system paths that refer to the file.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> ----------

From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of Tim Roberts[SMTP:xxxxx@probo.com]
Reply To: Windows System Software Devs Interest List
Sent: Wednesday, July 18, 2007 1:18 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] GetModuleFileName() question

> Please note it is simplified scenario and obvious approaches can’t be used (installer is involved and so on). It’d be sufficient if he can find LoadLibrary() returns the handle of a DLL from different directory than caller asked. I recommended him to try GetModuleFileName() but I’m affraid it’ll return the original name of the DLL.

Yes, it does. I just tried it.

Thank you.

> Using GetModuleHandle() to find if module was loaded before can’t be used because it is allowed case; process can already have new DLL loaded or no executed points #2 and #3. We’d just need a way how to find current name of loaded DLL after its move or rename.

I believe this is impossible. Even if you ignore the DLL portion of
this and think about the simpler case of having a handle to an open
file, I don’t believe you could do it. The mapping of file name to file
handle is one-way; a file handle just doesn’t know the current path name
of the file it is referring to, if any. In fact, what with symbolic
links, hard links, and reparse points, it is possible that there might
be zero, one, or even multiple file system paths that refer to the file.

I’m affraid you’re right. For loaded DLL it makes even more sense because there it is just an image section. I just hoped if there isn’t some way how to find backward pointer to current file name but you’re right “current” file name may not make too much sense and the mapping is one way.

Thanks.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

The only way I know how to do this is to map a SEC_IMAGE view of the DLL
that you want to check if matches the currently loaded DLL and then use the
(undocumented) NtAreMappedFilesTheSame. Internally this seems to compare
PSECTION_OBJECT_POINTERS->ImageSectionObject, such that that will be
different if the files were renamed on disk but had the same filename when
they were mapped. Note that you need to map the file as an image section
(SEC_IMAGE), like the loader does when mapping DLLs, for this to work.
NT_SUCCESS(NtAreMappedFilesTheSame(…)) will be true if the DLL was the
same.

Obviously not preferable to rely on undocumentedness though. Also, if
someone switches the DLLs back after you perform the NtAreMappedFilesTheSame
check, you’ll obviously get confused as well. Also, might be a bit hard to
work into how you need it to work in any case (this won’t give you a “new”
filename, just tell you that somebody swapped it, and you’ll need to keep a
file mapping pointer around to do the check), even if you can stomach the
undocumentedness…

Why does your coworker need this information at all, if I might ask? Seems
like a pretty weird situation to be into in the first place. Might be a
better way to accomplish it and circumvent this entire requirement, which
would be much preferable.

FYI, here’s a simple test app for demonstrating what I was speaking of
(error checking omitted - beware):

NTSYSAPI
NTSTATUS
NTAPI
NtAreMappedFilesTheSame(
IN PVOID Address1,
IN PVOID Address2
);

int
__cdecl
wmain(
int ac,
wchar_t **av
)
{
HMODULE hmod;
HMODULE hmod2;

hmod = LoadLibrary(L"dll.dll");

wprintf(L"%p\n", hmod);

getc(stdin); // swap dll.dll while we’re waiting on input

hmod2 = LoadLibrary(L"dll.dll");

wprintf(L"%p\n", hmod2);

HANDLE h;
HANDLE hs;
PVOID p;

h = CreateFile(L"dll.dll", GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
hs = CreateFileMapping(h, 0, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
p = MapViewOfFile(hs, FILE_MAP_READ, 0, 0, 0);

wprintf(L"%p\n", p);

wprintf(L"%x\n", NtAreMappedFilesTheSame(p, hmod));

return 0;
}


Ken Johnson (Skywing)
Windows SDK MVP
http://www.nynaeve.net
“Michal Vodicka” wrote in message
news:xxxxx@ntdev…
It is an user mode question but it is related to OS behaviour so it isn’t
hopefully much OT. My coworker asked me about following scenario:

1. a process has loaded a DLL using LoadLibrary()
2. the DLL is renamed/moved to the different directory
3. new DLL with the same name is copied to the original directory

Now, the process calls LoadLibrary() for the same DLL name again.
LoadLibrary internally increments the count of loaded original DLL and
returns its handle. That’s all expected but he’d like to distinguish this
case from the case when point #1 wasn’t performed and the new DLL is loaded,
instead.

Please note it is simplified scenario and obvious approaches can’t be used
(installer is involved and so on). It’d be sufficient if he can find
LoadLibrary() returns the handle of a DLL from different directory than
caller asked. I recommended him to try GetModuleFileName() but I’m affraid
it’ll return the original name of the DLL. Using GetModuleHandle() to find
if module was loaded before can’t be used because it is allowed case;
process can already have new DLL loaded or no executed points #2 and #3.
We’d just need a way how to find current name of loaded DLL after its move
or rename.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

N.B. I actually came up with a slightly more documented approach to take
here:

Open a file handle to the dll in question, use GetFileInformationByHandle
and save the 64-bit file id, keep the handle around.

Then, when you want to check if the file at that filename is still the same
file (dll) or if it has been swapped with something else that’s got the same
name, open a file handle, GetFileInformationByHandle again and compare file
ids. Should be identical if the same ``disk file’’ is referenced, different
if another file got swapped with the same filename. Of course, at that
point, maybe you might just want to md5 the two instead of going to all the
trouble.


Ken Johnson (Skywing)
Windows SDK MVP
http://www.nynaeve.net
“Skywing” wrote in message
news:xxxxx@ntdev…
> The only way I know how to do this is to map a SEC_IMAGE view of the DLL
> that you want to check if matches the currently loaded DLL and then use
> the (undocumented) NtAreMappedFilesTheSame. Internally this seems to
> compare PSECTION_OBJECT_POINTERS->ImageSectionObject, such that that will
> be different if the files were renamed on disk but had the same filename
> when they were mapped. Note that you need to map the file as an image
> section (SEC_IMAGE), like the loader does when mapping DLLs, for this to
> work. NT_SUCCESS(NtAreMappedFilesTheSame(…)) will be true if the DLL was
> the same.
>
> Obviously not preferable to rely on undocumentedness though. Also, if
> someone switches the DLLs back after you perform the
> NtAreMappedFilesTheSame check, you’ll obviously get confused as well.
> Also, might be a bit hard to work into how you need it to work in any case
> (this won’t give you a “new” filename, just tell you that somebody swapped
> it, and you’ll need to keep a file mapping pointer around to do the
> check), even if you can stomach the undocumentedness…
>
> Why does your coworker need this information at all, if I might ask?
> Seems like a pretty weird situation to be into in the first place. Might
> be a better way to accomplish it and circumvent this entire requirement,
> which would be much preferable.
>
> FYI, here’s a simple test app for demonstrating what I was speaking of
> (error checking omitted - beware):
>
> –
>
> NTSYSAPI
> NTSTATUS
> NTAPI
> NtAreMappedFilesTheSame(
> IN PVOID Address1,
> IN PVOID Address2
> );
>
> int
> __cdecl
> wmain(
> int ac,
> wchar_t **av
> )
> {
> HMODULE hmod;
> HMODULE hmod2;
>
> hmod = LoadLibrary(L"dll.dll");
>
> wprintf(L"%p\n", hmod);
>
> getc(stdin); // swap dll.dll while we’re waiting on input
>
> hmod2 = LoadLibrary(L"dll.dll");
>
> wprintf(L"%p\n", hmod2);
>
> HANDLE h;
> HANDLE hs;
> PVOID p;
>
> h = CreateFile(L"dll.dll", GENERIC_READ, FILE_SHARE_READ |
> FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
> hs = CreateFileMapping(h, 0, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
> p = MapViewOfFile(hs, FILE_MAP_READ, 0, 0, 0);
>
> wprintf(L"%p\n", p);
>
> wprintf(L"%x\n", NtAreMappedFilesTheSame(p, hmod));
>
> return 0;
> }
>
>
> –
> Ken Johnson (Skywing)
> Windows SDK MVP
> http://www.nynaeve.net
> “Michal Vodicka” wrote in message
> news:xxxxx@ntdev…
> It is an user mode question but it is related to OS behaviour so it isn’t
> hopefully much OT. My coworker asked me about following scenario:
>
> 1. a process has loaded a DLL using LoadLibrary()
> 2. the DLL is renamed/moved to the different directory
> 3. new DLL with the same name is copied to the original directory
>
> Now, the process calls LoadLibrary() for the same DLL name again.
> LoadLibrary internally increments the count of loaded original DLL and
> returns its handle. That’s all expected but he’d like to distinguish this
> case from the case when point #1 wasn’t performed and the new DLL is
> loaded, instead.
>
> Please note it is simplified scenario and obvious approaches can’t be used
> (installer is involved and so on). It’d be sufficient if he can find
> LoadLibrary() returns the handle of a DLL from different directory than
> caller asked. I recommended him to try GetModuleFileName() but I’m affraid
> it’ll return the original name of the DLL. Using GetModuleHandle() to find
> if module was loaded before can’t be used because it is allowed case;
> process can already have new DLL loaded or no executed points #2 and #3.
> We’d just need a way how to find current name of loaded DLL after its move
> or rename.
>
> Best regards,
>
> Michal Vodicka
> UPEK, Inc.
> [xxxxx@upek.com, http://www.upek.com]
>
>
>

Hey, that’s really useful info. Thank you.

Both ways seems useful. Personally, I’d prefer undocumented one as it works directly with mapped sections and there is not a window between file open and LoadLibrary. In addition, there can be original problem with LoadLibrary as you never really know which DLL is actually loaded. So file open may work with different file than LoadLibrary. Maybe there is a combonation of flags for LoadLibraryEx() which’d force loading just this exact file but in this case it’d be the solution of the original problem, too :slight_smile:

As for why he needs it… He explained but I immediatelly forgot it :slight_smile: It was some perverted interaction between MS installer and running unstoppable process (WinLogon) which has loaded old DLL version just updated by installer. There is also our smart delay loader involved which checks DLLs to find proper IDs/APIs and remember improper ones. On the end the DLL was updated but wasn’t loaded. Reboot would solve all the mess but it isn’t an option, at least not a good option :slight_smile:

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]


From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of Skywing[SMTP:xxxxx@valhallalegends.com]
Reply To: Windows System Software Devs Interest List
Sent: Wednesday, July 18, 2007 2:28 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] GetModuleFileName() question

N.B. I actually came up with a slightly more documented approach to take
here:

Open a file handle to the dll in question, use GetFileInformationByHandle
and save the 64-bit file id, keep the handle around.

Then, when you want to check if the file at that filename is still the same
file (dll) or if it has been swapped with something else that’s got the same
name, open a file handle, GetFileInformationByHandle again and compare file
ids. Should be identical if the same ``disk file’’ is referenced, different
if another file got swapped with the same filename. Of course, at that
point, maybe you might just want to md5 the two instead of going to all the
trouble.


Ken Johnson (Skywing)
Windows SDK MVP
http://www.nynaeve.net
“Skywing” wrote in message
> news:xxxxx@ntdev…
> > The only way I know how to do this is to map a SEC_IMAGE view of the DLL
> > that you want to check if matches the currently loaded DLL and then use
> > the (undocumented) NtAreMappedFilesTheSame. Internally this seems to
> > compare PSECTION_OBJECT_POINTERS->ImageSectionObject, such that that will
> > be different if the files were renamed on disk but had the same filename
> > when they were mapped. Note that you need to map the file as an image
> > section (SEC_IMAGE), like the loader does when mapping DLLs, for this to
> > work. NT_SUCCESS(NtAreMappedFilesTheSame(…)) will be true if the DLL was
> > the same.
> >
> > Obviously not preferable to rely on undocumentedness though. Also, if
> > someone switches the DLLs back after you perform the
> > NtAreMappedFilesTheSame check, you’ll obviously get confused as well.
> > Also, might be a bit hard to work into how you need it to work in any case
> > (this won’t give you a “new” filename, just tell you that somebody swapped
> > it, and you’ll need to keep a file mapping pointer around to do the
> > check), even if you can stomach the undocumentedness…
> >
> > Why does your coworker need this information at all, if I might ask?
> > Seems like a pretty weird situation to be into in the first place. Might
> > be a better way to accomplish it and circumvent this entire requirement,
> > which would be much preferable.
> >
> > FYI, here’s a simple test app for demonstrating what I was speaking of
> > (error checking omitted - beware):>
> >
> > –
> >
> > NTSYSAPI
> > NTSTATUS
> > NTAPI
> > NtAreMappedFilesTheSame(
> > IN PVOID Address1,
> > IN PVOID Address2
> > );
> >
> > int
> > __cdecl
> > wmain(
> > int ac,
> > wchar_t **av
> > )
> > {
> > HMODULE hmod;
> > HMODULE hmod2;
> >
> > hmod = LoadLibrary(L"dll.dll");
> >
> > wprintf(L"%p\n", hmod);
> >
> > getc(stdin); // swap dll.dll while we’re waiting on input
> >
> > hmod2 = LoadLibrary(L"dll.dll");
> >
> > wprintf(L"%p\n", hmod2);
> >
> > HANDLE h;
> > HANDLE hs;
> > PVOID p;
> >
> > h = CreateFile(L"dll.dll", GENERIC_READ, FILE_SHARE_READ |
> > FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
> > hs = CreateFileMapping(h, 0, PAGE_READONLY | SEC_IMAGE, 0, 0, 0);
> > p = MapViewOfFile(hs, FILE_MAP_READ, 0, 0, 0);
> >
> > wprintf(L"%p\n", p);
> >
> > wprintf(L"%x\n", NtAreMappedFilesTheSame(p, hmod));
> >
> > return 0;
> > }
> >
> >
> > –
> > Ken Johnson (Skywing)
> > Windows SDK MVP
> > http://www.nynaeve.net
> > “Michal Vodicka” wrote in message
> > news:xxxxx@ntdev…
> > It is an user mode question but it is related to OS behaviour so it isn’t
> > hopefully much OT. My coworker asked me about following scenario:
> >
> > 1. a process has loaded a DLL using LoadLibrary()
> > 2. the DLL is renamed/moved to the different directory
> > 3. new DLL with the same name is copied to the original directory
> >
> > Now, the process calls LoadLibrary() for the same DLL name again.
> > LoadLibrary internally increments the count of loaded original DLL and
> > returns its handle. That’s all expected but he’d like to distinguish this
> > case from the case when point #1 wasn’t performed and the new DLL is
> > loaded, instead.
> >
> > Please note it is simplified scenario and obvious approaches can’t be used
> > (installer is involved and so on). It’d be sufficient if he can find
> > LoadLibrary() returns the handle of a DLL from different directory than
> > caller asked. I recommended him to try GetModuleFileName() but I’m affraid
> > it’ll return the original name of the DLL. Using GetModuleHandle() to find
> > if module was loaded before can’t be used because it is allowed case;
> > process can already have new DLL loaded or no executed points #2 and #3.
> > We’d just need a way how to find current name of loaded DLL after its move
> > or rename.
> >
> > Best regards,
> >
> > Michal Vodicka
> > UPEK, Inc.
> > [xxxxx@upek.com, http://www.upek.com]
> >
> >
> >
>
>
> —
> Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
>