Коллега утверждает, что вызов GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, "ModuleName", &ModuleHandle) может привести к вызову LoadLibrary внутри при каких то условиях. Подтверждения в MSDN нет, но и явно опровержение не могу найти. Есть у кого-то точное знание? Заранее спасибо!
M>Если исполняемый файл скомпанован с библиотеками в режиме deferred DLL load и до этого ни разу библиотека не использовалась, то LoadLibrary для библиотеки будет вызван, но...
Пример:
void __cdecl _tmain(int argc, TCHAR *argv[])
{
HMODULE hModule{nullptr};
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"user32.dll", &hModule);
keybd_event(0,0,0,0);
}
Сборка:
>cl /Zi /MTd /EHsc test.cpp /link /RELEASE /OPT:REF /DELAYLOAD:user32.dll dloadhelper.lib
Отладчик:
test!wmain+0x16:
00007ff7`8a121036 4c8d442420 lea r8,[rsp+20h]
0:000> lsa @$ip
56:
57: void __cdecl _tmain(int argc, TCHAR *argv[])
58: {
59: HMODULE hModule{nullptr};
> 60: ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"user32.dll", &hModule);
61:
62: keybd_event(0,0,0,0);
63: }
Исполняем GetModuleHandleEx:
0:000> p
test!wmain+0x2d:
00007ff7`8a12104d 4533c9 xor r9d,r9d
0:000> lsa @$ip
58: {
59: HMODULE hModule{nullptr};
60: ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"user32.dll", &hModule);
61:
> 62: keybd_event(0,0,0,0);
63: }
User32 не появился:
0:000> ?? hModule
struct HINSTANCE__ * 0x00000000`00000000
0:000> lm
start end module name
00007ff7`8a120000 00007ff7`8a172000 test (private pdb symbols) test.pdb
00007ff8`00090000 00007ff8`00303000 KERNELBASE (deferred)
00007ff8`031b0000 00007ff8`03262000 KERNEL32 (deferred)
00007ff8`032c0000 00007ff8`034a1000 ntdll (pdb symbols) ~\symbols\ntdll.pdb\E7A53714619369B2356D6363BA34ACA31\ntdll.pdb
Трассируем первое использование:
0:000> p
ModLoad: 00007ff8`01990000 00007ff8`01b20000 C:\WINDOWS\System32\USER32.dll
ModLoad: 00007fff`ff720000 00007fff`ff740000 C:\WINDOWS\System32\win32u.dll
ModLoad: 00007ff8`00d10000 00007ff8`00d38000 C:\WINDOWS\System32\GDI32.dll
ModLoad: 00007fff`ff740000 00007fff`ff8d2000 C:\WINDOWS\System32\gdi32full.dll
ModLoad: 00007ff8`006b0000 00007ff8`0074f000 C:\WINDOWS\System32\msvcp_win.dll
ModLoad: 00007ff8`005b0000 00007ff8`006aa000 C:\WINDOWS\System32\ucrtbase.dll
ModLoad: 00007ff8`016b0000 00007ff8`016dd000 C:\WINDOWS\System32\IMM32.DLL
test!wmain+0x3d:
00007ff7`8a12105d 33c0 xor eax,eax
0:000> lm
start end module name
00007ff7`8a120000 00007ff7`8a172000 test (private pdb symbols) test.pdb
00007ff8`00090000 00007ff8`00303000 KERNELBASE (deferred)
00007ff8`005b0000 00007ff8`006aa000 ucrtbase (deferred)
00007ff8`006b0000 00007ff8`0074f000 msvcp_win (deferred)
00007ff8`00d10000 00007ff8`00d38000 GDI32 (deferred)
00007ff8`016b0000 00007ff8`016dd000 IMM32 (deferred)
00007ff8`01990000 00007ff8`01b20000 USER32 (deferred)
00007ff8`031b0000 00007ff8`03262000 KERNEL32 (deferred)
00007ff8`032c0000 00007ff8`034a1000 ntdll (pdb symbols) ~\symbols\ntdll.pdb\E7A53714619369B2356D6363BA34ACA31\ntdll.pdb
00007fff`ff720000 00007fff`ff740000 win32u (deferred)
00007fff`ff740000 00007fff`ff8d2000 gdi32full (deferred)
0:000> lsa @$ip
59: HMODULE hModule{nullptr};
60: ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"user32.dll", &hModule);
61:
62: keybd_event(0,0,0,0);
> 63: }
Что я делаю не так?
UPD:
Пример собран и запущен на Windows 10.0.17134.165
Бегло посмотрел в функцию GetModuleHandleEx из kernel32 в XP SP3 через IDA: никакой загрузки не нашел, все упирается в LdrGetDllHandle и LdrAddRefDll из ntdll.
В kernel32:
.text:7C801AF5 _LoadLibraryExW@12 proc near ; CODE XREF: LoadLibraryExA(x,x,x)+1Ap
.text:7C801AF5 ; LoadLibraryW(x)+Cp
.text:7C801AF5 ; BasepSxsFindSuitableManifestResourceFor(x,x,x)+48p
.text:7C801AF5 ; BaseDllFormatMessage(x,x,x,x,x,x,x,x)+C0C2p
.text:7C801AF5 ; BeginUpdateResourceW(x,x)+131p
.text:7C801AF5 ; DATA XREF: .text:off_7C802654o
.text:7C80E109 _LdrLoadDll@16 proc near ; CODE XREF: LoadLibraryExW(x,x,x)+C3p
.text:7C80E109 ; BasepCheckBadapp(x,x,x,x,x,x,x)+4993p
.text:7C80E109 ; BasepCheckWinSaferRestrictions(x,x,x,x,x,x)+4C46p
.text:7C80E109 ; UnhandledExceptionFilter(x)+4E7p
.text:7C80E109 ; SetConsolePalette(x,x,x)+2Cp
В ntdll:
.text:7C9163C3 _LdrLoadDll@16 proc near ; CODE XREF: LdrpCorValidateImage(x,x)+97p
.text:7C9163C3 ; LdrpCodeAuthzCheckDllAllowed(x,x)+24BF0p
.text:7C9163C3 ; LdrHotPatchRoutine(x)+FCp
.text:7C9163C3 ; AVrfpLoadAndInitializeProvider(x)+68p
.text:7C9163C3 ; ImportTablepHashCanonicalLists(x,x)+3Cp
.text:7C9163C3 ; LoadOle32Export(void * *,char * const)+27p
.text:7C9163C3 ; DATA XREF: .text:off_7C903428o
Здравствуйте, EreTIk, Вы писали:
В общем, так я и не нашёл, где я сегодня нашёл, что при отложенной загрузке библиотек, GetModuleHandle может вызвать загрузку библиотеки... Слишком бегло читал, видимо, совсем наискосок. Везде пишут, что при нулевом RefCount для библиотеки функция GetModuleHandle(ex) никогда не отработает.
Да и сами Microsoft пишут, что
...A workaround is to explicitly handle the data import yourself using LoadLibrary (or GetModuleHandle after you know the delay-load helper has loaded the DLL) and GetProcAddress.