本文主要针为进行内核编程的一些初学者提供一些错误,如有错误,希望大家能够指出。
这里先简单介绍一下概念。说到SSDT HOOK,可以从MEP技术说起,MEP(即执行路径修改)主旨就是拦截系统函数或相关处理例程,让它们转向我们自己的函数进行处理,这样就能实现过滤参数或者修改目标函数处理结果的目的。而SSDT(即 系统服务描述符表),主要是将位于Ring3的应用API函数和Ring0的内核函数联系起来,我们所要做的就是对文件监控所用的函数进行执行地址的修改,将它们转到我们自己编写的函数上来,实现挂钩。
所有编程的开始当然是对环境的搭建,这里推荐《寒江独钓》等书籍,只要按照上面的步骤去做的话,基本上环境的搭建是没有问题的,注意的问题是当你在安装服务的时候,输入程序路径要将文件名(比如first.sys)一同写进去,此外,Makefile文件可以在下载的winddk当中找一份样例即可。
关于编程语言,一般都是使用c或者c++,当然如果对于汇编语言比较熟悉也可以使用汇编。要注意的是c和c++的编译方式是不同的,意思是你不能用编译c++的方式去编译c的代码,在你所写的代码当中,如果出现了c语言和c++语言相混叠的情况,需要在代码中使用extern进行标注。
啰嗦的了半天,可以进行正式的代码部分了,很多人在开始写内核编程的代码时候其实是毫无头绪的(包括本人),这里推荐去看看关于Windows驱动开发部分内容的书籍。我们可以这么想,一般编程,都需要一个主函数,所以呢驱动开发同样需要一个主函数,称为驱动入口函数(DriverEntry)
#pragma code_seg("INIT")
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) //使用的是c++,出现的c语法部分添加 extern"C"
{
//函数内容
}
要注意的是,这个入口函数需要我们为它添加一块内存空间。既然有驱动入口,我们就要考虑驱动的问题了,我们的程序驱动的对象是什么呢,驱动的当然是设备了,所以这里我们开始创建设备,
//创建设备名称的字符串
UNICODE_STRING devName;
RtlInitUnicodeString(&devName, L"\\Device\\MySSDTHookDevice");
//创建设备
status = IoCreateDevice(pDriverObject,sizeof(DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
if (!NT_SUCCESS(status))//判断设备是否创建成功
return status;
pDevObj->Flags |= DO_BUFFERED_IO;//将设备设置为缓冲设备
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;//得到设备扩展
//创建符号链接
UNICODE_STRING symLinkName;
RtlInitUnicodeString(&symLinkName, L"\\??\\MySSDTHookDevice_link");
pDevExt->SymLinkName = symLinkName;
status = IoCreateSymbolicLink(&symLinkName, &devName);
if (!NT_SUCCESS(status)) //判断符号链接是否成功 失败则删除
{
IoDeleteDevice(pDevObj);
return status;
}
这里我们稍微说一说设备扩展,为什么会有设备扩展呢,因为默认的设备结构实际上是固定的,我们所要使用的设备绝非只有这一种结构,设备扩展给了我们这样一个机会能够像设备的结构当中添加我们所需要的内容。
写到这时候,我们发现驱动和设备都做好了,那么触发条件又在哪里呢?这时候,我们就用到了驱动派遣函数。派遣函数是windows驱动程序当中非常重要的概念,主要负责处理I/O请求。我们可以这么理解,我们所处的环境是用户模式,如果此时我们使用我们的鼠标双击打开一个文件时候,我们的操作