2011-04-07 18 views
5

Sto scrivendo un keylogger in C# ma sto avendo qualche problema a ottenere il mio metodo di hook chiamato dagli eventi della tastiera. Il mio codice sembra corretto ma per qualche motivo la richiamata non sta accadendo.Hook tastiera di basso livello non chiamato nell'applicazione .NET

Ecco il codice rilevante:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId); 

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); 

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr GetModuleHandle(string lpModuleName); 

private const int WH_KEYBOARD_LL = 13; 
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); 
private static IntPtr HookHandle = IntPtr.Zero; 

static void Main() 
{ 
    /* install low level global keyboard hook */ 
    HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, GetModuleHandle(null), 0); 

    /* every 60 seconds, process collected keystrokes */ 
    for (;;) 
    { 
     Thread.Sleep(60000); 
     SendKeyData(); 
    } 
} 

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) 
{ 
    /* code to handle key events would be here */ 

    return CallNextHookEx(HookHandle, nCode, wParam, lParam); 
} 

private static void SendKeyData() 
{ 
    /* code to send accumulated keystroke data to remote server would be here */ 
} 

La chiamata SetWindowsHookEx restituisce una maniglia (cioè non un null) come si deve, quindi dovrebbe significare che si è installato, ma quando ho messo un punto di interruzione in HookCallback , non è mai raggiunto.

Qualcuno può consigliare quello che potrei fare di sbagliato?

+1

Funziona se si commenta il blocco 'for'? –

+0

Nessun processo termina immediatamente se lo faccio. –

+2

Probabilmente è una pratica migliore usare un Timer invece di un ciclo infinito. Almeno con un Timer potresti fermarlo se necessario. – jlafay

risposta

4

Sembra che si stia scrivendo un'applicazione console. Questa dovrebbe essere un'applicazione di moduli, dal momento che stai gestendo gli eventi di Windows. Basta nascondere il modulo e dovrebbe funzionare.

Come un work-around per le applicazioni console, si potrebbe chiamare Application.DoEvents() in loop:

for (;;) 
{ 
    Thread.Sleep(1); 
    Application.DoEvents(); //Process event queue 
    SendKeyData(); 
} 

Utilizza questo per il bene, non il male.

+0

Non dormire per un minuto, si verificherà il timeout del blocco. 45 msec è un numero felice. Application.Run() è migliore. –

+0

Mille grazie! La combinazione delle risposte di entrambi mi ha portato a un risultato positivo. Non mi rendevo conto che avevo bisogno di un ciclo di messaggi esplicito. Ora il mio programma chiama Application.Run() per farlo, e l'invio dei dati chiave viene fatto usando un thread separato tramite un BackgroundWorker (e la comunicazione tra i due thread tramite Synchronized Queue). Aggiornerò la mia domanda con il codice funzionante. –

+0

Se è necessario usare 'sleep' usa' sleep (1) '. Questo codice ritarda tutti gli input da tastiera e IMO ha entrambi 45 ms come suggerito da @HansPassant e 450 ms non sono accettabili. La soluzione corretta sarebbe un invio di messaggi bloccanti, ma non ha idea di come farlo in un'applicazione console in C# senza chiamare direttamente le funzioni winapi. – CodesInChaos

0

provare a sostituire GetModuleHandle (null) con

GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName) 

e vedere se questo fa il trucco. Si noti che sia l'oggetto Process restituito da GetCurrentProcess() che l'oggetto ProcessModule restituito da MainModule sono eliminabili, pertanto è possibile dichiararli come variabili e quindi eliminarli manualmente; ancora meglio, mettili in un blocco using.

+0

Grazie per la tua risposta, ma non era questo il problema - anche se inizialmente avevo un problema con i parametri di SetWindowsHookEx, inserendo erroneamente un parametro per l'id di thread anche quando avevo solo bisogno dell'handle del modulo del processo corrente per l'hook globale. –

Problemi correlati