#c #winapi #dll #inject
#dll #самоссылка
Вопрос:
Возможно ли, чтобы функция, находящаяся внутри DLL, выгружала DLL? Мне нужно сделать это, чтобы я мог убедиться, что DLL не используется, а затем записать в файл DLL.
Ответ №1:
Насколько я понимаю, это МОЖЕТ быть сделано и должно быть сделано иногда (например, в случае внедрения dll с помощью CreateRemoteThread и других методов). Итак,
FreeLibraryAndExitThread(hModule, 0)
сделает именно это.
С другой стороны, вызов
FreeLibrary(hModule)
здесь не подойдет — из MSDN: «Если бы они вызывали FreeLibrary и ExitThread отдельно, существовало бы условие гонки. Библиотека может быть выгружена до вызова ExitThread «.В качестве замечания, ExitThread выполняет некоторую бухгалтерию, помимо простого возврата из функции потока.
Все это предполагает, что ваша Dll получила сам hModule, вызвав LoadLibrary изнутри загруженной Dll, или, скорее, вызвав изнутри загруженной Dll следующую функцию:
GetModuleHandleEx
(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)DllMain,
amp;hModule
)
Это увеличивает количество ссылок на Dll, чтобы вы знали, что если вы освободите библиотеку позже, используя этот дескриптор, и если библиотека действительно выгружена, то у вас была последняя ссылка на нее.
Если вместо этого вы пропустите увеличение количества ссылок на Dll и получите hModule только из аргумента DllMain во время DLL_PROCESS_ATTACH, тогда вам не следует вызывать FreeLibraryAndExitThread, поскольку код, который загрузил Dll, все еще использует его, и этот дескриптор модуля действительно не принадлежит вам. управлять.
Комментарии:
1. Это вообще не имеет никакого смысла… Когда вы загружаете DLL с
LoadLibrary
помощью нее, ссылка увеличивается на 1. Он никогда не уменьшает его. Затем вы вызываетеGetModuleHandleEx
, и он снова увеличивает его на 1 (дескриптор такой же, как в аргументе DllMain, кстати). Теперь вы вызываетеFreeLibraryAndExitThread
, и он уменьшает количество на 1. В итоге количество ссылок равно 1, а DLL никогда не выгружается!2. @ScienceDiscoverer Вы используете либо
LoadLibrary
илиGetModuleHandleEx
, нет необходимости в обоих. То, о чем я говорил в предыдущем посте, было чем-то другим. Я говорил, что если вы получаете дескриптор изDllMain
аргумента, то вам не следует использовать этот дескриптор для выгрузки, поскольку получение дескриптора изDllMain
вообще не увеличивает количество ссылок.
Ответ №2:
Используйте это, когда dll выполнила свою работу:
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, amp;__ImageBase, 0, NULL);
// terminate if dll run in a separate thread ExitThread(0);
// or just return out the dll
И __ImageBase — это структура PE заголовка вашей dll:
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
Комментарии:
1. Этот трюк может помочь, но теоретически он все равно может привести к состоянию гонки, если поток, вызывающий CreateThread, задерживается слишком долго после вызова CreateThread . Пожалуйста, посмотрите мой ответ относительно функции FreeLibraryAndExitThread .
Ответ №3:
Если вы спрашиваете, можете ли вы безопасно выгружать / разархивировать DLL, загруженную в процессе, из кода в самой DLL, ответ отрицательный — на самом деле нет безопасного способа сделать это.
Подумайте об этом так: выгрузка DLL выполняется путем уменьшения количества ссылок с помощью FreeLibrary(). Проблема, конечно, в том, что, как только количество ссылок в DLL достигает нуля, модуль отключается. Это означает, что код в DLL, который вызывал FreeLibrary(), исчез.
Даже если бы вы могли это сделать, вам все равно нужно было бы убедиться, что другие потоки не выполняют какие-либо экспортированные функции из библиотеки DLL.
Ответ №4:
Я не думаю, что это сработает. Вызов FreeLibrary с дескриптором извне (LoadLibrary был бы вызван из области за пределами DLL), поскольку код выполняется в ячейке памяти, которая больше не будет действительной.
Даже если это возможно, это пахнет как плохой дизайн. Может быть, вы хотите сделать какое-нибудь обновление или что-то подобное. Объясните немного больше, какой результат вы ожидаете. Выгрузка DLL изнутри самой себя — это не правильный путь.
Комментарии:
1. Пожалуйста, посмотрите мой ответ относительно функции FreeLibraryAndExitThread
2. Вызов FreeLibrary — не лучший вариант, если у вас есть фоновый поток в вашей DLL. Лучше использовать FreeLibraryAndExitThread . Эта функция — камень, который может убить 2 птиц.