![]() |
| ||
|
|
Новости |
Поиск |
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)
Где я напортачила ?
Riply (2007-09-30 15:30:00) [1]> [34] Leonid Troyanovsky © (30.09.07 14:01)
Спасибо большое !
В жизни не сумела бы самостоятельно увидеть разницу между
вызовом FreeLibraryAndExitThread и вызовом подряд FreeLibrary, ExitThread.
P.S.
Оказывается даже "три копейки" не так просты как кажутся :)
Leonid Troyanovsky (2007-09-30 14:01:00) [2]
> Riply © (30.09.07 11:24) [33]
> Стало страшно интересно: а что такого "хитрого" в FreeLibraryAndExitThread
http://www.rsdn.ru/Forum/Message.aspx?mid=111454&only=1
--
Regards, LVT.
Riply (2007-09-30 11:24:00) [3]>[32] Leonid Troyanovsky © (30.09.07 08:56)
> Не стоит беспокоиться, виновные уже расстреляны ;)
Для выживших (если таковые имеются :)
Стало страшно интересно: а что такого "хитрого" в FreeLibraryAndExitThread ?
Полезла на ReactOS, а они утверждают, что все так просто, как три копейки:
00265 VOID
00266 STDCALL
00267 FreeLibraryAndExitThread (
00268 HMODULE hLibModule,
00269 DWORD dwExitCode
00270 )
00271 {
00272 if ( FreeLibrary(hLibModule) )
00273 ExitThread(dwExitCode);
00274 for (;;)
00275 ;
00276 }
Они не обманывают ?
Правда, мне не понятно назначение for (;;)
Leonid Troyanovsky (2007-09-30 08:56:00) [4]
> Riply © (30.09.07 00:49) [29]
> Для первого раза поставим "на вид" (без занесения в личное
> дело),
Не стоит беспокоиться, виновные уже расстреляны ;)
--
Regards, LVT.
Leonid Troyanovsky (2007-09-30 08:54:00) [5]
> Германн © (30.09.07 01:04) [30]
> партком его, на партком!
Хе-хе, а я не член партии.
Я ее мозг ;)
--
Regards, LVT.
Германн (2007-09-30 01:04:00) [6]
> но в следующий раз "вынесем Ваше поведение на комсомольское
> собрание". :)
Не. Не солидно LVT вызывать на комсомольское собрание. На партком его, на партком!
:)
Riply (2007-09-30 00:49:00) [7]> [28] Leonid Troyanovsky © (29.09.07 21:23)
> Sorry.
Для первого раза поставим "на вид" (без занесения в личное дело),
но в следующий раз "вынесем Ваше поведение на комсомольское собрание". :)
(с) (из папиной школьной тетрадки с названием "Комплексный план" :)
Leonid Troyanovsky (2007-09-29 21:23:00) [8]
> Riply © (29.09.07 20:27) [27]
Во-ще-то, я был неточен, в примере код не исполняется в стеке,
да и сам пример не очень-то полезен для рассматриваемой задачи.
Sorry.
--
Regards, LVT.
Riply (2007-09-29 20:27:00) [9]> [26] Leonid Troyanovsky © (29.09.07 16:08)
Спасибо.
Leonid Troyanovsky (2007-09-29 16:08:00) [10]
> Riply © (29.09.07 14:19) [25]
> Господа, просвятите страждущих об этом трюке, ибо сеять
> знания - добро ! :)
Чего уж там доброго, если прикрыли :)
From: "Gary Nebbett" яП 13:58
Subject: Re: deleted oneself from disk while running in RAM
The appended code is my favourite approach for NT systems; it does not require
any additional files - just insert the code into an existing program.
Gary
#include
int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
ULONG p = ULONG(module) + 1;
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push p
push DeleteFile
push FreeLibrary
ret
}
return 0;
См. также
http://groups.google.com/group/fido7.su.win32.prog/msg/caa4674e5821a403
Но, в настоящее время, эта программка не делает, то,
зачем задумывалась, т.е. не удаляет себя с диска,
даже не по причине запрета исполнения кода из стека,
а, скажем, потому что не HANDLE(4),
FreeLibrary vs UnMapViewOfFile &etc
Гари позже писал, что использовал подобный код для самоудаления длл,
и, что он работал даже на xp, w2k3.
--
Regards, LVT.
Riply (2007-09-29 14:19:00) [11]> [21] Leonid Troyanovsky © (29.09.07 12:58)
> Г. Небетт как-то показывал трюк с выполнением кода из стека,
> но, эту возможность в любой момент могут(должны) прикрыть.
Посмотрела в "Windows NT 2000 Native API Reference",
но не нашла ничего похожего. Плохо смотрела или не там ?
>[24] Anatoly Podgoretsky © (29.09.07 13:15)
> Да я тоже зуб давать не буду, но читал
Господа, просвятите страждущих об этом трюке, ибо сеять знания - добро ! :)
Anatoly Podgoretsky (2007-09-29 13:15:00) [12]> Leonid Troyanovsky (29.09.2007 13:08:23) [23]
Да я тоже зуб давать не буду, но читал
Leonid Troyanovsky (2007-09-29 13:08:00) [13]
> Anatoly Podgoretsky © (29.09.07 13:02) [22]
> А разве еще не прикрыли
Анатолий, чес-слово, не в курсе.
Но, поверю тебе на слово :)
--
Regards, LVT.
Anatoly Podgoretsky (2007-09-29 13:02:00) [14]> Leonid Troyanovsky (29.09.2007 12:58:21) [21]
А разве еще не прикрыли, а DEP не к этому относится, а возможности современных процессоров?
Leonid Troyanovsky (2007-09-29 12:58:00) [15]
> Riply © (29.09.07 12:31) [19]
> Мне не совсем понятно :(
> Ведь в принципе этот поток может выгрузить DLL,
> ему надо только каким-то образом объяснить,
> что выгружать надо после того как он вызовет APC-Proc :)
За вызовом FL должно быть еще кое-что, чтобы поток
нормально вернулся из вызова APC_ProcBase.
Г. Небетт как-то показывал трюк с выполнением кода из стека,
но, эту возможность в любой момент могут(должны) прикрыть.
--
Regards, LVT.
Riply (2007-09-29 12:37:00) [16]> [18] Leonid Troyanovsky © (29.09.07 12:25)
>В ранних версиях Delphi поддержка variant была чуть ли не в system,
>поэтому при изучении примеров Рихтера мне пришлось пару раз
>переустанавливать NT4.
:)
Я после первого краха сделала загрузочную дискету,
с помощью которой можно было уничтожить файл злополучной DLL-ки из \System32\
Мне это сэкономило много времени :)
Riply (2007-09-29 12:31:00) [17]> [17] Leonid Troyanovsky © (29.09.07 12:13)
>Если это все, что делается, то поток-то один - GetCurrentThread.
>Понятно, что поручать ему FLAET нет смысла.
Мне не совсем понятно :(
Ведь в принципе этот поток может выгрузить DLL,
ему надо только каким-то образом объяснить,
что выгружать надо после того как он вызовет APC-Proc :)
Ну а если он такой непонятливый, то будем считать
что "отдельный поток для FLAET вполне оправдан" :)
Leonid Troyanovsky (2007-09-29 12:25:00) [18]
> Riply © (29.09.07 11:59) [16]
> Попробуем на варианте загрузки из AppInit_DLLs (самый непиятный
> вариант, брр... :)
Кстати, на счет вариант :)
В ранних версиях Delphi поддержка variant была чуть ли не в system,
поэтому при изучении примеров Рихтера мне пришлось пару раз
переустанавливать NT4.
--
Regards, LVT.
Leonid Troyanovsky (2007-09-29 12:13:00) [19]
> Riply © (29.09.07 11:59) [16]
> Некое приложение загрузило наш Loader и в нем мы попадаем
> в DLL_PROCESS_ATTACH.
> Здесь мы только вызываем QueueUserAPC(@APC_LibLoadProc,
> GetCurrentThread, ...
> и больше ничего не делаем.
Ну, а где ж APC-нить?
Если это все, что делается, то поток-то один - GetCurrentThread.
Понятно, что поручать ему FLAET нет смысла.
Т.е., в данном случае - отдельный поток для FLAET
вполне оправдан, IMHO.
--
Regards, LVT.
Riply (2007-09-29 11:59:00) [20]> [15] Leonid Troyanovsky © (29.09.07 11:22)
> Опиши, плиз, словами все, что происходит с момента загрузки,
> начиная с потока, который загружает длл.
Попробуем на варианте загрузки из AppInit_DLLs (самый непиятный вариант, брр... :)
Некое приложение загрузило наш Loader и в нем мы попадаем в DLL_PROCESS_ATTACH.
Здесь мы только вызываем QueueUserAPC(@APC_LibLoadProc, GetCurrentThread, ...
и больше ничего не делаем.
Внутри APC_LibLoadProc мы пытаемся
1. Загрузить настоящую DLL-ку (которая и будет работать).
2. Вызвать из нее функцию, если таковая указана
3. Все. Мы (Loader) свою работу выполнили и больше не нужны в этом процессе. Пытаемся отсюда выгрузиться.
Но выгрузиться прямо из APC_LibLoadProc не получается, поэтому
посупаем как сказано в [13] (создаум доп. нить).
Можно извратиться и попробовать код APC_LibLoadProc записать в память
процесса и выгружаться оттуда. Но я не уверена, что это получиться.
И кто потом будет освобождать эту память ?