Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.049 c
2-1190724118
alles
2007-09-25 16:41
2007.10.21
Как правильно использовать TServerSocket?


11-1174241380
Dmitriy___
2007-03-18 21:09
2007.10.21
StatusBar


15-1190604782
Slider007
2007-09-24 07:33
2007.10.21
С днем рождения ! 23 сентября 2007 воскресенье


2-1191237333
matt
2007-10-01 15:15
2007.10.21
Ini-файлы


2-1190706757
Uchenik
2007-09-25 11:52
2007.10.21
Поведение кнопки TToolButton со стилем tbsDropDown





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский