Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.10.21;
Скачать: CL | DM;

Вниз

FreeLibrary для самой себя из APC-нити   Найти похожие ветки 

 
Riply ©   (2007-09-28 13:47) [0]

Здравствуйте !
Написала маленький 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)
Где я напортачила ?


 
Anatoly Podgoretsky ©   (2007-09-28 13:50) [1]

> Riply  (28.09.2007 13:47:00)  [0]

Это прерогатива ОС, процесс же только оповещает о своем желании.
ОС же вольна к этому не прислушиваться.


 
Riply ©   (2007-09-28 14:14) [2]

> [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);


то все выгружается в ту же секунду, и следа не остается :)
В чем разница ?


 
Игорь Шевченко ©   (2007-09-28 14:22) [3]

FreeLibraryAndExitThread ?


 
Игорь Шевченко ©   (2007-09-28 14:23) [4]


> только сам загрузчик(APC_Loader) после срабатывания APC_ProcBase
> не выгружается из процесса :(


NtTerminateThread(NtCurrentThread, STATUS_SUCCESS); ?


 
Leonid Troyanovsky ©   (2007-09-28 14:43) [5]


> Riply ©   (28.09.07 13:47)  

> Планировалось, что APC_Loader, загрузившись в процесс,

А как он туда загружается?

Хотя, в любом случае, кроме [3], весьма трудоемко,
а, наверное, невозможно полностью корректно выгрузить
длл из кода в ней самой.

Лучше было бы услышать всю постановку задачи.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2007-09-28 14:49) [6]


> Riply ©   (28.09.07 14:14) [2]

> то все выгружается в ту же секунду, и следа не остается

Странно, что без AV.

Ну, то, что выгружается оно понятно, поток-то работает
в районе kernel32.dll, которая, считай, что не выгружается.

--
Regards, LVT.


 
Riply ©   (2007-09-28 15:13) [7]

>[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-а.

>а, наверное, невозможно полностью корректно выгрузить
>длл из кода в ней самой.
Здесь (на этом форуме) мне тысячу раз доказали, что "возможно все" :).
И Вы были среди доказывающих :)


 
Riply ©   (2007-09-28 15:29) [8]

>[6] Leonid Troyanovsky ©   (28.09.07 14:49)
>Странно, что без AV.
А почему оно должно быть ?
P.S.
Перед такими фокусами мы, разумеется, заботимся о
том, чтобы к нам больше из процесса не обращались.


 
Leonid Troyanovsky ©   (2007-09-28 16:10) [9]


> Riply ©   (28.09.07 15:29) [8]

> >Странно, что без AV.
> А почему оно должно быть ?

CreateThread вернет результат,
а длл к этому моменту м.б. уже выгружена,
особенно, если есть несколько процессоров,
или, м.б., ядер.

Все же, полная постановка нужна.
И модули, в любом случае, нужно писать
с оглядкой на dll-specific

--
Regards, LVT.


 
Игорь Шевченко ©   (2007-09-28 16:27) [10]


> А внутри нашей APC-нити так разве можно ?


А почему нельзя ?


 
Riply ©   (2007-09-28 16:45) [11]

> [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] остается в силе ?


 
Leonid Troyanovsky ©   (2007-09-28 18:50) [12]


> Riply ©   (28.09.07 16:45) [11]

> В случае с CreateRemoteThread, [9] остается в силе ?

Дык, он же, все равно, в том же процессе.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2007-09-29 09:50) [13]


> 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.


 
Riply ©   (2007-09-29 10:46) [14]

> [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 11:22) [15]


> Riply ©   (29.09.07 10:46) [14]

> А я очень надеялась, что можно будет выгрузиться прямо из
> APC-нити.

Опиши, плиз, словами все, что происходит с момента загрузки,
начиная с потока, который загружает длл.

> У нас как минимум три потока: базовый (в котором "сидит"
> и работает Loader),
> APC-нить и поток, реализующий FreeLibraryAndExitThread.
> "изначальный поток" - какой из первых двух имеется ввиду

Хотел лишь сказать, что после создания потока, реализующего FLAET, других обращений к длл (или незавершенных вызовов) быть не должно,
т.е. ни один из потоков не должен "сидеть" в длл.

--
Regards, LVT.


 
Riply ©   (2007-09-29 11:59) [16]

> [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 записать в память
процесса и выгружаться оттуда. Но я не уверена, что это получиться.
И кто потом будет освобождать эту память ?


 
Leonid Troyanovsky ©   (2007-09-29 12:13) [17]


> Riply ©   (29.09.07 11:59) [16]

> Некое приложение загрузило наш Loader и в нем мы попадаем
> в DLL_PROCESS_ATTACH.
> Здесь мы только вызываем QueueUserAPC(@APC_LibLoadProc,
> GetCurrentThread, ...
> и больше ничего не делаем.

Ну, а где ж APC-нить?
Если это все, что делается, то поток-то один - GetCurrentThread.
Понятно, что поручать ему FLAET нет смысла.

Т.е., в данном случае - отдельный поток для FLAET
вполне оправдан, IMHO.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2007-09-29 12:25) [18]


> Riply ©   (29.09.07 11:59) [16]

> Попробуем на варианте загрузки из AppInit_DLLs (самый непиятный
> вариант, брр... :)

Кстати, на счет вариант :)
В ранних версиях Delphi поддержка variant была чуть ли не в system,
поэтому при изучении примеров Рихтера мне пришлось пару раз
переустанавливать NT4.

--
Regards, LVT.


 
Riply ©   (2007-09-29 12:31) [19]

