⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl键盘驱动 2.htm

📁 JIURL键盘驱动
💻 HTM
📖 第 1 页 / 共 3 页
字号:
      而且通常我们传给 CreateFile,ReadFile,WriteFile,DeviceIoControl,CloseHandle 
      的参数所找到的那个设备对象,会是它所在设备栈的 PDO(也就是它所在设备栈最底下的一个设备对象)。CreateFile, ReadFile, 
      WriteFile, DeviceIoControl, CloseHandle 
      会首先通过找到的这个设备对象,获得它所在设备栈中最顶端的那个设备对象,然后将 IRP 
      发向设备栈的最顶端的那个设备对象。所以不管我们通过参数找到的设备对象在它所在的设备栈中处于什么位置,顶端,中间,底下,不管处在什么位置,IRP 
      都会发往这个设备栈的栈顶。<BR><BR>&nbsp;&nbsp;&nbsp; 上面的内容是通过跟踪 nt!NtCreateFile 和 
      nt!NtReadFile 发现的。<BR><BR>2.5 nt!NtCreateFile简介<BR><BR>&nbsp;&nbsp;&nbsp; 
      我们简单介绍一下 nt!NtCreateFile。<BR><BR>通过一系列的调用 nt!NtCreateFile 最终会调用 
      nt!IopParseDevice。下面的 call stack 
      显示了这个调用过程。<BR><BR>...<BR>nt!IopParseDevice+0xa04<BR>nt!ObpLookupObjectName+0x4c4<BR>nt!ObOpenObjectByName+0xc5<BR>nt!IoCreateFile+0x3ec<BR>nt!NtCreateFile+0x2e<BR>nt!KiSystemService+0xc4<BR>...<BR><BR>在 
      nt!IopParseDevice 中&nbsp;<BR><BR>调用 nt!IoGetAttachedDevice 
      ,获得设备栈最顶端的设备对象。调用 IoAllocateIrp 创建 IRP。调用 nt!ObCreateObject 
      创建文件对象。初始化这个文件对象。该文件对象的 +04 struct _DEVICE_OBJECT *DeviceObject 
      赋值为通过传入参数找到的那个设备对象。调用 nt!IopfCallDriver,也就是 IoCallDriver,将 IRP 
      发给设备栈的栈顶。<BR><BR>驱动处理完这个 IRP 之后,返回 nt!IopParseDevice 
      继续执行。nt!IopParseDevice 一路返回到 nt!ObOpenObjectByName。在 nt!ObOpenObjectByName 
      中继续执行,调用 nt!ObpCreateHandle 
      在进程的句柄表中创建一个新的句柄,这个句柄对应的对象是刚才创建初始化的那个文件对象。<BR><BR>2.6 
      nt!NtReadFile简介<BR><BR>&nbsp;&nbsp;&nbsp; 我们简单介绍一下 nt!NtReadFile。传入参数中有前面 
      CreateFile 打开的句柄,通过句柄可以在进程句柄表中找到一个文件对象,在这个文件对象中保存有一个设备对象的指针。调用 
      IoGetRelatedDeviceObject 获得这个设备对象所在设备栈栈顶的设备对象。调用 IoAllocateIrp 创建 
      IRP。初始化这个 IRP ,并根据传入的参数,设置好这个 IRP。然后调用 IoCallDriver 将这个 IRP 
      发给设备对象,让驱动进行处理。发往的这个设备对象就是前面使用 IoGetRelatedDeviceObject 所得到的设备栈栈顶的设备对象。下面的 
      call stack 
      显示了这个调用过程。<BR><BR>...<BR>nt!IopfCallDriver+0x35<BR>nt!IopSynchronousServiceTail+0x60<BR>nt!NtReadFile+0x5f4<BR>nt!KiSystemService+0xc4<BR>...<BR><BR><B>3 
      键盘驱动的应用层</B><BR><BR>&nbsp;&nbsp;&nbsp; 
      哪一个应用程序在使用键盘驱动?它是如何使用键盘驱动的?这是讨论键盘驱动肯定要遇到的问题,我们现在就来简单的讨论它。<BR><BR>3.1 
      键盘驱动的使用者<BR><BR>&nbsp;&nbsp;&nbsp; 键盘驱动的使用者是线程 win32k!RawInputThread 。线程 
      win32k!RawInputThread 的进程是 csrss.exe。<BR><BR>&nbsp;&nbsp;&nbsp; 我最早是通过 
      WinDbg 的 !irpfind 
      命令看到了这一点。后来看键盘驱动时,观察kbdclass!KeyboardClassRead,kbdclass!KeyboardClassCreate 
      的 call stack 也看到了这一点。<BR><BR>&nbsp;&nbsp;&nbsp; 
      kbdclass!KeyboardClassCreate 是,键盘设备栈最顶端的设备对象的驱动中处理 IRP_MJ_CREATE 
      的函数。所以当有人使用 CreateFile 来打开键盘设备栈上的某个设备对象的句柄的时候,CreateFile 最终会发一个 
      IRP_MJ_CREATE 的 IRP 给键盘设备栈最顶端的设备对象,这将导致 kbdclass!KeyboardClassCreate 
      被调用。于是我们在这个函数上下断点,看看是谁引起了这个函数的调用。看看是谁要得到键盘的句柄。<BR><BR>&nbsp;&nbsp;&nbsp; 
      在系统初始化的末期,在 kbdclass!KeyboardClassCreate 
      上发生了打断,进入调试器。首先我们看看这时的当前线程是谁。<BR><BR>kd&gt; !thread<BR>THREAD fe42e5e0 Cid 
      a0.bc Teb: 00000000 Win32Thread: e194a9e8 RUNNING<BR>IRP 
      List:<BR>fe43e9a8: (0006,0148) Flags: 00000884 Mdl: 00000000<BR>Not 
      impersonating<BR>Owning Process fe43b760<BR>Wait Start TickCount 5168 
      Elapsed Ticks: 0<BR>Context Switch Count 9&nbsp;<BR>UserTime 
      0:00:00.0000<BR>KernelTime 0:00:00.0250<BR>Start Address 
      win32k!RawInputThread (0xa000e7cd)<BR>Stack Init f90f0000 Current f90ef864 
      Base f90f0000 Limit f90ed000 Call 0<BR>Priority 19 BasePriority 13 
      PriorityDecrement 0 DecrementCount 0<BR><BR>ChildEBP RetAddr Args to 
      Child<BR>f90ef608 8041f54b fe4f5df0 fe43e9a8 fe43e9b8 
      kbdclass!KeyboardClassCreate<BR>f90ef61c 804a3e54 804a392a fe4dd718 
      f90ef90c nt!IopfCallDriver+0x35<BR>f90ef7a4 8044e27e fe4dd730 00000000 
      f90ef850 nt!IopParseDevice+0xa04<BR>f90ef810 804957ae 00000000 f90ef900 
      00000000 nt!ObpLookupObjectName+0x4c4<BR>f90ef920 804a78b8 00000000 
      00000000 e18f5900 nt!ObOpenObjectByName+0xc5<BR>f90ef9f4 804a0c5b e197101c 
      00100001 f90efb14 nt!IoCreateFile+0x3ec<BR>f90efa34 80461691 e197101c 
      00100001 f90efb14 nt!NtCreateFile+0x2e<BR>f90efa34 804009d1 e197101c 
      00100001 f90efb14 nt!KiSystemService+0xc4<BR>f90efad8 a000e304 e197101c 
      00100001 f90efb14 nt!ZwCreateFile+0xb<BR>f90efb2c a000e192 e1971008 
      80400b46 00000001 win32k!OpenDevice+0x8e<BR>f90efb58 a000eb74 00000001 
      00000000 00000000 win32k!ProcessDeviceChanges+0x92<BR>f90efda8 804524f6 
      00000003 00000000 00000000 win32k!RawInputThread+0x463<BR>f90efddc 
      80465b62 a000e7cd f8d5f7d0 00000000 
      nt!PspSystemThreadStartup+0x69<BR>00000000 f000ff53 f000e2c3 f000ff53 
      f000ff53 nt!KiThreadStartup+0x16<BR>f000ff53 00000000 00000000 00000000 
      00000000 +0xf000ff53<BR><BR>看到 Start Address 为 win32k!RawInputThread。说明线程 
      win32k!RawInputThread 在通过 CreateFile 来获得键盘的句柄。<BR><BR>看到 Cid 为 a0.bc 
      。说明线程的进程为 a0。<BR><BR>我们看看 a0 进程是谁。<BR><BR>kd&gt; !process a0 
      0<BR>Searching for Process with Cid == a0<BR>PROCESS fe43b760 SessionId: 0 
      Cid: 00a0 Peb: 7ffdf000 ParentCid: 0090<BR>DirBase: 03642000 ObjectTable: 
      fe43b6c8 TableSize: 53.<BR>Image: csrss.exe<BR><BR>看到 a0 进程的 Image 为 
      csrss.exe。<BR><BR>&nbsp;&nbsp;&nbsp; kbdclass!KeyboardClassRead 
      是,键盘设备栈最顶端的设备对象的驱动中处理 IRP_MJ_READ 的函数。所以当有人使用 ReadFile 来要求读入数据的时候,ReadFile 
      最终会发一个 IRP_MJ_Read 的 IRP 给键盘设备栈最顶端的设备对象,这将导致 kbdclass!KeyboardClassRead 
      被调用。于是我们在这个函数上下断点,看看是谁引起了这个函数的调用。看看是谁要求从键盘读入数据。<BR><BR>&nbsp;&nbsp;&nbsp; 
      在 kbdclass!KeyboardClassCreate 上发生打断后,进入调试器。我们看看这时的当前线程是谁。<BR><BR>kd&gt; 
      !thread<BR>THREAD fe42e5e0 Cid a0.bc Teb: 00000000 Win32Thread: e194a9e8 
      RUNNING<BR>...<BR>Start Address win32k!RawInputThread 
      (0xa000e7cd)<BR>...<BR><BR>看到 Start Address 为 win32k!RawInputThread。说明线程 
      win32k!RawInputThread 在通过 ReadFile 来要求从键盘读取数据。<BR><BR>看到 Cid 为 a0.bc 
      。说明线程的进程还是 a0。<BR><BR>这些足以说明键盘驱动的使用者是线程 win32k!RawInputThread 。线程 
      win32k!RawInputThread 的进程是 csrss.exe。<BR><BR>3.2 win32k!RawInputThread 
      获得句柄简介<BR><BR>&nbsp;&nbsp;&nbsp; win32k!RawInputThread 会调用 nt!ZwCreateFile 
      ,获得一个可以找到键盘设备栈的 PDO 的句柄,供以后的 ZwReadFile,ZwDeviceIoControlFile 
      等使用。<BR><BR>&nbsp;&nbsp;&nbsp; 首先我们看看断在 kbdclass!KeyboardClassCreate 时的 
      call stack ,看看引起 kbdclass!KeyboardClassCreate 的整个调用过程。<BR><BR># ChildEBP 
      RetAddr Args to Child&nbsp;<BR>00 f90ef608 8041f54b fe4f5df0 fe43e9a8 
      fe43e9b8 kbdclass!KeyboardClassCreate(struct _DEVICE_OBJECT * DeviceObject 
      = 0xfe4f5df0, struct _IRP * Irp = 0xfe43e9a8) (CONV: stdcall)<BR>01 
      f90ef61c 804a3e54 804a392a fe4dd718 f90ef90c nt!IopfCallDriver+0x35 (FPO: 
      [0,0,2])<BR>02 f90ef7a4 8044e27e fe4dd730 00000000 f90ef850 
      nt!IopParseDevice+0xa04 (FPO: [Non-Fpo])<BR>03 f90ef810 804957ae 00000000 
      f90ef900 00000000 nt!ObpLookupObjectName+0x4c4 (FPO: [Non-Fpo])<BR>04 
      f90ef920 804a78b8 00000000 00000000 e18f5900 nt!ObOpenObjectByName+0xc5 
      (FPO: [Non-Fpo])<BR>05 f90ef9f4 804a0c5b e197101c 00100001 f90efb14 
      nt!IoCreateFile+0x3ec (FPO: [Non-Fpo])<BR>06 f90efa34 80461691 e197101c 
      00100001 f90efb14 nt!NtCreateFile+0x2e (FPO: [Non-Fpo])<BR>07 f90efa34 
      804009d1 e197101c 00100001 f90efb14 nt!KiSystemService+0xc4 (FPO: [0,0] 
      TrapFrame @ f90efa68)<BR>08 f90efad8 a000e304 e197101c 00100001 f90efb14 
      nt!ZwCreateFile+0xb (FPO: [11,0,0])<BR>09 f90efb2c a000e192 e1971008 
      80400b46 00000001 win32k!OpenDevice+0x8e (FPO: [Non-Fpo])<BR>0a f90efb58 
      a000eb74 00000001 00000000 00000000 win32k!ProcessDeviceChanges+0x92 (FPO: 
      [EBP 0xf90efda8] [1,5,4])<BR>0b f90efda8 804524f6 00000003 00000000 
      00000000 win32k!RawInputThread+0x463 (FPO: [Non-Fpo])<BR>0c f90efddc 
      80465b62 a000e7cd f8d5f7d0 00000000 nt!PspSystemThreadStartup+0x69 (FPO: 
      [Non-Fpo])<BR>0d 00000000 f000ff53 f000e2c3 f000ff53 f000ff53 
      nt!KiThreadStartup+0x16<BR>WARNING: Frame IP not in any known module. 
      Following frames may be wrong.<BR>0e f000ff53 00000000 00000000 00000000 
      00000000 0xf000ff53<BR><BR><BR>&nbsp;&nbsp;&nbsp; 我简单的跟了一下 
      win32k!RawInputThread 
      获得句柄的过程,下面我对这个过程做一个简单的介绍。<BR><BR>win32k!RawInputThread 通过 
      GUID_CLASS_KEYBOARD 获得键盘设备栈中的 PDO (简单的说 PDO 是设备栈最下面的那个设备对象)的 
      SymbolicLink(符号链接)名。执行到 win32k!OpenDevice,它的一个参数可以找到 键盘设备栈的 PDO 
      的符号链接(SymbolicLink)名。win32k!OpenDevice 有一个 OBJECT_ATTRIBUTES 
      结构的局部变量,它自己初始化这个局部变量,用传入参数中的键盘设备栈的 PDO 的符号链接(SymbolicLink)名 赋值这个 
      OBJECT_ATTRIBUTES +0x8 处的 PUNICODE_STRING ObjectName 。然后调用 
      ZwCreateFile。ZwCreateFile 完成得到句柄的工作,最后通过传入的参数返回得到的句柄。win32k!RawInputThread 
      把得到的句柄保存起来,供后面的 ReadFile, DeviceIoControl等使用。<BR><BR>ZwCreateFile 
      通过系统服务,调用内核中的 NtCreateFile。NtCreateFile 执行到 nt!IopParseDevice 中 ,<BR>调用 
      nt!IoGetAttachedDevice ,通过 PDO 的设备对象获得键盘设备栈最顶端的设备对象。用得到的这个设备对象的 +30 char 
      StackSize 作为参数来 IoAllocateIrp,创建 IRP。调用 nt!ObCreateObject 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -