На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Keyboard hook - ошибка с памятью
    Для определения времени печатания пришлось ставить хук на клавиатуру. Взял готовую библиотеку из примера клавиатурного шпиона, немного подправил. Все вроде заработало: клавиши ловятся, передаются в приложение, время считается. Однако после запуска программы и установки хука почти все приложения в системе от фотошопа до блокнота стали периодически (раз в несколько минут или чаще) выдавать ошибки нарушения доступа к памяти с сообщением "Ошибка по адресу траляля. Память не может быть READ" При отключении ловушки (просто снес dll-ку из папки) ошибки прекратились. Проверено на двух компах. Я сделал вывод, что библиотека где-то делает грубую ошибку при работе с памятью, но сам не докумекал.
    Плиз, собственно, хелп.

    Код приложения
    ExpandedWrap disabled
      procedure TForm1.WndProc(var Msg: TMessage);
      var
      CharCode:char;
      begin
      inherited ;
      if Msg.Msg = WM_MYKEYHOOK then
              begin
              if Msg.wParam<>0 then LastKeyPressedTime:=GetTickCount;
              end;
      end;
       
      procedure TForm1.StartLogKey();
      var
        Hook: procedure (switch : Boolean; hMainProg: HWND) stdcall;
      begin
        @hook:= nil;
        HookDLLHandle:= LoadLibrary(PChar(installpath+'keyproc.dll'));
        if HookDLLHandle > HINSTANCE_ERROR then
          begin                          
            @hook:=GetProcAddress(HookDLLHandle, 'hook');
            hook(true, form1.Handle);
          end;
      end;
       
      procedure TForm1.StopLogKey();
      var
        Hook: procedure (switch : Boolean; hMainProg: HWND) stdcall;
      begin
        @hook:= nil;
        if HookDLLHandle > HINSTANCE_ERROR then
          begin          
            @hook:=GetProcAddress(HookDLLHandle, 'hook');  
            hook(false, Form1.Handle);
            if FreeLibrary(HookDLLHandle) then
                    begin
                    log(0,'Keyproc close ok');
                    end
                    else
                    begin
                    log(0,'Error close keyproc');
                    end;
          end;
      end;
       
       
      initialization
      WM_MYKEYHOOK:= RegisterWindowMessage('WM_MYKEYHOOK');


    Код ловушки
    ExpandedWrap disabled
      -------------------------------------------------------------------
      library keyproc;
       
      uses
        SysUtils,
        Windows,
        Messages;
       
      const
        MMFName: PChar = 'KeyMMF';
      type
        PGlobalDLLData = ^TGlobalDLLData;
        TGlobalDLLData = packed record
          SysHook: HWND;
          MyAppWnd: HWND;
        end;
       
      var
        GlobalData: PGlobalDLLData;
        MMFHandle: THandle;
        WM_MYKEYHOOK: Cardinal;
        a:integer;
       
      function KeyboardProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
      var
          AppWnd: HWND;  // дескриптор приложения, в котором произошло нажатие клавишы
      begin
        if code < 0 then
        begin
          Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
          Exit;
        end;
       
        if (Code = HC_ACTION) and (((lParam shr 16) and KF_UP) = 0)
              then SendMessage(GlobalData^.MyAppWnd, WM_MYKEYHOOK, wParam, AppWnd);
        CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
        Result:= 0;
      end;
       
      {Процедура установки HOOK-а}
      procedure hook(switch : Boolean; hMainProg: HWND) export; stdcall;
      begin
        if switch=true then
        begin
          {Устанавливаю HOOK, если он не установлен (switch=true). }
          GlobalData^.SysHook := SetWindowsHookEx(WH_keyboard, @KeyboardProc, HInstance, 0);
          GlobalData^.MyAppWnd:= hMainProg;
          if GlobalData^.SysHook <> 0 then a:=1
              //MessageBox(0, 'KEYBOARD HOOK установлен !', 'Message from keyhook.dll', 0)
            else                           a:=0;
      //        MessageBox(0, 'HOOK установить не удалось !', 'Message from keyhook.dll', 0);
        end
        else
        begin
          {Удаляю функцию-фильтр, если она установлена (т.е. switch=false). }
          if UnhookWindowsHookEx(GlobalData^.SysHook) then a:=1
      //      MessageBox(0, 'HOOK снят !', 'Message from keyhook.dll', 0)
          else a:=1;
      //      MessageBox(0, 'HOOK снять не удалось !', 'Message from keyhook.dll', 0);
        end;
      end;
       
      procedure OpenGlobalData();
      begin
        {регестрируем свой тип сообщения в системе}
        WM_MYKEYHOOK:= RegisterWindowMessage('WM_MYKEYHOOK');
        {получаем объект файлового отображения}
        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;
       
      exports hook;
       
      begin
      //MessageBox(0, PChar(Application.ExeName), 'Message from keyhook.dll', 0);
        {назначим поцедуру переменной DLLProc}
        DLLProc:= @DLLEntryPoint;
        {вызываем назначенную процедуру для отражения факта присоединения данной
         библиотеки к процессу}
        DLLEntryPoint(DLL_PROCESS_ATTACH);
      end.
      M
      Тема перенесена из Delphi -> Delphi: Общие вопросы.
        в KeyboardProc аргумент wParam должен иметь тип Longint
          ExpandedWrap disabled
            function KeyboardProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
            var
                AppWnd: HWND;  // дескриптор приложения, в котором произошло нажатие клавишы
            begin
              if code < 0 then
              begin
                Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
                Exit;
              end;
             
              if (Code = HC_ACTION) and (((lParam shr 16) and KF_UP) = 0)
                    then SendMessage(GlobalData^.MyAppWnd, WM_MYKEYHOOK, wParam, AppWnd);
              CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
              Result:= 0;
            end;

          GlobalData и AppWnd здесь могут быть неопределены
          Поставьте проверку
          if GlobalData = nil then error
          if NOT IsWindow(AppWnd) then error
            Цитата alex31 @
            в KeyboardProc аргумент wParam должен иметь тип Longint

            :yes:
              Цитата Serge @
              GlobalData и AppWnd здесь могут быть неопределены

              Чушь...
              И каким образом они могут быть не определены?
              по DLL_PROCESS_ATTACH отрабатывает OpenGlobalData, где и происходит MapViewOfFile, а SetWindowsHookEx происходит в procedure hook, без которой невозможен вызов KeyboardProc

              а вот тут:
              ExpandedWrap disabled
                procedure DLLEntryPoint(dwReason: DWord); stdcall;

              явный перебор с stdcall...
              Собственно здесь у тебя и происходит вылет №1 при попытке выгрузки хука...
              Смотри реализацию здесь: Перехват API функций
              и вот здесь: Перехват recv
              Ну и естественно классический CALLBACK KeyboardProc выглядит вот так:
              ExpandedWrap disabled
                function KeyboardProc(Code: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;

              Где ты спокойно ловишь вылет №2...

              Ну и в заключение, а нафига спрашивается козе баян в виде неотлаженных библиотек, когда можно спокойно поставить LowLevelHook при помощи константы WH_KEYBOARD_LL = 13 и ловить все сообщения через application-defined callback function, которая аналогичны вышеописаной?
                Цитата Rouse_ @
                Цитата Serge @
                GlobalData и AppWnd здесь могут быть неопределены

                Чушь...
                И каким образом они могут быть не определены?

                AppWnd будет не определена...
                это локальная переменная функции KeyboardProc
                я не вижу где эта переменная там устанавливается
                  alex31, точно, пропустил я это дело с AppWnd...
                  Да вот только тут мало того что она не определена, а вообще непонятно какое значение будет иметь ибо пустая переменная, поэтому ее можно откидывать, роли она никакой не сыграет...
                    Цитата Rouse_ @
                    alex31, точно, пропустил я это дело с AppWnd...
                    Да вот только тут мало того что она не определена, а вообще непонятно какое значение будет иметь ибо пустая переменная, поэтому ее можно откидывать, роли она никакой не сыграет...

                    Всего скорее,судя по комментарию, автор забыл поставить
                    AppWnd:=GetForegroundWindow;
                      Да, автор не забыл, там это и было - ведь шпион должен не только логить клавиши, но и записывать в каком приложении они были нажаты. Я это убрал, потому что не шпиона делал, а от переменной забыл избавится.[b]

                      В общем я принял непростое, но единственно верное решение - передрать внаглую все у _Rouse и не думать из расчета что много будешь знать скоро состаришься :) Копирайты ессно оставил :) Все завелось с полоборота :) За сим всех благодарю и желаю долгих лет жизни, здоровья, счастья и всего самого наилучшего! :)
                        Цитата мыш @
                        передрать внаглую все у _Rouse и не думать из расчета что много будешь знать скоро состаришься

                        Спасибо, конечно, за характеристику, но советую всежтаки прочесть Рихтера хотя бы в качестве теории... Если и дальше будешь заниматься системой, то можешь много шишек набить при отладке хуков, а это потраченое впустую время... :)
                          Rouse_, твой пример почему то у меня ловит только нажатия клавиш в моем приложении, из других сообщения не приходят. Почему так может быть?
                            Цитата мыш @
                            Rouse_, твой пример почему то у меня ловит только нажатия клавиш в моем приложении, из других сообщения не приходят. Почему так может быть?

                            Не знаю, у меня все нормально, вот еще раз собрал демку - держи в архиве...
                            Прикреплённый файлПрикреплённый файлKeyboardHook.rar (187.39 Кбайт, скачиваний: 93)
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0.0936 ]   [ 16 queries used ]   [ Generated: 5.07.26, 03:31 GMT ]