memorymappingsegment发生段错误,如何回溯

memorymappingsegment发生段错误,如何回溯,第1张

相比,微内核调度系统中最突出的特征是增加了处理机和处理机集及线程的管理,并且向用户提供了灵活的手段来控翩自己的程序在处理机上的运行.这{羊,微内核系统就能很好地支持多处理机体系结构.同时,线程为用户提供了细粒度的并行处理机制,使得同一个用户任务中的不同线程可以同时在多个处理机上运行.

进程相比,线程中所带的资源很少,因此,创建线程和撤消线程的开销就比进程小.线程也称为“轻进程.在系统调度中,线程的切换开销也比进程步,但是不同任务中的线程切换会引起任务的切换,在这种情况下,线程和进程的调度开销就变成一样了.为了优化系统效率,减步由于线程切换而弓I起的任务切换,在调度算法中加入了以下代码:

IF (所选中的线程和当前运行的城程属于同一十任务)

THEN 不做任务切换}

ELSE进行任务切换 *** 作}

显然,这种方法在某种情况下会对系统性能有所帮助,但是这种方法在很大程度上属于一种“被动的,或者说是一种“碰运气”的方法.另外,单纯以线程为主的调度算法对用户任务有失公平性,以线程为主的调度算法是完全参照传统 *** 作系统中的调度算法设计而成的.当线程投入运行时,系统为它分配周定大小的时间片,系统中线程按时间片轮转.这样,就产生了公平性问题:如果一个任务中有两个线程,那么,从理论上讲,它将比只用一个线程实现的任务多获得近1倍的处理机时间.在传统的进程调度系统中,一个用户可以通过创建多个进程来获得更多的处理机调度机会,但是,它是建立在增加了创建进程和进程间通讯的系统开销代价的基础上的相比之下,创建线程的开销非常小,同一任务间的线程之闭通讯开销也很小为了解决上述问题,我们提出并实现了一种将传统的任务和新的线程调度机翩相结合的方法:以任务为单位分配时间片(这样可以保证调度的公平性),在线程调度时,当一个线程不是由于任务时间片用完的原因而放弃处理机时,只要系统中没有高优先级线程,就从本任务中选取线程,从而使得由线程切换而引起的任务切换 *** 作开销达到最小.

从目前的发展来看,用户任务的并行粒度越来越小,即用户任务中的线程越来越多,而每个线程所执行的 *** 作会越来越步.因此,使用线程+任务的方法可以有效地减少单纯的以线程为主的系统调度所引起的系统开销.

2 微内核虚拟存储管理技术

微内核虚拟存储管理系统弓『入了存储对象(Memory Object)的概念,将物理内存看成外部存储对象的(如磁盘)高速缓存(Cache),实现了虚拟存储器写时拷贝(Copy onWrite)技术,引入了lazy evaluation技术.定义了虚拟存储器和硬件存储管理机制的接口(Pmap),实现了与机器无关的虚拟存储系统.

虚拟存储器写时拷贝算法是微内核虚拟存储管理系统的核心算法.它的弓f入使得虚拟存储器管理的效率大大提高了一步.但是,它的实现依赖于硬件存储管理机制的页面保护机制,对于一个具有写时拷贝共享属性的存储区,其页面保护被设置成写保护.多个用户可以共享的方式对它进行读 *** 作,但是,当用户试图对这块区域进行写 *** 作时,将产生写保护故障,页面故障管理程序将为用户进程复制物理页面.从而达到写时拷贝的目的.

在I386体系结构下,只有用户态页面允许写保护,在其他机器状态下,硬件存取机制将绕过页面保护机翩,直接对页面进行写 *** 作.在这种状态下,写时拷贝算法将失效.而在微内核体系结构中,可能有各种状态下的服务器,如在内核态下运行的服务器.为了解决这个问题。我们引入了写时拷贝和访问时拷贝(Copy oil Reference)相结合的算法.

即在用户态上使用写时拷贝算法,在其他状态下使用访问时拷贝算法来替换写时拷贝算法,以解决写时拷周算法失效的问题.访问时拷贝算法的实现依赖于页面保护机制的映页机制.这样,在其他状态下,在设置页面保护时将写保护改成映页即可.新的方法在效率上比写时拷贝算法低,但是比完全拷贝的方法高出许多,特别是与lazy evaluation技术相配合时

