使用Windows Api与驱动交互流程(CreateFile 为例):
KdPrint和Dbgprintf的区别是什么
对于Check版本,KdPrint只是DbgPrint的一个宏定义,而对于Free版本,KdPrint将被优化掉。这些输出信息可以通过DebugView对内核的监控来看到。
NTLDR(NTLDR全称是NT Loader,是系统加载程序)从注册表什么位置以此加载驱动
ntldr依次从HKEY_LOCAL_MACHINE\System\CurrentControlSet键下读取机器安装的驱动程序,然后依次加载驱动程序,初始化底层设备驱动,在注册表HKEY_LACAL_MACHINE\System\CurrentControlSet\Service键下查询Start键的值为0和1的设备驱动(“Start”键的值可以为0,1,2,3,4数值越小,启动越早)
SERVICE_BOOT_START(0)表示内核刚刚初始化,此时加载的都是与系统核心有关的重要驱动程序,例如磁盘驱动。
SERVICE_SYSTEM_START(1)稍晚一些。
SERVICE_AUTO_START(2)是从登陆界面出现的时候开始,如果登陆速度较快,很可能驱动还没有加载就已经登陆了。
SERVICE_DEMAN_START(3)表示在需要的时候手动加载。
SERVICE_DISABLED(4)表示禁止加载。
内核模块运行在什么空间
内核模块位于内核空间,而内核空间又被所有进程共享,因此实际上内核模块位于任意一个进程空间中。
x64和x86操作系统的用户空间和内核空间的范围分别是多少
X86用户空间0x00000000~0x7FFFFFFF
X86内核空间0x80000000~0xFFFFFFFF
X64用户空间0x0000000000000000~0x7FFFFFFFFFFFFFFF
X64内核空间0x8000000000000000~0xFFFFFFFFFFFFFFFF
内核创建线程的API
系统线程函数是PsCreateSystemThread()
简单讲讲如何使用内核实现病毒扫描、文件加密
Windows中很多组件都有自己的DRIVER_OBJECT比如所有的硬件驱动程序、所有的类驱动(Disk Cdron)文件系统(NTFS、FastFat)都有各自的DRIVER_OBJCET以及其他的内核组件,可以通过编写内核程序,能找到这些关键的驱动对象结构(比如NTFS文件操作系统),然后改写下面的分发函数,替换成我们自己的函数,可能就能捕获Windows文件的功能,比如扫描病毒、文件加密、这就是分发函数Hook技术。
分页内存和非分页内存的区别
Windows规定有些虚拟内存可以交换到文件中,这类内存被称为分页内存。
有些虚拟内存永远不会交换到文件中,这些内存叫非分页内存。
区别在于:
分页内存是低中断级别的例程可以访问的,而非分页内存则是各个中断级别的例程都可以使用的。
请写出指定函数位置的预编译指令以及作用
需要注意的是PAGE节函数不可在Dispatch级中调用,因为这种函数调用可能诱发页中断,而缺页中断处理不能再Dispatch级完成,为此一般都用一个宏PAGED_CODE()进行测试,如果发现当前中断级为Dispacth级,则程序直接报异常。
#pragma alloc_text宏用来指定某个函数可执行代码在编译出来之后在sys文件中的位置,
内核模块编译出来之后是一个PE格式的sys文件,这个文件的代码段(text段)中有不同的节(Section),不同的节被加载到内存中之后处理情况不同,分别有三种节。
INT节:初始化完成之后就释放,也就是说不再占用内存空间了。
PAGE节:可以进行分页交换内存空间,这些内存空间在内存紧张时可以被交换到硬盘上以节省内存。
PAGELK节:是默认节,加载后位置不可分页交换的内存地址中
(1)#pragma alloc_text(INIT,DriverEntry);
(2)#pragma alloc_text(PAGE,NdisProtUnload);
(3)#pragme alloc_text(PAGE,NdisProtOpen);
(4)#pragma alloc_text(PAGE,NdisProtClose);
需要注意的是PAGE节函数不可在Dispatch中断级中调用,因为这种函数调用可能诱发页中断,而缺页中断处理不能再Dispatch中断级完成,为此一般都用一个宏PAGED_CODE()进行测试,如果发现当前中断级为Dispacth级,则程序直接报异常。
#pragma PAGEDCODE
VOID Fun()
{
PAGED_CODE(); //do something
}
注意: PAGED_CODE()是DDK提供的宏,只在check版本中生效,它会检查这个函数是否运行在低于DISPATCH_LEVAL的中断请求,如果等于或高于这个中断请求级,则产生一个断言。当程序运行在DISPATCH_LEVEL之上时(包括本层),程序只能使用非分页内存,否则将导致蓝屏死机。
常见的内核API函数以及Ex、Zw、Nt、Rtl、Io系列函数是做什么的
常见Windows内核API
Ex系列函数(常用于内核分配,获取互斥体等)
ExAllocatPool:内存分配,相当于C RunTime库里的malloc函数
ExFreePool:内存释放,相当于 C RunTime库里的free函数
ExAcquireFastMutex:获取一个快速互斥体,互斥体用于多线程环境中的同步
ExReleaseFastMutex:释放一个快速互斥体。
ExRaiseStatus:抛出一个异常,带有错误status值,这个函数用于从代码很深的地方直接报错
Zw系列函数与Nt系列函数(读写、打开、请求)
Zw函数和同名的Nt函数有相同的作用实际上就是简单的跳转关系,被称为Native API
ZwCreateFile、NtCreateFile:打开文件(实际上也可以用于打开一个设备)
ZwWrite、NtWirte:写入文件(实际上也可以用于发送请求给设备)
ZwReadFile、NtReadFile:读同上
ZwQueryDirectoryFile、NtQueryDirectoryFile:目录查询
ZwDeviceIoControFile、NtDeviceIoControFile:发出设备控制请求
ZwCreateKey、NtCreayeKey:打开一个注册表键
ZwQueryValueKey、NtQueryValueKey读取一个注册表中的值
Rtl系列函数(字符串操作、内存操作)
RtInitUincodeString:初始化一个字符串
RtlCopyUnicodeString:拷贝字符串
RtlAppendUnicodeToString:将一个字符串追加到另一个字符串后
RtlStringCbPrintf:将字符串打印到一个字符串中,相当于sprintf
RtlCopyMemory:内存数据块的拷贝
RtlMoveMemory:内存数据块移动
RtlZeroMemory:内存数据清空
RtlCompareMemroy:比较内存
RtlGetVersion:获取当前Windows版本
Io系列函数(IO管理器、IRP、消息发送)
IoCreateFile:打开一个文件相比ZwCrateFile更加底层
IoCreateDevice:生成一个设备对象
IoCallDriver:发送请求,实际上这个函数可能是IoCallDriver的一个别名Windows管理器调用这个函数吧不同IRP发送不同的设备
IoComplateRequest:完成请求,这实际是通知IO管理器这个IRP已经完成了
IoCopyCurrentIrpSatckLocationToNext:获取当前IRP栈空间拷贝到下一个栈空间
IoSkipCurrentIrpStackLocationToNext:跳过当前IRP栈空间
IoGetCurrentIrpStackLocation:获得IRP当前栈空间指针
简单讲讲应用程序和内核通信的原理
如果一个驱动需要和应用程序通信,那么首先要生成一个设备对象(Device Object),在Windows驱动开发体系中,设备对象是非常重要的元素。设备对象和分发函数构成了整个内核体系的基本框架。设备对象可以在内核中暴露出来给应用层,应用层可以像操作文件一样操作它,用于和应用程序通信的设备往往用来控制这个内核驱动,所以往往被称为,控制设备对象(Control Device Object CDO)
应用层一般通过打开符号连接,来跟指定的设备驱动进行通信。
创建设备对象与符号链接的示例:
#include<ntifs.h>
//创建设备对象
NTSTATUS CreateDevice(PDRIVER_OBJECT driver) //driver是驱动对象
{
NTSTATUS status;
UNICODE_STRING MyDriver; //驱动字符串
PDEVICE_OBJECT device=NULL;//用于存放设备对象
RtlInitUnicodeString(&MyDriver, L"\\DEVICE\\MyDriver");//驱动设备名字
status = IoCreateDevice(driver, sizeof(driver->DriverExtension), &MyDriver, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device);
if (status == STATUS_SUCCESS)//STATUS_SUCCESS)
{
KdPrint(("zdsoft:驱动设备对象创建成功\n"));
//创建符号链接
UNICODE_STRING uzSymbolName; //符号链接名字
RtlInitUnicodeString(&uzSymbolName, L"\\??\\MyDriver"); //CreateFile
status = IoCreateSymbolicLink(&uzSymbolName, &MyDriver);
if (status == STATUS_SUCCESS)
{
KdPrint(("zdsoft:创建符号链接 %wZ 成功 ", &uzSymbolName));
}
else
{
KdPrint(("zdsoft:创建符号链接 %wZ 失败 status=%X", &uzSymbolName, status));
}
}
else
{
KdPrint(("zdsoft:驱动设备对象创建失败,删除设备\n"));
IoDeleteDevice(device);
}
return status;
}
参考文章
https://blog.youkuaiyun.com/qq_18811919/article/details/109473504