Форум: "WinAPI";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];
ВнизПомогите разобраться с хуками Найти похожие ветки
← →
RagE (2004-06-04 16:29) [0]Заранее благодарен.
Вот текст длл которую я использую.
// Example3; //
// @Aleksey Pavlov //
// Demo of WH_KEYBOARD hook - DLL module //
library Shell98;
uses
SysUtils,
Windows,
Messages,
Forms;
const
MMFName: PChar = "KeyMMF"; // имя объекта файлового отображения
WM_SHELL = WM_USER + 200;
{структура, поля которой будут отображены в файл подкачки}
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
SysHook: HWND; // дескриптор установленной ловушки
MyAppWnd: HWND; // дескриптор нашего приложения
end;
var
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
WM_MYKEYHOOK: Cardinal;
Counter:byte;
function KeyboardProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
function GetShellWnd: THandle;
begin
Result:=FindWindow(nil, "Калькулятор");
end;
begin
case Code of
HSHELL_WINDOWCREATED: if GetShellWnd=wParam then
begin
// sleep(100);
postmessage(GetShellWnd,wm_close,0,0);
end;
end;
Result:=CallNextHookEx(GlobalData^.SysHook, Code, WParam, LParam);
end;
{Процедура установки HOOK-а}
procedure hook(switch : Boolean; hMainProg: HWND) export; stdcall;
begin
if switch=true then
begin
{Устанавливаю HOOK, если он не установлен (switch=true). }
GlobalData^.SysHook := SetWindowsHookEx(WH_SHELL, @KeyboardProc, HInstance, 0);
GlobalData^.MyAppWnd:= hMainProg;
if GlobalData^.SysHook <> 0 then
// MessageBox(0, "KEYBOARD HOOK установлен !", "Message from keyhook.dll", 0)
else
MessageBox(0, "HOOK установить не удалось !", "Message from keyhook.dll", 0);
end
else
begin
{Удаляю функцию-фильтр, если она установлена (т.е. switch=false). }
if UnhookWindowsHookEx(GlobalData^.SysHook) then
// MessageBox(0, "HOOK снят !", "Message from keyhook.dll", 0)
else
MessageBox(0, "HOOK снять не удалось !", "Message from keyhook.dll", 0);
end;
end;
procedure OpenGlobalData();
begin
{регестрируем свой тип сообщения в системе}
WM_MYKEYHOOK:= RegisterWindowMessage("WM_MYKEYHOOK");
{получаем объект файлового отображения}
// MMFHandle:= CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName); // можно так, но лучше: см. след. строку
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName);
if MMFHandle = 0 then
begin
MessageBox(0, "Can""t create FileMapping", "Message from keyhook.dll", 0);
Exit;
end;
{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, "Can""t make MapViewOfFile", "Message from keyhook.dll", 0);
Exit;
end;
end;
procedure CloseGlobalData();
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MMFHandle);
end;
procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenGlobalData;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;
procedure inithook;
begin
hook(true,0);
end;
procedure deinithook;
begin
hook(false,0);
end;
exports hook;
exports inithook;
exports deinithook;
begin
Counter:=0;
//MessageBox(0, PChar(Application.ExeName), "Message from keyhook.dll", 0);
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Цель не дает запуститься калькулятору. Все работает только вот explorer постоянно недопустимые операции выполняет. Помогите плиз решить проблему
Есть еще аналогичная которая перехватывает нажатую клавишу. Там дела тоже плохо обстоят. ВЫлетают все приложения которые используют ввод с клавиатуры. В частности ICQ при отсылке сообщения
← →
Hedrox (2004-06-05 19:43) [1]Удалено модератором
← →
default © (2004-06-05 19:58) [2]". Все работает только вот explorer постоянно недопустимые операции выполняет." так доставай ремень
← →
Sirgfine (2004-06-06 05:38) [3]Что-то текста много. Это всё проще делается...(если цель - незапустить калькулятор)
← →
DelphiN! (2004-06-06 20:55) [4]В Длл не надо никаких действий выполнять, просто посылай из Длл сообщение главному процессу, о нажатой клавише или че там тебе надо... А главный процесс пусть делает что надо с получиными от Длл данными
← →
NS (2004-06-07 08:01) [5]Смущает этот текст, ... оооочень смущает:
begin
Counter:=0;
//MessageBox(0, PChar(Application.ExeName), "Message from keyhook.dll", 0);
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
end.
Зачем ее вызывать, если после объявления DLLProc:= @DLLEntryPoint; при проецировании библиотеки в адресное пространство другого процесса данная проедура и так запустится!
2. Кидай по хук для клавиатуры, посмотрим, что там нарисовал.
← →
RagE (2004-06-08 14:34) [6]to NS
а в хуке для клавиатуры тоже самое только обработка чуток другая. Если нажата клавшиа то послать мессадж. Вобщем то стоит действительно попробовать убрать вызов DLLEntryPoint.
ЗЫ. код был не мой а так как я с таким первый раз работаю, поэтому решил всецело довериться.
← →
Sirgfine (2004-06-09 04:56) [7]Там много срезать надо! Правильно NS указывает. В итоге получится код с инициализацией (3-4 строчки), самим хуком (5 строчек), процедурой выгрузки (3 строчки), и... вроде всё больше ничего не надо
← →
RagE (2004-06-09 17:26) [8]2 Sirgfine & NS
Ребят я тут попробовал убрать вызов этой злосчастной DLLEntryPoint так все рухнуло напрочь. Аж система слегла. Походу надо начинать писать с нуля и свое. И не смотреть как это делают другие
← →
Sirgfine (2004-06-10 06:05) [9]В чём цель данного проекта? (может у меня такой готовый есть)
← →
Sirgfine (2004-06-10 06:11) [10]Если просто калькулятор вырубать, то dll тут не нужен.
Ты ведь будешь его вызывать какой-то прогой, а потом висеть в памяти... => эта прога должна каждые 100 раз в секунду отсылать сообщение о закрытии калькулятору, а не подгружать сложную dll.
Насчёт точной строки сообщения боюсь ошибиться, но если тебе надо сегодня посмотрю, попробую и напишу.
← →
NS (2004-06-10 08:28) [11]Я посмотрел свои старые проекты, которые писал, когда был еще зеленым, в которых использовал Хуки на дельфях - там вообще инициализация памяти для глобальных переменных через отображаемый файл происходит в блоке, где у тебя стоит текст:
begin
Counter:=0;
//MessageBox(0, PChar(Application.ExeName), "Message from keyhook.dll", 0);
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;
{вызываем назначенную процедуру для отражения факта присоединения данной
библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Реально должно выгладеть так:
begin
DLLProc:= @DLLEntryPoint;
MMFHandle:= CreateFileMapping(THandle($FFFFFFFF), Nil,
^^^^^^^^- Правильно
PAGE_READWRITE, 0, 4096, MMFName);
^^^^^- Кратно 4096, потому что Windows оперирует страницами памяти по 4 кб, и если ты будешь резервировать 8 байт (столько в твоем примере занимает твоя структура [запись] с глобальными переменными), создавая объект отображения, то под объект все равно выделится 4 кб, так что зачем мелочиться.
Дальше:
if MMFHandle = 0 then begin
MessageBox(0, "Can""t create FileMapping", "Message from keyhook.dll", 0);
Exit;
end;
GlobalData := MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0,
0, 0);
^^^ - отображаем весь файл.
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, "Can""t make MapViewOfFile", "Message from keyhook.dll", 0);
Exit;
end;
end.
А в самой процедуре DLLEntryPoint пишем:
procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
If (dwReason = DLL_PROCESS_DETACH) then CloseGlobalData;
end;
Честно говоря, в Delphi реализация инициализации DLL не совсем корректная (по сравнению с C++). Я не хочу как-то хаять Delphi - это очень хороший пакет, но некоторые системные вещи, которые я пытался в нем реализовать у меня не получились, именно из-за того, что реализация некоторых функций в нем урезана и адаптирована к условиям платформы Delphi.
И вообще, правильно говорит DelphiN!, убивать в DLL что-либо последнее дело, лучше передай через postmessage в свою прогу, которая грузит библиотеку и ставит хук, сообщение о том, кого грохнуть (передай хэндл окна / процесса), а уж она затем займется жертвой.
Да, и для "убиения" используй лучше KillProcess, чтобы в программе не возникало сообщений: "вы действительно хотите завершить столь полезную, важную и незамению программу как Калькулятор?" (это для примера, если в программах есть обработка события OnCloseQuery с выводом предупреждающего сообщения). У KillProcess есть плюс - грохает сразу, почти все что угодно, без компрописсов, ожиданий и т.п. Но есть и минуст, не высвобождается память, выделенная в самом приложении, ведь никто не будет вызывать процедуры Free для всех созданных объектов :))).
← →
Aleksey Pavlov © (2004-06-10 09:49) [12]>> RagE (04.06.04 16:29):
Если модифицируете чужой код, то не надо подписывать его именем автора :)
А то Ваши ошибки могут принять за ошибки автора =)
>>NS (07.06.04 08:01) [5]:
Если это:
DLLProc:= @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
Вас смущает, см. Стив Тейксейра, Ксавье Пачеко Том 1, Глава 9, Листинг 9.7. и нижеследующее объяснение и пример =)
Далее:CreateFileMapping(THandle($FFFFFFFF), Nil
Теперь задумываемся, почему в MSDN указана константа INVALID_HANDLE_VALUE, а не значение $FFFFFFFF.
Задумались, во что превратится $FFFFFFFF при переходе на 64 разряда? Вот то-то и оно =) А в случае использования константы всё будет нормально.
Дальнейшие придирки типа "зачем мелочиться" и "отображаем весь файл" не существенны и не влияют (в данном случае) на работу программы. Хотя подход типа "если лезет, то пропихивай" imho не есть хорошо, но это уже из области стилей программирования.
Далее. Delphi - это не пакет и не платформа ;) И делать вывод о том, что "реализация инициализации DLL не совсем корректная (по сравнению с C++)" только потому, что у Вас "некоторые системные вещи не получились" это как-то по-детски =)
← →
RagE (2004-06-10 11:04) [13]2 Aleksey Pavlov
Я прошу прощения. Обещаю впредь так не делать.Кстати есть такой вопрос. Я читал вашу статью, не помню уже точно но там было написано что то типа того, что в Win2K не обязательно использовать FileMapping но это более корректно. Лично у меня в Win2K и XP вообще FileMapping отказывается работать в вашем примере который я оставлял без изменений.
2 Sirgfine
Конечная цель написать службу которая будет запрещать запускать одно и тоже приложение чаще чем раз в минуту напрммер. Делается это для облегчения работы сотрудникам инет-кафе в которых некоторые посетители любят наживать кнопку мыши по 20 раз пока не появится IE. В приведенном мною коде я всего лишь решил потренироваться на калькуляторе.
2 NS
Я не нашел какого либо описания функции KillProcess. Нашел только TerminateProcess. Возникает вопрос. Коим образом можно определить handle процесса зная HWND окна?
← →
Aleksey Pavlov © (2004-06-10 11:47) [14]>>RagE (10.06.04 11:04) [13]:
Дело в том, что, как мне кажется, в Win2k реализация передачи сообщения по цепочке хуков была усовершенствована и сделана более лоничной, чем в Win9x. Хотя утверждать этого не могу, т.к. нигде не нашёл этому документального подтверждения. Вывод сделал в результате тестирования различных проектов.
Т.е. в Win2k при вызовеCallNextHookEx(hHookHandle, Code, WParam, LParam);
c параметром hHookHandle = 0, сообщение всё равно передавалось по цепочке остальным ф-иям обработки (такое поведение imho правильно). Т.к. это недокументированная фича, которая воспроизводилась мной на конкретных машинах, то рекомендовать её для использования я не могу.
А что до падучести FileMapping, то тут надо смотреть. В Windows NT/2000/XP никто не отменял ни MapViewOfFile ни остальные ф-ии File Mapping"а =)
← →
NS (2004-06-10 11:59) [15]Aleksey Pavlov:
Век живи, век учись.... :))))
Кстати, вопрос на засыпку (к разговору об особенностях Дельфи). Как в дельфи осуществить перехват функций WinAPI. Пытался реализовать через модификацию таблицы импорта, но столкнулся с проблемой таблицу меняю, но результат отсутствует!
Позже где-то видел разговор про какие-то особенности Дельфи касательно работы с PE-заголовками (точнее сказать не могу - не помню), но все было сказано как-то невнятно и расплывчато...
RagE:
Извиняюсь, свою функцию с WinAPI"шной попутал. Именно TerminateProcess! Попробуй через GetWindowThreadProcessId. Даешь хэндл окна, получаешь номер создавшего его процесса. Зная его, используй функцию OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessId), которая вернет тебе хэндл процесса.
Да, и еще! Меня терзают смутные сомнения, но по моему нужно проверить - не является ли окно дочерним, если так, то найти родительское окно и уж потом действовать как описано выше.
← →
Игорь Шевченко © (2004-06-10 13:17) [16]
> А что до падучести FileMapping, то тут надо смотреть
То не падает.
> Т.е. в Win2k при вызове CallNextHookEx(hHookHandle, Code,
> WParam, LParam); c параметром hHookHandle = 0, сообщение
> всё равно передавалось по цепочке остальным ф-иям обработки
> (такое поведение imho правильно)
Ты будешь удивлен, но судя по всему, этот параметр вообще не используется, для экперимента можешь передать произвольное случайное число :)
← →
Aleksey Pavlov © (2004-06-10 13:48) [17]>>Игорь Шевченко © (10.06.04 13:17) [16]:
Угу, я пробовал совать в CallNextHookEx всякий бред =) Про 0 это я так сказал =)
Интересно почему нигде в документации не сказано про это.
>>NS (10.06.04 11:59) [15]:
Да статей по перехвату - полно. Посмотри в поисковиках =)
← →
Игорь Шевченко © (2004-06-10 13:56) [18]Aleksey Pavlov © (10.06.04 13:48)
> Интересно почему нигде в документации не сказано про это.
Для совместимости с Win9x ? :)
← →
RagE © (2004-06-10 18:09) [19]2 NS
Спасибо за наводку. Буду пробовать.
P.S. За функцию тоже буду очень благодарен.
2 Aleksey Pavlov
примерно я так и понял кстати. Только почему файл маппинг у меня слетал самому интересно. Впринципе не столь важно.
← →
Sirgfine (2004-06-11 04:54) [20]Если цель - предотвращшения запуска одного и того же приложения то не мудрите... просто раз 10 в секунду опрашивайте систему.
Более простого пути нет. А код - минимальный.
← →
NS (2004-06-11 07:57) [21]Самый надежный способ, которым пользуюсь я, чтобы мои сотрудники "вола не юзали" в рабочее время - перехватываю функции CreateProcessA и CreateProcessW, в которых проверяю входит ли программа в список разрешенных (именно разрешенных, а то с утра до вечера будешь "Черные списки" править). И если все в порядке, вызываю оригинальную функцию. Если это ненужный процесс, не вызываю оригинальную функцию, и возвращаю код ошибки, что процесс не загружен, мол "извиняйте ребята, но распитие Пепси на территории ликеро-водочного завода строжайше запрещено". :)))
Только есть тут одна проблема: как уже говорил у меня не получилось сделать перехват функции WinAPI на Delphi.
← →
NS (2004-06-11 08:07) [22]> RageE
>Конечная цель написать службу которая будет запрещать запускать
>одно и тоже приложение чаще чем раз в минуту напрммер. Делается
>это для облегчения работы сотрудникам инет-кафе в которых
>некоторые посетители любят наживать кнопку мыши по 20 раз пока
>не появится IE.
Есть простое решение твоей задачи (если это касается только IE, ну и вообще нескольких программ): замени все ярлыки IE на рабочем компьютере на ссылку на твою программу, в которой реализован запуск оригинальной программы IE и имеется защита от запуска второй копии (например через мьютекс). Примерный алгоритм:
- создал мьютекс. Если он уже есть - выходим.
- запустил оригинальный IE;
- Команда Sleep(60000); // задерка 60000 милисек. = 1 минута
- убил мьютекс.
← →
RagE © (2004-06-11 11:11) [23]2 NS
Да я уже как раз думал над тем чтобы в реестре подправить ассоциацию с исполняемыми файлами. Но с практической точки зрения мне бы было интересней все же службу написать.
2 Sirgfine
Думаю действительно стоит так попробовать. Спасибо.
Кстати вопросик немного не в тему. Никому не приходилось запускать исполняемый файл из памяти. Условие ничего не писать на диск. У меня проблема в том что я не знаю как потом запустить правильно процесс. А то от того что я поразмещал секции и все такое толку мало. Может у кого есть инфа вообще как это делается, в каком порядке и так далее. Буду признателен любой информации. Хотя бы ващи соображения на этот счет.
← →
Alexis © (2004-06-11 15:19) [24]
> NS (11.06.04 07:57) [21]
> Самый надежный способ, которым пользуюсь я, чтобы мои сотрудники
> "вола не юзали" в рабочее время - перехватываю функции CreateProcessA
> и CreateProcessW, в которых проверяю входит ли программа
> в список разрешенных (именно разрешенных, а то с утра до
> вечера будешь "Черные списки" править). И если все в порядке,
> вызываю оригинальную функцию. Если это ненужный процесс,
> не вызываю оригинальную функцию, и возвращаю код ошибки,
> что процесс не загружен, мол "извиняйте ребята, но распитие
> Пепси на территории ликеро-водочного завода строжайше запрещено".
> :)))
> Только есть тут одна проблема: как уже говорил у меня не
> получилось сделать перехват функции WinAPI на Delphi.
Могли бы вы закинуть код программы мне на мыло aleksej_a2003@yahoo.com? Буду очень признателен...
Кстати о перехвате WinAPI на Delphi
http://www.xakep.ru/post/22263/default.htm
Может поможет :)
Только я не очень понимаю, как же вы
перехватываю функции CreateProcessA и CreateProcessW,
если
Только есть тут одна проблема: как уже говорил у меня не получилось сделать перехват функции WinAPI на Delphi.
← →
NS (2004-06-11 16:30) [25]> Alexis ©
С++ Builder пришел на помощь... А ведь этот сайт по Дельфи.
Вот и говорю, что на Дельфи перехват не получился.
Статья интересная - полная копия Рихтера, адаптированная на Дельфи. Надеюсь оно работает. Приду домой попробую найти ошибку у себя в модуле перехвата под Дельфи. Спасибо!
← →
Alexis © (2004-06-12 15:29) [26]
> NS (11.06.04 16:30) [25]
Если получится(и если прога не коммерческая) скинь исходники на мыло plz.
← →
RagE © (2004-06-14 09:38) [27]>NS
И мне, если не затруднит.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.036 c