效率会更高.由于微内核提供的写时拷贝算法是对用户透明的,即对于用户编写的任何状态下的服务器都将使用写时拷贝算法.因此,在I386体系结构下,在非用户态上运行的用户服务器有可能出错,新的算法解决了这个问题.

3 微内核计时模型

在传统 *** 作系统中,为统计出每个进程的处理机时间使用量的单元.系统计时一般是放在处理机时钟中断服务程序中.系统

IF (当前盎程处于用户态)

增加当前进程的用户奋处理机时间使用量

在每个进程结构中都没有统计进程使用处理机时间

般采用如下代码段来进行用户进程的时间统计.

ELSE

增加当前进程的系统态处理机时闻使用量

由于在传统的 *** 作系统中, *** 作系统提供的服务完全由 *** 作系统内核来完成。用户通过系统调用进入内核来取得服务.因此,采用上述方法能比较准确地统计出用户所用的处理机时间.但是,这种计时方法是一种比较粗糙的计时方法.每次时钟中断时,它就将一个固定的时间片(时钟中断周期)加入披中断的进程中,而不管该进程是否完全使用了这些处理机对向.由于这种方法实现起来非常简单,系统开销很小,几乎所有的 *** 作系绕都采用了这种方法.在新的 *** 作系统中引入了细粒度的并行执行部件—— 线程。对于线程的计时也采用了和进程相同的方法.为了取得精确的处理机时同统计精度.一些新型 *** 作系统弓『入了新的计时机制.如MACH 3.0中引^了基于时间戳的精确计时机制.在微内核体系结构下.传统的 *** 作系统功能是通过服务器的方式来实现的.服务器和用户任务一样,也作为一个进程运行.当用户进程调用 *** 作系统服务时,微内核通过消息将系统服务的参数传递给 *** 作系统服务器,由 *** 作系统服务器来完成用户请求,并将结果通过消息传递给用户进程.这样,如果采用传统的方法来进行进程的处理机时问统十。就会将 *** 作系统为用户提供服务所用的处理机时间记入服务器中.而不是用户进程中.

为了解决这个问题,我们引^了委托线程的概念,建立了新的用户进程计时模型.在客户/服务器模型中,用户通过消息请求服务器的服务,服务器接收用户的消息完成用户的请求,再通过消息将结果传给用户.在这种体系结构下,可看成用户将自己的一部分工作委托给服务器完成,服务器是在为委托线程服务.当用户线程向服务器发出请求时,将用户线程标识传递给服务器,当服务器中的某个线程处理这个请求时,将用户线程标识记^服务器线程结构中的委托线程域中.在系统时钟中断服务程序中增加为委托线程计时的代码。就可将 *** 作系统服务器为用户进程限务的时同计算到用户进程中.

IF(当前线程结构中有委托线程)

IF(当前线程赴于用户态)

增加委托线程的用户态赴理机时间使用量

ELSE

增加委托线程的系统态处理机时间使用量

在多服务器体系结构下,一个用户请求往往需要多个服务器的协同服务,如一个文件读 *** 作,需要文件服务器的服务,如果文件服务器发现数据存放在磁盘中,它就需要请求设备服务器的眼务,设备服务器实际上是在为用户线程服务.因此,在多服务器情况下,当一个服务器向另一个服务器发出请求时,必须将自己的委托线程标识号传递给目标服务器.这样, *** 作系统为一个线程提供所有服务所使用的处理机时间都将计算到用户线程中击.为了完成以上功能,必须对微内核的消息传递机制进行扩充,使用户在请求服务时能将线程的标识传递给服务器,服务器在接收消息时能接收到委托线程标识.所有这些 *** 作必须对用户透明.微内核的消息传递机制由消息发送和消息接收两部分组成.通过在这两个原语中加入以下逻辑来实现委托线程标识的发送和接收.

SEND :

IF(当前线程结构中有委托线程标识)

将委托线程标识传递出去

ELSE

将当前线程的标识传递出击

RECEIVE:

IF(当前线程是服务器)

将委托线程号放凡服务器线程结构

