• 内核与应用通讯的几种方式转载


    转载于: https://www.cnblogs.com/endenvor/p/9057856.html 感谢作者的详细记录.
    内容如下做个备份:

    应用程序与驱动程序据我所知,细分可以分6种,ReadFile,WirteFile方式的缓冲区设备读写,直接方式读写,和其他方式读写。Io设备控制操作(即DeviceControl)的缓冲内存模式IOCTL,直接内存方式的IOCTL,其他内存方式的IOCTL!当然还有一种就是创建文件,然后文件读写也应该算是一种通信吧,这里不讨论这个!

    1,缓冲区方式设备读写:

    在创建Device后,须要指定方式为Device的Flags有DO_BUFFERED_IO!通过应用层Api函数ReadFile,WriteFile,等函数,ntoskrnl.exe创建Irp后,ReadFile和WriteFile参数的缓冲区就在irp->AssociatedIrp.Systembuffer,同时要求读写的偏移量,和长度都在PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp) 数据类型中的stack->Parameters.Read.Length,stack->Parameters.Read.ByteOffset(该类型为Large_Interge类型),

    2,直接方式读写

    在创建Device后,须要指定方式为Device的Flags有DO_DIRECT_IO!通过应用层APi函数ReadFile,WriteFile等函数,ntoskrnl.exe创建的Irp后,ReadFile和WriteFile参数的缓冲区将被锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样应用层的缓冲区和内存层的就指向同一个物理内存!而内核模式用MDL数据结构记录这段内存,这个虚拟内存大小在MmGetByteCount(pIrp->MdlAddress),首地址在MmGetMdlVirtualAddress(pIrp->MdlAddress);偏移量为MmGetMdlByteOffset(pIrp->MdlAddress)(这里的偏移量不是文件读写的偏移量,而是在MDL中的偏移量)然后文件的长度还是stack->Parameters.Read.Length,这个值和MmGetByteCount(pIrp->MdlAddress)是一样的,要不然就出错了,而真正的读写偏移量还是在stack->Parameters.Read.ByteOffset!这里无论是读还是写,都要得到MDL在内核模式下的映射,因此还要用MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority)将其转化为内核模式,然后可以读写该地址,就会转化到应用层相应的内存!!

    3其他方式读写

    这种方式很少用到,在创建Device后,Flags既不标志DO_BUFFERED_IO也不标志DO_DIRECT_IO,ReadFile和WriteFile提供的缓冲区内存地址,可以再IRP的pIrp->UserBuffer字段得到,而长度和偏移量还是在stack->Paameters.Read中,但是用这种方法须要注意的是ReadFile可能把空指针地址或者非法地址传递给驱动程序,因此驱动程序使用用户模式地址钱须要检查是否可读或者可写,可以用ProbeForWrite或者ProbeForWrite函数和try模块。

    这里有个问题困扰着我,就是应用层用GetFileSize函数时用第一种方法处理该Irp时结果是正确的,就是冲pIrp->AssociatedIrp.SystemBuffer;得到PFILE_STANDARD_INFORMATION结构指针,然后讲该结构的EndOfFile设置为你自己文件的长度,然后结束该IRP,GetFileSize就能得到正确的文件长度,但是用方法三就是的时候用GetFileSize,我同样用pIrp->UserBufer得到PFILE_STANDARD_INFORMATION结构指针,然后设置后,在GetFileSize里面去得不到正确的长度!!这个是为什么?还有就是该Irp的CurrentStackLocation-stack,该字段里面的stack->Parameters.QueryFile.Length指的是什么,显示的都是24,无论文长度为多少,还是用哪种方法都市24,很郁闷!!!

    下面是方式都是用IO设备控制操作的方法基本上与上面3中相对应!

    对于IO设备控制操作,不知道为什么可以用设置DO_DIRECT_IO后就能对三种方式都适用,而且stack->Parameters.Read.Length/Write.Length 都是对应应用层的DeviceIoControl函数中的第6个参数也就是输出缓冲区!DeviceIoControl函数的输入输出缓冲区长度都再stack->Parameters.DeviceioControl.InputBufferLength/OutputBufferLength中

    4缓冲内存IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_BUFFERED,在内核模式中输入缓冲区很输出缓冲区都为pIrp->AssociatedIrp.SystemBuffer,

    5直接方式IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_IN_DIRECT/METHOD_OUT_DIRECT(最好使用第一个,因为第一个对所有的打开设备方式都通用)!对于第4中的区别是输入缓冲区还在pIrp->AssocatedIrp.Systembuffer中,但是输出缓冲区却是pIrp->MdlAddress,因此在内核对输出的写应该写在MmGetSystemAddressForMdlSafe(pIrp->MdlAddress)中,

    6其他方式IOCTL,在DeviceIoControl函数第二个参数的时候,使用CTL_CODE来产生该常数,其中Method字段设置为MEHTOD_NEITHER,输入缓冲区为stack->Parameters.DeviceIoControl.Tyep3InputBuffer;输出缓冲区为pIrp->Userbuffer

    作者:IBinary


    坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。

    详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
  • 相关阅读:
    Gremlin基本使用
    SpringData JdbcTemplate Jdbc使用简介
    DOS命令行使用pscp实现远程文件和文件夹传输(转)
    vscode:让文件支持右键vscode打开
    vue-webpack项目本地开发环境设置代理解决跨域问题
    VueJS中学习使用Vuex详解
    Object.create()和new 创建对象的区别
    vue组件和插件的区别
    创建vue组件与自定义一个vue组件时的区别
    [Vue] : 自定义指令
  • 原文地址:https://www.cnblogs.com/iBinary/p/15622566.html
Copyright © 2020-2023  润新知