Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 31.05.2009, 07:16   #1
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию FAQ (как бы) по БОТАМ & нет Хукам!

Несколько последних тем по WinAPI сконцентрированы на одном - как симулировать нажатие клавиш-кнопок (будто нет других вопросов). Здесь я напишу кое-чего. А знающие люди пусть поправят/добавят своё.

Вопрос "возможно ли симулировать действия пользователя (интерфейс) в Windows", сводится к вопросу - "есть ли в библиотеках .dll функции, симулирующие эти действия". И, как известно, они есть.
BaronTreep вне форума Ответить с цитированием
Старый 31.05.2009, 07:17   #2
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

Клавиши

Что происходит, когда мы нажимаем кнопку на клавиатуре? Ну сначала работает аппаратная часть, это опускаем, срабатывает прерывание... А вот тут интересно - функция симуляции НАПРЯМУЮ обращается к драйверу клавиатуры и происходит прерывание.

вот что говорит SDK:

Функция (проце-дура) keybd_event синтезирует нажатие клавиши. Даже больше - она показывает зажата ли клавиша, или поднята.

VOID keybd_event(
BYTE bVk,
BYTE bScan,
DWORD dwFlags,
DWORD dwExtraInfo
);

bVk - апаратно независимый номер клавиши от 1 до 254.
bScan - апаратно зависимый номер. Чтобы получить его для bVk используем функцию MapVirtualKey(bvk, 0)
dwFlags - либо 0, либо KEYEVENTF_KEYUP, либо KEYEVENTF_EXTENDEDKEY.
dwExtraInfo - 32-битное значение ассоциированное с нажатой кнопкой (???)

Как узнать номера клавиш? Часто нужно взять название и подставить VK_. Например VK_SHIFT, потом (в Delphi) нажимаете CTRL, жмете на эту константу и попадаете на список всех клавиш...

И вот я пишу:

Код:
S:='PRIVET';		//Пишем любую строку уттт
for i:=1 to Length(S) do begin
  keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), 0, 0);   // Нажимаем шифт
  keybd_event(ord(S[i]), MapVirtualKey(ord(S[i]), 0), 0, 0); // Эмулируем буковки
end;
keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_KEYUP, 0);   // Отжимаем шифт, а то так и будет
И если фокус на текстовом поле то появляется PRIVET, а если раскладка была руской то - ЗКШМУЕ.

Теперь, чтобы узнать, нажата ли клавиша используем GetKeyState(key).

Между прочим нажимать таким образом можно кнопки и на мыши:

VK_LBUTTON = 1; //Левая кнопка мыши
VK_RBUTTON = 2; Правая кнопка мыши
VK_MBUTTON = 4; //Центральная кнопка мыши

Последний раз редактировалось BaronTreep; 31.05.2009 в 09:20.
BaronTreep вне форума Ответить с цитированием
Старый 31.05.2009, 07:18   #3
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

Немного кайфа.

Кайф такой - все это работает ДАЖЕ КОГДА ПРИЛОЖЕНИЕ НЕ АКТИВНО!!!

Можно покричать ещё так - НЕ НАДО СТАВИТЬ ЛОВУШЕК НА КЛАВИШИ И МЫШИ!!! NO SYSTEMHOOK!!!

Например - хочу прогу, которую не видит мама с папой, и которая по нажатию ЦентральнаяКнопкаМыши+1 вставляет в активное текстовое поле МОЙ пароль. Так что, "fuck keylogers".

Ну просто. Открываем Notepad, пишем

Код:
program Paster;

uses SysUtils, Windows;

const
  Parol1 = 'ABCDEFG';
  Parol2 = 'MYWEBPAGE';
  {и другие пароли}

var
  i : Byte;
  OK1 : Boolean = TRUE;

begin
 while true do
   if (-GetKeyState(4) in [127, 128])and(-GetKeyState(ord('1')) in [127, 128]) then begin
        if OK1 then begin
          for i:=1 to Length(Parol1) do
            keybd_event(ord(Parol1[i]), MapVirtualKey(ord(Parol1[i]), 0), 0, 0);
          OK1 := False;
        end;
   end
   else OK1 := True;

   {то же для других паролей}
end.
Сохраняем с расширением dpr, щелкаем компилим. Все! Это процесс, виден только в процессах. Где угодно жмем центральную кнопку + 1 и у нас появляется эта единичка, плюс пароль. НО есть несколько ограничений - все пароли должны быть записаны латиницей, большими буквами. Если у вас отжат капслок, то набираются маленькие буквы, иначе большие. Если раскладка английская - набирается то что и в константе, иначе - сами понимаете.

Плюс там непрерывный цыкл, поэтому процесс страшно хавает процессор :-) Но это все легко оптимизировать. Главное метод рабочий!

Хуки

Есть ещё одно предположение к обсуждению:

В Windows некоторые вещи реализованы как (подобно) ловушки. В частности абстракции над прерываниями клавиатуры и мыши. Поэтому ставить хуки на мышь/клаву НЕ надо, приложение может взять всю информацию будочи не активным