在发送原语中,可将委托线程标识从一个服务器传递到另一个服务器.在接收逻辑中,通过增加服务器标识的判断可以避免非服务器线程之间的偶发通讯而导致的用户线程的计时错误.

4 结论

微内核技术是当今 *** 作系统发展的最新成果.在体系结构方面,它采用了面向对象技术来描述 *** 作系统内核对象,提出并实现了基于客户服务器体系结构的 *** 作系统.在算法方面,提出了许多高教新颖的算法,如线程及处理机调度算法、写时拷贝算法、与硬件无关的存储管理算法以及精确计时算法等等.在国产微内核 *** 作系统COSIX2.0的研制过程中,通过对国外微内核技术的消化和研究,提出并实现了一些新的算法和模型,改进了系统的性能,提高了系统的可靠性,做到了有所继承,有所刨新目前,我们正在进行基于微内核的JAVA虚拟机,支持服务质量(Quality of Services)的调度系统微内核热重启(Hot Restart)技术的研究.以上内容是我们一部分研究工作的总结.

另外,站长团上有产品团购,便宜有保证

cpu上下文是指cpu在运行任何任务之前都要依赖的环境。cpu上下文包括两个部分,cpu寄存器和程序计数器。cpu上下文切换,指的就是把上一个任务寄存器和程序计数器的值保存起来(保存在内存特定的数据结构中)然后设置新任务cpu寄存器和程序计数器值的过程。

每次上下文切换需要几十纳秒到数微妙的cpu时间。

根据任务类型的不同,cpu上下文切换可以分为进程上下文切换,线程上下文切换,中断上下文切换。

还有一种情况比较特殊,系统调用的过程中也发生了上下文切换,这种切换被称为特权模式切换。

一个进程从用户态到内核态的转变,需要通过系统调用来完成。

从用户态切换到内核态,cpu寄存器原来的用户态的指令位置需要保存起来,然后加载内核态的指令位置到cpu寄存器中。

系统调用结束后,cpu寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行。所以,一次系统调用的过程,其实是发生了两次cpu上下文切换。

进程的上下文切换比系统调用多了一步,在保存当前进程的内核状态和cpu寄存器之前,需要先把该进程的虚拟内存,栈等保存下来。而加载了下一个进程的内核态之后,还需要刷新进程的虚拟内存和用户栈。

线程与进程的最大区别在于,线程是调度的基本单位,而进程则是资源拥有的基本单位。内核中的任务调度,实际上调度的对象是线程。

当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量资源。这些资源在上下文切换时是不需要修改的。另外,线程也有自己的私有数据,比如栈和寄存器等。这些在上下文切换也是需要保存的。

线程的上下文切换分为两种情况:

1 ) 前后两个线程属于不同的进程。这时,切换线程就和切换进程一样。

2 ) 前后两个线程属于同一个进程。因为虚拟内存是共享的,所以在切换时,虚拟内存这些共享资源保存不动,只要切换线程的私有数据,寄存器等不共享的数据。

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而执行中断处理程序。对于同一个cpu来说,中断处理比进程拥有更高的优先级。

跟进程上下文切换不同,内核的中断上下文切换并不涉及到进程的用户态。进程的用户态切换由cpu硬件来处理。所以即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存,全局变量等用户态资源。这些由cpu硬件来保存和恢复。

参考资料:

中断进入就是从当前线程的用户态切换到当前线程的内核态。怎么进入内核态呢?唯一的答案就是中断。而 int中断实现了从用户态到内核态的转变

简单的说,保留用户态信息,还原内核态信息。

(1)启动中断时,

(2)

(3)

(1)从系统调用返回后,判断当前线程是否需要需要让出CPU,即是否需要进行schedule。当时间片用尽,或者线程启动磁盘读写等 *** 作时,会让出CPU。

(2)执行调度函数前,会把当前线程的返回函数地址压栈;然后跳转执行调度

(1) 调用schedule,进入switch_to。

(2)内核栈切换

(1)

一般在内核SSDT HOOK的时候就是直接钩住SSDT表替换NtOpenProcess的地址来达到保护进程的目的。而在InlineHook中,侧需要更进一步的了解NtOpenProcess函数,才能更好的做inlinehook。

