zoukankan      html  css  js  c++  java
  • WriteFile

    从R3 ,到磁盘

    1:kernel32  WriteFile

    1)

    挺惊讶的,符号好使了,

    前面大概4条判断,根据句柄判断要写到什么地方,一共有4个地方可能要去,

    stdin   stdout   stderr   还有最后一个  控制台

    2)然后就是一个异步的判断

    如果是异步,那么整理信息,然后调用NtWriteFile,根据返回值判断情况成功了,返回1

    否则返回0

    这里不考虑,主要考虑同步的情况

    3)同步的位置

    倒是不拖拉,直接就走Nt函数准备进内核了

    2:

    1)内核里面,一个深情的问候,先获取有用的信息,ETHREAD,和FILE_OBJECT,还有设备对象

    2)打了招呼,开始干活

    Zw函数的标准玩法,先判断处于用户模式还是内核模式,其实我就很搞不懂,

    驱动里面,Zw函数和Nt函数就那么点区别,一个判断内核模式,一个不判断内核模式,

    判断了之后,简单地说,就是修改模式之后,Zw调用Nt,然后再走原有流程,

    这里直接判断了,应该是优化了吧。

    3)做完环境判断之后,

    开始准备可能用到的结构了,

    4)准备结构之后,还有一个步骤,

      1.就是判断是否为同步操作,

      

      如果是同步操作的话,那么后面直接走

      2.并行的步骤还有个判断异步的

      

      这里顺带判断了,如果传入字符个数是0个,并且又是非管道或者邮槽操作,

      (这里要说一下,其实,管道等的操作,写入地址是NULL,写入字符个数0个,实际上是个常规操作,不算是违规操作)

    5)这里先看同步操作吧

    1。首先,设置当前状态,给文件系统,告诉它我现在在忙,我有同步的事情正在做

    如果以前有人设置了,那么v17 = 0,否则减个引用计数,然后v17 = 1。

    2。如果之前有人设置过了,那么这里自己获取一个文件对象锁

    这里有个细节,其实挺奇怪的,这里加了锁,但是后面没有地方Release这个锁,所以是不是可以考虑,这个锁根本就不会加,

    也就是说不会走到这里,也就是说当前文件不会有其他人在用,但是这不科学,这个理论说不通。

    其实后面有地方SetEvnet了。是不是就为了这个锁而存在的。

    3。

    如果要写入的字符个数为0个,并且v35,没有修正,或者值有异常,

    那么就把它修正为当前文件的偏移位置。

    4。又是一个分水岭,这里,如果这个成员有值,则继续走内部流程,否则就走到外面去了,外面就是和异步流程相同的其它流程了

    其实,这个成员是干嘛的,我就没搞清楚

    An opaque member, set only by file systems, that points to handle-specific information and that is used for Cache Manager interaction.

    MSDN上,只有这么一段话,说一个不透明的成员,只有文件系统可以操作它,类似于句柄,是和CM交互用的。

    我是不是可以猜测成,这个东西的存在,就是说CM中,我要改写的这个文件已经进入缓存了,我直接修改缓存就可以了,所以才出现这个判断。

    没有缓存的话,那就自然不是简单操作就能完成任务的。

    5。这个判断,真的搞得我好郁闷,

    首先判断 v35 的高位 < 0 ,就是说,它必须是 0xFFFF,

    然后并且,v35 的值不为 -1 ,就是说,v35的值必须是 0xFFFF0000 ~ 0xFFFFFFFE

    这是要判断什么呢,根据前面的经验,实际上这里出现这种值得可能性几乎没有,因为在前面已经通过各种设置,

    设置了v35的值,不会变成这个样子,除非是文件位置的有意为之。

    v35实际上是文件指针当前偏移,

    6。终于到了同步最后一个位置了

    这里的操作比较好理解,首先

     1 typedef
     2 BOOLEAN
     3 FAST_IO_WRITE (
     4     __in struct _FILE_OBJECT *FileObject,
     5     __in PLARGE_INTEGER FileOffset,
     6     __in ULONG Length,
     7     __in BOOLEAN Wait,
     8     __in ULONG LockKey,
     9     __in PVOID Buffer,
    10     __out PIO_STATUS_BLOCK IoStatus,
    11     __in struct _DEVICE_OBJECT *DeviceObject
    12     );
    View Code

    fastiowrite的原型是这样的,也就是说,调用的时候,函数包含了,哪个设备(文件所在设备),哪个文件(FILE_OBJECT 对应的文件),从哪写,写多少,甚至是否加锁是否等待都有了,

    返回值是 BOOLEAN,符合要求,返回成功失败,如果函数调用成功了,判断 STATUS,是否执行也成功,执行也成功的话,

    走进函数内部了。

    第一个函数 IopUpdateWriteOperationCount ,具体做什么的网上没找到,自己看,发现它内部先更新了一个全局的写操作计数器,

    然后又更新了一下ETHREAD里面的一个位置,很可能是解锁相关的

    第二个函数 IopUpdateWriteTransferCount ,看名字,以及参数的用途,大概是提交修改字符的个数,

    后续一系列的返回数据整理,然后设置Event,如果文件在忙,就给文件设置为空闲状态,如果文件在等待,那么就给它一个Event,

    最后释放了句柄,就可以返回了。

    6)异步操作部分

    1。也是先判断偏移

    不符合标准,直接就滚蛋了,这里不管

    2。这里是我最喜欢的部分,创建IRP,然后整理IRP的初始化的部分

    这部分操作结束之后

    3。代码开始逐渐明朗了,把两块互斥的指针初始化

    如果是 DO_BUFFERED_IO 的话,那么就是用 systembuffer

    如果设置成功的话,标记IRP标志为48,也就是0x30,翻译成中文就是

    这里使用的是 Buffered IO,用完之后,管理器需要把Buffer 释放

    如果设置失败,那么就修改flags值为16,也就是0x10,和上面区别就是,你别删了,其实根本就用不了

    4。代码第二块

    也就是非 DO_BUFFERED_IO 的情况下,先判断是否为 MDL 方式,如果是的话,给IRP创建一个MDL,然后LOCK住,

    如果不是MDL的情况,那么直接挂UserBuffer 为应用层传来的空间,这种方法非常危险,

    标识位为0,鸡毛都没有

    5。这块,主要是告诉下面处理的地方,这里都是什么操作

    最后就是一个分发操作,开始让IRP干活去吧

    至此,整个流程基本完成了,

    实际上我们可以看出,

    大体流程并不是很多,

    大致流程就是

    应用层的 WriteFile

    然后进内核NtWriteFile

    里面判断同步异步,

    同步走磁盘设备的FastIoWrite

    调用失败,或者异步的话,就自己创建IRP来实现,

    整体流程就这么短。

    剩下的就是FastIoWrite里面,或者文件系统驱动去对照IRP写磁盘了。

    还有几处我不懂得地方,就是那个UserBuffer,为什么它在里面竟然写了东西,

    IDA实际上没有识别出那个UserBuffer,是我自己根据偏移算出来的,

    也不知道我算得是否正确

  • 相关阅读:
    ExtJS的定时任务(转)
    Web开发系列–GIS(转)
    Windows Mobile 6.0模拟器的浏览器中不能访问本机网址
    JS定时保存表单数据(UserData 行为)
    查询Sqlserver数据库死锁的一个存储过程(转)
    ExtJS4.0在IE9中出现了SCRIPT5007: 无法获取属性“flex”的值
    Microsoft Device Emulator 模拟器菜单 中文
    错误:网站辅助进程已被 IIS 终止(Debug 时是不是弹出)
    集成验证时IE采用Kerberos 还是NTLM验证方式?(摘抄)
    SQLServer 2005死锁终极大法(自动杀) 转
  • 原文地址:https://www.cnblogs.com/suanguade/p/5857746.html
Copyright © 2011-2022 走看看