Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Hook для программ эмулирующих нажатие кнопок мыши


Автор: RedHat 11.7.2006, 09:40
Вот тут на форуме много примеров как с эмулировать нажатие кнопок мыши или клавиатуры в другой программе. А как в своей программе можно организовать мехонизм противодействующий этому или хотя бы что бы он показывал процес который эмулирует эти сообщения???
  

Автор: BUGOR 11.7.2006, 10:40
Это же очевидно - перехват соответствующих апи функций и обработка результата их выполнения. 

Автор: RedHat 11.7.2006, 10:44
А пример моно или сылку где есть об этом инфа  smile  

Автор: Rouse_ 11.7.2006, 13:54
WH_DEBUG 

Автор: Alexeis 12.7.2006, 00:36
BUGOR, А разве можно в принципе отличить
SendMessage от реального нажатия?

Цитата(RedHat @  11.7.2006,  09:40 Найти цитируемый пост)
организовать мехонизм противодействующий этому
Можно, как вариант, использовать (где это возможно) неоконные компоненты, которые не могут ничего получать непосредственно сами. 

Автор: BUGOR 12.7.2006, 12:11
Можно проследить откуда идёт сообщение 

Автор: Romikgy 12.7.2006, 12:57
Цитата(BUGOR @  12.7.2006,  11:11 Найти цитируемый пост)
Можно проследить откуда идёт сообщение  

Как? 

Автор: Alexeis 12.7.2006, 13:52
Цитата(BUGOR @  12.7.2006,  12:11 Найти цитируемый пост)
Можно проследить откуда идёт сообщение 

Вот именно как? Я вчера 2 часа локальный хук на клавиатуру долбал smile так и не нашел как получить адрес отправителя... 

Автор: BUGOR 12.7.2006, 14:56
Разберём метод под названием сплайсинг, на примере SendMessage, суть метода заключается в замене первых пяти байт вначале api функции(в нашем случае SendMessage) на длинный прыжок, который будет вести на функцию-обработчик(которая в свою очередь принимает все те же параметры, что и оригинальная SendMessage), функция обработчик находится в dll(в самом простом случае), а dll инжектится во все процессы(CreateRemoteThread или опять же с помощью хуков, это значения не имеет), так вот суть функции обработчика такова:
1.Заменить первые пять байт на оригинальные
2.Вызвать функцию с оригинальными параметрами
3.Обработать результат
4.Вернуть прыжок на себя вначало функции

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

 

Автор: RedHat 13.7.2006, 09:48
Цитата(BUGOR @ 12.7.2006,  14:56)
2.Вызвать функцию с оригинальными параметрами
3.Обработать результат
4.Вернуть прыжок на себя вначало функции

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

вот то что  я сделал для FindWindow. прошу не судить строго это моя первая подобного рода программа
Код

//----------------Замена стандартной API на свою
function NewFindWindow(lpClassName, lpWindowName: PChar): HWND; stdcall;

var
 Written : DWORD;
 tmp : PAnsiChar;

begin
//----------------Востанавливаем первые байты на родные
WriteProcessMemory(INVALID_HANDLE_VALUE, FiWAdr,@OldFiw, SizeOf(OldCode), Written);
tmp:=lpWindowName;

if tmp <> 'Название окна' then //Название окна 
 begin
 Result :=FindWindow(lpClassName,lpWindowName)
 end
else
 begin
 //Вот сюда то что нужно сделать
 //GetModuleFileNameStr(Hinstance); // dll name
//GetModuleFileNameStr(0); // exe name 
Showmessage(GetModuleFileNameStr(0)); // здесь ми выводим откуда была вызвана функция  для данного окна 
 //Изменяем функцию поиска окна  на всякий бред
 Result :=FindWindow(lpClassName,'E776B913-040E-4E9C-8BF9-02DE977727CC')
 end;
//----------------Востанавливаем первые байты на новые
WriteProcessMemory(INVALID_HANDLE_VALUE, FiWAdr,@JmpFiW, SizeOf(far_jmp), Written);
end;