首先说说Windows中用户层 OpenProces,WIN32函数OpenProces执行后,调用NTDLLDLL中NtOpenProcess函数,然后此函数INT2E自陷进入内核,开始从SSDT表中查找NtOpenProcess函数地址,继而在内核中执行NtOpenProcess函数。这是OpenProcess调用的路径。如图。

那么就这样说,在Windows中,OpenProcess函数是对NtOpenProcess调用的一个包装。NtOpenProcess包含在内核模块NTOSKRNLEXE当中。

内核中NtOpenProcess函数结构如下:

NTSTATUS NtOpenProcess (

OUT PHANDLE ProcessHandle,

IN ACCESS_MASK DesiredAccess,

IN POBJECT_ATTRIBUTES ObjectAttributes,

IN PCLIENT_ID ClientId OPTIONAL);

ClientID参数是OpenProcess传递的实际PID。这个参数是可选的,但是根据我们的观察,OpenProcess在调用NtOpenProcess的时候总是使用这个参数。

在内核中执行的时候,NtOpenProcess主要实现3个功能:

1 它通过调用PsLookupProcessByProcessId函数来验证进程是否存在。

2 它通过调用ObOpenObjectByPointer来打开进程的句柄。

3 如果打开进程句柄成功,就将句柄返回给调用者。

那么很自然的,PsLookupProcessByProcessId函数和ObOpenObjectByPointer函数就成为我们inlinehook的目标

先看PsLookupProcessByProcessId函数:

lkd> u 805caefa

nt!NtOpenProcess+0x1fc:

805caefa 45 inc ebp

805caefb dc50ff fcom qword ptr [eax-1]

805caefe 75d4 jne nt!NtOpenProcess+0x1d6 (805caed4)

805caf00 e8617a0000 call nt!PsLookupProcessByProcessId (805d2966)

805caf05 ebde jmp nt!NtOpenProcess+0x1e7 (805caee5)

805caf07 8d45e0 lea eax,[ebp-20h]

805caf0a 50 push eax

805caf0b ff75cc push dword ptr [ebp-34h]

lkd> u nt!PsLookupProcessByProcessId

nt!PsLookupProcessByProcessId:

805d2966 8bff mov edi,edi

805d2968 55 push ebp

805d2969 8bec mov ebp,esp

805d296b 53 push ebx

805d296c 56 push esi

805d296d 64a124010000 mov eax,dword ptr fs:[00000124h]

805d2973 ff7508 push dword ptr [ebp+8]

805d2976 8bf0 mov esi,eax

805d2978 ff8ed4000000 dec dword ptr [esi+0D4h]

805d297e ff35c0385680 push dword ptr [nt!PsThreadType+0x4 (805638c0)]

805d2984 e803ad0300 call nt!ExEnumHandleTable+0x408 (8060d68c)

805d2989 8bd8 mov ebx,eax

805d298b 85db test ebx,ebx

805d298d c745080d0000c0 mov dword ptr [ebp+8],0C000000Dh

805d2994 7432 je nt!PsLookupProcessByProcessId+0x62 (805d29c8)

再看ObOpenObjectByPointer函数:

lkd> u 805caf15

nt!NtOpenProcess+0x217:

805caf15 8d8548ffffff lea eax,[ebp-0B8h]

805caf1b 50 push eax

805caf1c ff75c8 push dword ptr [ebp-38h]

805caf1f ff75dc push dword ptr [ebp-24h]

805caf22 e8bd07ffff call nt!ObOpenObjectByPointer (805bb6e4)

805caf27 8bf8 mov edi,eax

805caf29 8d8548ffffff lea eax,[ebp-0B8h]

805caf2f 50 push eax

lkd> u nt!ObOpenObjectByPointer

nt!ObOpenObjectByPointer:

805bb6e4 8bff mov edi,edi

805bb6e6 55 push ebp

805bb6e7 8bec mov ebp,esp

805bb6e9 81ec94000000 sub esp,94h

805bb6ef 53 push ebx

805bb6f0 8b5d08 mov ebx,dword ptr [ebp+8]

805bb6f3 56 push esi

805bb6f4 57 push edi

知道NtOpenProcess执行的过程后,为防止打开某特定进程的句柄,可以直接inlinehook ObOpenObjectByPointer函数,Hook 这个函数有一大好处,那就是进程线程都一起保护了