> [17] Leonid Troyanovsky ©   (29.09.07 12:13)
>Если это все, что делается, то поток-то один - GetCurrentThread.
>Понятно, что поручать ему FLAET нет смысла.
Мне не совсем понятно :(
Ведь в принципе этот поток может выгрузить DLL,
ему надо только каким-то образом объяснить,
что выгружать надо после того как он вызовет APC-Proc :)
Ну а если он такой непонятливый, то будем считать
что "отдельный поток для FLAET вполне оправдан" :)


 
Riply ©   (2007-09-29 12:37) [20]

> [18] Leonid Troyanovsky ©   (29.09.07 12:25)
>В ранних версиях Delphi поддержка variant была чуть ли не в system,
>поэтому при изучении примеров Рихтера мне пришлось пару раз
>переустанавливать NT4.
:)
Я после первого краха сделала загрузочную дискету,
с помощью которой можно было уничтожить файл злополучной DLL-ки из \System32\
Мне это сэкономило много времени :)


 
Leonid Troyanovsky ©   (2007-09-29 12:58) [21]


> Riply ©   (29.09.07 12:31) [19]

> Мне не совсем понятно :(
> Ведь в принципе этот поток может выгрузить DLL,
> ему надо только каким-то образом объяснить,
> что выгружать надо после того как он вызовет APC-Proc :)

За вызовом FL должно быть еще кое-что, чтобы поток
нормально вернулся из вызова APC_ProcBase.

Г. Небетт как-то показывал трюк с выполнением кода из стека,
но, эту возможность в любой момент могут(должны) прикрыть.

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2007-09-29 13:02) [22]

> Leonid Troyanovsky  (29.09.2007 12:58:21)  [21]

А разве еще не прикрыли, а DEP не к этому относится, а возможности современных процессоров?


 
Leonid Troyanovsky ©   (2007-09-29 13:08) [23]


> Anatoly Podgoretsky ©   (29.09.07 13:02) [22]

> А разве еще не прикрыли

Анатолий, чес-слово, не в курсе.
Но, поверю тебе на слово :)

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2007-09-29 13:15) [24]

> Leonid Troyanovsky  (29.09.2007 13:08:23)  [23]

Да я тоже зуб давать не буду, но читал


 
Riply ©   (2007-09-29 14:19) [25]

> [21] Leonid Troyanovsky © (29.09.07 12:58)
> Г. Небетт как-то показывал трюк с выполнением кода из стека,
> но, эту возможность в любой момент могут(должны) прикрыть.
Посмотрела в "Windows NT 2000 Native API Reference",
но не нашла ничего похожего. Плохо смотрела или не там ?

>[24] Anatoly Podgoretsky © (29.09.07 13:15)
> Да я тоже зуб давать не буду, но читал

Господа, просвятите страждущих об этом трюке, ибо сеять знания - добро ! :)


 
Leonid Troyanovsky ©   (2007-09-29 16:08) [26]


> Riply ©   (29.09.07 14:19) [25]

> Господа, просвятите страждущих об этом трюке, ибо сеять
> знания - добро ! :)

Чего уж там доброго, если прикрыли :)

From: "Gary Nebbett" <gary.nebb...@syngenta.com>                    яП 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 <windows.h>

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 20:27) [27]

> [26] Leonid Troyanovsky ©   (29.09.07 16:08)
Спасибо.


 
Leonid Troyanovsky ©   (2007-09-29 21:23) [28]


> Riply ©   (29.09.07 20:27) [27]

Во-ще-то, я был неточен, в примере код не исполняется в стеке,
да и сам пример не очень-то полезен для рассматриваемой задачи.
Sorry.

--
Regards, LVT.


 
Riply ©   (2007-09-30 00:49) [29]

> [28] Leonid Troyanovsky ©   (29.09.07 21:23)
> Sorry.
Для первого раза поставим "на вид" (без занесения в личное дело),
но в следующий раз "вынесем Ваше поведение на комсомольское собрание". :)
(с) (из папиной школьной тетрадки с названием "Комплексный план" :)


 
Германн ©   (2007-09-30 01:04) [30]


> но в следующий раз "вынесем Ваше поведение на комсомольское
> собрание". :)

Не. Не солидно LVT вызывать на комсомольское собрание. На партком его, на партком!
:)


 
Leonid Troyanovsky ©   (2007-09-30 08:54) [31]


> Германн ©   (30.09.07 01:04) [30]

> партком его, на партком!

Хе-хе, а я не член партии.
Я ее мозг ;)

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2007-09-30 08:56) [32]


> Riply ©   (30.09.07 00:49) [29]

> Для первого раза поставим "на вид" (без занесения в личное
> дело),

Не стоит беспокоиться, виновные уже расстреляны ;)

--
Regards, LVT.


 
Riply ©   (2007-09-30 11:24) [33]

>[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 14:01) [34]


> 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 15:30) [35]

> [34] Leonid Troyanovsky ©   (30.09.07 14:01)
Спасибо большое !
В жизни не сумела бы самостоятельно увидеть разницу между
вызовом FreeLibraryAndExitThread и вызовом подряд FreeLibrary, ExitThread.
P.S.
Оказывается даже "три копейки" не так просты как кажутся :)



Страницы: 1 вся ветка

Текущий архив: 2007.10.21;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.017 c
2-1191129666
SveTTT
2007-09-30 09:21
2007.10.21
Курсор по SetFocus


2-1191124887
Alex8
2007-09-30 08:01
2007.10.21
свойство "Custom.Constrstraint"


2-1190362266
АндрейК
2007-09-21 12:11
2007.10.21
Delphi7 и FastReport 3.19


15-1190201615
alles
2007-09-19 15:33
2007.10.21
Как в IIS (WIN2003) оставить только GET POST и HEAD?


15-1190640366
мастерПакость
2007-09-24 17:26
2007.10.21
HTML