Код

  hUser32 := GetModuleHandle('user32.dll');
  MbaAdr  := GetProcAddress(hUser32, 'FindWindowA');
  ReadProcessMemory(INVALID_HANDLE_VALUE, FiWAdr, @OldFiW, SizeOf(OldCode), Bytes);
  JmpMba.PuhsOp  := $68;
  JmpMba.PushArg := @NewFindWindow;
  JmpMba.RetOp   := $C3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, FiWAdr, @JmpFiW, SizeOf(far_jmp), Bytes);


 

Автор: RedHat 13.7.2006, 12:12
Существует программа AutoIt3
Не подскажите как можно боротся с такими программами на уровне своей программы то есть не позвалять ей нажимать в своей программе кнопки?????
AutoIt3 посылает нажатие кнопок в другую программу если не сложно преведите список API для посылки команд другому приложению  

Автор: Alexeis 13.7.2006, 12:21
Цитата(RedHat @  13.7.2006,  12:12 Найти цитируемый пост)
если не сложно преведите список API для посылки команд другому приложению  

SendMessage
PostMessage

Добавлено @ 12:24 
Цитата(RedHat @  13.7.2006,  12:12 Найти цитируемый пост)
Не подскажите как можно боротся с такими программами на уровне своей программы то есть не позвалять ей нажимать в своей программе кнопки?????

А чем указанный выше метод BUGOR не устраивает?
 

Автор: Romikgy 13.7.2006, 12:38
Цитата(alexeis1 @  13.7.2006,  11:21 Найти цитируемый пост)
А чем указанный выше метод BUGOR не устраивает?

а я его не понял smile 

Автор: Alexeis 13.7.2006, 12:51
Цитата(Romikgy @  13.7.2006,  12:38 Найти цитируемый пост)
а я его не понял
Я так понял, что речь идет в изменении кода оригинальной библиотеки ядра, с тем чтобы вазвавший функцию sendmessage, поток вызвал не оригинальную, а нашу. Мы смотрим, не отправили ли это сообщение нам, если так, то блокировать иначе вызвать настоящую sendmessage. 
Только если вдруг драйвер мыши шлет сообщения таким же образом, то ничего не выйдет

Добавлено @ 12:55 
Хотя поскольку dll работает в контексте приложения его вызвавшего, можно узнать номер потока и сравнить его с номером потока драйвера мыши или системного потока, который может за мышь отвечает.  

Автор: Romikgy 13.7.2006, 13:43
А как узнать 
Цитата(alexeis1 @  13.7.2006,  11:51 Найти цитируемый пост)
номер потока 

из перехваченой 
Цитата(alexeis1 @  13.7.2006,  11:51 Найти цитируемый пост)
sendmessage

?
Вот это я не понял? 

Автор: Alexeis 13.7.2006, 14:23
Номер потока узнаем при помощи GetCurrentThreadId
Фокус получается такой, ложная функция sendmessage будет выполнятся в контексте того приложения которое ее вызвало, а значит GetCurrentThreadId укажет виновника, остается передать это значение в свою програму любым методом, хоть при помощи буфера обмена! 

Автор: RedHat 13.7.2006, 14:23
Цитата(alexeis1 @  13.7.2006,  12:51 Найти цитируемый пост)
 так понял, что речь идет в изменении кода оригинальной библиотеки ядра, с тем чтобы вазвавший функцию sendmessage, поток вызвал не оригинальную, а нашу. Мы смотрим, не отправили ли это сообщение нам, если так, то блокировать иначе вызвать настоящую sendmessage. 
Только если вдруг драйвер мыши шлет сообщения таким же образом, то ничего не выйдет

Добавлено @ 12:55 
Хотя поскольку dll работает в контексте приложения его вызвавшего, можно узнать номер потока и сравнить его с номером потока драйвера мыши или системного потока, который может за мышь отвечает.  


