《自己动手写操作系统》第三章 pmtest5源码解析——特权级变换与堆栈切换实例详解

来源:互联网 发布:淘宝软文编辑技巧 编辑:程序博客网 时间:2024/05/22 21:56
摘要:在pmtest4中,我们已经看到,对于非一致性代码,如何从低特权级转移向高特权级。但是我们该怎样从高特权级别,转移到低特权级别呢?本文,主要是为你解答这些疑问,展现实现这种特权级别转移的方法。另外,我们将在实践中探讨,为什么要设定RPL,是不是相对与DPL多此一举呢?在调试环节,我们将通过改动代码,排查相关错误来深入理解特权级检测机制。

一、预备理论

1.关于堆栈我们都知道,可以通过calljmp实现长跳转或者短跳转(段内转移或者段间转移)。但是jmpcall毕竟是有分别的,其中call指令是会影响到堆栈的:对于短调用,call指令执行时,下一条指令的eip入栈,ret指令执行时候,这个eip就会从堆栈中弹出。短调用call指令执行前后堆栈的变化如下图所示(注意带有参数的ret指令):长调用的情况与此相似,不同的是call指令执行时,被压栈的还有cs
2.特权级变换注意到:如果我们采用call指令进行长跳转,而且特权级别发生了变换,这个时候就发生了堆栈切换,比如从A切换到了B。但是我们的数据保存在A上面,如何从B中返回呢?原来,intel提供了一种机制,能够将A上的一些内容copyB堆栈中。同时,A堆栈要切换到B堆栈,但是它怎么知道B堆栈在哪里呢?答案:原来这个内容保存在任务的TSS结构中,TSS是任务状态段。每个任务都最多有四个堆栈段,但是只有一个espssTSS就解决了堆栈切换方面的数据保存问题。TSS的相关介绍,可以参考:保护模式及其编程——任务切换http://blog.csdn.net/trochiluses/article/details/19768579。比如,我们目前是ring 3,需要转移到ring 1,那时,堆栈将自动切换到ss1esp1。(由于只是从外层到内层切换,才从TSS中取得堆栈信息,所以,TSS中没有ring 3相关的堆栈信息。那么从内层向外层切换,如何获得目的地的信息呢)。切换过程中有关堆栈的处理,可以参考:保护模式及其编程——保护的详尽意义:通过调用门转移特权级http://blog.csdn.net/trochiluses/article/details/19573651好了,我们已经知道call------ret分别实现特权级高低转化,可能我们平时一直先使用call,然后再使用ret,以至于你对它的印象好像ifelse,实际上不是这样的,我们通过retf指令,单独使用就可以实现特权级别从03,从高到低。

二、代码分析

pmtest5.a:我们需要增加一个ring 3的代码段,堆栈段,另外为了在rign 3下打印字符,需要将video段的DPL改成3.我们先来写一个测试版本a:程序执行流程和前面没有太大区别,在保护模式重打印字符串之后,我们让程序进入ring 3代码段,并且死循环,需要添加如下代码。
push     SelectorStack3push     TopOfStack3push     SelecorCodeRing3push    0
        但是,如果我们去改动SelectorStack3和SelecorCodeRing3的描述符中RPL的字段,变成0,发现这个程序pmtest5.asm并没有像我们想象的那样,进入ring3.显然,retf的指令没有被正确执行。想一想,为什么?
      pmtest5.b:在a的基础上,我们让程序在ring3代码段,进入死循环之前,调用调用门。在pmtest4的和a的基础上,我们需要做如下改动:改动调用门的描述符和选择符到ring3;添加TSS以便能够从低特权级别转移到高特权级,并进行相关初始化。      最后,我们让程序在调用门的目标段,也就是ring 0中,跳入局部任务。      总结一下,pmtest5的执行流程:实模式---保护模式32b代码段ring 0---通过retf进入ring 3的代码段——通过调用门,进入ring 0的目标代码段——通过jmp,跳转到LDT局部任务。

三、调试过程中发现的错误与分析

