![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
FreeLibrary для самой себя из APC-нити
Riply © (2007-09-28 13:47:00)Здравствуйте !
Написала маленький DLL-загрузчик, примерно такого вида:
library APC_Loader;
//...
procedure APC_ProcBase(pInjectInfo: PInjectLib); stdcall;
//...
begin
with pInjectInfo^ do
begin
//... Загружаем нашу Dll-ку
LastStatus := LdrGetDllHandle(nil, nil, @uLibName, @hInjectLib);
if hInjectLib = 0 then
begin
LastStatus := LdrLoadDll(nil, nil, @uLibName, @hInjectLib);
//... Если надо, вызываем из нее функцию
LastStatus := LdrGetProcedureAddress(Pointer(hInjectLib), @aFunct, nil, @@_CallBack);
if (LastStatus = STATUS_SUCCESS) and (@_CallBack <> nil)
then RetResult := _CallBack(RetResult)
//... Пытаемся выгрузить себя
LastStatus := LdrGetDllHandle(nil, nil, @uLoaderName, @hLoaderLib);
if hLoaderLib <> 0 then
begin
LastStatus := LdrUnloadDll(@hLoaderLib);
//...
end;
var
InjectInfo: TInjectLib;
procedure EntryPointProc(Reason: integer);
begin
case Reason of
DLL_PROCESS_ATTACH:
begin
InjectInfo._InitSelf;
if not QueueUserAPC(@APC_ProcBase, GetCurrentThread, DWord(pInjectInfo)) then
//...
end;
begin
DllProc := @EntryPointProc;
EntryPointProc(DLL_PROCESS_ATTACH);
end.
Планировалось, что APC_Loader, загрузившись в процесс, через APC-нить загружает
нужную библиотеку, вызывает(если надо) из нее функцию и выгружается.
Все работает, только сам загрузчик(APC_Loader) после срабатывания APC_ProcBase
не выгружается из процесса :(
(Возвращаемый LastStatus - STATUS_SUCCESS)
Где я напортачила ?
Leonid Troyanovsky (2007-09-29 11:22:00) [21]
> Riply © (29.09.07 10:46) [14]
> А я очень надеялась, что можно будет выгрузиться прямо из
> APC-нити.
Опиши, плиз, словами все, что происходит с момента загрузки,
начиная с потока, который загружает длл.
> У нас как минимум три потока: базовый (в котором "сидит"
> и работает Loader),
> APC-нить и поток, реализующий FreeLibraryAndExitThread.
> "изначальный поток" - какой из первых двух имеется ввиду
Хотел лишь сказать, что после создания потока, реализующего FLAET, других обращений к длл (или незавершенных вызовов) быть не должно,
т.е. ни один из потоков не должен "сидеть" в длл.
--
Regards, LVT.
Riply (2007-09-29 10:46:00) [22]> [13] Leonid Troyanovsky © (29.09.07 09:50)
>Напомни, что такое APC-нить.
Ну я так для себя обозвала нить, которая создается,
например, с помощью QueueUserAPC, чтобы не путать с другими видами:)
>Скорее всего, задуманное можно сделать, если создать поток,
>который и сделает FreeLibraryAndExitThread.
>Т.к. параметров 2, то его тело придется прописать в длл.
В свете ([3] и [9]) попробовала сделать именно так, как Вы советуете :)
Сейчас вовсю тестирую на разных процессах и разными видами загрузки.
Все, вроде, работает и выгружается.
Но мне не очень нравиться, что нити плодятся как кролики :).
А я очень надеялась, что можно будет выгрузиться прямо из APC-нити.
>Создание этого потока д.б. последним, что выполняет
>изначальный поток (кста, а какие меры для этого применялись?).
У нас как минимум три потока: базовый (в котором "сидит" и работает Loader),
APC-нить и поток, реализующий FreeLibraryAndExitThread.
"изначальный поток" - какой из первых двух имеется ввиду ?
>Вот тебе еще, для общего развития
> http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx
Спасибо :)
Leonid Troyanovsky (2007-09-29 09:50:00) [23]
> Riply © (28.09.07 16:45) [11]
> нашей APC-нити и "настоящей", если таковая имеется.
Напомни, что такое APC-нить.
Скорее всего, задуманное можно сделать, если создать поток,
который и сделает FreeLibraryAndExitThread.
Т.к. параметров 2, то его тело придется прописать в длл.
Создание этого потока д.б. последним, что выполняет
изначальный поток (кста, а какие меры для этого применялись?).
Учитывая, что система стартует новые потоки с некоторой
задержкой (не помню, где прочитал), то все д.б. гладко.
И еще, следует помнить, что DLL*DETACH будет выполняться
в его контексте.
Вот тебе еще, для общего развития
http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx
--
Regards, LVT.
Leonid Troyanovsky (2007-09-28 18:50:00) [24]
> Riply © (28.09.07 16:45) [11]
> В случае с CreateRemoteThread, [9] остается в силе ?
Дык, он же, все равно, в том же процессе.
--
Regards, LVT.
Riply (2007-09-28 16:45:00) [25]> [10] Игорь Шевченко © (28.09.07 16:27)
> А почему нельзя ?
Честно, говоря не знаю. Так же смутно себе представляю взаимоотношения
нашей APC-нити и "настоящей", если таковая имеется.
Метод "научного тыка" показал следующее:
При использовании FreeLibraryAndExitThread можно вместе с выгрузкой DLL-ки
выйти(прибить) и из целевого процесса :)
Пока все удачно идет с вариантом использования
pThreadRtn := GetProcAddress(hKernel32, 'FreeLibrary');
CreateRemoteThread(GetCurrentProcess, nil, 0, pThreadRtn, Pointer(hLoaderLib), ...);
вместо LastStatus := LdrUnloadDll(@hLoaderLib);
но я напугана [9] Leonid Troyanovsky ©.
В случае с CreateRemoteThread, [9] остается в силе ?
Игорь Шевченко (2007-09-28 16:27:00) [26]
> А внутри нашей APC-нити так разве можно ?
А почему нельзя ?
Leonid Troyanovsky (2007-09-28 16:10:00) [27]
> Riply © (28.09.07 15:29) [8]
> >Странно, что без AV.
> А почему оно должно быть ?
CreateThread вернет результат,
а длл к этому моменту м.б. уже выгружена,
особенно, если есть несколько процессоров,
или, м.б., ядер.
Все же, полная постановка нужна.
И модули, в любом случае, нужно писать
с оглядкой на dll-specific
--
Regards, LVT.
Riply (2007-09-28 15:29:00) [28]>[6] Leonid Troyanovsky © (28.09.07 14:49)
>Странно, что без AV.
А почему оно должно быть ?
P.S.
Перед такими фокусами мы, разумеется, заботимся о
том, чтобы к нам больше из процесса не обращались.
Riply (2007-09-28 15:13:00) [29]>[3] Игорь Шевченко © (28.09.07 14:22)
>FreeLibraryAndExitThread ?
Спасибо. Попробую.
>[4] Игорь Шевченко © (28.09.07 14:23)
> NtTerminateThread(NtCurrentThread, STATUS_SUCCESS); ?
А внутри нашей APC-нити так разве можно ?
> [5] Leonid Troyanovsky © (28.09.07 14:43)
> А как он туда загружается?
>Лучше было бы услышать всю постановку задачи.
Этот загрузчик замысливался для того, чтобы можно было
при написании любого юнита (который может быть использован в DLL),
не задумываться о том, как она(DLL-ка) будет загружаться в процесс.
Если планируется "опасная" загрузка (например, не прошла инициализация),
то загружаем с помощью Loader-а.
>а, наверное, невозможно полностью корректно выгрузить
>длл из кода в ней самой.
Здесь (на этом форуме) мне тысячу раз доказали, что "возможно все" :).
И Вы были среди доказывающих :)
Leonid Troyanovsky (2007-09-28 14:49:00) [30]
> Riply © (28.09.07 14:14) [2]
> то все выгружается в ту же секунду, и следа не остается
Странно, что без AV.
Ну, то, что выгружается оно понятно, поток-то работает
в районе kernel32.dll, которая, считай, что не выгружается.
--
Regards, LVT.
Leonid Troyanovsky (2007-09-28 14:43:00) [31]
> Riply © (28.09.07 13:47)
> Планировалось, что APC_Loader, загрузившись в процесс,
А как он туда загружается?
Хотя, в любом случае, кроме [3], весьма трудоемко,
а, наверное, невозможно полностью корректно выгрузить
длл из кода в ней самой.
Лучше было бы услышать всю постановку задачи.
--
Regards, LVT.
Игорь Шевченко (2007-09-28 14:23:00) [32]
> только сам загрузчик(APC_Loader) после срабатывания APC_ProcBase
> не выгружается из процесса :(
NtTerminateThread(NtCurrentThread, STATUS_SUCCESS); ?
Игорь Шевченко (2007-09-28 14:22:00) [33]FreeLibraryAndExitThread ?
Riply (2007-09-28 14:14:00) [34]> [1] Anatoly Podgoretsky © (28.09.07 13:50)
>Это прерогатива ОС, процесс же только оповещает о своем желании.
>ОС же вольна к этому не прислушиваться.
Да. Это так, но если использовать внутри библиотеки
для выгрузки, примерно такой код:
pFreeLib := GetProcAddress(GetModuleHandle(kernel32), 'FreeLibrary');
if pFreeLib <> nil then
begin
hThread:= CreateThread(nil, 0, pFreeLib, Pointer(hInstance), 0, ThreadID);
то все выгружается в ту же секунду, и следа не остается :)
В чем разница ?
Anatoly Podgoretsky (2007-09-28 13:50:00) [35]> Riply (28.09.2007 13:47:00) [0]
Это прерогатива ОС, процесс же только оповещает о своем желании.
ОС же вольна к этому не прислушиваться.