![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Dll injection [D7, Win2k, WinXP]
nomshar © (2004-09-26 17:46:00)Внедрил свою dll в SysListView32 (для тех, кто не знает, иерархия такая: Progman -> SHELLDLL_DefView -> SysListView32). Все нормально, хук установился, оконная процедура заменилась. В общем, работает. Одна только проблема. Как выгрузить эту dll-ку, не перезагружая explorer.exe.
Бился я довольно-таки долго. Даже предка менял (SetParent), но ничего не помогло, хотя и не могло помочь. У каждого процесса хендл одной и той же библиотеки разный.
Есть вариант внедрения в код explorer.exe и выгрузка уже из него этой самой библиотеки. Но как это сделать? А может есть и другие варианты. Обратился к Рихтеру. У него по этому поводу ничего не сказано.
Может кто-нибудь уже сталкивался с этой проблемой и решил ее или есть какие-нибудь идеи. Подскажите, буду благодарен. Тема очень интересная и веселая, особенно, когда пользователь видит, что знакомая ему с "ранних лет" программа чудит что-то невообразимое. :)
Ertong (2004-10-07 07:49:00) [1]Я внедрял с помощью CreateRemoteThread.
Слудующий код самовыгружает DLL.
function thread(p:pointer):integer; stdcall;
begin
{Делаем нашу работу}
CreateThread(nil,0,GetProcAddress(GetModuleHandle('kernel32'),'FreeLibrary'),pointer(hInstance),0,id);
end;
begin
HThread:=CreateThread(nil,0,@Thread,nil,0,ThreadID);
end.
Cobalt (2004-10-05 16:15:00) [2]Да, получается, что адрес "старой" оконной процедуры тоже надо хранить в файле.
P.S. терпения моего не хватило, я больше писать сюда не буду.
nomshar (2004-10-05 15:53:00) [3]Кстати, по этой тематике на RSDN вышла очень хорошая статья:
http://www.rsdn.ru/article/?522
Digitman (2004-10-05 15:47:00) [4]
> надо, чтобы мой процесс внедрил dll и его (мой процесс)
> можно было спокойно "убить", а внедренная библиотека спокойно
> работала
и что этому мешает ?
твой процесс выполнил CreateRemoteThread и преспокойно завершается
в ходе же исполнения тела удаленного трэда в "чужое" АП загружается твоя ДЛЛ и "живет" там хоть вплоть до завершения "чужого" процесса
nomshar (2004-10-05 15:35:00) [5]
> Digitman
> и вообще - ради внедрения в АП одного-единственного процесса
> неразумно ударяться в глоб.хуки, достаточно просто внедрить
> в АП этого процесса свою ДЛЛ (CreateRemoteThread) или, если
> процесс еще не существует, отслеживать его старт и по факту
> оного немедленно выполнить внедрение тем же CreateRemoteThread
Согласен, только понимаешь, мне надо, чтобы мой процесс внедрил dll и его (мой процесс) можно было спокойно "убить", а внедренная библиотека спокойно работала. Поэтому меня и привлек метод с хуками и заменой оконной процедуры.
Digitman (2004-10-05 15:16:00) [6]
> Библиотека загружается только при срабатываении нашего хука
>
..и загружается отдельным экз-ром в АП этого GUI-процесса
> после отработки процедуры хука счетчик использования dll
> уменьшается на один и она (библиотека) выгружается
нет, не выгружается
выгружена она будет в ходе исполнения UnhookWindowsHookEx
и вообще - ради внедрения в АП одного-единственного процесса неразумно ударяться в глоб.хуки, достаточно просто внедрить в АП этого процесса свою ДЛЛ (CreateRemoteThread) или, если процесс еще не существует, отслеживать его старт и по факту оного немедленно выполнить внедрение тем же CreateRemoteThread
nomshar (2004-10-05 14:14:00) [7]По поводу цепочки хуков. Да, действительно MyHook равен нулю и цепочка хуков не вызывается.
Но по поводу проекции на все процессы:
Из Рихтера, глава 22, книга Создание эффективных win32 приложений...
"
Аргумент WH_GETMESSAGE определяет тип ловушки, а параметр GetMsgProc — адрес функции (в адресном пространстве Вашего процесса), которую система должна вызывать всякий раз, когда окно собирается обработать сообщение Параметр hinstDll идентифицирует DLL, содержащую функцию GetMsgProc В Windows значение htnstDll для DLL фактически задаст адрес в виртуальной памяти, по которому DLL спроецирована на адресное пространство процесса. И, наконец, последний аргумент, 0, указывает поток, для которого предназначена ловушка. Поток может вызвать SelWindowsHookEx и передать ей идентификатор другого потока в системе Передавая 0, мы сообщаем системе, что ставим ловушку для всех существующих в ней GUI-потоков
Теперь посмотрим, как все это действует:
1. Поток процесса В собирается направить сообщение какому-либо окну.
2. Система проверяет, не установлена ли для данного потока ловушка WH_GETMESSAGE.
3. Затем выясняет, спроецирована ли DLL, содержащая функцию GctMsgProc, на адресное пространство процесса В
4. Если указанная DLL еще не спроецирована, система отображает ее на адресное пространство процесса В и увеличивает счетчик блокировок (lock count) проекции DLL в процессе В на 1
5. Система проверяет, не совпадают ли значения hinstDll этой DLL, относящиеся к процессам А и В Если hinstD!l в обоих процессах одинаковы, то и адрес GetMsgProc в этих процессах тоже одинаков Тогда система может просто вызвать GetMsgProc в адресном пространстве процесса А. Если же hinstDll различны, система определяет адрес функции GetMsgProc в адресном пространстве процесса В по формуле:
GetMsgProc В = histDll В + (GetMsgProc А - hinstDll А)
Вычитая hinstDll из GetMsgProcA, Вы получаете смещение (в байтах) адреса функции GetMsgProc. Добавляя это смещение к hinstDll В, Вы получаете адрес GetMsgProc, соответствующий проекции DLL в адресном пространстве процесса В
6. Счетчик блокировок проекции DLL в процессе В увеличивается на 1.
7. Вызывается GetMsgProc в адресном пространстве процесса В.
8. После возврата из GetMsgProc счетчик блокировок проекции DLL в адресном пространстве процесса В уменьшается на 1.
Кстати, когда система внедряет или проецирует DLL, содержащую функцию фильтра ловушки, проецируется вся DLL, а не только эта функция. А значит, потокам, выполняемым в контексте процесса В, теперь доступны все функции такой DLL."
Итак. Библиотека загружается только при срабатываении нашего хука и после отработки процедуры хука счетчик использования dll уменьшается на один и она (библиотека) выгружается.
Может я что-то неправильно понимаю, то разъясните.
Cobalt (2004-10-05 11:41:00) [8]hMod
Identifies the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
2 nomshar
Будь так добр - прислушивайся к людям - статьи тут не лохи писали всё-таки.
Файл, проецируемый в память, тебе нужен для того, что бы идентификатор хука был актуален в АП "Проводника" - ты ведь должен вызывать следующие хуки в цепочке.
myHook:= SetWindowsHookExты делаешь в АП своей проги, а хук вызывается в АП "Проводника".
Это описано в статье - а ты не обратил внимание:
Наш Process1 устанавливает глобальную ловушку из DLL находящейся в адресном пространстве (АП) нашего процесса (Process1). DLL, находящаяся в АП процесса1 имеет свои данные, обозначенные на рисунке как Dll data. Когда система посылает событие, на которое мы установили ловушку, в Process2, то в Process2 отображается код DLL, находящийся в первом процессе (Dll code), НО НЕ ДАННЫЕ ! Все данные, только что отображённой в Process2 DLL, инициализируются заново (т.е. равны 0, nil, False в зависимости от типа). То есть, Process2 знать не знает о существовании Process1, и всё что в нём находится никак не относится к АП первого процесса, из которого произошло отображение кода DLL.
А вот адрес оконной процедуры, в принципе, можно хранить только в АП "Проводника" - т.е. локальной переменной длл-ки. Но это не красиво - не едино.
Digitman (2004-10-05 11:00:00) [9]
> nomshar
приведи цитату из документации MS, где явно сказано, что при указанных тобой ненулевых параметрах hInstance и dwThreadId образ хук-DLL будет проецироваться тольков ВАП того процесса, который создал трэд с указанным тобой dwThreadId
nomshar (2004-10-05 10:41:00) [10]Итак, друзья. По просьбам общественности я прочел указанную статью. Хорошая статья. А теперь поговорим о моей dll (попутно я буду ссылаться на некоторые фразы из статьи).
1.
>dwThreadID: данный параметр идентифицирует поток, с которым >будет связана ловушка. Мы ведём речь о глобальных ловушках, >поэтому данный параметр будет всегда равен 0, что означает, >что ловушка будет связана со всеми потоками в системе.
Это утверждение правильно только лишь в том случае, если мы хотим получать сообщения от всех процессов. Я же внедряю dll в конкретный процесс и мне нужны только сообщения от этого конкретного процесса, поэтому я и передаю в параметре dwThreadID идентификатор потока SysListView32.
2.
>Пусть в Process2 возникает событие на которое поставлена >ловушка, тогда Dll из первого процесса проецируется на АП >Process2, а данные DLL в Process2 инициализируются заново, и >получается, что в Process2 в переменной, в которой "лежал" >дескриптор поставленной ловушки в Process1, будет равен 0.
>Для того, что бы все экземпляры DLL, находящиеся в разных >процессах, имели доступ к дескриптору ловушки, надо выделить >какую-то область, доступ к которой будут иметь все "желающие".
Об этом по-подробнее. Согласен, при проецировании dll в чужое адресное пространство дескриптор хука теряется. Но я же делаю совсем иначе. Я работаю в одном процессе, создаю хук также в одном процессе, так что никакого обнуления данных не происходит. Так что мне нафиг не нужны файлы проецируемые в память.
Cobalt (2004-10-05 00:35:00) [11]Неее, это ты не понял - Рихтер использует особенность.. ну, в общем-то, не языка - это, наверное, относится к возможностям компилятора, - объявление в ДЛЛ сегмента данных, которое является общим для образов этой dllво всех процессах. В Дельфях такое недоступно.
Ещё раз - почитай статью - и приведи в соответствие. Если хочешь, конечно, продолжать обсуждение твоей проблемы.
nomshar (2004-10-04 10:41:00) [12]to all again. У меня складывается впечатление, что меня недопоняли. Я хочу внедрить dll в чужой процесс, это не банальная установка хука.
Теперь по ответам.
>Digiman.
> параметр этот требует не идентификатор процесса, а >идентификатор
> трэда
Согласен. Просто я так его обозвал, уж извини, запутал может быть.
> хотя в справке черным по белому сказано, что глоб.хук требует
> указания hInstance при ThreadId = 0
Обратимся к первоисточнику, то есть к MSDN.
SetWindowsHookEx Function
...
hMod
[in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
dwThreadId
[in] Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.
hMod должен быть нулевым, если dwThreadId указывает на поток созданный текущим процессом и если процедура хука ассоциирована с текущим процессом. А мы что делаем. Мы внедряем dll в другой процесс и соответственно явно указываем на поток процесса, передавая его id, найденный GetProcessThreadId, и передаем ссылку на нашу библиотеку.
Далее.
> Lin7
> Это зачем? Когда ставишь хук, твою dll в захученный процесс
> подгружает винда по SetWindowsHookEx и выгружает по >UnHookWindowsHookEx
> тоже винда.
Как зачем. Мы должны увеличить счетчик ссылок explorer.exe. Для этого мы и загружаем dll-ку саму в себя, так сказать.
> Переменная myHook должна быть в расшаренной области памяти.
> В таком варианте прога конечно не свалится, но так оччччччень
> не хорошо по отношению к другим прогам при работе под виндой
> ниже Win2000.
Согласен, правильней было бы и так. Но! Можно и оставить так как есть. Все нормально. Переменная myHook, как уже ранее указал Cherry, может измениться.
> Cobalt
> что у Рихтера написано - оно использует особенности языка
> C, а в паскале такое не прокатит.
Извини, но ты меня увидил. Рихтер в своих книгах иногда ссылается на библиотеку C от Microsoft, но в большей мере он использует WinAPI. И кто тебе мешает использовать функции WinAPI в приложениях, написанных на Delphi?!
CherrY (2004-10-04 09:57:00) [13]Hi all!!!
2 Lin7:
> 1.Переменная myHook должна быть в расшаренной области памяти.
> В таком варианте прога конечно не свалится, но так оччччччень
> не хорошо по отношению к другим прогам при работе под виндой
> ниже Win2000.
Разъясни чем плохо, если требуется загрузить Dll, установить хук, внедриться в другой процесс (путём загрузки Dll), и снять хук.
За это время переменная, описывающая указатель на хук может измениться????
> 2.
>
> > if loadLibrary('injectdll.dll') <> 0 then
>
> Это зачем? Когда ставишь хук, твою dll в захученный процесс
> подгружает винда по SetWindowsHookEx и выгружает по UnHookWindowsHookEx
> тоже винда.
Если внимательно посмотреть, то эта тема называется Dll injection, а это значит внедрение в чужой процесс.
Это делается для того, чтобы увеличить счётчик использования Dll.
Чтоб не свалить Explorer. И чтоб Dll которая внедрялась осталась в том процессе(Explorere) после закрытия основной программы.
Вопрос и от меня для всех...
Может nomshar не правильно Вам чтото отписал в вопросе, но меня тоже интересует вопрос возможности выгрузки Dll из чужого процесса, при наличии в нём моего кода.
Попытки FreeLibrary c хендлом данной Dll полученным GetModuleHandle с именем и с NULL ни к чему не привели.
Может чего то недопонимаю просветите.
Cobalt (2004-10-01 23:22:00) [14]2 nomshar
Значит так - приводи свой код в соответсвие с описанием по вышеприведённой статье - и выкладывай сюда - только тогда уже можно будет двигаться дальше, потому что то, что у Рихтера написано - оно использует особенности языка C, а в паскале такое не прокатит.
Ждём-с.
Lin7 (2004-10-01 17:13:00) [15]Мона я тоже подключюсь? :)
> nomshar (29.09.04 18:28) [6]
1.Переменная myHook должна быть в расшаренной области памяти. В таком варианте прога конечно не свалится, но так оччччччень не хорошо по отношению к другим прогам при работе под виндой ниже Win2000.
2.
> if loadLibrary('injectdll.dll') <> 0 then
Это зачем? Когда ставишь хук, твою dll в захученный процесс подгружает винда по SetWindowsHookEx и выгружает по UnHookWindowsHookEx тоже винда.
3. Если есть в dll string, то почему в uses нет ShareMem? ИМХО здесь можно избавиться от string'а.
4. Можно (и хорошо бы) избавиться от SysUtils и Classes в uses - dll будет значительно меньше. Правда прийдётся переписать пару функций.
Это может пригодиться :)
http://www.delphimaster.ru/articles/hooks/index.html
Удачи.
Digitman (2004-10-01 16:50:00) [16]
> ProcId - это уж, как ты понимаешь, идентификатор нужного
> нам процесса.
неверно.
параметр этот требует не идентификатор процесса, а идентификатор трэда
в действительности ты как раз и передаешь ид-р трэда, но почему он обзывается тобой ид-ром "процесса" ? процесс и трэд - две совершенно разные сущности ! и это наводит на мысль о полной твоей дезориентации в объектах ОС ... подтверждение тому - явное указание тобой ненулевого параметра hInstance, хотя в справке черным по белому сказано, что глоб.хук требует указания hInstance при ThreadId = 0
nomshar (2004-10-01 16:27:00) [17]> Digitman Все очень просто. Ставим хук на все сообщения (WH_GETMESSAGE), указываем адрес call-back функции.
ProcId - это уж, как ты понимаешь, идентификатор нужного нам процесса.
Что тебе не нравится в этой функции установки хука? Все довольно-таки логично.
Digitman (2004-10-01 08:15:00) [18]
> nomshar
> околопредметные сообщения
душу отвел ?
теперь вернемся к нашим баранам ..
myHook:= SetWindowsHookEx(WH_GETMESSAGE, @myHookProc, hInstance, ProcId);
комментируй, что, для чего и почему именно так а не иначе ты передаешь в кач-ве параметров в вызов ф-ции
пока не разберешься досконально, дальше двигаться нет смысла
nomshar (2004-09-30 19:46:00) [19]> Digiman Слушай, меня, честно говоря, очень расстроило твое высказывание о якобы "бездумно содранной" библиотеки.
Dll написана на чистом WinAPI. Если это плагиат, что все, кто использует WinAPI плагиатчики. Далее. Ты Рихтера когда-нибудь читал?! А Руссиновича, а Шрайбера. Ты знаешь, они все используют WINAPI, все используют при подготовки своих проектов чужой код (исходники Windows, Руссинович в предисловии к книги прямо об этом заявляет). Они получается тоже "бездумно сдирают".
Прошу прощения за off-topic, просто не очень приятно слышать обвинения в плагиате, тем более от человека, который уже давно на форуме и, как я думал, является неплохим специалистом в своем деле. Еще раз извиняюсь за околопредметные сообщения.
nomshar (2004-09-30 19:34:00) [20]> all. Народ, обижаете. Библиотека написана лично мной и не откуда я ее не сдирал. Это во-первых. Во-вторых, метод, которым я пользуюсь, очень хорошо описан у того же Рихтера. Идею, да, содрал (вернее перенял), но библиотеку своими руками писал. Даже обидно как-то. Сам написал, а тебе говорят, что содрал.
> Cobalt. Действительно explorer падает при попытке выгрузить библиотеку.
> Так вот - тебе надо добавить такую вещь - что бы при постановке
> хука оконная процедура не заменяла "родную" на свою, а наоборот.
Что ты имеешь в виду? Не подменять оконную процедуру. Тогда, скажи, как же я буду обрабатывать сообщения окна?