摘要:本节,我们将通过分析pmtest4来实现利用调用门进行段间转移。
一、背景与原理
在汇编语言中,我们不能执行这样的指令:mov ds100h和movcs,ax;也就是说,段寄存器的值,是不能像通用寄存器一样,随意赋值的。具体的cs寄存器而言,它涉及到程序的控制转移,需要借助jmp、call、ret、sysenter,sysexit,int n,iret来实现,或者通过中断和异常来完成。我们知道,jmp和call指令,实现的跳转形式如下jmp selector:offset,其中,selector可以指向:
2)调用门描述符(->目标代码段选择子)
3)TSS(->目标代码段选择子)
4)任务门(->tss-->目标代码段)
其中第一类属于直接转移,剩下三种属于简介转移。
我们知道,通过jmp和call指令的一般转移,对于非一致性代码段,只能在同特权级之间进行。如果想在不同特权级之间自由切换,需要借助门描述符或者TSS。门描述符有任务门、中断门、陷阱门、异常门:其中中断门和陷阱门属于特殊的调用门。门描述符(目标选择子+入口地址+属性)的结构可以参考这里:http://blog.csdn.net/trochiluses/article/details/20312479
但是,call和jmp在控制转移的时候,作用不是完全相同的,如果代码段A通过调用门G转移到代码段B,call和jmp对应的特权级规则如下:
也就是说,通过call和调用门,可以实现从低特权级转移到高特权级。
2.程序流程概览:
pmtest4这个程序,我们主要将讲解如何通过调用门实现,低特权级代码向高特权级别的代码转移——就像鲤鱼越龙“门”。
保护模式下32b代码段:打印初始化字符,通过调用门,进入目标代码段32b
目标代码段:打印字符C,然后通过retf指令,返回32b代码段
32b代码段:通过jmp,进入LDT中的codeA段,、
LDT中的codeA段:打印字符L,通过jmp指令,回到16b代码段
16b代码段:回到实模式下
通过以上分析,我们知道:只需要在pmtest3的代码中添加目标代码段和门描述符就可以了。
二、代码解惑
按照以往的惯例,我们仍然采用分段的方式,分析代码:
1.GDT中注意:
上述多了一个调用门的选择子和描述符,它也被放在GDT之中
2.调用门目标段中的retf指令和ret指令有哪些不同?
retf指令的意义
ret 弹出一个参数,给ip,返回
retf 弹出2个参数,一个给 ip,一个给 cs
iref 弹出 3个参数,一个给 ip,一个 给 cs ,一个 给 flag标志位
他们都是返回调用点的,看你调用的时候,用的什么调用的,是 call 段内转移 ,还是call 段间转移,还是int 调用中断。
3.对于实模式第一个段的分析:
1)、为什么需要在这里初始化各个段描述符的相关属性呢?
答:开始,没有进入保护模式。同时CS的值已经被刷新。目前,程序运行的代码已经被dos加载到内存的相关部分,GDT的表才刚刚落户,所以我们才刚刚得到GDT的基地址,所以我们在这个时候刷新各个段的描述符属性。
2)、为何要加载GDT?
加载GDT是能够进行保护模式寻址的关键,不然我们仅仅知道段选择子,还是没法找到段描述符。GDTR中包含32b段基地址和16b段限长,这一点我们已经在gdt段中定义过了。
3)、重新回到实模式以后,是否有必要刷新ds、es、ss、sp等?
这是程序编写的一般流程,即使不刷新,也不一定会产生错误,我们可以亲自尝试一下。
4.保护模式
1)、这个段完成了什么功能?
显示初始化的字符串;通过调用门完成打印字母‘C’;通过跳入局部任务,打印字母‘L’;定义了一个局部程序DisplayReturn
2)、为什么要在jmp之前,设置ldt?
和GDT的设定是同样的道理。
实际代码如下:
- %include "head.inc"
- org 0100h
- jmp LABEL_BEGIN
- [SECTION .gdt]
- ;GDT base, length, attr
- LABEL_GDT: Descriptor 0, 0, 0
- LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW
- LABEL_DESC_CODE16: Descriptor 0, 0FFFFH, DA_C
- LABEL_DESC_DATA: Descriptor 0, SegDataLen-1, DA_DRW
- LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
- LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32
- LABEL_DESC_CODE_DEST: Descriptor 0, SegCodeDestLen-1,DA_C+DA_32
- LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT
- LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
- LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,0,0,DA_386CGate + DA_DPL0
- GdtLen equ $-LABEL_GDT
- GdtPtr dw GdtLen-1;注意,长度都是实际长度减1
- dd 0 ;段基地址,注意,这里之所以没有直接制定,是因为还没有确定保护模式下gdt的基地址
- ;选择子
- SelectorData equ LABEL_DESC_DATA - LABEL_GDT
- SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
- SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
- SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
- SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
- SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT
- SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT
- SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT
- SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
- ;end of section gdt
- ;--------------------------------------------------------------
- [SECTION .data]
- [BITS 32]
- ALIGN 32
- LABEL_SEG_DATA:
- SPValueInRealModel dw 0
- PMMessage: db "Coming into protect mode now !",0
- OffsetPMMessage equ PMMessage - $$
- StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
- OffsetStrTest equ StrTest - $$
- SegDataLen equ $ - LABEL_SEG_DATA
- ;end of section data
- ;-----------------------------section:global stack------------------
- [SECTION .gs]
- ALIGN 32
- [BITS 32]
- LABEL_SEG_STACK:
- times 512 db 0
- TopOfStack equ $-LABEL_SEG_STACK-1
- ;----------------------section:LDT----------------------------------
- [SECTION .ldt]
- align 32
- [bits 32]
- LABEL_SEG_LDT:
- LABEL_DESC_CODEA: Descriptor 0,CodeALen -1,DA_C+DA_32
- LDTLen equ $- LABEL_SEG_LDT
- SelectorCodeA equ LABEL_DESC_CODEA - LABEL_SEG_LDT + SA_TIL
- ;end of ldt segment
- ;-------------------------------section:codeA------------------------
- [section .codeA]
- align 32
- [bits 32]
- LABEL_SEG_CODEA:
- mov ax,SelectorVideo
- mov gs,ax
- mov ah,0ch
- mov al,'L'
- mov edi,(2*80+0)*2
- mov [gs:edi],ax
- jmp SelectorCode16:0
- CodeALen equ $-LABEL_SEG_CODEA
- ;end of secion codeA
- ;------------------------------section:s16 begin---------------------
- [SECTION .s16]
- [BITS 16]
- LABEL_BEGIN:
- xchg bx,bx
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,0100h
- mov [LABEL_GO_BACK_TO_REAL+3],ax
- mov [SPValueInRealModel],sp
- ;for segment code32
- xor eax,eax
- mov eax,cs
- shl eax,4
- add eax,LABEL_SEG_CODE32;
- mov word [LABEL_DESC_CODE32 +2],ax
- shr eax,16
- mov byte [LABEL_DESC_CODE32 + 4],al
- mov byte [LABEL_DESC_CODE32 + 7],ah
- ;for segment code16
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_CODE16;
- mov word [LABEL_DESC_CODE16 +2],ax
- shr eax,16
- mov byte [LABEL_DESC_CODE16 + 4],al
- mov byte [LABEL_DESC_CODE16 + 7],ah
- ;for segment data
- xor eax,eax
- mov eax,ds
- shl eax,4
- add eax,LABEL_SEG_DATA;
- mov word [LABEL_DESC_DATA +2],ax
- shr eax,16
- mov byte [LABEL_DESC_DATA + 4],al
- mov byte [LABEL_DESC_DATA + 7],ah
- ;for segment ldt
- xor eax,eax
- mov eax,ds
- shl eax,4
- add eax,LABEL_SEG_LDT;
- mov word [LABEL_DESC_LDT +2],ax
- shr eax,16
- mov byte [LABEL_DESC_LDT + 4],al
- mov byte [LABEL_DESC_LDT + 7],ah
- ;for segment codeA
- xor eax,eax
- mov eax,ds
- shl eax,4
- add eax,LABEL_SEG_CODEA;
- mov word [LABEL_DESC_CODEA +2],ax
- shr eax,16
- mov byte [LABEL_DESC_CODEA + 4],al
- mov byte [LABEL_DESC_CODEA + 7],ah
- ;for segment stack
- xor eax,eax
- mov eax,ds
- shl eax,4
- add eax,LABEL_SEG_STACK;
- mov word [LABEL_DESC_STACK +2],ax
- shr eax,16
- mov byte [LABEL_DESC_STACK+ 4],al
- mov byte [LABEL_DESC_STACK+ 7],ah
- ;no need for video base
- ;for segment dstcode
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_CODE_DEST
- mov word [LABEL_DESC_CODE_DEST +2],ax
- shr eax,16
- mov byte [LABEL_DESC_CODE_DEST +4],al
- mov byte [LABEL_DESC_CODE_DEST +7],ah
- xor eax,eax
- mov ax,ds
- shl eax,4
- add eax, LABEL_GDT
- mov dword [GdtPtr +2 ],eax
- lgdt [GdtPtr]
- cli
- in al,92h
- or al,02h
- out 92h,al
- mov eax,cr0
- or eax,1
- mov cr0,eax
- jmp dword SelectorCode32:0
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- LABEL_REAL_ENTRY: ;come here from protect model
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,[SPValueInRealModel]
- in al,92h
- and al,11111101b
- out 92h,al
- sti
- mov ax,4c00h
- int 21h
- ;end of section .s16
- ;------------------------section:code32,start of protect model--------
- [SECTION .s32]
- [BITS 32]
- LABEL_SEG_CODE32:
- mov ax,SelectorVideo
- mov gs,ax
- mov ax,SelectorData
- mov ds,ax
- mov ax,SelectorStack
- mov ss,ax
- mov esp,TopOfStack
- mov ah,0ch
- xor esi,esi
- xor edi,edi
- mov esi,OffsetPMMessage
- mov edi,(80*11+0)*2
- cld
- .loopPmMessage:
- lodsb
- test al,al
- jz .end
- mov [gs:edi],ax
- add edi,2
- jmp .loopPmMessage
- .end: ;
- call DispReturn
- call SelectorCallGateTest:0
- ;Load LDT
- mov ax,SelectorLDT
- lldt ax
- jmp SelectorCodeA:0
- ;function: read and print 8 byte from es:0
- TestRead:
- xor esi,esi
- mov ecx,8
- .loopForEightBype:
- mov al,[es:esi]
- call DispAL
- inc esi
- loop .loopForEightBype
- call DispReturn
- ret; be sure of this
- ;funtion:
- ;write 8byte to es:OffsetStrTest
- ;input:es
- TestWrite:
- push esi
- push edi
- xor esi,esi
- xor edi,edi
- mov esi,OffsetStrTest
- cld
- .loopForEightBype:
- lodsb ;ds:si->al
- test al,al
- jz .end
- mov [es:edi],al
- inc edi
- jmp .loopForEightBype
- .end:
- pop edi
- pop esi
- ret
- ;funtion DispAL
- ; display the number in AL
- ;input: AL-the number
- ; edi-the position to display
- ;modified:ax,edi
- DispAL:
- push ecx
- push edx
- mov ah,0ch
- mov dl,al
- shr al,4
- mov ecx,2
- .begin:
- and al,01111b
- cmp al,9
- ja .moreThanNine
- add al,'0'
- jmp .end
- .moreThanNine:
- sub al,0ah
- add al,'A'
- .end:
- mov [gs:edi],ax
- add edi,2
- mov al,dl
- loop .begin
- add edi,2
- pop edx
- pop ecx
- ret
- ;DispAL
- ;function DispReturn
- ;if edi=(a*80 + b)*2
- ;then edi=(a*80 + 80)*2
- DispReturn:
- push eax
- push ebx
- mov eax,edi
- mov bl,160
- div bl
- and eax,0ffh;
- inc eax
- mov bl,160
- mul bl
- mov edi,eax
- pop ebx
- pop eax
- ret
- ;end for function DispReturn
- SegCode32Len equ $-LABEL_SEG_CODE32
- ;end of section .s32
- ;---------------------section s16code,before return to real-----------
- [SECTION .s16code]
- ALIGN 32
- [BITS 16]
- LABEL_SEG_CODE16:
- ;return to real model
- mov ax,SelectorNormal
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov eax,cr0
- and al,11111110b
- mov cr0,eax
- LABEL_GO_BACK_TO_REAL:
- jmp 0:LABEL_REAL_ENTRY;
- Code16Len equ $-LABEL_SEG_CODE16
- ;end of section s16code
- ;---------------------section:sdest---------------------------------
- [section .sdest]
- [bits 32]
- LABEL_SEG_CODE_DEST:
- mov ax,SelectorVideo
- mov gs,ax
- mov edi,(80*12+0)*2
- mov ah,0ch
- mov al,'C'
- mov [gs:edi],ax
- retf
- SegCodeDestLen equ $-LABEL_SEG_CODE_DEST