ObOpenObjectByPointer(

IN PVOID Object,

IN ULONG HandleAttributes,

IN PACCESS_STATE PassedAccessState OPTIONAL,

IN ACCESS_MASK DesiredAccess,

IN POBJECT_TYPE ObjectType OPTIONAL,

IN KPROCESSOR_MODE AccessMode,

OUT PHANDLE Handle

)

NTSTATUS

T_ObOpenObjectByPointer(

IN PVOID Object,

IN ULONG HandleAttributes,

IN PACCESS_STATE PassedAccessState OPTIONAL,

IN ACCESS_MASK DesiredAccess,

IN POBJECT_TYPE ObjectType OPTIONAL,

IN KPROCESSOR_MODE AccessMode,

OUT PHANDLE Handle

)

{

PEPROCESS EPROCESS;

if ((Object != NULL) && (MmIsAddressValid(Object))) // 地址有效性验证

{

if (OBJECT_TO_OBJECT_HEADER(Object) -> Type == PsProcessType) // 若为进程对象

{

if ((PsGetCurrentProcess() != ProtectedProcess)) // 若 *** 作者不是受保护的进程自己

{

if (Object == ProtectedProcess) // 若被 *** 作进程是受保护进程

{

return STATUS_ACCESS_DENIED; // 拒绝访问

}

}

}

else

if (OBJECT_TO_OBJECT_HEADER(Object) -> Type == PsThreadType) // 若为线程对象

{

EPROCESS = IoThreadToProcess(Object); // 获取线程对应进程的 EPROCESS

if (EPROCESS == ProtectedProcess) // 若是受保护进程

{

if ((PsGetCurrentProcess() != ProtectedProcess)) // 若 *** 作者不是受保护进程自己

{

return STATUS_ACCESS_DENIED; // 拒绝访问

}

}

}

}

// 正常调用,执行原 API

return My_ObOpenObjectByPointer(

Object,

HandleAttributes,

PassedAccessState,

DesiredAccess,

ObjectType,

AccessMode,

Handle

);

}

My_ObOpenObjectByPointer(

Object,

HandleAttributes,

PassedAccessState,

DesiredAccess,

ObjectType,

AccessMode,

Handle

);

函数中,执行完ObOpenObjectByPointer函数前几字节后JMP到ObOpenObjectByPointer函数内部。

在系统内核有一个内核文件的加载的镜像(内核模块),NTOSKRNL或ntkrnlpa及ntkrnlmp、ntkrnlup、ntkrpamp都是OS内核文件,它提供了一整套核心态函数,供用户态和核心态调用,我们在用户态调用的函数大多数在最后都进入了核心态如kernel32dll的OpenProcess,在调用OpenProcess,以后会进入Ntdlldll中的NtOpenProcess然后调用系统函数调用号进入核心态的NtOpenProcess,所以核心态的钩子才是王道,核心态的钩子有SSDT HOOK和SDT INLINE HOOK,上面说了,内核导出了一系列的函数供用户态调用,那么导出的这个函数表就是SSDT(系统服务描述表),它的地址可由内核导出的一个变量 KeServiceDescriptorTable 查询,每4个字节(long 大小)为一个地址,在SSDT HOOK时我们只需要修改SSDT表中的地址为我们的地址即可,相当简单

例:修改NtOpenProcess:

(ULONG)(KeServiceDescriptorTable+(0x7A4))=(ULONG)MyOpenProcess

0x7A为NtOpenProcess的系统调用号,每个调用号占4个字节,KeServiceDescriptorTable+(0x7A4)就代表了NtOpenProcess地址的存放位置,MyOpenProcess为我们自定义的函数,这样系统在执行NtOpenProcess的时候就会跳到MyOpenProcess里。还有一种就是Inline Hook它和用户态的一样直接修改函数前5个字节即可,这里不再赘述。但是在核心态的inline hook比较危险,这涉及到多线程调用,有兴趣的朋友可以去查阅该方面资料。

以上就是关于memorymappingsegment发生段错误,如何回溯全部的内容,包括:memorymappingsegment发生段错误,如何回溯、解析windows线程调度策略、用户线程与内核线程的问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9821416.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存