Вот именно как посмотреть сообщение нам предназначается или нет вот в этом загвостка!!
и по поводу блокировке если можна примерчик
 

Автор: Alexeis 13.7.2006, 14:44
Цитата(RedHat @  13.7.2006,  14:23 Найти цитируемый пост)
Вот именно как посмотреть сообщение нам предназначается или нет вот в этом загвостка!!

Это как раз просто, мы же знаем заголовок нашего приложения, находим главное окно, дальше находим всех его детей, детей их детей и т.д. и сверяем handl - ы(можно ограничется поиском одного окна, того которое нам нужно), если handle окна назначения совпадает с hendl-ом одного из наших контролов, то ясно что нам отправляют.
Цитата(RedHat @  13.7.2006,  14:23 Найти цитируемый пост)
и по поводу блокировке если можна примерчик

тут и пример не нужен мы же после проверки (вдруг не нам!) должны переслать это сообщение правельному адресату, соответствено если адресат оказалсянашим окном, то мы этого не делаем
Код

if not(наше окно)
then
  правим адрес входа и шлем куда надо
else
  не отправляем!(ничего не делаем)

 

Автор: RedHat 13.7.2006, 17:05
Цитата(alexeis1 @  13.7.2006,  14:44 Найти цитируемый пост)
Это как раз просто, мы же знаем заголовок нашего приложения, находим главное окно, дальше находим всех его детей, детей их детей и т.д. и сверяем handl - ы(можно ограничется поиском одного окна, того которое нам нужно), если handle окна назначения совпадает с hendl-ом одного из наших контролов, то ясно что нам отправляют.


понятно, но смотри ми же делаем инъекцию dll в чужой процесс так как ми будем знать handl той программы которую нужно защищать то есть как передать параметр???
 

Автор: Alexeis 13.7.2006, 17:53
Цитата(RedHat @  13.7.2006,  17:05 Найти цитируемый пост)
handl той программы которую нужно защищать то есть как передать параметр???

Ничего не тужно передавать его можно узнать используя функции
FindWindow
EnumWindows
EnumChildWindows 

Автор: Alexeis 13.7.2006, 21:54
Я подумал, можно еще упростить решение даже не портя системные dll.
Просто поставить глобальный хук на сообщение WM_LBUTTONDOWN, и поскольку хук выполнится в контексте пославшего сообщение потока, то GetCurrentThreadId или подобные функции должены дать нам все что надо! Зная все параметры нашего окна, мы с легкостю его найдем. 

Автор: RedHat 14.7.2006, 11:12
Цитата(alexeis1 @  13.7.2006,  17:53 Найти цитируемый пост)
Ничего не тужно передавать его можно узнать используя функции
FindWindow


Код

function NEWSendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

var
 Written : DWORD;

begin
if FindWindow(nil,'имя_программы')<>0 then
 h:= FindWindow(nil,'имя_программы');

//----------------Востанавливаем первые байты на родные
WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr,@OldMba, SizeOf(OldCode), Written);
//-----------------------Code-----------------
if hWnd <> h then
 result:= SendMessage(hWnd,Msg,wParam,lParam)
else
  begin
   //---------------------вот тут встроить проверку на то кто посылает
   ??????????
     result:= SendMessage(hWnd,Msg,wParam,lParam);
  end;
//-----------------------End Code-------------
//----------------Востанавливаем первые байты на новые
WriteProcessMemory(INVALID_HANDLE_VALUE, MbaAdr,@JmpMba, SizeOf(far_jmp), Written);
end;


В программе есть горячие клавиши (стрелки) , выше приведёный код работает нормально но толко если блокировать все сообщения идущие по handl окна то блокируются и сами стрелки!!! 
вот вместо ????? вопросов надо вставить код который смотрит чужое приложение послало нажатие или нет если чужое то блокировать если нет то разрешить выполнение???? если кого не затруднит обяснить как это моно реализовать а то я зашёл в тупик  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)