Ну понятно, что к этому (может бредовому) предположению меня привел пример, который я выше показал.

Последний раз редактировалось BaronTreep; 31.05.2009 в 10:04.
BaronTreep вне форума Ответить с цитированием
Старый 31.05.2009, 07:18   #4
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

О Мышах

Понятно, что все то же самое можно проделать и с мышкой. Как же надругаться над этим бедным животным? Для этого используем mouse_event из того же user32.dll:

Функция (проце-дура) mouse_event синтезирует нажатие кнопок и перемещение мыши.

VOID mouse_event(
DWORD dwFlags,
DWORD dx,
DWORD dy,
DWORD dwData,
DWORD dwExtraInfo
);

флаги принимают значения:

MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_MOVE, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_WHEEL

Можно догадаться как их применять. Также не вызывает проблем dx и dy.

Ну а последние два параметра - специальные.

Для примера создайте таймер, определите глобальные переменные

i, dx, dy : integer;

И напишите в функции таймера

Код:
    inc(i);
    dx := round(100*(sin(i)));
    dy := round(100*(cos(i)));
    mouse_event(MOUSEEVENTF_MOVE, dx, dy, 0, 0);
Теперь мышь бегает по кругу, и этот круг "перемещается" при движении мыши, полный запар...

А вот код для плавного перемещения

Код:
    i:=i+0.1;
    dx := round(10*(sin(i)));
    dy := round(10*(cos(i)));
    mouse_event(MOUSEEVENTF_MOVE, dx, dy, 0, 0);
Если эта тема была кому-нибудь полезна, то и хорошо.

Последний раз редактировалось BaronTreep; 31.05.2009 в 09:25.
BaronTreep вне форума Ответить с цитированием
Старый 02.06.2009, 06:35   #5
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

Оптимизация цикла

Система при выполнении цикла "захлёбывается", но стоит ввести небольшое ожидание в теле цикла и ресурсы снова распределяются как следует:

Код:
while true do begin
   sleep(1);   // -> kernel.dll
   ...
end;
Или так:

Код:
var
  h : THandle;   // THandle = LongWord
...
begin
  h := CreateEvent(nil, true, false, 'et');  // -> kernel.dll
  while true do begin
     WaitForSingleObject(h, 1) ;             // -> kernel.dll
     ...
  end;
  Closehandle(h);                            // -> kernel.dll
end.
Можно поставить ожадание в несколько секунд (сек*1000), если необходимо следить за ходом выполнения цикла в реальном времени.

Дополнения по функциям user32.dll

Функция ShowCursor(bShow: BOOL) делает курсор видимым/невидимым. Вот этот код заставит курсор мыши мигать:
Код:
var
  Sh : Boolean = True;
...
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Sh then begin
    ShowCursor(False);
    Sh := False;
end
else begin
    ShowCursor(True);
    Sh := True;
end;
end;
SetCursorPos(X, Y : Integer) - более простой способ способ установить позицию курсора.
GetCursorPos(var lpPoint: TPoint) - такой же простой метод снять позицию курсора, пример кода записывающего перемещение мыши в массив, и кода который сможет эти перемещения затем воспроизвести:
Код:
var
  Pnt : Tpoint;

...
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  GetCursorPos(Pnt);
  Mas[i, 1] := Pnt.X;
  Mas[i, 2] := Pnt.Y;
  inc(i);
end;

...
procedure TForm1.Timer2Timer(Sender: TObject);
begin
  inc(i);
  SetCursorPos(Mas[i, 1], Mas[i, 2]);
end;

...
//предыдущий таймер не оптимальный, вот как лучше воспроизводить по массиву:
procedure TForm1.Timer3Timer(Sender: TObject);
begin
  inc(i);
  mouse_event(MOUSEEVENTF_MOVE, Mas[i+1, 1] - Mas[i, 1], Mas[i+1, 2] - Mas[i, 2], 0, 0);
end;
ClipCursor(lpRect: TRect) сажает мышь в клетку. Нужно определить структуру Rct : TRect и задать ей четыре угла, затем вызвать функцию.
функция GetClipCursor(var lpRect: TRect) сравнивает область мыши с областью-аргументом и при совпадении возвращает true.

Ещё одна специя - SwapMouseButton(fSwap: BOOL): BOOL; меняет кнопки мыши для левши и обратно.

GetKeyState(nVirtKey: Integer) : SHORT; Уже была использована в примере. Для виртуальной клавиши она возвращает состояние - если старший бит 1, то клавиша нажата. На практике это означает равенство либо -127, либо -128, что можно проверить так:

(-GetKeyState(vk) in [127, 128]);

function VkKeyScan(ch: Char): SHORT; переводит символ из Char в VK, при этом в нижнем байте записан VK код, а в верхнем флаги, идентифицирующие нажатия кнопок shift, ctrl, alt в разных комбинациях.

Последний раз редактировалось BaronTreep; 02.06.2009 в 09:29.
BaronTreep вне форума Ответить с цитированием
Старый 02.06.2009, 08:14   #6
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Пара комментарий:
1.Клавиши
А что будет с твоим примером если окно куда нужно все это вписать будет не в фокусе? Он будет писать в то окно которое имеет фокус т.е. куда угодно. Я бы лчше использовал для передачи текстовой информации окну другие способы, Клипбоард или WM_SETTEXT например, ибо в этом случае я ЧЕТКО могу указать получателя (его хендл)

