-
-
[原创]Windows内核学习笔记之系统调用
-
发表于: 2021-12-19 19:50 20911
-
NT内核会把操作系统的代码和数据映射到系统中所有进程的内核空间中。这样,每个进程内的应用程序代码便可以很方便地调用内核空间中的系统服务。这里的”很方便“有多层含义,一方面是内核代码和用户代码在一个地址空间中,应用程序调用系统服务时不用切换地址空间,另一方面是整个系统中内核空间的地址是统一的,编写内核空间的代码时会简单很多。但是,如此设计带来了一个很大的问题,那就是用户空间中的程序指针可以指向内核空间中的数据和代码,因此必须防止用户代码破坏内核空间中的操作系统。做法就是利用权限控制来实现对内核空间的保护。
Windows定义了两种访问模式,分别是用户模式和内核模式。应用程序运行在用户模式下,操作系统运行在内核模式下。内核模式对应于处理器的最高级别权限(ring 0),在内核模式下执行的代码可以访问所有系统资源并具有使用所有特权指令的权利。相对而言,用户模式对应于较低的处理器优先级(ring 3),在用户模式下执行的代码只可以访问系统运行其访问的内存空间且没有使用特权指令的权力。
因为内核模式下的数据和代码具有更高的优先级,所以用户模式下的代码不可以直接访问内核空间中的数据,也不可以直接调用内核空间中的任何函数或例程。任何这样的尝试都会导致保护性错误。也就是说,即使用户空间中的代码指针正确指向了要访问的数据或代码,但一旦访问发生,那么处理器就会检测到该访问是违法的,会停止该访问并产生保护性异常(#GP)。
虽然不能直接访问,但是应用程序可以通过调用系统服务来间接访问内核空间中的数据或间接调用,执行内核空间中的代码。当调用系统服务的时候,主调线程会从用户模式切换到内核模式,调用结束后在返回用户模式,也就是所谓的模式切换。在线程的KTHEREAD结构中,定义了UserTime和KernelTime两个字段,分别用来记录这个线程在用户模式和内核模式的运行事件(以时钟中断计数为单位)。
对于应用程序的运行即进程而言,操作系统内核的作用体现在一组可以供其调用的函数,称为”系统调用“,正是这些系统调用加上一些辅助的手段构成了应用软件的运行环境,即日常所说的”运行平台“。从应用软件的角度看,这些系统调用都是操作系统为其提供的服务,所以也称为”系统服务“。
系统调用所提供的服务是在内核中,一般是在”系统空间“中实现的,而应用软件则都在用户空间运行,二者之间有着空间的间隔。所以,在应用软件和内核之间必定存在一个明确定义的”系统调用界面”。
Windows系统服务界面是隐藏不公开的,公开的是由用户空间一些高层库函数构成的界面,称为“Win32应用程序界面”,即Win32 API。用户模式下的代码通过调用这些Win32 API来调用系统服务完成需要的操作。
因运行状态和执行的程序所在的内存区间的不同,CPU既可以运行于非特权的“用户态”,或者说运行于“用户空间”,也可也运行于特权的“系统态”,或者说运行于“系统空间”。CPU要从系统空间转入用户空间是容易的,因为运行于系统态的CPU可以通过一些特权指令来改变其运行状态。但是,反过来要从用户空间转入系统空间就不容易了,因为运行于用户态的CPU是不能执行特权指令的。所以,一般而言只有三种手段或原因可以使运行于用户空间的CPU转入系统空间:
中断:在开启中断机制的情况下,只要有外部设备的中断请求到来,CPU就会自动转入系统空间,并从(系统空间中)某个预定的地址开始执行指令,从而可以在系统空间对外部设备的中断请求作出反应,或者说提供服务。中断只发生在两条指令之间,因而不会使正在执行的指令半途而废。对于CPU而言,因中断而进入系统空间是被动的,并且CPU是完全无法预知何时将发生中断,所以中断的发生又是“异步”的。
异常:不管是用户空间或系统空间,执行指令时的失败都会引起一次”异常“,CPU也会因此而转入系统空间(如果原来不再系统空间),并从某个预定的地址开始执行指令,从而可以在系统空间对发生的失败做出反应。异常在形式上与中断十分相似,只是异常发生在执行一条指令的过程中,而不是两条指令之间,所以当前指令的执行已经半途而废。同样,对于CPU而言,因异常而进入系统空间也是被动的,无法预知的。但是,这只是一般而言,实践中也可也通过故意引起异常而进入内核。例如,在用户空间故意访问系统某个特定地址,就会因访问权限的问题而引起主动的异常,而内核空间中的异常处理程序则可以根据所访问的地址判定其目的,从而做出预定的反应。
自陷:为了让CPU能够主动地进入系统空间,绝大多数CPU都设有专门地”自陷“指令,系统调用通常就是靠自陷指令实现地。一执行这样的指令,CPU就转入系统空间并从某个预定地地址开始执行指令,就像掉进了陷阱一样。自陷指令在形式上与中断相似,就像是一次由CPU主动发出的中断请求。对于CPU而言,这是成功执行了一条指令的结果,所以是主动的,尽管该指令其实是由程序员安排的。对于程序而言,则一条自陷指令的作用相当于一次子程序调用,只是这个子程序存在于系统空间中。
传统的Windows系统调用正是通过自陷指令”int 0x2E"进入内核实现系统调用的,但是,从Pentium II开始,Intel又在x86系列的CPU中增加了一对指令sysenter和sysexit,用来实现一种称为“快速系统调用”的机制,并为此增加了三个寄存器。
应用程序为了调用系统服务,就需要进行模式切换,将处理器从用户模式切换到内核模式下。模式切换的工作并不需要由应用程序自己来完成,Windows提供了一个系统模块ntdll.dll,已经实现了所有系统服务的模式切换工作,在用户模式下只需要通过调用Win32 API就可以由ntdll.dll实现相应的模式切换工作,切换到内核模式以后就可以使用系统提供的系统服务。模式切换依赖于硬件系统结构,接下来以ReadProcessMemory为例,来具体看看切换的过程。
ReadProcessMemory是kernel32.dll中的一个导出函数,根据反汇编的结果可以看到,该函数的主要行为就是调用NtReadVirtualMemory函数来完成功能
NtReadVirtualMemory的功能很简单,将服务号0x0BA赋给eax,该服务号决定了进入内核模式以后使用的系统服务,随后将0x7FFE0300赋给edx,在调用edx保存的地址中保存的函数地址
要理解edx保存的内容,首先要知道,在Windows的虚拟地址空间管理中,系统空间有一个特殊的页面会映射到每个进程地址空间中。也就是说,该页面是系统地址空间和进程地址空间共享的。
它在系统空间的地址由以下宏定义决定
在进程空间的地址则是由以下的宏定义决定
该共享页面是在内存管理器初始化时分配的,记录了当前系统的一些关键状态信息,数据结构KUSER_SHARED_DATA定义了该页面内部的结构,该结构定义如下:
其中偏移0x300的SystemCall指示了从用户模式切换到内核模式的函数地址,而偏移0x304的SystemCallReturn则指示了从内核模式返回至用户模式的函数地址。因此,在ntdll.dll中的NtReadVirtualMemory的edx被赋予了SystemCall的值。
在初始化阶段,系统会根据当前处理器的特征信息来决定SystemCall保存的函数。当通过eax=1来执行cpuid指令的时候,处理器的特征信息会被存放到ecx和edx寄存器中,其中edx包含了一个SEP位(第11位),当该位为1说明当前处理器支持快速系统调用,此时SystemCall中保存的就会是通过快速系统调用机制切换到内核模式的KiFastSystemCall的函数地址,否则保存的就是通过自陷指令进入系统内核的KiIntSystemCall。
根据KiIntSystemCall反汇编的结果可以知道,函数首先会将传入的参数的地址赋给edx,随后使用"int 0x2E"指令通过中断门来切换到内核模式
Windows将0x2E号向量专门用于系统调用,在启动早期初始化中断描述符表(IDT)时便注册好了服务例程。因此当ntdll.dll中的函数发出int 0x2E指令以后,CPU便会通过IDT找到相应的函数进行执行。由于该函数是位于内核空间的,所以CPU在把执行权交给该函数之前,会做好从用户模式切换到内核模式的各种工作,包括:
权限检测,即检测源位置和目标位置所在的代码段权限,核实是否可以转移
准备内核模式使用的栈,为了保证内核安全,所有线程在内核态执行的时候都必须使用位于内核空间的内核栈,内核栈的大小一般为8KB或12KB
下图是int 0x2E指令的跳转流程,处理器在IDT中查找0x2E的表项,IDTEntry包含一个段选择符和中断例程的段内偏移,所以,处理器还需要在GDT中再查找一次表项,得到段选择符指定的段的虚拟基地址。段基地址加上中断例程偏移,最终得到中断例程的虚拟地址。
在Windows中,IDT的0x2E表项的段选择符是0x0008,中断例程偏移为_KiSystemService例程的地址。这里段选择符0x0008指向第一个段,段内基址为0x0,正是内核中使用的cs段。因此,最终的中断服务例程为内核中的_KiSystemService函数。
Intel x86处理器在不同模式下使用不同的栈,用户模式代码使用用户栈,内核模式代码使用内核栈,因此,当一个线程通过"int 0x2E"指令从用户模式切换到内核模式时,必然会伴随有栈的切换。下图是栈切换的示意图,处理器在将控制器交给目标例程以前,首先将原来的ss, esp, eflags, cs和eip寄存器的值放到内核栈中,并且让新的esp指向内核栈顶位置。
处理器在用户模式下执行,如何知道内核栈的位置,即内核栈的ss和esp?答案在于处理器的当前任务环境。每个处理器都总数在一个任务环境中运行,处理器的任务寄存器(TR寄存器)指向当前任务环境的TSS,其中包含每一特权级使用的栈,其中Ring0的esp位于TSS+4的位置。Windows系统在每个处理器初始化时,会在GDT中为它构造一个TSS段,然后利用ltr指令,设置处理器的任务环境的。另外,Windows每次切换线程时,总会设置好TSS中Ring0的esp,使它指向当前线程的内核栈。
当内核模式下的中断例程完成中断处理以后,它通过iret/iretd指令返回到用户模式代码。iret/iretd指令从内核中弹出eip, cs, eflags以及esp和ss,然后将控制权交给eip所指的用户模式代码。
由于通过int 0x2E指令进入内核带来的系统开销比较大。所以,从Pentium II处理器开始,Intel引入一对新的指令sysenter/sysexit,实现快速的模式切换。可以看到KiFastSystemCall函数就是通过sysenter指令切换到内核模式
在模式切换过程中,Sysenter要做的事情与"int 0x2E"指令类似,但是,它会尽可能地减少内存访问和权限检查的开销,其做法是,尽可能避免内存访问,而通过处理器的内部寄存器来指定必要的信息。Sysenter使用三个MSR寄存器来指定目标地址和栈信息,如下表所示。操作系统可以在内核模式下通过rdmsr/wrmsr指令来设置这三个寄存器
Sysenter指令的内部逻辑是:将IA32_SYSENTER_CS和IA32_SYSENTER_EIP分别装载到cs和eip寄存器中;将IA32_SYSENTER_CS+8和IA32_SYSENTER_ESP分别装载到ss和esp寄存器中;切换到特权级0;清除eflags中的VM标志(虚拟8086模式);执行目标例程。注意,sysenter指令对于跳转目标的代码段和栈段有如下的要求:
代码段和栈段在GDT中必须是相邻的,IA32_SYSENTER_CS指向代码段的GDT表项,紧随其后的表项应该是栈段描述符
代码段描述符指定的是一个基地址是0,段范围可达4GB的特权级0的段,具有执行和读访问权限
栈描述符指定的也是一个基地址为0,范围可达4GB的特权级0的段,但具有读写访问和向上扩展的权限
Sysexit的内部逻辑是:将IA32_SYSENTER_CS+16装载到cs寄存器;将edx寄存器中的指针装载到eip寄存器中;将IA32_SYSENTER_CS+24装载到ss寄存器中;将ecx寄存器中的指针装载到esp寄存器中;切换特权级3;执行eip寄存器中指定的用户模式代码。类似地,sysexit也要求IA32_SYSENTER_CS+16和IA32_SYSENTER_CS+24指定地用户模式代码段和栈段,即GDT中紧跟Sysenter用到地两个段描述符之后地两个GDT表项,符合在特权级3下执行或读写方面的要求。
因此MSR寄存器IA32_SYSENTER_CS实际上指定了GDT中的4个段描述符符合上述sysenter/sysexit要求。而且,用户模式代码在调用sysenter指令以前,必须将要返回的指令地址和栈指针值保存到edx和ecx寄存器中,否则,内核模式代码将无法设置正确的值,以使sysexit还能回到用户模式代码的原来位置。另外,sysenter指令并不负责将用户栈中的参数传递到内核栈中,参数的传递由用户模式代码和内核模式代码来完成,sysenter仅提供跨模式跳转和栈切换的能力。下图显示了sysenter/sysexit指令的跳转示意图,sysenter和sysexit指令旁边的粗箭头表示该指令的跳转依赖于这些寄存器。
从sysexit回到用户模式代码的地址和栈指针,即sysexit指令执行前的edx和ecx寄存器值,需要用户模式diamagnetic和内核例程来约定。也就是说,处理器在执行sysenter指令时并没有将线程信息保存在这两个寄存器中。所以,用户模式代码由责任将返回用户模式后的eip和esp通过某种方式传递到内核例程中,以便内核例程在发送sysexit指令前设置好edx和ecx。
实际上,sysenter/sysexit指令要求代码段和栈段必须执行满足相应的特权级保护要求的0~4GB地址空间,即段的基地址是0,大小可达4GB。Sysenter指令在执行时,cs寄存器被赋予IA32_SYSENTER_CS寄存器的值,但是,cs寄存器内部的段描述符并非拷贝自GDT中的表项,而是硬编码的固定值,ss寄存器也使用同样的方法。类似地,sysexit指令在执行时,cs和ss段寄存器虽然被赋予IA32_SYSENTER_CS+16或IA32_SYSENTER_CS+24的值,但是,内部的段描述符也是硬编码的固定值。所以GDT的4个表项并未真正被使用。
因此,不难理解,sysenter和sysexit只使用固定的值或寄存器的值来完成跳转,从而达到快速切换代码段和栈段的目的。而且,使用固定内容的段描述符,省去了特权级检查的步骤,可进一步提升这两条指令的效率。对于频繁进行模式切换的应用线程来说,使用sysenter指令比"int 0x2E"有显著的性能优势。
上面说到,通过"int 0x2E"指令进入内核的时候,KiSystemService函数获得控制权,而如果是通过"Sysenter"指令进入内核,则KiFastCallEntry函数获得控制权。而这两个函数在内核获得控制权以后,首先要做的就是先建立一个陷阱帧(trap frame),陷阱帧对应的结构体是_KTRAP_FRAME,该结构体定义如下:
可以看到,该结构体保存了是各种寄存器的信息,而要理解内核入口函数是如何填充这个结构体,首先要理解KPCR。
每一个CPU在内核都有对应的一个结构体来描述CPU的信息,该结构体就是KPCR结构体。该结构体中保存了CPU需要使用的一些数据,比如GDT,IDT和线程相关的一些数据,结构体定义如下:
其中NtTib结构体的定义如下:
_KPRCB结构体的定义如下:
0x30段选择子对应的段描述符所指的基地址就是KPCR的地址
接下来看看KiSystemService是如何填充陷阱帧,首先由于是KiSystemService获得控制权,所以是通过"int 0x2E"指令切换进内核。那么此时栈中已经保存了ss, esp, eflags, cs, eip。所以这个时候是从Errcode开始填充
将0x30赋给fs寄存器,让fs寄存器指向KPCR后继续填充
填充到PreviousMode的时候,此时的esp所指的是陷阱帧偏移0x48的地址,接下来将esp减去0x48,就是将esp移动到陷阱帧的头部,此时esp + 0x68 + arg_0就会是陷阱帧偏移0x6C的位置,保存的是切换到内核模式前的cs段寄存器的内容,将其除去与1进行与操作,如果为1则说明是从用户模式切换进内核模式,将其保存到线程的先前模式中
将esp赋给ebp,这样ebp也指向陷阱帧的顶部,随后将线程的TrapFrame填充到正在填充的TrapFram的到edx中,在将当前正在填充的TrapFrame赋值给线程的TrapFrame
继续对陷阱帧进行填充
判断当前线程是否处于调试模式
如果DebugActive不为-1,则处于调试模式,会跳转到Dr_kss_a执行,如果不处于调试模式,则会直接跳转到loc_406932地址继续执行
当KiFastCallEntry获得控制权的时候,说明是通过sysenter指令进入内核,此时并为将esp指针指向内核栈中,且也没有像KiSystemService一样进入内核的时候就已经填充了5个字段。所以,这个时候就首先需要获得内核栈的esp,然后开始从SS寄存器开始填充
由于快速系统调用的方式进入内核的时候,直接用esp为edx赋值,所以edx要加上8,这样才能让esp指向参数的地址
从cs开始继续填充
填充完了以后就会继续向下执行loc_406932的代码,KiSystemService填充完陷阱帧以后也是跳转到这里开始执行。
填充完陷阱帧以后,接下来就需要调用内核的服务函数。在ntdll.dll的存根函数中,在进入内核之前会为eax指定一个服务号,内核就是根据这个服务号来知道要调用内核中哪个系统服务例程,以及从用户栈拷贝多少数据到内核栈中,这一过程被称为系统服务分发。
Windows实现系统服务分发的关键是一个称为SDT(服务描述符表)的表。Windows支持多个SDT,系统服务存根函数指定的系统服务号,即eax寄存器的值,包含了表的索引和表内的服务索引。eax的低12位(即0~11位)指定了表内的系统服务索引,12~13位指定了表的索引。内核全局变量KeServiceDescriptorTable是一个数组,每个元素指向一个SDT,所以,系统服务分发代码根据系统服务号,首先定位到KeServiceDescriptorTable的元素,然后找到特定的系统服务项。
以下是与系统服务表有关的定义:
以上可以看出,Windows系统支持2个SDT。KeServiceDescriptorTableShadow是一个内部数组,它的第二个元素,即KeServiceDescriptorTableShadow[1]专门用于Windows子系统,其他表项与KeServiceDescriptorTable完全相同。KeServiceDescriptorTable[1]元素不再使用。因此,Windows内核系统服务号范围是0x0000000~0x00000FFF;而Windows子系统服务号的范围是0x00001000~0x00001FFF。
KSERVICE_TABLE_DESCRIPTOR数组结构描述的每一个SDT中,Base域指向一个由系统服务例程构成的32位地址数组;Count域是一个指针成员,指向一个计数器数组,数组中的每个元素记录了相应的系统服务被调用的次数,次域仅用于内核的调试版本;Limit域记录了该SDT中系统服务的数量;Number域也是一个指针,指向一个字节数组,数组中的每个元素对应于一个系统服务所需要传递的参数区的长度,该长度是以字节为单位。
接下来从loc_406932继续分析,看看内核是如何完成系统调用的。
将服务号赋给edi以后,edi右移了8位,此时保留了系统服务号的8~13位,又将edi与0x30异或,那就会保留服务号的12~13位,此时edi会等于0x00或0x10,接下来就从线程结构体中将KeServiceDescriptorTable取出与edi进行相加就可以得到想要使用的系统服务表基址
将系统服务号保存到ebx以后,保留系统服务号的低12位,与系统服务表中的Limit域进行比较,如果超过Limit域的内容则说明越界,跳转到想要代码执行
判断ecx是否等于0x10,ecx的值在上面计算edi的最后进行赋值,所以它会等于0x00或0x10,如果等于0x10则说明此时要查询的是子系统SDT表,否则就是系统使用的基本SDT
通过检查以后,就要准备调用相应的函数,但是首先需要将参数从用户栈赋值到内核栈中,此时edx保存的就是用户栈参数的地址,将它赋给esi已备后面的赋值。从Number域和Base域中分别将要调用的函数和参数长度取出赋给ebx和ecx。但是要注意此时参数的长度是以字节为单位,而程序在进行参数传递的时候会将4个字节当作一个参数,所以ecx需要进行右移操作算出参数个数,有了参数个数就可以移动相应大小的栈顶用来保存参数
在对陷阱帧中的保存的eflags和cs进行判断以后
就会跳转到KiSystemServiceCopyArguments函数执行,在这个函数中就会完成参数的赋值,注意此时的esi指向的是用户栈参数地址,而edi指向的是用来保存参数的内核栈的地址,ebx保存的就是要调用系统服务函数的地址
当系统服务函数调用返回以后,接下来就需要返回到用户层继续执行,所以接下来就需要恢复相应的寄存器来返回到用户层。
将esp恢复到陷阱帧的顶部,在将保存在edx中的线程原来的TrapFrame取出赋值到当前线程的TrapFrame中
程序继续向下执行会执行到KiServiceExit,该函数从TrapFrame中取出保存的Eflagls和cs判断是否是虚拟8086模式,是否是从用户模式发起的调用
如果是8086模式或者是从用户层发起的请求就会执行以下代码,如果不是上述情况就会跳转到loc_406A23执行,而以下代码是与APC相关,主要内容就是先通过KfRaiseIrql将CPU的运行级别提升到APC_LEVEL,然后就调用KiDeleverApc来执行用户APC,随后在通过KfLowerIrql将运行级别降低到PASSIVE_LEVEL。
如果不用执行APC代码,就会接着执行以下的代码,将陷阱帧中的保存的数据复制到线程中,这样就恢复了切换进内核模式前的一部分数据,然后判断是否处于调试模式
从陷阱帧中恢复几个寄存器的值
此时esp指向陷阱帧中的ErrorCode,然后继续判断保存的cs寄存器的值,如果cs寄存器的值小于0x80就会判断是否是用户模式发起的调用还是内核模式发起的调用,如果是从内核模式发起的调用,则会把返回地址赋值到edx中,然后通过jmp指令跳转
如果是用户模式发起的调用,则会进行跳转,而跳转的地址会根据是否支持快速调用而不同,如果不支持快速调用,跳转的地址就会是KiSystemCallExit,如果支持快速调用,系统就会将跳转地址从KiSystemCallExit修改为KiSystemCallExit2。
如果执行的是KiSystemCallExit,就会通过iret指令返回用户层
如果执行的是KiSystemCallExit2,就会将eip和esp分别赋值给edx和ecx以后调用sysexit指令来返回到用户层
《Windows内核原理与实现》
《Windows内核情景分析》(上册)
《软件调试》(第二版)卷2
.text:
7C8021D0
;
BOOL
__stdcall ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T
*
lpNumberOfBytesRead)
.text:
7C8021D0
public _ReadProcessMemory@
20
.text:
7C8021D0
_ReadProcessMemory@
20
proc near ; CODE XREF: GetProcessVersion(x)
+
2F18B
↓p
.text:
7C8021D0
; GetProcessVersion(x)
+
2F1AA
↓p ...
.text:
7C8021D0
.text:
7C8021D0
hProcess
=
dword ptr
8
.text:
7C8021D0
lpBaseAddress
=
dword ptr
0Ch
.text:
7C8021D0
lpBuffer
=
dword ptr
10h
.text:
7C8021D0
nSize
=
dword ptr
14h
.text:
7C8021D0
lpNumberOfBytesRead
=
dword ptr
18h
.text:
7C8021D0
.text:
7C8021D0
mov edi, edi
.text:
7C8021D2
push ebp
.text:
7C8021D3
mov ebp, esp
.text:
7C8021D5
lea eax, [ebp
+
nSize]
.text:
7C8021D8
push eax ; NumberOfBytesRead
.text:
7C8021D9
push [ebp
+
nSize] ; NumberOfBytesToRead
.text:
7C8021DC
push [ebp
+
lpBuffer] ;
Buffer
.text:
7C8021DF
push [ebp
+
lpBaseAddress] ; BaseAddress
.text:
7C8021E2
push [ebp
+
hProcess] ; ProcessHandle
.text:
7C8021E5
call ds:__imp__NtReadVirtualMemory@
20
; NtReadVirtualMemory(x,x,x,x,x)
.text:
7C8021EB
mov ecx, [ebp
+
lpNumberOfBytesRead]
.text:
7C8021EE
test ecx, ecx
.text:
7C8021F0
jnz short loc_7C8021FD
.text:
7C8021F2
.text:
7C8021F2
loc_7C8021F2: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
32
↓j
.text:
7C8021F2
test eax, eax
.text:
7C8021F4
jl short loc_7C802204
.text:
7C8021F6
xor eax, eax
.text:
7C8021F8
inc eax
.text:
7C8021F9
.text:
7C8021F9
loc_7C8021F9: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
3C
↓j
.text:
7C8021F9
pop ebp
.text:
7C8021FA
retn
14h
.text:
7C8021FD
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
7C8021FD
.text:
7C8021FD
loc_7C8021FD: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
20
↑j
.text:
7C8021FD
mov edx, [ebp
+
nSize]
.text:
7C802200
mov [ecx], edx
.text:
7C802202
jmp short loc_7C8021F2
.text:
7C802204
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
7C802204
.text:
7C802204
loc_7C802204: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
24
↑j
.text:
7C802204
push eax ; Status
.text:
7C802205
call _BaseSetLastNTError@
4
; BaseSetLastNTError(x)
.text:
7C80220A
xor eax, eax
.text:
7C80220C
jmp short loc_7C8021F9
.text:
7C80220C
_ReadProcessMemory@
20
endp
.text:
7C8021D0
;
BOOL
__stdcall ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T
*
lpNumberOfBytesRead)
.text:
7C8021D0
public _ReadProcessMemory@
20
.text:
7C8021D0
_ReadProcessMemory@
20
proc near ; CODE XREF: GetProcessVersion(x)
+
2F18B
↓p
.text:
7C8021D0
; GetProcessVersion(x)
+
2F1AA
↓p ...
.text:
7C8021D0
.text:
7C8021D0
hProcess
=
dword ptr
8
.text:
7C8021D0
lpBaseAddress
=
dword ptr
0Ch
.text:
7C8021D0
lpBuffer
=
dword ptr
10h
.text:
7C8021D0
nSize
=
dword ptr
14h
.text:
7C8021D0
lpNumberOfBytesRead
=
dword ptr
18h
.text:
7C8021D0
.text:
7C8021D0
mov edi, edi
.text:
7C8021D2
push ebp
.text:
7C8021D3
mov ebp, esp
.text:
7C8021D5
lea eax, [ebp
+
nSize]
.text:
7C8021D8
push eax ; NumberOfBytesRead
.text:
7C8021D9
push [ebp
+
nSize] ; NumberOfBytesToRead
.text:
7C8021DC
push [ebp
+
lpBuffer] ;
Buffer
.text:
7C8021DF
push [ebp
+
lpBaseAddress] ; BaseAddress
.text:
7C8021E2
push [ebp
+
hProcess] ; ProcessHandle
.text:
7C8021E5
call ds:__imp__NtReadVirtualMemory@
20
; NtReadVirtualMemory(x,x,x,x,x)
.text:
7C8021EB
mov ecx, [ebp
+
lpNumberOfBytesRead]
.text:
7C8021EE
test ecx, ecx
.text:
7C8021F0
jnz short loc_7C8021FD
.text:
7C8021F2
.text:
7C8021F2
loc_7C8021F2: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
32
↓j
.text:
7C8021F2
test eax, eax
.text:
7C8021F4
jl short loc_7C802204
.text:
7C8021F6
xor eax, eax
.text:
7C8021F8
inc eax
.text:
7C8021F9
.text:
7C8021F9
loc_7C8021F9: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
3C
↓j
.text:
7C8021F9
pop ebp
.text:
7C8021FA
retn
14h
.text:
7C8021FD
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
7C8021FD
.text:
7C8021FD
loc_7C8021FD: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
20
↑j
.text:
7C8021FD
mov edx, [ebp
+
nSize]
.text:
7C802200
mov [ecx], edx
.text:
7C802202
jmp short loc_7C8021F2
.text:
7C802204
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.text:
7C802204
.text:
7C802204
loc_7C802204: ; CODE XREF: ReadProcessMemory(x,x,x,x,x)
+
24
↑j
.text:
7C802204
push eax ; Status
.text:
7C802205
call _BaseSetLastNTError@
4
; BaseSetLastNTError(x)
.text:
7C80220A
xor eax, eax
.text:
7C80220C
jmp short loc_7C8021F9
.text:
7C80220C
_ReadProcessMemory@
20
endp
.text:
7C92D9E0
public NtReadVirtualMemory
.text:
7C92D9E0
NtReadVirtualMemory proc near ; CODE XREF: .text:
7C93FFD1
↓p
.text:
7C92D9E0
; LdrCreateOutOfProcessImage
+
7C
↓p ...
.text:
7C92D9E0
mov eax,
0BAh
; 服务号赋给eax
.text:
7C92D9E5
mov edx,
7FFE0300h
.text:
7C92D9EA
call dword ptr [edx]
.text:
7C92D9EC
retn
14h
.text:
7C92D9EC
NtReadVirtualMemory endp
.text:
7C92D9E0
public NtReadVirtualMemory
.text:
7C92D9E0
NtReadVirtualMemory proc near ; CODE XREF: .text:
7C93FFD1
↓p
.text:
7C92D9E0
; LdrCreateOutOfProcessImage
+
7C
↓p ...
.text:
7C92D9E0
mov eax,
0BAh
; 服务号赋给eax
.text:
7C92D9E5
mov edx,
7FFE0300h
.text:
7C92D9EA
call dword ptr [edx]
.text:
7C92D9EC
retn
14h
.text:
7C92D9EC
NtReadVirtualMemory endp
#define KI_USER_SHARED_DATA 0xFFDF0000
#define KI_USER_SHARED_DATA 0xFFDF0000
#define MM_SHARED_USER_DATA_VA 0x7FFE0000
#define MM_SHARED_USER_DATA_VA 0x7FFE0000
kd> dt _KUSER_SHARED_DATA
nt!_KUSER_SHARED_DATA
+
0x000
TickCountLow : Uint4B
+
0x004
TickCountMultiplier : Uint4B
+
0x008
InterruptTime : _KSYSTEM_TIME
+
0x014
SystemTime : _KSYSTEM_TIME
+
0x020
TimeZoneBias : _KSYSTEM_TIME
+
0x02c
ImageNumberLow : Uint2B
+
0x02e
ImageNumberHigh : Uint2B
+
0x030
NtSystemRoot : [
260
] Uint2B
+
0x238
MaxStackTraceDepth : Uint4B
+
0x23c
CryptoExponent : Uint4B
+
0x240
TimeZoneId : Uint4B
+
0x244
Reserved2 : [
8
] Uint4B
+
0x264
NtProductType : _NT_PRODUCT_TYPE
+
0x268
ProductTypeIsValid : UChar
+
0x26c
NtMajorVersion : Uint4B
+
0x270
NtMinorVersion : Uint4B
+
0x274
ProcessorFeatures : [
64
] UChar
+
0x2b4
Reserved1 : Uint4B
+
0x2b8
Reserved3 : Uint4B
+
0x2bc
TimeSlip : Uint4B
+
0x2c0
AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+
0x2c8
SystemExpirationDate : _LARGE_INTEGER
+
0x2d0
SuiteMask : Uint4B
+
0x2d4
KdDebuggerEnabled : UChar
+
0x2d5
NXSupportPolicy : UChar
+
0x2d8
ActiveConsoleId : Uint4B
+
0x2dc
DismountCount : Uint4B
+
0x2e0
ComPlusPackage : Uint4B
+
0x2e4
LastSystemRITEventTickCount : Uint4B
+
0x2e8
NumberOfPhysicalPages : Uint4B
+
0x2ec
SafeBootMode : UChar
+
0x2f0
TraceLogging : Uint4B
+
0x2f8
TestRetInstruction : Uint8B
+
0x300
SystemCall : Uint4B
+
0x304
SystemCallReturn : Uint4B
+
0x308
SystemCallPad : [
3
] Uint8B
+
0x320
TickCount : _KSYSTEM_TIME
+
0x320
TickCountQuad : Uint8B
+
0x330
Cookie : Uint4B
kd> dt _KUSER_SHARED_DATA
nt!_KUSER_SHARED_DATA
+
0x000
TickCountLow : Uint4B
+
0x004
TickCountMultiplier : Uint4B
+
0x008
InterruptTime : _KSYSTEM_TIME
+
0x014
SystemTime : _KSYSTEM_TIME
+
0x020
TimeZoneBias : _KSYSTEM_TIME
+
0x02c
ImageNumberLow : Uint2B
+
0x02e
ImageNumberHigh : Uint2B
+
0x030
NtSystemRoot : [
260
] Uint2B
+
0x238
MaxStackTraceDepth : Uint4B
+
0x23c
CryptoExponent : Uint4B
+
0x240
TimeZoneId : Uint4B
+
0x244
Reserved2 : [
8
] Uint4B
+
0x264
NtProductType : _NT_PRODUCT_TYPE
+
0x268
ProductTypeIsValid : UChar
+
0x26c
NtMajorVersion : Uint4B
+
0x270
NtMinorVersion : Uint4B
+
0x274
ProcessorFeatures : [
64
] UChar
+
0x2b4
Reserved1 : Uint4B
+
0x2b8
Reserved3 : Uint4B
+
0x2bc
TimeSlip : Uint4B
+
0x2c0
AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+
0x2c8
SystemExpirationDate : _LARGE_INTEGER
+
0x2d0
SuiteMask : Uint4B
+
0x2d4
KdDebuggerEnabled : UChar
+
0x2d5
NXSupportPolicy : UChar
+
0x2d8
ActiveConsoleId : Uint4B
+
0x2dc
DismountCount : Uint4B
+
0x2e0
ComPlusPackage : Uint4B
+
0x2e4
LastSystemRITEventTickCount : Uint4B
+
0x2e8
NumberOfPhysicalPages : Uint4B
+
0x2ec
SafeBootMode : UChar
+
0x2f0
TraceLogging : Uint4B
+
0x2f8
TestRetInstruction : Uint8B
+
0x300
SystemCall : Uint4B
+
0x304
SystemCallReturn : Uint4B
+
0x308
SystemCallPad : [
3
] Uint8B
+
0x320
TickCount : _KSYSTEM_TIME
+
0x320
TickCountQuad : Uint8B
+
0x330
Cookie : Uint4B
.text:
7C92E500
public KiIntSystemCall
.text:
7C92E500
KiIntSystemCall proc near ; DATA XREF: .text:off_7C923428↑o
.text:
7C92E500
.text:
7C92E500
arg_4
=
byte ptr
8
.text:
7C92E500
.text:
7C92E500
lea edx, [esp
+
arg_4] ;将参数地址赋给edx
.text:
7C92E504
int
2Eh
; DOS
2
+
internal
-
EXECUTE COMMAND
.text:
7C92E504
; DS:SI
-
> counted CR
-
terminated command string
.text:
7C92E506
retn
.text:
7C92E506
KiIntSystemCall endp
.text:
7C92E500
public KiIntSystemCall
.text:
7C92E500
KiIntSystemCall proc near ; DATA XREF: .text:off_7C923428↑o
.text:
7C92E500
.text:
7C92E500
arg_4
=
byte ptr
8
.text:
7C92E500
.text:
7C92E500
lea edx, [esp
+
arg_4] ;将参数地址赋给edx
.text:
7C92E504
int
2Eh
; DOS
2
+
internal
-
EXECUTE COMMAND
.text:
7C92E504
; DS:SI
-
> counted CR
-
terminated command string
.text:
7C92E506
retn
.text:
7C92E506
KiIntSystemCall endp
.text:
7C92E4F0
public KiFastSystemCall
.text:
7C92E4F0
KiFastSystemCall proc near ; DATA XREF: .text:off_7C923428↑o
.text:
7C92E4F0
mov edx, esp
.text:
7C92E4F2
sysenter
.text:
7C92E4F2
KiFastSystemCall endp
.text:
7C92E4F0
public KiFastSystemCall
.text:
7C92E4F0
KiFastSystemCall proc near ; DATA XREF: .text:off_7C923428↑o
.text:
7C92E4F0
mov edx, esp
.text:
7C92E4F2
sysenter
.text:
7C92E4F2
KiFastSystemCall endp
MSR寄存器名称 | MSR地址 | 含义 |
---|---|---|
IA32_SYSENTER_CS | 0x174 | 低16位指定了特权级0的代码段和栈段的段描述符 |
IA32_SYSENTER_ESP | 0x175 | 内核栈指针的32位偏移 |
IA32_SYSENTER_EIP | 0x176 | 目标例程的32位偏移,指向KiFastCallEntry函数 |
kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
+
0x000
DbgEbp : Uint4B
+
0x004
DbgEip : Uint4B
+
0x008
DbgArgMark : Uint4B
+
0x00c
DbgArgPointer : Uint4B
+
0x010
TempSegCs : Uint4B
+
0x014
TempEsp : Uint4B
+
0x018
Dr0 : Uint4B
+
0x01c
Dr1 : Uint4B
+
0x020
Dr2 : Uint4B
+
0x024
Dr3 : Uint4B
+
0x028
Dr6 : Uint4B
+
0x02c
Dr7 : Uint4B
+
0x030
SegGs : Uint4B
+
0x034
SegEs : Uint4B
+
0x038
SegDs : Uint4B
+
0x03c
Edx : Uint4B
+
0x040
Ecx : Uint4B
+
0x044
Eax : Uint4B
+
0x048
PreviousMode : Uint4B
+
0x04c
ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x050
SegFs : Uint4B
+
0x054
Edi : Uint4B
+
0x058
Esi : Uint4B
+
0x05c
Ebx : Uint4B
+
0x060
Ebp : Uint4B
+
0x064
ErrCode : Uint4B
+
0x068
Eip : Uint4B
+
0x06c
SegCs : Uint4B
+
0x070
EFlags : Uint4B
+
0x074
HardwareEsp : Uint4B
+
0x078
HardwareSegSs : Uint4B
+
0x07c
V86Es : Uint4B
+
0x080
V86Ds : Uint4B
+
0x084
V86Fs : Uint4B
+
0x088
V86Gs : Uint4B
kd> dt _KTRAP_FRAME
nt!_KTRAP_FRAME
+
0x000
DbgEbp : Uint4B
+
0x004
DbgEip : Uint4B
+
0x008
DbgArgMark : Uint4B
+
0x00c
DbgArgPointer : Uint4B
+
0x010
TempSegCs : Uint4B
+
0x014
TempEsp : Uint4B
+
0x018
Dr0 : Uint4B
+
0x01c
Dr1 : Uint4B
+
0x020
Dr2 : Uint4B
+
0x024
Dr3 : Uint4B
+
0x028
Dr6 : Uint4B
+
0x02c
Dr7 : Uint4B
+
0x030
SegGs : Uint4B
+
0x034
SegEs : Uint4B
+
0x038
SegDs : Uint4B
+
0x03c
Edx : Uint4B
+
0x040
Ecx : Uint4B
+
0x044
Eax : Uint4B
+
0x048
PreviousMode : Uint4B
+
0x04c
ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x050
SegFs : Uint4B
+
0x054
Edi : Uint4B
+
0x058
Esi : Uint4B
+
0x05c
Ebx : Uint4B
+
0x060
Ebp : Uint4B
+
0x064
ErrCode : Uint4B
+
0x068
Eip : Uint4B
+
0x06c
SegCs : Uint4B
+
0x070
EFlags : Uint4B
+
0x074
HardwareEsp : Uint4B
+
0x078
HardwareSegSs : Uint4B
+
0x07c
V86Es : Uint4B
+
0x080
V86Ds : Uint4B
+
0x084
V86Fs : Uint4B
+
0x088
V86Gs : Uint4B
kd> dt _KPCR
nt!_KPCR
+
0x000
NtTib : _NT_TIB
+
0x01c
SelfPcr : Ptr32 _KPCR
+
0x020
Prcb : Ptr32 _KPRCB
+
0x024
Irql : UChar
+
0x028
IRR : Uint4B
+
0x02c
IrrActive : Uint4B
+
0x030
IDR : Uint4B
+
0x034
KdVersionBlock : Ptr32 Void
+
0x038
IDT : Ptr32 _KIDTENTRY
+
0x03c
GDT : Ptr32 _KGDTENTRY
+
0x040
TSS : Ptr32 _KTSS
+
0x044
MajorVersion : Uint2B
+
0x046
MinorVersion : Uint2B
+
0x048
SetMember : Uint4B
+
0x04c
StallScaleFactor : Uint4B
+
0x050
DebugActive : UChar
+
0x051
Number : UChar
+
0x052
Spare0 : UChar
+
0x053
SecondLevelCacheAssociativity : UChar
+
0x054
VdmAlert : Uint4B
+
0x058
KernelReserved : [
14
] Uint4B
+
0x090
SecondLevelCacheSize : Uint4B
+
0x094
HalReserved : [
16
] Uint4B
+
0x0d4
InterruptMode : Uint4B
+
0x0d8
Spare1 : UChar
+
0x0dc
KernelReserved2 : [
17
] Uint4B
+
0x120
PrcbData : _KPRCB
kd> dt _KPCR
nt!_KPCR
+
0x000
NtTib : _NT_TIB
+
0x01c
SelfPcr : Ptr32 _KPCR
+
0x020
Prcb : Ptr32 _KPRCB
+
0x024
Irql : UChar
+
0x028
IRR : Uint4B
+
0x02c
IrrActive : Uint4B
+
0x030
IDR : Uint4B
+
0x034
KdVersionBlock : Ptr32 Void
+
0x038
IDT : Ptr32 _KIDTENTRY
+
0x03c
GDT : Ptr32 _KGDTENTRY
+
0x040
TSS : Ptr32 _KTSS
+
0x044
MajorVersion : Uint2B
+
0x046
MinorVersion : Uint2B
+
0x048
SetMember : Uint4B
+
0x04c
StallScaleFactor : Uint4B
+
0x050
DebugActive : UChar
+
0x051
Number : UChar
+
0x052
Spare0 : UChar
+
0x053
SecondLevelCacheAssociativity : UChar
+
0x054
VdmAlert : Uint4B
+
0x058
KernelReserved : [
14
] Uint4B
+
0x090
SecondLevelCacheSize : Uint4B
+
0x094
HalReserved : [
16
] Uint4B
+
0x0d4
InterruptMode : Uint4B
+
0x0d8
Spare1 : UChar
+
0x0dc
KernelReserved2 : [
17
] Uint4B
+
0x120
PrcbData : _KPRCB
偏移 | 成员 | 作用 |
---|---|---|
0x000 | NtTib | 包含异常,线程栈等信息 |
0x01C | SelfPrc | 指向_KPCR结构体本身的地址 |
0x020 | Prcb | 指向扩展结构体PRCB |
0x038 | IDT | IDT表基址 |
0x03C | GDT | GDT表基址 |
0x040 | TSS | 指向TSS |
0x051 | Number | CPU编号 |
0x120 | PrcbData | 指向_KPRCB结构体 |
kd> dt _NT_TIB
ntdll!_NT_TIB
+
0x000
ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x004
StackBase : Ptr32 Void
+
0x008
StackLimit : Ptr32 Void
+
0x00c
SubSystemTib : Ptr32 Void
+
0x010
FiberData : Ptr32 Void
+
0x010
Version : Uint4B
+
0x014
ArbitraryUserPointer : Ptr32 Void
+
0x018
Self : Ptr32 _NT_TIB
kd> dt _NT_TIB
ntdll!_NT_TIB
+
0x000
ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x004
StackBase : Ptr32 Void
+
0x008
StackLimit : Ptr32 Void
+
0x00c
SubSystemTib : Ptr32 Void
+
0x010
FiberData : Ptr32 Void
+
0x010
Version : Uint4B
+
0x014
ArbitraryUserPointer : Ptr32 Void
+
0x018
Self : Ptr32 _NT_TIB
偏移 | 成员 | 作用 |
---|---|---|
0x000 | ExceptionList | 指向当前线程内核异常链表(SEH) |
0x004 | StackBase | 内核栈的基地址 |
0x008 | StackLimit | 内核栈的边界 |
0x018 | Self | 指向_NT_TIB结构本身地址 |
kd> dt _KPRCB
nt!_KPRCB
+
0x000
MinorVersion : Uint2B
+
0x002
MajorVersion : Uint2B
+
0x004
CurrentThread : Ptr32 _KTHREAD
+
0x008
NextThread : Ptr32 _KTHREAD
+
0x00c
IdleThread : Ptr32 _KTHREAD
+
0x010
Number : Char
+
0x011
Reserved : Char
+
0x012
BuildType : Uint2B
+
0x014
SetMember : Uint4B
+
0x018
CpuType : Char
+
0x019
CpuID : Char
+
0x01a
CpuStep : Uint2B
+
0x01c
ProcessorState : _KPROCESSOR_STATE
+
0x33c
KernelReserved : [
16
] Uint4B
+
0x37c
HalReserved : [
16
] Uint4B
+
0x3bc
PrcbPad0 : [
92
] UChar
+
0x418
LockQueue : [
16
] _KSPIN_LOCK_QUEUE
+
0x498
PrcbPad1 : [
8
] UChar
+
0x4a0
NpxThread : Ptr32 _KTHREAD
+
0x4a4
InterruptCount : Uint4B
+
0x4a8
KernelTime : Uint4B
+
0x4ac
UserTime : Uint4B
+
0x4b0
DpcTime : Uint4B
+
0x4b4
DebugDpcTime : Uint4B
+
0x4b8
InterruptTime : Uint4B
+
0x4bc
AdjustDpcThreshold : Uint4B
+
0x4c0
PageColor : Uint4B
+
0x4c4
SkipTick : Uint4B
+
0x4c8
MultiThreadSetBusy : UChar
+
0x4c9
Spare2 : [
3
] UChar
+
0x4cc
ParentNode : Ptr32 _KNODE
+
0x4d0
MultiThreadProcessorSet : Uint4B
+
0x4d4
MultiThreadSetMaster : Ptr32 _KPRCB
+
0x4d8
ThreadStartCount : [
2
] Uint4B
+
0x4e0
CcFastReadNoWait : Uint4B
+
0x4e4
CcFastReadWait : Uint4B
+
0x4e8
CcFastReadNotPossible : Uint4B
+
0x4ec
CcCopyReadNoWait : Uint4B
+
0x4f0
CcCopyReadWait : Uint4B
+
0x4f4
CcCopyReadNoWaitMiss : Uint4B
+
0x4f8
KeAlignmentFixupCount : Uint4B
+
0x4fc
KeContextSwitches : Uint4B
+
0x500
KeDcacheFlushCount : Uint4B
+
0x504
KeExceptionDispatchCount : Uint4B
+
0x508
KeFirstLevelTbFills : Uint4B
+
0x50c
KeFloatingEmulationCount : Uint4B
+
0x510
KeIcacheFlushCount : Uint4B
+
0x514
KeSecondLevelTbFills : Uint4B
+
0x518
KeSystemCalls : Uint4B
+
0x51c
SpareCounter0 : [
1
] Uint4B
+
0x520
PPLookasideList : [
16
] _PP_LOOKASIDE_LIST
+
0x5a0
PPNPagedLookasideList : [
32
] _PP_LOOKASIDE_LIST
+
0x6a0
PPPagedLookasideList : [
32
] _PP_LOOKASIDE_LIST
+
0x7a0
PacketBarrier : Uint4B
+
0x7a4
ReverseStall : Uint4B
+
0x7a8
IpiFrame : Ptr32 Void
+
0x7ac
PrcbPad2 : [
52
] UChar
+
0x7e0
CurrentPacket : [
3
] Ptr32 Void
+
0x7ec
TargetSet : Uint4B
+
0x7f0
WorkerRoutine : Ptr32 void
+
0x7f4
IpiFrozen : Uint4B
+
0x7f8
PrcbPad3 : [
40
] UChar
+
0x820
RequestSummary : Uint4B
+
0x824
SignalDone : Ptr32 _KPRCB
+
0x828
PrcbPad4 : [
56
] UChar
+
0x860
DpcListHead : _LIST_ENTRY
+
0x868
DpcStack : Ptr32 Void
+
0x86c
DpcCount : Uint4B
+
0x870
DpcQueueDepth : Uint4B
+
0x874
DpcRoutineActive : Uint4B
+
0x878
DpcInterruptRequested : Uint4B
+
0x87c
DpcLastCount : Uint4B
+
0x880
DpcRequestRate : Uint4B
+
0x884
MaximumDpcQueueDepth : Uint4B
+
0x888
MinimumDpcRate : Uint4B
+
0x88c
QuantumEnd : Uint4B
+
0x890
PrcbPad5 : [
16
] UChar
+
0x8a0
DpcLock : Uint4B
+
0x8a4
PrcbPad6 : [
28
] UChar
+
0x8c0
CallDpc : _KDPC
+
0x8e0
ChainedInterruptList : Ptr32 Void
+
0x8e4
LookasideIrpFloat : Int4B
+
0x8e8
SpareFields0 : [
6
] Uint4B
+
0x900
VendorString : [
13
] UChar
+
0x90d
InitialApicId : UChar
+
0x90e
LogicalProcessorsPerPhysicalProcessor : UChar
+
0x910
MHz : Uint4B
+
0x914
FeatureBits : Uint4B
+
0x918
UpdateSignature : _LARGE_INTEGER
+
0x920
NpxSaveArea : _FX_SAVE_AREA
+
0xb30
PowerState : _PROCESSOR_POWER_STATE
kd> dt _KPRCB
nt!_KPRCB
+
0x000
MinorVersion : Uint2B
+
0x002
MajorVersion : Uint2B
+
0x004
CurrentThread : Ptr32 _KTHREAD
+
0x008
NextThread : Ptr32 _KTHREAD
+
0x00c
IdleThread : Ptr32 _KTHREAD
+
0x010
Number : Char
+
0x011
Reserved : Char
+
0x012
BuildType : Uint2B
+
0x014
SetMember : Uint4B
+
0x018
CpuType : Char
+
0x019
CpuID : Char
+
0x01a
CpuStep : Uint2B
+
0x01c
ProcessorState : _KPROCESSOR_STATE
+
0x33c
KernelReserved : [
16
] Uint4B
+
0x37c
HalReserved : [
16
] Uint4B
+
0x3bc
PrcbPad0 : [
92
] UChar
+
0x418
LockQueue : [
16
] _KSPIN_LOCK_QUEUE
+
0x498
PrcbPad1 : [
8
] UChar
+
0x4a0
NpxThread : Ptr32 _KTHREAD
+
0x4a4
InterruptCount : Uint4B
+
0x4a8
KernelTime : Uint4B
+
0x4ac
UserTime : Uint4B
+
0x4b0
DpcTime : Uint4B
+
0x4b4
DebugDpcTime : Uint4B
+
0x4b8
InterruptTime : Uint4B
+
0x4bc
AdjustDpcThreshold : Uint4B
+
0x4c0
PageColor : Uint4B
+
0x4c4
SkipTick : Uint4B
+
0x4c8
MultiThreadSetBusy : UChar
+
0x4c9
Spare2 : [
3
] UChar
+
0x4cc
ParentNode : Ptr32 _KNODE
+
0x4d0
MultiThreadProcessorSet : Uint4B
+
0x4d4
MultiThreadSetMaster : Ptr32 _KPRCB
+
0x4d8
ThreadStartCount : [
2
] Uint4B
+
0x4e0
CcFastReadNoWait : Uint4B
+
0x4e4
CcFastReadWait : Uint4B
+
0x4e8
CcFastReadNotPossible : Uint4B
+
0x4ec
CcCopyReadNoWait : Uint4B
+
0x4f0
CcCopyReadWait : Uint4B
+
0x4f4
CcCopyReadNoWaitMiss : Uint4B
+
0x4f8
KeAlignmentFixupCount : Uint4B
+
0x4fc
KeContextSwitches : Uint4B
+
0x500
KeDcacheFlushCount : Uint4B
+
0x504
KeExceptionDispatchCount : Uint4B
+
0x508
KeFirstLevelTbFills : Uint4B
+
0x50c
KeFloatingEmulationCount : Uint4B
+
0x510
KeIcacheFlushCount : Uint4B
+
0x514
KeSecondLevelTbFills : Uint4B
+
0x518
KeSystemCalls : Uint4B
+
0x51c
SpareCounter0 : [
1
] Uint4B
+
0x520
PPLookasideList : [
16
] _PP_LOOKASIDE_LIST
+
0x5a0
PPNPagedLookasideList : [
32
] _PP_LOOKASIDE_LIST
+
0x6a0
PPPagedLookasideList : [
32
] _PP_LOOKASIDE_LIST
+
0x7a0
PacketBarrier : Uint4B
+
0x7a4
ReverseStall : Uint4B
+
0x7a8
IpiFrame : Ptr32 Void
+
0x7ac
PrcbPad2 : [
52
] UChar
+
0x7e0
CurrentPacket : [
3
] Ptr32 Void
+
0x7ec
TargetSet : Uint4B
+
0x7f0
WorkerRoutine : Ptr32 void
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]CVE-2022-21882提权漏洞学习笔记 16383
- [原创]CVE-2021-1732提权漏洞学习笔记 19489
- [原创]CVE-2014-1767提权漏洞学习笔记 15192
- [原创]CVE-2018-8453提权漏洞学习笔记 18526
- [原创]CVE-2020-1054提权漏洞学习笔记 13542