1)为什么要有RPL,我们都知道有“别名段”,那么别名段意味着什么呢?同一个段,可以对应着不同的selector,也就能够对应不同的RPL,这样就有利于实现自由的权限管理。 我们回忆,最开始的retf并没有生效,猜想到可能是权限的问题。我们从ring0 经过retf ring 3call,从ring 3--->ring 0,要求:CPL<=DPL_G,RPL<=RPL_G,CPL>=DPL_B;变化以后CPL=DPL_B=0retf是相反的过程,ring 0--->ring 3,要求:CPL<DPL_BRPL<DPL_B!!!注意,retf只能用于不同特权级之间,所以没有等于,这也就是为什么开始转移失败了。
2)堆栈切换的特权级检查
    更改TSS段中,将ss对应部分改成selectorstack3,然后就能在调试bochs的时候收到如下信息:
00082857633e[CPU0  ] call_protected: SS selector.rpl != CS descr.dpl    注明:开启出错信息的方法,在.bochsrc中添加对于log信息的注释#log
程序代码如下:
%include"head.inc"org 0100hjmp LABEL_BEGIN[SECTION .gdt];GDTbase,length,attrLABEL_GDT:      Descriptor         0,                0, 0 LABEL_DESC_NORMAL:Descriptor0,0ffffh,DA_DRWLABEL_DESC_CODE16:Descriptor0,0FFFFH,DA_CLABEL_DESC_DATA:Descriptor0,SegDataLen-1,DA_DRWLABEL_DESC_STACK:Descriptor0,TopOfStack,DA_DRWA+DA_32LABEL_DESC_CODE32:Descriptor0,SegCode32Len-1,DA_C+DA_32LABEL_DESC_CODE_DEST: Descriptor0,SegCodeDestLen-1,DA_C+DA_32LABEL_DESC_LDT:Descriptor0,LDTLen-1,DA_LDTLABEL_DESC_VIDEO:Descriptor0B8000h,0ffffh,DA_DRW + DA_DPL3LABEL_DESC_CODE_RING3:Descriptor0,SegCodeRing3Len-1,DA_C + DA_32 + DA_DPL3LABEL_DESC_STACK3:Descriptor  0,TopOfStack3,DA_DRWA + DA_32 + DA_DPL3LABEL_DESC_TSS:Descriptor0,TSSLen-1,DA_386TSSLABEL_CALL_GATE_TEST:GateSelectorCodeDest,0,0,DA_386CGate + DA_DPL3GdtLenequ$-LABEL_GDTGdtPtrdwGdtLen-1;注意,长度都是实际长度减1dd0;段基地址,注意,这里之所以没有直接制定,是因为还没有确定保护模式下gdt的基地址;选择子SelectorDataequLABEL_DESC_DATA-LABEL_GDTSelectorCode16equLABEL_DESC_CODE16-LABEL_GDTSelectorCode32equLABEL_DESC_CODE32-LABEL_GDTSelectorStackequLABEL_DESC_STACK-LABEL_GDT SelectorNormalequLABEL_DESC_NORMAL-LABEL_GDT SelectorLDTequLABEL_DESC_LDT-LABEL_GDT SelectorCodeDest equLABEL_DESC_CODE_DEST -LABEL_GDT SelectorCallGateTest equLABEL_CALL_GATE_TEST -LABEL_GDT +SA_RPL3SelectorVideoequLABEL_DESC_VIDEO-LABEL_GDTSelectorCodeRing3equLABEL_DESC_CODE_RING3 -LABEL_GDT+SA_RPL3 SelectorStack3equLABEL_DESC_STACK3-LABEL_GDT+SA_RPL3 SelectorTSSequLABEL_DESC_TSS-LABEL_GDT ;end of section gdt;--------------------------------------------------------------[SECTION .data][BITS 32]ALIGN 32LABEL_SEG_DATA:SPValueInRealModeldw0PMMessage:db"Coming into protect mode now !",0OffsetPMMessageequPMMessage - $$StrTest:db"ABCDEFGHIJKLMNOPQRSTUVWXYZ",0OffsetStrTestequStrTest - $$SegDataLenequ$ - LABEL_SEG_DATA ;end of section data;-----------------------------section:global stack------------------[SECTION .gs]ALIGN32[BITS 32]LABEL_SEG_STACK:times512db0TopOfStackequ$-LABEL_SEG_STACK-1;----------------------section:LDT----------------------------------[SECTION .ldt]align32[bits32]LABEL_SEG_LDT:LABEL_DESC_CODEA:Descriptor0,CodeALen -1,DA_C+DA_32LDTLenequ$- LABEL_SEG_LDTSelectorCodeA equLABEL_DESC_CODEA - LABEL_SEG_LDT + SA_TIL;end of ldt segment;-------------------------------section:codeA------------------------[section.codeA]align32[bits32]LABEL_SEG_CODEA:movax,SelectorVideomovgs,axmovah,0chmoval,'L'movedi,(2*80+0)*2mov[gs:edi],axjmpSelectorCode16:0CodeALen equ$-LABEL_SEG_CODEA ;end of secion codeA;------------------------------section:s16 begin---------------------[SECTION .s16][BITS 16]LABEL_BEGIN:xchg bx,bxmovax,csmovds,axmoves,axmovss,axmovsp,0100hmov[LABEL_GO_BACK_TO_REAL+3],axmov[SPValueInRealModel],sp;for segment code32xoreax,eaxmoveax,csshleax,4addeax,LABEL_SEG_CODE32;movword[LABEL_DESC_CODE32 +2],axshreax,16movbyte[LABEL_DESC_CODE32 + 4],almovbyte[LABEL_DESC_CODE32 + 7],ah;for segment code16xoreax,eaxmovax,csshleax,4addeax,LABEL_SEG_CODE16;movword[LABEL_DESC_CODE16 +2],axshreax,16movbyte[LABEL_DESC_CODE16 + 4],almovbyte[LABEL_DESC_CODE16 + 7],ah;for segment dataxoreax,eaxmoveax,dsshleax,4addeax,LABEL_SEG_DATA;movword[LABEL_DESC_DATA +2],axshreax,16movbyte[LABEL_DESC_DATA + 4],almovbyte[LABEL_DESC_DATA + 7],ah;for segment ldtxoreax,eaxmoveax,dsshleax,4addeax,LABEL_SEG_LDT;movword[LABEL_DESC_LDT +2],axshreax,16movbyte[LABEL_DESC_LDT + 4],almovbyte[LABEL_DESC_LDT + 7],ah;for segment codeAxoreax,eaxmoveax,dsshleax,4addeax,LABEL_SEG_CODEA;movword[LABEL_DESC_CODEA  +2],axshreax,16movbyte[LABEL_DESC_CODEA + 4],almovbyte[LABEL_DESC_CODEA + 7],ah;for segment stackxoreax,eaxmoveax,dsshleax,4addeax,LABEL_SEG_STACK;movword[LABEL_DESC_STACK +2],axshreax,16movbyte[LABEL_DESC_STACK+ 4],almovbyte[LABEL_DESC_STACK+ 7],ah;no need for video base;for segment dstcodexoreax,eaxmovax,csshleax,4addeax,LABEL_SEG_CODE_DESTmovword[LABEL_DESC_CODE_DEST +2],axshreax,16movbyte[LABEL_DESC_CODE_DEST +4],almovbyte[LABEL_DESC_CODE_DEST +7],ah;for segment code ring 3 xoreax,eaxmovax,csshleax,4addeax,LABEL_SEG_CODE_RING3movword[LABEL_DESC_CODE_RING3 +2],axshreax,16movbyte[LABEL_DESC_CODE_RING3 +4],almovbyte[LABEL_DESC_CODE_RING3 +7],ah;for segment code stack 3 xoreax,eaxmovax,csshleax,4addeax,LABEL_SEG_STACK3 movword[LABEL_DESC_STACK3 +2],axshreax,16movbyte[LABEL_DESC_STACK3 +4],almovbyte[LABEL_DESC_STACK3 +7],ah;for segment code stack 3 xoreax,eaxmovax,csshleax,4addeax,LABEL_SEG_TSSmovword[LABEL_DESC_TSS +2],axshreax,16movbyte[LABEL_DESC_TSS +4],almovbyte[LABEL_DESC_TSS +7],ahxor eax,eaxmovax,dsshleax,4addeax, LABEL_GDTmovdword[GdtPtr +2 ],eaxlgdt[GdtPtr]cliin al,92horal,02hout92h,almoveax,cr0oreax,1movcr0,eaxjmpdword SelectorCode32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LABEL_REAL_ENTRY:;come here from protect modelmovax,csmovds,axmoves,axmovss,axmovsp,[SPValueInRealModel]inal,92handal,11111101bout92h,alstimovax,4c00hint21h;end of section .s16;------------------------section:code32,start of protect model--------[SECTION .s32][BITS32]LABEL_SEG_CODE32:movax,SelectorVideomovgs,axmovax,SelectorDatamovds,axmovax,SelectorStackmovss,axmovesp,TopOfStackmovah,0chxoresi,esixoredi,edimovesi,OffsetPMMessagemovedi,(80*11+0)*2cld.loopPmMessage:lodsbtestal,aljz.endmov[gs:edi],axaddedi,2jmp.loopPmMessage.end:;callDispReturnmovax,SelectorTSSltraxpushSelectorStack3pushTopOfStack3pushSelectorCodeRing3push0xchgbx,bxretfxchgbx,bxcallSelectorCallGateTest:0;Load LDTmovax,SelectorLDTlldtaxjmpSelectorCodeA:0;function: read and print 8 byte from es:0TestRead:xoresi,esimovecx,8.loopForEightBype:moval,[es:esi]callDispALincesiloop.loopForEightBypecallDispReturnret; be sure of this;funtion:;write 8byte to es:OffsetStrTest;input:esTestWrite:pushesipushedixoresi,esixoredi,edimovesi,OffsetStrTestcld.loopForEightBype:lodsb;ds:si->altestal,aljz.endmov[es:edi],alincedijmp.loopForEightBype.end:popedipopesiret;funtion DispAL;display the number in AL;input: AL-the number;edi-the position to display;modified:ax,ediDispAL:pushecxpushedxmovah,0chmovdl,alshral,4movecx,2.begin:andal,01111bcmpal,9ja.moreThanNineaddal,'0'jmp.end.moreThanNine:subal,0ahaddal,'A'.end:mov[gs:edi],axaddedi,2moval,dlloop.beginaddedi,2popedxpopecxret;DispAL;function DispReturn;if edi=(a*80 + b)*2;then edi=(a*80 + 80)*2DispReturn:pusheaxpushebxmoveax,edimovbl,160divblandeax,0ffh;inceaxmovbl,160mulblmovedi,eaxpopebxpopeaxret;end for function DispReturnSegCode32Lenequ$-LABEL_SEG_CODE32;end of section .s32;---------------------section s16code,before return to real-----------[SECTION .s16code]ALIGN32[BITS 16]LABEL_SEG_CODE16:;return to real modelmovax,SelectorNormal movds,axmoves,axmovfs,axmovgs,axmovss,axmoveax,cr0andal,11111110bmovcr0,eaxLABEL_GO_BACK_TO_REAL:jmp0:LABEL_REAL_ENTRY;Code16Lenequ$-LABEL_SEG_CODE16;end of section s16code;---------------------section:sdest---------------------------------[section.sdest][bits32]LABEL_SEG_CODE_DEST:movax,SelectorVideomovgs,axmovedi,(80*12+0)*2movah,0chmoval,'C'mov[gs:edi],ax;load LDTmovax,SelectorLDTlldtaxjmpSelectorCodeA:0SegCodeDestLenequ$-LABEL_SEG_CODE_DEST;-------------------section stack ring3-----------------------------[section .s3]align 32[bits 32]LABEL_SEG_STACK3:times512db0TopOfStack3equ$-LABEL_SEG_STACK3-1;----------------------section CodeRing3-----------------------------[section .CodeRing3][bits32]LABEL_SEG_CODE_RING3:movax,SelectorVideomovgs,axmovedi,(80*14+0)*2movah,0chmoval,'3'mov[gs:edi],axcallSelectorCallGateTest:0jmp$SegCodeRing3Lenequ$-LABEL_SEG_CODE_RING3;------------------------section TSS-------------------------------[section .tss][bits 32]LABEL_SEG_TSS:dd0ddTopOfStackddSelectorStackdd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dd0dw0dw$-LABEL_SEG_TSS +2db0ffhTSSLenequ$ - LABEL_SEG_TSS 


0 0