2.
Цитата:
В Windows некоторые вещи реализованы как (подобно) ловушки. В частности абстракции над прерываниями клавиатуры и мыши. Поэтому ставить хуки на мышь/клаву НЕ надо, приложение может взять всю информацию будочи не активным
Приведи ка пример. Наверное имеется ввиду проверка в таймере через GetKeystate... Но поверь - у хуков тут огромнейшее преимущество, хотя бы в том что хук может позволить себе отменить доставку сообщения до получателя.
К тому же если речь идет о клавиатуре хук поставить не так уж и сложно, и даже без DLL.
3.
Цитата:
Теперь мышь бегает по кругу, и этот круг "перемещается" при движении мыши, полный запар...
Хм... По ручкам за такие шутки... Это я как администратор утверждаю.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 02.06.2009, 08:50   #7
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

1.
Цитата:
А что будет с твоим примером если окно куда нужно все это вписать будет не в фокусе? Он будет писать в то окно которое имеет фокус т.е. куда угодно.
Ну так и будет, когда пользователь нажимет кнопку, символ появляется в АКТивном поле, и когда симуляция её нажимает - то же самое.
я же говорю не о способах передачи текста, а о способах симуляции пользователя, и я подозреваю что mouse/keyboard_event - самые примитивные=низкоуровневые функции которые можно взять из kernell для этой цели.

2. Ну во первых хуки грузят систему, это тот же цикл, который windows постоянно прокручивает; потом они, эти жуки, часто используются вредоносным ПО, и приходится добавлять добропорядочную программу в исключения сканеров^анти, это ЕЩЁ грузит систему.

GetKeyState - работает когда окно не активно/когда окна нет/оно будет работать даже в сервисе.
То же относится к GetCursorPos(Pnt), SetCursorPos.
Код HTML:
The keybd_event function synthesizes a keystroke. ... . The keyboard driver's interrupt handler calls the keybd_event function.
3. ++_ нельзя расслабляться! а то без мышы как без ... крыши;

Можно написать программку: она смотрит нажатые кнопки и сравнивает на предмет вхождения в два словаря - руский и английский, и если вхождение в один словарь, а раскладка другая, переключает раскладку и меняет символы на верные.
Прим. : эта симуляция клавиатуры 1000 символов забивает мнугвенно.
BaronTreep вне форума Ответить с цитированием
Старый 06.06.2009, 05:46   #8
BaronTreep
Форумчанин
 
Регистрация: 29.05.2009
Сообщений: 320
По умолчанию

Написал программКу... Есть у неё пара проблема, но уже кое-что можно, например ВОТ эта подсветка текста на Паскале сделана не мной, программой...

Код:
{ set privelage to process
 Parametres - token, name_of_privelage, on/off flag. Result - OK or not.
 for exemple - SeDebugPrivilege, SeSecurityPrivilege }

function SetPrivilege(hToken: dword; lpPrivName : PChar; bEnable : Boolean) : Boolean;
var
   NameValue: integer;
   tkp: TOKEN_PRIVILEGES;
   ReturnLength: Cardinal;
begin
 Result := False;
 if hToken = 0 then
            OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_ADJUST_PRIVILEGES
                                                    or TOKEN_QUERY, hToken);

 if not LookupPrivilegeValue(nil, lpPrivName, NameValue) then
  begin
   CloseHandle(hToken);
   exit;
  end;
 tkp.PrivilegeCount := 1;
 tkp.Privileges[0].Luid := NameValue;
 if bEnable then
        tkp.Privileges[0].Attributes := (SE_PRIVILEGE_ENABLED)
 else begin
        tkp.Privileges[0].Attributes := (SE_PRIVILEGE_ENABLED and
                                         tkp.Privileges[0].Attributes);
 end;
 AdjustTokenPrivileges(hToken, FALSE, tkp, sizeof(TOKEN_PRIVILEGES),
                       tkp, ReturnLength);
 if (GetLastError <> ERROR_SUCCESS) then exit;

 Result := TRUE;
 CloseHandle(hToken);
end;
1. Загружается в один процесс - не получится создать несколько копий программы.
2. По нажатию правый CTRL+F8 берет буфер обмена (если там есть текст, и только текст) заменяет одни символы на другие на основе словаря words.ini.
3. Выгружается по правый CTRL+F12, нужно щелкнуть сообщение о закрытии.

Ну вот как он выдал... Проблемы:
1. Русские символы забиваются вопросами...
2. Иногда (если быстро от неё требовать ответа) брыкается
...

Если кому интересно, Вот :
Вложения
Тип файла: rar Paster.rar (2.5 Кб, 20 просмотров)

Последний раз редактировалось BaronTreep; 06.06.2009 в 05:51.
BaronTreep вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вопрос по хукам внутри прораммы Leloush Win Api 2 31.01.2009 19:05