博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
保护模式
阅读量:2399 次
发布时间:2019-05-10

本文共 47161 字,大约阅读时间需要 157 分钟。

WikiPlanner
computer
diary
emacs
misc 保护模式
┌┐┌┐∞
【 80386保护模式简介 】 ┘└┘└┘
--------------------------------------------------------------------------
在保护模式下有很多新的名词 ,包含 GDT.LDT.IDT 以及 CR0-CR3 ,笔者对保护
模式并不清楚 ,所以底下资料可能有错误。这里使用大量的线性记忆体观念 ,请您
一定要从头往後看 ,否则很可能会看不懂 ,且必须懂线性记忆体计算方式。
--------------------------------------------------------------------------
【 GDT 介绍 】
在真实模式下每个区段都等於64K ,可是保护模式下每个区段的大小却是可变动
的 ,每个区段有多大呢 ,就是由 GDT 来决定。
您可以用 SGDT CS:[BX] 的方式将 GDT 的值读出 ,它的长度为 6 BYTE ,底下
是笔者写的小程式读出。
XXXX:0000 FF 0F 00 20 C0 00
^^^^^^^^^^^GDT表所在的线性记忆体位址
^^^^^GDT表长度+1
将此表资料读出来.
X:00C02000 00 00 00 00 00 00 00 00-FF FF 00 A0 C2 9B 40 00 ........... B.@.
X:00C02010 FF FF B0 DD 01 93 40 00-FF FF E0 B3 00 9A 00 00 ..0]..@...`3....
X:00C02020 FF FF E0 B3 00 93 00 00-00 00 00 20 C1 82 80 00 ..`3....... A...
X:00C02030 00 00 00 20 C1 93 C0 00-00 00 00 20 C0 93 C0 00 ... A.@.... @.@.
X:00C02040 00 00 00 00 00 92 40 00-FF FF 00 80 0B 92 40 00 ......@.......@.
它所代表的意思是如下图所示:(每组 8 byte)
┌——————————————————————┐
1│ Limit bit 0-15 │ 0 byte
├——————————————————————┤
3│ Base bit 0-15 │ 2
├——————————┬———————————┤
5│ 存取权 │ Base bit 16-23 │ 4
├——————————┼———————————┤
7│ Base bit 24-31 │G│..│limit bit 16-19│ 6
└——————————┴———————————┘
"G"代表 Limit 的单位是 Byte 或 PAGE(4K)
所以....
#0000 Segment not present.
#0008 Base=00C2A000 Limit=0000FFFF Flags=9B USE32 Byte granularity
#0010 Base=0001DDB0 Limit=0000FFFF Flags=93 USE32 Byte granularity
#0018 Base=0000B3E0 Limit=0000FFFF Flags=9A USE16 Byte granularity
#0020 Base=0000B3E0 Limit=0000FFFF Flags=93 USE16 Byte granularity
#0028 Base=00C12000 Limit=00000000 Flags=82 Page granularity
#0030 Base=00C12000 Limit=00000000 Flags=93 USE32 Page granularity
#0038 Base=00C02000 Limit=00000000 Flags=93 USE32 Page granularity
#0040 Base=00000000 Limit=00000000 Flags=92 USE32 Byte granularity
#0048 Base=000B8000 Limit=0000FFFF Flags=92 USE32 Byte granularity
#0050 Base=0001F56C Limit=000007FF Flags=92 USE32 Byte granularity
#0058 Base=00000000 Limit=00000144 Flags=92 USE32 Page granularity
#0060 Base=00000000 Limit=00000144 Flags=93 USE32 Page granularity
#0068 Base=00127F48 Limit=0000C32F Flags=9B USE16 Byte granularity
#0070 Base=00134278 Limit=000028F7 Flags=93 USE16 Byte granularity
#0078 Base=00000000 Limit=00000000 Flags=92 USE16 Byte granularity
^^^^^Selector ^^存取权
Base 就是指这个Secector:00000000对应到线性记忆体的何处 ,也就是说将线性记
忆体从 Base 所指的地方开始长度为 Limit ,剪下来变成一个独立的区段 ,如果您
在该区段想看超过 LIMIT 长度的记忆体 ,则会发生保护模式错误...应用程式可拦
截所发生的中断适当的加以处理。
注意 ,Limit的单位可以是 byte ,也可以是page(4k) ,由 "G" 是否为 1 来决定
至於 Selector 的数值我猜想应该是被标上 8 的倍数吧 ,因为很多书都是如此介
绍它。
--------------------------------------------------------------------------
【 LDT 介绍 】
上面介绍了 GDT 可以设定很多个Secector ,而 LDT 则是在这些被定义出来
的Selector中再切割出更小的单元。也就是说 LDT 的资料长度只有 2 BYTE ,这
个值直接就是指 Selector。
※这个命令必需在最高权力下才能执行 ,所以笔者使用 386DEBUG 来执行 ,在传
统 Real Mode/V86 都不能执行。
C:/>386debug 386debug.exp (改过的.exp档)
000C:0002743C 660F0007 SLDT [EDI]
-T
-D EDI
0014:00000000 28 00 <-- LDT 所指的Selector为0028
根据 GDT 的资料查表得到下表 ,但是由於 0028 这段落禁止观看 ,所以我改看0030
的段落 ,因为它的 Base 是一样的。
#0028 Base=00C12000 Limit=00000000 Flags=82 Page granularity
#0030 Base=00C12000 Limit=00000000 Flags=93 USE32 Page granularity
-D 30:0
0030:00000000 FF 00 F0 CE 09 92 40 00-31 00 00 00 CA 9B C0 00 ..pN..@.1...J.@.
0030:00000010 31 00 00 00 CA 93 C0 00-FF FF 00 80 0B 92 40 00 1...J.@.......@.
0030:00000020 FF 00 F0 CE 09 92 40 00-4D 00 90 CE 09 92 40 00 ..pN..@.M..N..@.
0030:00000030 44 01 00 00 00 93 C0 00-00 00 00 00 00 92 40 00 D.....@.......@.
0030:00000040 FF FF 00 80 0B 92 40 00-00 00 00 00 00 92 40 00 ......@.......@.
0030:00000050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0030:00000060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0030:00000070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-DL 0
#0004 Base=0009CEF0 Limit=000000FF Flags=92 USE32 Byte granularity
#000C Base=00CA0000 Limit=00000031 Flags=9B USE32 Page granularity
#0014 Base=00CA0000 Limit=00000031 Flags=93 USE32 Page granularity
#001C Base=000B8000 Limit=0000FFFF Flags=92 USE32 Byte granularity
#0024 Base=0009CEF0 Limit=000000FF Flags=92 USE32 Byte granularity
#002C Base=0009CE90 Limit=0000004D Flags=92 USE32 Byte granularity
#0034 Base=00000000 Limit=00000144 Flags=93 USE32 Page granularity
#003C Base=00000000 Limit=00000000 Flags=92 USE32 Byte granularity
#0044 Base=000B8000 Limit=0000FFFF Flags=92 USE32 Byte granularity
#004C Base=00000000 Limit=00000000 Flags=92 USE32 Byte granularity
#0054 Segment not present.
#005C Segment not present.
#0064 Segment not present.
#006C Segment not present.
#0074 Segment not present.
#007C Segment not present.
--------------------------------------------------------------------------
【 IDT 介绍 】
在以往中断向量表都是用 4 byte 来表示 ,但是在保护模式下则由 8 byte 表
示 ,至於那几个 byte 表示什麽 ,笔者还未搞懂 ,底下只弄懂几个。
C:/>386debug 386debug.exp (改过的.exp档)
000C:00027434 660F010F SIDT [EDI]
-D EDI
0014:00000000 FF 07 6C F5 01 00 .. ..-.. .. .. .. .. .. .. ..
^^^^^^^^^^^线性记忆体位址
^^^^^长+1
因为该线性记忆体已对映到 50:0
#0050 Base=0001F56C Limit=000007FF Flags=92 USE32 Byte granularity
所以:
0050:00000000 00 34 08 00 00 EE 00 00-0A 34 08 00 00 EE 00 00 .4...n...4...n..
0050:00000010 14 34 08 00 00 EE 00 00-1E 34 08 00 00 EE 00 00 .4...n...4...n..
0050:00000020 28 34 08 00 00 EE 00 00-32 34 08 00 00 EE 00 00 (4...n..24...n..
0050:00000030 3C 34 08 00 00 EE 00 00-6C 16 C8 0F 00 8E 00 00 <4...n..F4...n..
0050:00000040 50 34 08 00 00 EE 00 00-5A 34 08 00 00 EE 00 00 P4...n..Z4...n..
0050:00000050 64 34 08 00 00 EE 00 00-6E 34 08 00 00 EE 00 00 d4...n..n4...n..
0050:00000060 78 34 08 00 00 EE 00 00-82 34 08 00 00 EE 00 00 x4...n...4...n..
0050:00000070 8C 34 08 00 00 EE 00 00-96 34 08 00 00 EE 00 00 .4...n...4...n..
-DI 0
#0000 Selector=0008 Offset=00003400 Flags=EE ;int_0
#0001 Selector=0008 Offset=0000340A Flags=EE ;int_1
#0002 Selector=0008 Offset=00003414 Flags=EE ;int_2
#0003 Selector=0008 Offset=0000341E Flags=EE ;int_3
#0004 Selector=0008 Offset=00003428 Flags=EE
#0005 Selector=0008 Offset=00003432 Flags=EE
#0006 Selector=0008 Offset=0000343C Flags=EE
#0007 Selector=0FC8 Offset=0000166C Flags=8E ;此处为Q387使用
#0008 Selector=0008 Offset=00003450 Flags=EE
#0009 Selector=0008 Offset=0000345A Flags=EE
#000A Selector=0008 Offset=00003464 Flags=EE
#000B Selector=0008 Offset=0000346E Flags=EE
#000C Selector=0008 Offset=00003478 Flags=EE
#000D Selector=0008 Offset=00003482 Flags=EE
#000E Selector=0008 Offset=0000348C Flags=EE
#000F Selector=0008 Offset=00003496 Flags=EE
请仔细看一看这个表的对应情形 ,笔者故意载入Q387 以便让 INT_7 的 Selector 与
众不同 ,让您更易判断中断表对应关系。
--------------------------------------------------------------------------
实例解说:
底下是读取 SoftICE INT_0 的程式码□例:
Load IDT
LDT = FF 07 12 C0 80 00 所以观看 0080C012 的记忆体
0080C012 47 2C 18 00 00 EE 00 00-4C 2C 18 00 00 EE 00 00 G,...□.L,...□.
0080C022 51 2C 18 00 00 EE 00 00-56 2C 18 00 00 EE 00 00 Q,...□.V,...□.
0080C032 5B 2C 18 00 00 EE 00 00-60 2C 18 00 00 EE 00 00 [,...□.`,...□.
0080C042 65 2C 18 00 00 EE 00 00-6A 2C 18 00 00 EE 00 00 e,...□.j,...□.
0080C052 6F 2C 18 00 00 EE 00 00-74 2C 18 00 00 EE 00 00 o,...□.t,...□.
0080C062 79 2C 18 00 00 EE 00 00-7E 2C 18 00 00 EE 00 00 y,...□.~,...□.
由此得知 INT_0 是放在 0018:00002C47 的位址 ,於是查GDT表..
Load GDT
GDT = C8 00 18 C8 80 00 所以观看 0080C818 的记忆体
0080C818 00 00 00 00 00 00 00 00-FF FF 10 11 83 93 00 00 ............儞..
0080C828 FF FF 00 6E 81 93 00 00-FF FF 00 6E 81 9B 00 00 ...n亾.....n仜..
0080C838 FF FF 00 00 00 93 CF 00-FF 7F 00 00 0B 92 00 00 .....摗?..?.
0080C848 FF 7F 00 80 0B 92 00 00-FF FF 00 00 0C 92 00 00 .?.?......?.
0080C858 FF FF F0 32 82 9A 00 00-FF FF 00 C0 80 93 C0 00 ..□倸.....□摗?nbsp;
0080C868 0F 00 00 C0 7F 92 C0 00-68 20 00 00 81 8B 00 00 ...□挕鮤 ..亱..
得到 Selector=0018=线性记忆体位址 816E00 处
於是我们就可以得知该中断程式放在 816E00:2C47 了 ,於是笔者把 816E00 的记忆体
搬到 8000:0000 ,然後用 DEBUG 来查看。
-u 8000:2c47
8000:2C47 6A00 PUSH 00
8000:2C49 E9F4D6 JMP 0340
8000:2C4C 6A01 PUSH 01
8000:2C4E E9C7D8 JMP 0518
8000:2C51 6A02 PUSH 02
8000:2C53 E98ADC JMP 08E0
8000:2C56 6A03 PUSH 03
8000:2C58 E9D6DC JMP 0931
8000:2C5B 6A04 PUSH 04
8000:2C5D E9E0D6 JMP 0340
8000:2C60 6A05 PUSH 05
8000:2C62 E9DBD6 JMP 0340
8000:2C65 6A06 PUSH 06
8000:2C67 E943DF JMP 0BAD
8000:2C6A 6A07 PUSH 07
8000:2C6C E975E0 JMP 0CE4
8000:2C6F 6A08 PUSH 08
8000:2C71 E97BE1 JMP 0DEF
8000:2C74 6A09 PUSH 09
8000:2C76 E91605 JMP 318F
8000:2C79 6A0A PUSH 0A
8000:2C7B E9C4D5 JMP 0242
8000:2C7E 6A0B PUSH 0B
8000:2C80 E9BFD5 JMP 0242
--------------------------------------------------------------------------
看了上面几个例子後 ,再来就是练习进入保护模式 ,底下的例子请勿载入 EMM 系
列的保护模式软体 ,以免等级权限相冲当机。
code segment
assume cs:code,ds:code
start proc near
jmp next
buffer1 db 18h,00h,00h,00h,00h,00h
; ---+--- ------+--------
; | |
; | |
; | GDT 表的记忆体位址
; |
; +----------GDT 表的长度
;
;
buffer2 db 000h,000h,000h,000h,000h,000h,000h,000h ;保留段
db 0ffh,0ffh,000h,000h,000h,09bh,000h,000h ;程式段code:0
db 0ffh,0ffh,000h,080h,00bh,093h,000h,000h ;萤幕段B800:0
db 0100h dup (0)
; ------+-------
; |
; |
; 线性记忆体位址
;
msg_1 db ????Enter Protect Mode !????
msg_2 db 0dh,0ah,????Return Real Mode !????,0dh,0ah,????$????
.386p
next :
mov ax,0600h ;
mov bx,0700h ;
mov cx,0000h ;
mov dx,184fh ;
int 10h ; CLS
mov ah,02h ;
mov bh,00h ;
mov dx,0100h ;
int 10h ;
mov ax,cs
mov ds,ax
mov es,ax
xor eax,eax
xor ebx,ebx
mov ax,cs
mov cl,04h
shl eax,cl
mov bx,offset buffer2
add eax,ebx
mov bx,offset buffer1+2
mov cs:[bx],eax ;GDT 位址设定
NOP
xor eax,eax
xor ebx,ebx
mov ax,cs
mov cl,04h
shl eax,cl
add eax,ebx
mov bx,offset buffer2
mov cs:[bx+0ah],eax ;GDT Table 设定
mov byte ptr cs:[bx+0dh],9bh ;存取权
mov ax,cs
mov ds,ax
mov es,ax
mov bx,offset buffer1
xor ecx,ecx
cli
cli
lgdt cs:[bx] ;载入GDT
mov eax,cr0
or eax,01h
mov cr0,eax
jmp protection ;进入保护模式
protection :
db 66h
mov ax,code
mov ds,ax
mov si,offset msg_1
mov bx,0010h
mov es,bx
mov di,0000h
mov cx,0014h
mov ah,70h
show :
cld ;将CS:MSG_1搬到 0010:00000000
lodsb ;(0010的区段=B8000 请参考GDT
stosw ; 表)
loop show ;
mov eax,cr0
and al,not 1
mov cr0,eax
db 0eah
dw real_mode,code ;返回真实模式
real_mode :
sti
mov ax,cs
mov ds,ax
mov ah,09h
mov dx,offset msg_2
int 21h
mov ax,4cffh
int 21h
start endp
code ends
end start
--------------------------------------------------------------------------
上面这个例子并没有设定 IDT (中断表) ,如果您要设定中断表的话 ,记得返回
真实模式时要还原 IDT 表.
--------------------------------------------------------------------------
如果您希望在载入 QEMM386 後还能正常进入保护模式的话 ,则必需透过 VCPI
的命令来切入保护模式 ,详情可翻阅 VCPI 的书籍。
-- 软蛀 --
┌┐┌┐∞
【 80386保护模式简介二 】 ┘└┘└┘
--------------------------------------------------------------------------
进入保护模式可以得到很多好处 ,让你的程式不再有 640K 限制 ,可以产生虚
拟记忆体、拦 I/O ,所有的应用程式读写系统暂存器 ,产生中断....都可以完全拦
截 ,而且 TSS 工作切换能力可以让你不占用 DOS 下的堆叠区 ,还有很多好处无法
一一叙述 ,因此由笔者来教你如何切入保护模式吧....从简单的开始。
在保护模式下有很多新的名词 ,包含 GDT.LDT.IDT 以及 CR0-CR3 ,笔者对保护
模式并不清楚 ,所以底下资料可能有错误。这里使用大量的线性记忆体观念 ,请您
一定要从头往後看 ,否则很可能会看不懂 ,且必须懂线性记忆体计算方式。
--------------------------------------------------------------------------
在进入保护模式时 ,首先你要先设定 GDT 表格 ,这个表格描述主要是来定义每
个段落的记忆体起始位址与长度、存取权。 这个情形就好像传统 REAL MODE 那
样 ,REAL MODE 每个区段的记忆体开始位址与长度都已经由 CPU 定死了 ,比如说当
我们看到 1000:0000 ,其实它就是指记忆体的第 64K 位址 ,同理看到 2000:0000
就代表是第 128K 位址 ,定址方式就是 Segment:Offset。
而保护模式的段落起始位址与长度却是可程式变动的 ,这个可变动的段落起始
位址与长度就是由 GDT 来设定的 ,根据这个值 ,你可以将每个段落改成64K ,或是
1MB...甚至更多 ,可任意设定 1BYTE~4GB ,所以定址方式变成 Selector:Offset
或许您曾用过 386DEBUG ,看过定址方式为 XXXX:XXXXXXXX ,根据後面这八位数 ,
理论上可定址到 4GB ,其实这是不行的 ,如果你在 GDT 表格设定的记忆体为 1K
则你尝试 DUMP 1K 以後的记忆体都会看到 FF ,就好像没有记忆体一般。
---------------------------------------------------------------------------
Gdtadds dw 0018h,GdtTable 32 位元线性位址
GdtTable db 00h,00h,00h,00h,00h,00h,00h,00h ;
db 7fh,ffh,00h,08h,0bh,93h,00h,00h ;B800:0 32K
db ffh,ffh,56h,34h,12h,93h,0fh,78h ;
^^^^^^^ ^^^^^^^^^^^ ^^^ ^^^ ^^^
↑ ↑ ↑ ↑ ↑
│ │ └——————93=可读写区段
│ │ │ │
└———————————┴————0fffff+1=1MB (Limits)
│ │
└—————————┴——12345678 (Base)
它所代表的意思是如下图所示:(每组 8 byte)
┌——————————————————————┐
1│ Limit bit 0-15 │ 0 byte
├——————————————————————┤
3│ Base bit 0-15 │ 2
├——————————┬———————————┤
5│ 存取权 │ Base bit 16-23 │ 4
├——————————┼———————————┤
7│ Base bit 24-31 │G│..│limit bit 16-19│ 6
└——————————┴———————————┘
"G"代表 Limit 的单位是 Byte 或 PAGE(4K)
所以....
#0000 Segment not present.
#0008 Base=000B8000 Limit=0000FFFF Flags=93 USE32 Byte granularity
#0010 Base=12345678 Limit=000FFFFF Flags=93 USE32 Byte granularity
^^^^^Selector ^^存取权
设定完後 ,就是切入保护模式 ,只要将 CR0 暂存器的 Bit0 设为 ????1???? ,再用一个
跳越指令 ,就进入保护模式了。
---------------------------------------------------------------------------
讲不懂没关系 ,现在来看看实例 ,这样比较容易懂..
C:/>386MICE SAMPLE.EXE
-G 1AE
EAX=00044A1C EBX=00000003 ECX=00000000 EDX=00000100
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0000FFFE
DS=4A1C SS=4A1C ES=4A1C FS=4A0C GS=4A0C
-U 1AE
4A1C:000001AE CLI
4A1C:000001AF LGDT CS:[BX] ——→ DUMP CS:[BX] ——→
4A1C:00000003 18 00 C9 A1 04 00 <--- GDT 表放在 0004A1C9 长度 18h
4A1C:000001B3 MOV
EAX,CR0 │
4A1C:000001B6 OR
EAX,1 ↓
4A1C:000001BA MOV CR0,EAX
4A1C:00000009 00 00 00 00 00 00 00 00-FF FF C0 A1 04 9B 00-00
4A1C:000001BD JMP 01C0
4A1C:00000010 FF FF 00 80 0B 93 00 00 (GDT表)
4A1C:000001BF NOP
4A1C:000001C0 MOV AX,0008H
4A1C:000001C3 MOV DS,AX
4A1C:000001C5 MOV WORD PTR DS:[0000H],7041h
由上面的 GDT 表知道 此程式共规划了三个区段 ,其中 0000 区段是不使用
故区段的表示方式如下:
#0000 Segment not present.
#0008 Base=0004A1C0 Limit=0000FFFF Flags=9B USE32 Byte granularity
#0010 Base=000B8000 Limit=0000FFFF Flags=93 USE32 Byte granularity
-G 1BD
EAX=00000001 EBX=00000003 ECX=00000000 EDX=00000100
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0000FFFE
DS=4A1C SS=4A1C ES=4A1C FS=4A0C GS=4A0C
4A1C:000001BD JMP 01C0
-T (这儿就算是进入保护模式了)
EAX=00000001 EBX=00000003 ECX=00000000 EDX=00000100
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0000FFFE
DS=0000 SS=0000 ES=0000 FS=0000 GS=0000
0000:000001C0 MOV AX,0008H
0000:000001C3 MOV DS,AX
0000:000001C5 MOV WORD PTR DS:[0000H],7041h
因为进入保护模式 ,所以 Selector 的区段应该要去查 GDT 表格 ,这个例
子的 Selector 0010 的 Base = B8000 ,所以...
保护模式下的 0010:00000000 = 真实模式下的 B800:0000 ,这样您懂了吗?
在行号 1C5 的位址有一行写入 7041 的动作 ,就是在萤幕秀 ????A???? 反白字元.
最後要进入真实模式时 ,只要将 CR0 的 Bit0 设为 ????0???? ,再用一个跳越指
令就回到真实模式了..
--------------------------------------------------------------------------
後记:
若有问题 ,烦在本站『站内信箱』留信给我....尽量避免使用网路信 ,
且尽快提出 ,否则接下来的课程将会更难懂 ,如果你是完全不懂 ,麻烦也留
信给我 ,我会再把这一章节再细细重新说明。至於对组合语言不懂 ,或是对
保护模式没兴趣的人 ,本人就帮不上忙了。
A:下一次笔者将继续解说 V86 模式下的工作切换
B:等级权限 / 拦 I/O
┌———————————————————————————————————┐
│ Soft Bugger 软体蛀虫 90:90/2 软体新技术的实行者 │
│ BBS:02-5955461 24HR ID:Werong Ho -- 软蛀 -- │
└———————————————————————————————————┘
┌┐┌┐∞
【 80386 保护模式简介四 】 ┘└┘└┘
==========================================================================
前言:
本集的内容主要是由第三集改进解释的方式 ,重新再介绍一次 V86 拦 I/O 的
动作 ,因为好像有不少人对於第三集的解释方式一知半解....可能是我写的还不是
很好吧 ,所以重写一次。
--------------------------------------------------------------------------
┌————————┐
│80386 暂存器介绍│
└————————┘
80386 的暂存器除了扩充成 32 位元以外 ,亦增加了许多新的暂存器 ,除了一般
使用者暂存器(AX.BX....SI.DI)各位已经了解以外 ,也增加了系统暂存器、以及扩充
的旗标 暂存器....等等。
A.使用者暂存器 → EAX.EBX.ECX.EDX.ESI,EDI.EBP.ESP
B.指令指标暂存器 → CS.EIP 两个暂存器
C.区段暂存器 → CS.SS.DS.ES.FS.GS
虽然 80386 已经进入 32 位元时代 ,但是这几个暂存器仍是 16 位元的 ,且多
了 FS.GS 两个暂存器 ,这两个暂存器并无特殊意义 ,各位可以把它当做 DS.ES
来看待。
D.系统暂存器
A. 控制暂存器:包含 CR0.CR2.CR3 三个 ,各位可能看到漏了一个 CR1 ,原因是
386.486.586 都没有此暂存器
B. 除错暂存器:包含 DR0.DR1.DR2.DR3.DR6.DR7 共六个 ,也是漏了 DR4.DR5 两
个 ,原因同上
C. 保护模式分段控制:IDT.GDT.LDT.TR
注:自 586 起新增 CR4.DR4.DR5 系统暂存器
--------------------------------------------------------------------------
┌————┐
│工作切换│
└————┘
当您设定某些系统暂存器以後 ,电脑并不会马上反应所设定的工作 ,必需透过工
作切换的动作才会起动 ,这个工作切换很难用文字表达 ,笔者认为工作切换就是等级
切换的动作。可造成工作切换的指令包含 INT_X 、JMP TSS区段...等 ,其中 INT_X
是指在 V86下的程式若发生中断 ,电脑会自动切换至保护模式 ,并呼叫保护模式下的
中断处理程式 ,再由保护模式下的程式决定是否呼叫原来 V86 下的中断向量表 ,而
这切换到保护模式、再切回 V86 下 , 共发生两次工作切换......
┌——┐
│等级│
└——┘
保护模式下 ,等级共有 0.1.2.3 四个等级 ,其中第0级等级最高 ,第3级最低 ,
而0级因为是最高等级 ,因此也有人称为「特权等级」 ,而应用程式的等级为多少呢?
这表示在 EFLAG 的 IOPL (BIT12.13) 里 ,在 V86 下的等级多半是最低的第3级 ,所
以此值为 ????11????。
或许各位会认为自己去修改这个旗标将自己的等级调高就好了 ,事实上改好後还
要经过工作切换的动作 ,等级才能被修改 ,而经过工作切换的动作後 ,你的程式控制
权将转交给别人 ;再简单的说 ,发生 INT_X 时 ,电脑会将等级切换成最高等级(事实
上是由中断表上决定的) ,并进入保护模式 ,之後保护模式的程式再来决定将使用者的
EFLAG 切成什麽等级 ,然後再 IRETD切回 V86 ,於是应用程式根本抢不过最早进入保
护模式的家伙。(这样你有办法在V86下抢到最高等级吗....不可能嘛)
等级的高低可以决定自己有多少控制权 ,例如等级最高的人才可以读写系统暂存
器 ,其馀的人想读写系统暂存器都会发生 General Protection Error 0D ,你可以把
它想像成等级不够 ,却要读取系统资源 ,会发生 INT_0D ,而原本这行指令将不会被
执行 ,而堆叠里所摆的 EIP 值也停在这行上面 ,如果 INT_0D 的处理程式不去跳过
这个指令 ,则会永远停在这个指令里(形同当机)。 ※注二
在 V86 下发生中断时 ,会自动 PUSH EIP.CS.EFLAG.ESP.SS......数个暂存器 ,
并自动将 SS.ESP 的值替换 ,以免发生中断时 ,会动用到 V86 的堆叠 ,可是如果发
生的是 General Protection Error(俗称异常),则会在 PUSH EIP 之前再多摆入一个
DWORD 的错误代码 ,如果您的程式在 IRETD 前不减去这个可能存在的错误代码 ,则
会发生不可预知的後果。这也是保护模式下的程式不好写的原因之一。 而 SS 与ESP
所替换的值 ,则是最初进入保护模式後 ,由最高等级的人决定的(摆於TSS区段)。
第二集里笔者有介绍 GDT 表 ,其中有个 93 代表可写区段 ,如果设成 89 ,则表
示此区段是 TSS 表格 ,再由 TR 暂存器来指定发生中断时 ,取用那一个区段的表格.
举例来说 ,下面是 GDT 表格
gdttab db 000h,000h,000h,000h,000h,000h,000h,000h ;00
db 0ffh,0ffh,000h,000h,000h,09bh,000h,000h ;08
db 0ffh,0ffh,000h,000h,000h,093h,08fh,000h ;10
db 0ffh,0ffh,000h,000h,000h,089h,000h,000h ;18
db 0ffh,0ffh,000h,000h,000h,089h,000h,000h ;20
db 0ffh,0ffh,000h,000h,000h,093h,000h,000h ;28
db 0ffh,007h,000h,000h,000h,093h,000h,000h ;30
db 0ffh,0ffh,000h,080h,00bh,093h,000h,000h ;38
db 0ffh,0ffh,000h,000h,000h,093h,000h,000h ;40
我们可以看到 18.20 两个 Selector 正好就是 89h ,也就是说它们俩个都可以是
TSS 描述表格 ,如果 MOV AX,0018、LTR AX ,则表示发生工作切换时 ,取用 0018 的
描述表格。
注一:General Protection Error 发生後会去呼叫该中断 ,但是一般产生中断只会
存入 EIP.CS.EFLAG.ESP.SS.... ,但是发生 General Protection Error 的话
堆叠会存入 错误代码.EIP.CS.EFLAG.ESP.SS.....
堆叠多存放了一个"错误代码" ,记得在切回 V86 前要将此值减去唷 !!
注二:前面说发生 GP Error #0D 等於呼叫 INT_0D ,这只能说是半对 ,原因『注一』
已说明 ,不再重复。
--------------------------------------------------------------------------
┌——————┐
│TSS 表格简介│
└——————┘
TSS 也有人称为「工作切换」 ,其表格设定如下 ,详情可看书比较详细。
tssltr dd 00000000h
dd 0000ff00h ;ESP
dw 0028h,0000h ;SS.0
dd 0,0,0,0,0
dw offset enter_v86,0000h ;EIP
dd 00000200h ;EFlag
dd 0,0,0,0
dd 0000ff00h ;ESP
dd 0,0,0
dw 0010h,0000h ;ES.0
dw 0008h,0000h ;CS.0
dw 0028h,0000h ;SS.0
dw 0010h,0000h ;DS,0
dw 0010h,0000h ;FS.0
dw 0010h,0000h ;GS.0
dw 0000h,0000h ;LDT.0
dw 0000h,0068h ;0.IOMAP起点
db 1000h dup (0) ;4K IOMAP 表
dw 0ffffh
如果您的程式使用 JMP XXXX:YYYYYYYY 的方式跳到本区节的话 ,原本指定的
YYYYYYYY 将无用途 ,因为所有的暂存器将被替换成此表格的数值(含CS.EIP) ,并
完成等级切换的动作。
--------------------------------------------------------------------------
┌———————┐
│进入 V86 模式│
└———————┘
cli
lgdt fword ptr cs:gdtadds
lidt fword ptr cs:idtadds
mov eax,cr0
or al,01h
mov cr0,eax
mov bx,0018h
ltr bx ;发生工作切换时 ,SS:ESP 将参考 0018 的区段表格
jmp 0020h:0000h ;进入工作切换 ,会跳到此表格内指定的 CS:EIP
(LTR.JMP 不可指向同一表格)
enter_v86 : ;假设您已将 CS:EIP 指向此处继续执行
xor eax,eax
mov ax,code
push eax ;GS
push eax ;FS
push eax ;DS
push eax ;ES
push eax ;SS
mov ax,0f000h
push eax ;ESP
mov eax,00023000h ;设定VM=1 等级=3
push eax ;Eflag
xor eax,eax
mov ax,code
push eax ;CS
mov ax,offset return_dos
push eax ;EIP
clts ;将 387 切换成 32 位元模式
iretd ;回到 V86 (共弹出24h BYTE)
紧接著就程式回到 V86 下继续执行著...
--------------------------------------------------------------------------
┌————————┐
│中断向量表的处理│
└————————┘
在 V86 下产生中断後 ,电脑会自动切回保护模式 ,并从 LTR 所指定的位址取得
TSS 表格 ,然後以表格内的资料重新设定 SS.ESP ,然後把 V86 下的各暂存器值摆入
此堆叠内 ,在此需注意的是它摆放在堆叠的资料是32位元方式 ,所以对於 DS.ES....
这类16位元暂存器摆於堆叠 ,不足部份补 ????0000???? ,用以凑足 32Bit。
简单来说 ,在真实模式下或 V86下使用一组 SS:SP ,一但透过中断进入保护模式
後 ,原先的 SS:SP 暂存器将被置换另一组数值(定义於TSS表) ,然後再将大部份的暂
存器值摆放在这个新堆叠区内(包含SS.ESP) ,直到执行 IRETD 回到 V86 後 ,SS:ESP
暂存器值才会从原先堆叠中弹出。换句话说 ,在 V86下发生中断会使用自己的堆叠 ,
而不会破坏 V86 的堆叠区 ,这也就是为什麽像 S-ICE 除错程式执行 ????T???? 的命令却
不会更动 User 的堆叠资料。
存於保护模式堆叠内的 CS:EIP 会指向 V86下 "INT_X" 的下一行 ,而 SS:SP 值
却仍维持原来数值(不像以往产生中断会自动减6 ,然後堆叠内摆入 FLAG.CS.IP),因
此保护模式下处理中断的程式必需修改 V86 的 SP 值减6 ,并将 V86 的 CS.IP.FLAG
摆入 V86 的堆叠 ,最後再去查 0000:0000 的表格 ,将保护模式堆叠内的 CS:EIP 值
修改、指向此中断向量表 ,最後保护模式的程式执行 IRETD 返回 V86 後 ,跳到 V86
下的中断所指位址 ,这样便完成整个模拟 DOS 中断的效果。
PS:保护模式下堆叠会存放 EFLAG.EIP.ECS.ESP.SS...... 忘了 ,比 Real Mode 还要
多好多喔。
底下仅列出部份中断的处理方式....您必需处理 256 个中断表。
new_20 :
push 0020h
jmp int_emu
new_21 :
push 0021h
jmp int_emu
new_22 :
push 0022h
jmp int_emu
new_23 :
push 0023h
jmp int_emu
int_emu :
push bp
mov bp,sp
add bp,04h
push eax
push ebx
mov ax,0010h ;
mov ds,ax ;(Selector 0010h 的 Base=0)
mov ax,ss:[bp+0ch] ;
sub ax,06h ;改V86的SP-6
mov ss:[bp+0ch],ax ;
xor eax,eax ;
xor ebx,ebx ;修改V86下的SS:SP ,帮它摆入
mov ax,ss:[bp+10h] ;INT_X 後的下一行位址 ,供V86
shl eax,04h ;下的程式IRET返回INT_X的下一行用
mov bx,ss:[bp+0ch] ;
add ebx,eax ;
mov ax,ss:[bp+00h] ;
mov ds:[ebx],ax ;
mov ax,ss:[bp+04h] ;
mov ds:[ebx+02h],ax ;
mov ax,ss:[bp+08h] ;
mov ds:[ebx+04h],ax ;
nop
xor ebx,ebx ;
mov bx,ss:[bp-02h] ;
shl ebx,02h ;
mov ax,ds:[ebx] ;IRETD 後到V86中断表所指的位址继续执行
mov ss:[bp+00h],ax ;(查 0000:0000 的中断表)
mov ax,ds:[ebx+02h] ;
mov ss:[bp+04h],ax ;
mov eax,ss:[bp+08h]
or eax,00032000h ;等级=3 VM=1
and eax,0fffffeffh ;关闭????T????旗标
mov ss:[bp+08h],eax
pop ebx
pop eax
pop bp
add sp,02h
iretd
--------------------------------------------------------------------------
┌——————┐
│拦 I/O 能力│
└——————┘
TSS 表格内除了可定义产生工作切换後 ,SS.ESP.DS.ES....各暂存器替换值 ,也
可以开一块记忆体做 IOMAP ,这块记忆体每个 Bit 代表一个 PORT ,一般习惯是开4K
大小 (65536埠),当某位元设定为 ????1???? 後 ,只要不是最高等级的人去读写此埠 ,都会
发生 GP Err #0D ,当然在最低等级的 V86 程式也不例外 ,发生此错误後 ,就形同拦
到 I/O 动作了 ,紧接著透过最高等级的处理程式去判断发生错误的原因 ,例如判断
程式码是否为 『EC IN AL,DX』、『EE OUT DX,AL』 ,或是其它程式码 ,就可以分
辨发生的原因是读或写产生的 ,拦到 I/O 後 ,你是否会写骗 I/O 的程式 ?
以 S-ICE 的拦 I/O 能力为例 ,它先使用 IO-MAP 的方式去拦 I/O ,然後再判别
"EE.E4.EC.E6...." 等等程式码。
注:IOMAP 表是也是 TSS 表格的一部份。
--------------------------------------------------------------------------
┌———————┐
│相容性的处理一│ 系统暂存器的相容处理法
└———————┘
或许您曾经在挂入 QEMM386、EMM386 之後 ,在 V86 下执行 MOV EAX,CR0 的指
令 ,但是前面笔者提到读写系统暂存器必需在最高等级才可执行 ,为什麽 User 仍可
在最低等级下执行本命令呢 ? 底下是欺骗方式。
(User) V86 下执行 MOV EAX,CR0
发生 General Protection 0D
CPU 自动切入保护模式 ,并执行 INT_0D 的处理程式
(堆叠里多储存了错误代码 DWORD)
(EMM) 检查发生错误的原因
读取 EAX,CR0 (因此时已是最高等级 ,本行可以正确执行)
(EMM) 修改堆叠内的 EIP 值 ,指向下一行指令
(EMM) 修改使用者等级 3 / 设定 VM 旗标等於 1
(EMM) ESP 值扣掉错误代码 4byte
(EMM) IRETD 切回 V86
(User) 使用者取得 EAX 的数值
由於程式有一大半在保护模式下执行 ,所以使用者根本感觉不到 ,只知道自己真
的读到系统暂存器。这便是 EMM 系的欺骗手段。
本来标准的程式是不会在 V86 下读写系统暂存器 ,可是确实也有不正常的程式
是这样搞的 ,例如倚天中文会执行 MOV EAX,CR3 ,或是一些保护程式会写入除错暂存
器 (DRx)。所以为了相容性 ,这些最好做进去。
注:判别发生的原因也可以利用判断 I/O 的那种方法 ,但写起来很麻烦。
--------------------------------------------------------------------------
┌———————┐
│相容性的处理二│ HIMEM.SYS
└———————┘
HIMEM.SYS 是一个可以控制 1MB 以外记忆体的程式 ,不过之前笔者有提过 ,要
读写超过 1MB 以外的记忆体必需进入保护模式才行(据说有後门可用) ,那麽载入自
己的保护模式程式後 ,再遇到呼叫 HIMEM.SYS 去搬移 1MB 以外的记忆体 ,电脑竟然
会发生 GP Err #0D ,原来这是因为 HIMEM.SYS 在执行搬移记忆体的命令後会去呼叫
BIOS 的 AH=87h INT_15h 去搬记忆体 ,换句话说就是因为这个 BIOS 中断会进入保
护模式去搬记忆体 ,所以才会造成当机 ,因此你的保护模式介面程式必需去模拟这个
BIOS 函式 ,就可以与 HIMEM.SYS 相容了。
注:BIOS AH=87h INT_15h 会重设 GDT.IDT 表 ,然後进入保护模式去搬记忆体 ,然後
就当在 LIDT 或 LGDT 的命令上。
另外如果你的程式摆在 1MB 以上的记忆体位址去执行 ,还会有另一个问题产生 ,
不过如果你已经学会上面的这些功能 ,再尝试去写个程式去试试 ,你自然会知道
它会发生什麽问题 ,解决的办法也很简单 ,你一定会解决。
--------------------------------------------------------------------------
切入 V86 後 ,还有很多问题要处理 ,不过上面提到的两个问题如果你都能处理
的话 ,基本上就不会有其它大问题 ,等你会进入保护模式後 ,再来学习 VCPI、DPMI
就很简单了。
如果各位会切入保护模式的话 ,接下来应该是学习 VCPI 的切入方式 ,虽然有很
多书籍有介绍 ,但是要真正了解并不容易。建议各位去买套大宇出品的激斗战士、战
国策 ,它的外加保护就是切入保护模式的最佳范例 ,包含透过 VCPI、自己切286.386
保护模式 ,虽然这是不道德的行为 ,但是却是一个最佳范本。花个五百块学新知绝对
划算。
有关保护模式的部份笔者暂时介绍到此 ,下一集笔者将为您介绍虚拟记忆体 ,如
果情况允许 ,还会顺便介绍更难懂的分页机能。教各位如何写出类似 S-ICE 的 BPR
功能 ,锁定某一块记忆体的读写状态。
┌———————————————————————————————————┐
│ Soft Bugger 软体蛀虫 90:90/2 软体新技术的实行者 │
│ BBS:02-5955461 24HR ID:Werong Ho -- 软蛀 -- │
└———————————————————————————————————┘
┌┐┌┐∞
【 80386 保护模式简介五 】 ┘└┘└┘
==========================================================================
前言:
底下是进入保护模式、进入 V86 的精简范例 ,执行前请确定 CPU 是处在真实模
式 ,程式码因为用到 386 指令 ,请用 TASM 3.1 来编译。
--------------------------------------------------------------------------
┌——————┐
│进入保护模式│
└——————┘
进入保护模式的程式范例 ,其目地是进入保护模式 ,并在保护模式下用绝对记忆
体读写的方式 ,直接将 ????Protection Mode !???? 字串写入 Video Ram (B800:0000) ,
本程式以最精简的方式撰写 ,没有任何错误处理 ,因此请确定电脑现在处在真实模式
下才可执行本程式。(禁挂 EMM 系保护模式软体)
程式流程如下:(底下所指记忆体位址皆为 32bit 绝对位址)
1. 设定 GDTtab 表所在的记忆体位址填入 GDTadds
2. 设定 Selector 0008 的记忆体起始位址就是现在 CS 的记忆体位址
设定 Selector 0010 的记忆体起始位址就是现在 CS 的记忆体位址
Selector 0018 的记忆体起始位址就是 000B8000 = (B800:0000)
3. 执行 LGDT FWORD PTR CS:GDTadds 告诉 CPU 一但进入保护模式 ,各
区段的记忆体起始位址、长度
4. 设定 CR0 的 Bit0 = ????1???? ,并透过 JMP 指令进入保护模式
※ 进入保护模式後 ,DS.ES.SS.CS.GS.FS 等等暂存器定址方式不再
是 Segment ,而变成 Selector
5. 秀字 将 0010:MSG_1 搬到 0018:0000
意即将 ????Protection Mode !???? 字串搬到 Video Ram 去
6. 设定 CR0 的 Bit0 = ????0???? ,并透过 JMP 指令回到真实模式
※ 回到真实模式後 ,DS.ES.SS.CS.GS.FS 等等暂存器定址方式不再
是 Selector ,而变成 Segment
5. 秀字 将 CS:MSG_2 搬到 B800:00A0
意即将 ????Return Real Mode !???? 字串搬到 Video Ram 去
6. 结束程式
----------------------------- P.ASM ------------------------------------
code segment
assume cs:code,ds:code
.386p
start proc near
jmp next
gdtadds dw 001fh,0000h,0000h
gdttab db 000h,000h,00h,00h,00h,00h,00h,00h ;00 Null
db 0ffh,0ffh,00h,00h,00h,9bh,00h,00h ;08 PRG Seg
db 0ffh,0ffh,00h,00h,00h,93h,00h,00h ;10 PRG Seg
db 0ffh,0ffh,00h,80h,0bh,93h,00h,00h ;18 B8000
msg_1 db ????Protection Mode !????
msg_2 db ????Return Real Mode !????
next :
xor eax,eax ;
xor ebx,ebx ;
mov ax,cs ;设定 GDTadds
shl eax,04h ;
mov bx,offset gdttab ;
add eax,ebx ;
mov di,offset gdtadds+02h ;
mov cs:[di],eax ;
NOP
xor eax,eax ;
xor ebx,ebx ;
mov ax,cs ;
shl eax,04h ;
mov di,offset gdttab+08h ;设定 GDTtab 内的
mov si,offset gdttab+10h ;Selector 0008 及 0010
mov cs:[di+02h],ax ;两个段落的记忆体起始位址
mov cs:[si+02h],ax ;
shr eax,10h ;
mov cs:[di+04h],al ;
mov cs:[si+04h],al ;
mov cs:[di+07h],ah ;
mov cs:[si+07h],ah ;
NOP
cli
lgdt fword ptr cs:gdtadds ;载入 GDT 表格
mov eax,cr0 ;
or al,01h ;
mov cr0,eax ;
jmp protection_mode ;进入保护模式
protection_mode : ;
mov ax,0010h ;
mov ds,ax ;
mov si,offset msg_1 ;
mov ax,0018h ;将 0010:MSG_1 搬到 0018:0000
mov es,ax ;
mov di,0000h ;
mov ah,70h ;
mov cx,0011h ;
cld ;
L1 : ;
lodsb ;
stosw ;
loop L1 ;
NOP
mov eax,cr0 ;
and al,0feh ;
mov cr0,eax ;回到真实模式
jmp return_real_mode ;
return_real_mode : ;
sti
mov ax,cs ;
mov ds,ax ;
mov si,offset msg_2 ;
mov ax,0b800h ;
mov es,ax ;将 CS:MSG_2 搬到 B800:00A0
mov di,00a0h ;
mov ah,70h ;
mov cx,0012h ;
cld ;
L2 : ;
lodsb ;
stosw ;
loop L2 ;
mov ax,4cffh
int 21h
start endp
code ends
end start
--------------------------------------------------------------------------
因为保护模式下不能呼叫真实模式下的中断 ,所以笔者以直接填写显示卡记忆体
的方式秀字。这是一个简单、尚未使用中断向量表的范例。
注: 所谓一山不容二虎 ,如果已载入其它保护模式的程式 ,那本程式将会与它打架 ,
造成电脑当机。
┌————————┐
│进入虚拟 86 模式│ 为求精简 ,本程式毫无错误处理能力
└————————┘
------------------------ V86.ASM ---------------------------------------
code segment
assume cs:code,ds:code
.386p
start proc near
jmp next
gdtadds dw 002fh,0000h,0000h
gdttab db 000h,000h,000h,000h,000h,000h,000h,000h ;00 Null
db 0ffh,0ffh,000h,000h,000h,09bh,000h,000h ;08 PRG Seg
db 0ffh,0ffh,000h,000h,000h,093h,08fh,000h ;10 Dos=Page
db 0ffh,0ffh,000h,000h,000h,089h,000h,000h ;18 TSSltr
db 0ffh,0ffh,000h,000h,000h,089h,000h,000h ;20 TSSjmp
db 0ffh,003h,000h,000h,000h,093h,000h,000h ;28 Stack (1K)
tssltr dd 00000000h
dd 000003ffh ;ESP
dw 0028h,0000h ;SS.0
dd 0,0,0,0,0
dw offset enter_v86,0000h ;EIP
dd 00000200h ;EFlag
dd 0,0,0,0
dd 000003ffh ;ESP
dd 0,0,0
dw 0010h,0000h ;ES.0
dw 0008h,0000h ;CS.0
dw 0028h,0000h ;SS.0
dw 0010h,0000h ;DS,0
dw 0010h,0000h ;FS.0
dw 0010h,0000h ;GS.0
dw 0000h,0000h ;LDT.0
dw 0000h,0068h ;0.IOMAP
dw 0ffffh
tssjmp dd 00000000h
dd 000003ffh ;ESP
dw 0028h,0000h ;SS.0
dd 0,0,0,0,0
dw offset enter_v86,0000h ;EIP
dd 00000000h ;EFlag
dd 0,0,0,0
dd 000003ffh ;ESP
dd 0,0,0
dw 0010h,0000h ;ES.0
dw 0008h,0000h ;CS.0
dw 0028h,0000h ;SS.0
dw 0010h,0000h ;DS,0
dw 0010h,0000h ;FS.0
dw 0010h,0000h ;GS.0
dw 0000h,0000h ;LDT.0
dw 0000h,0068h ;0.IOMAP
iomap db 1000h dup (0)
dw 0ffffh
buffer1 db 0400h dup (0) ;Stack
idtadds dw 07ffh,0000h,0000h
idttab dw offset new_00,0008h,0ee00h,0000h,offset
new_01,0008h,0ee00h,0000h
dw offset new_02,0008h,0ee00h,0000h,offset
new_03,0008h,0ee00h,0000h
dw offset new_04,0008h,0ee00h,0000h,offset
new_05,0008h,0ee00h,0000h
dw offset new_06,0008h,0ee00h,0000h,offset
new_07,0008h,0ee00h,0000h
dw offset new_08,0008h,0ee00h,0000h,offset
new_09,0008h,0ee00h,0000h
dw offset new_0a,0008h,0ee00h,0000h,offset
new_0b,0008h,0ee00h,0000h
dw offset new_0c,0008h,0ee00h,0000h,offset
new_0d,0008h,0ee00h,0000h
dw offset new_0e,0008h,0ee00h,0000h,offset
new_0f,0008h,0ee00h,0000h
dw offset new_10,0008h,0ee00h,0000h,offset
new_11,0008h,0ee00h,0000h
dw offset new_12,0008h,0ee00h,0000h,offset
new_13,0008h,0ee00h,0000h
dw offset new_14,0008h,0ee00h,0000h,offset
new_15,0008h,0ee00h,0000h
dw offset new_16,0008h,0ee00h,0000h,offset
new_17,0008h,0ee00h,0000h
dw offset new_18,0008h,0ee00h,0000h,offset
new_19,0008h,0ee00h,0000h
dw offset new_1a,0008h,0ee00h,0000h,offset
new_1b,0008h,0ee00h,0000h
dw offset new_1c,0008h,0ee00h,0000h,offset
new_1d,0008h,0ee00h,0000h
dw offset new_1e,0008h,0ee00h,0000h,offset
new_1f,0008h,0ee00h,0000h
dw offset new_20,0008h,0ee00h,0000h,offset
new_21,0008h,0ee00h,0000h
dw offset new_22,0008h,0ee00h,0000h,offset
new_23,0008h,0ee00h,0000h
dw offset new_24,0008h,0ee00h,0000h,offset
new_25,0008h,0ee00h,0000h
dw offset new_26,0008h,0ee00h,0000h,offset
new_27,0008h,0ee00h,0000h
dw offset new_28,0008h,0ee00h,0000h,offset
new_29,0008h,0ee00h,0000h
dw offset new_2a,0008h,0ee00h,0000h,offset
new_2b,0008h,0ee00h,0000h
dw offset new_2c,0008h,0ee00h,0000h,offset
new_2d,0008h,0ee00h,0000h
dw offset new_2e,0008h,0ee00h,0000h,offset
new_2f,0008h,0ee00h,0000h
dw offset new_30,0008h,0ee00h,0000h,offset
new_31,0008h,0ee00h,0000h
dw offset new_32,0008h,0ee00h,0000h,offset
new_33,0008h,0ee00h,0000h
dw offset new_34,0008h,0ee00h,0000h,offset
new_35,0008h,0ee00h,0000h
dw offset new_36,0008h,0ee00h,0000h,offset
new_37,0008h,0ee00h,0000h
dw offset new_38,0008h,0ee00h,0000h,offset
new_39,0008h,0ee00h,0000h
dw offset new_3a,0008h,0ee00h,0000h,offset
new_3b,0008h,0ee00h,0000h
dw offset new_3c,0008h,0ee00h,0000h,offset
new_3d,0008h,0ee00h,0000h
dw offset new_3e,0008h,0ee00h,0000h,offset
new_3f,0008h,0ee00h,0000h
dw offset new_40,0008h,0ee00h,0000h,offset
new_41,0008h,0ee00h,0000h
dw offset new_42,0008h,0ee00h,0000h,offset
new_43,0008h,0ee00h,0000h
dw offset new_44,0008h,0ee00h,0000h,offset
new_45,0008h,0ee00h,0000h
dw offset new_46,0008h,0ee00h,0000h,offset
new_47,0008h,0ee00h,0000h
dw offset new_48,0008h,0ee00h,0000h,offset
new_49,0008h,0ee00h,0000h
dw offset new_4a,0008h,0ee00h,0000h,offset
new_4b,0008h,0ee00h,0000h
dw offset new_4c,0008h,0ee00h,0000h,offset
new_4d,0008h,0ee00h,0000h
dw offset new_4e,0008h,0ee00h,0000h,offset
new_4f,0008h,0ee00h,0000h
dw offset new_50,0008h,0ee00h,0000h,offset
new_51,0008h,0ee00h,0000h
dw offset new_52,0008h,0ee00h,0000h,offset
new_53,0008h,0ee00h,0000h
dw offset new_54,0008h,0ee00h,0000h,offset
new_55,0008h,0ee00h,0000h
dw offset new_56,0008h,0ee00h,0000h,offset
new_57,0008h,0ee00h,0000h
dw offset new_58,0008h,0ee00h,0000h,offset
new_59,0008h,0ee00h,0000h
dw offset new_5a,0008h,0ee00h,0000h,offset
new_5b,0008h,0ee00h,0000h
dw offset new_5c,0008h,0ee00h,0000h,offset
new_5d,0008h,0ee00h,0000h
dw offset new_5e,0008h,0ee00h,0000h,offset
new_5f,0008h,0ee00h,0000h
dw offset new_60,0008h,0ee00h,0000h,offset
new_61,0008h,0ee00h,0000h
dw offset new_62,0008h,0ee00h,0000h,offset
new_63,0008h,0ee00h,0000h
dw offset new_64,0008h,0ee00h,0000h,offset
new_65,0008h,0ee00h,0000h
dw offset new_66,0008h,0ee00h,0000h,offset
new_67,0008h,0ee00h,0000h
dw offset new_68,0008h,0ee00h,0000h,offset
new_69,0008h,0ee00h,0000h
dw offset new_6a,0008h,0ee00h,0000h,offset
new_6b,0008h,0ee00h,0000h
dw offset new_6c,0008h,0ee00h,0000h,offset
new_6d,0008h,0ee00h,0000h
dw offset new_6e,0008h,0ee00h,0000h,offset
new_6f,0008h,0ee00h,0000h
dw offset new_70,0008h,0ee00h,0000h,offset
new_71,0008h,0ee00h,0000h
dw offset new_72,0008h,0ee00h,0000h,offset
new_73,0008h,0ee00h,0000h
dw offset new_74,0008h,0ee00h,0000h,offset
new_75,0008h,0ee00h,0000h
dw offset new_76,0008h,0ee00h,0000h,offset
new_77,0008h,0ee00h,0000h
dw offset new_78,0008h,0ee00h,0000h,offset
new_79,0008h,0ee00h,0000h
dw offset new_7a,0008h,0ee00h,0000h,offset
new_7b,0008h,0ee00h,0000h
dw offset new_7c,0008h,0ee00h,0000h,offset
new_7d,0008h,0ee00h,0000h
dw offset new_7e,0008h,0ee00h,0000h,offset
new_7f,0008h,0ee00h,0000h
dw offset new_80,0008h,0ee00h,0000h,offset
new_81,0008h,0ee00h,0000h
dw offset new_82,0008h,0ee00h,0000h,offset
new_83,0008h,0ee00h,0000h
dw offset new_84,0008h,0ee00h,0000h,offset
new_85,0008h,0ee00h,0000h
dw offset new_86,0008h,0ee00h,0000h,offset
new_87,0008h,0ee00h,0000h
dw offset new_88,0008h,0ee00h,0000h,offset
new_89,0008h,0ee00h,0000h
dw offset new_8a,0008h,0ee00h,0000h,offset
new_8b,0008h,0ee00h,0000h
dw offset new_8c,0008h,0ee00h,0000h,offset
new_8d,0008h,0ee00h,0000h
dw offset new_8e,0008h,0ee00h,0000h,offset
new_8f,0008h,0ee00h,0000h
dw offset new_90,0008h,0ee00h,0000h,offset
new_91,0008h,0ee00h,0000h
dw offset new_92,0008h,0ee00h,0000h,offset
new_93,0008h,0ee00h,0000h
dw offset new_94,0008h,0ee00h,0000h,offset
new_95,0008h,0ee00h,0000h
dw offset new_96,0008h,0ee00h,0000h,offset
new_97,0008h,0ee00h,0000h
dw offset new_98,0008h,0ee00h,0000h,offset
new_99,0008h,0ee00h,0000h
dw offset new_9a,0008h,0ee00h,0000h,offset
new_9b,0008h,0ee00h,0000h
dw offset new_9c,0008h,0ee00h,0000h,offset
new_9d,0008h,0ee00h,0000h
dw offset new_9e,0008h,0ee00h,0000h,offset
new_9f,0008h,0ee00h,0000h
dw offset new_a0,0008h,0ee00h,0000h,offset
new_a1,0008h,0ee00h,0000h
dw offset new_a2,0008h,0ee00h,0000h,offset
new_a3,0008h,0ee00h,0000h
dw offset new_a4,0008h,0ee00h,0000h,offset
new_a5,0008h,0ee00h,0000h
dw offset new_a6,0008h,0ee00h,0000h,offset
new_a7,0008h,0ee00h,0000h
dw offset new_a8,0008h,0ee00h,0000h,offset
new_a9,0008h,0ee00h,0000h
dw offset new_aa,0008h,0ee00h,0000h,offset
new_ab,0008h,0ee00h,0000h
dw offset new_ac,0008h,0ee00h,0000h,offset
new_ad,0008h,0ee00h,0000h
dw offset new_ae,0008h,0ee00h,0000h,offset
new_af,0008h,0ee00h,0000h
dw offset new_b0,0008h,0ee00h,0000h,offset
new_b1,0008h,0ee00h,0000h
dw offset new_b2,0008h,0ee00h,0000h,offset
new_b3,0008h,0ee00h,0000h
dw offset new_b4,0008h,0ee00h,0000h,offset
new_b5,0008h,0ee00h,0000h
dw offset new_b6,0008h,0ee00h,0000h,offset
new_b7,0008h,0ee00h,0000h
dw offset new_b8,0008h,0ee00h,0000h,offset
new_b9,0008h,0ee00h,0000h
dw offset new_ba,0008h,0ee00h,0000h,offset
new_bb,0008h,0ee00h,0000h
dw offset new_bc,0008h,0ee00h,0000h,offset
new_bd,0008h,0ee00h,0000h
dw offset new_be,0008h,0ee00h,0000h,offset
new_bf,0008h,0ee00h,0000h
dw offset new_c0,0008h,0ee00h,0000h,offset
new_c1,0008h,0ee00h,0000h
dw offset new_c2,0008h,0ee00h,0000h,offset
new_c3,0008h,0ee00h,0000h
dw offset new_c4,0008h,0ee00h,0000h,offset
new_c5,0008h,0ee00h,0000h
dw offset new_c6,0008h,0ee00h,0000h,offset
new_c7,0008h,0ee00h,0000h
dw offset new_c8,0008h,0ee00h,0000h,offset
new_c9,0008h,0ee00h,0000h
dw offset new_ca,0008h,0ee00h,0000h,offset
new_cb,0008h,0ee00h,0000h
dw offset new_cc,0008h,0ee00h,0000h,offset
new_cd,0008h,0ee00h,0000h
dw offset new_ce,0008h,0ee00h,0000h,offset
new_cf,0008h,0ee00h,0000h
dw offset new_d0,0008h,0ee00h,0000h,offset
new_d1,0008h,0ee00h,0000h
dw offset new_d2,0008h,0ee00h,0000h,offset
new_d3,0008h,0ee00h,0000h
dw offset new_d4,0008h,0ee00h,0000h,offset
new_d5,0008h,0ee00h,0000h
dw offset new_d6,0008h,0ee00h,0000h,offset
new_d7,0008h,0ee00h,0000h
dw offset new_d8,0008h,0ee00h,0000h,offset
new_d9,0008h,0ee00h,0000h
dw offset new_da,0008h,0ee00h,0000h,offset
new_db,0008h,0ee00h,0000h
dw offset new_dc,0008h,0ee00h,0000h,offset
new_dd,0008h,0ee00h,0000h
dw offset new_de,0008h,0ee00h,0000h,offset
new_df,0008h,0ee00h,0000h
dw offset new_e0,0008h,0ee00h,0000h,offset
new_e1,0008h,0ee00h,0000h
dw offset new_e2,0008h,0ee00h,0000h,offset
new_e3,0008h,0ee00h,0000h
dw offset new_e4,0008h,0ee00h,0000h,offset
new_e5,0008h,0ee00h,0000h
dw offset new_e6,0008h,0ee00h,0000h,offset
new_e7,0008h,0ee00h,0000h
dw offset new_e8,0008h,0ee00h,0000h,offset
new_e9,0008h,0ee00h,0000h
dw offset new_ea,0008h,0ee00h,0000h,offset
new_eb,0008h,0ee00h,0000h
dw offset new_ec,0008h,0ee00h,0000h,offset
new_ed,0008h,0ee00h,0000h
dw offset new_ee,0008h,0ee00h,0000h,offset
new_ef,0008h,0ee00h,0000h
dw offset new_f0,0008h,0ee00h,0000h,offset
new_f1,0008h,0ee00h,0000h
dw offset new_f2,0008h,0ee00h,0000h,offset
new_f3,0008h,0ee00h,0000h
dw offset new_f4,0008h,0ee00h,0000h,offset
new_f5,0008h,0ee00h,0000h
dw offset new_f6,0008h,0ee00h,0000h,offset
new_f7,0008h,0ee00h,0000h
dw offset new_f8,0008h,0ee00h,0000h,offset
new_f9,0008h,0ee00h,0000h
dw offset new_fa,0008h,0ee00h,0000h,offset
new_fb,0008h,0ee00h,0000h
dw offset new_fc,0008h,0ee00h,0000h,offset
new_fd,0008h,0ee00h,0000h
dw offset new_fe,0008h,0ee00h,0000h,offset
new_ff,0008h,0ee00h,0000h
new_00 :
push 0000h
jmp int_emu
new_01 :
push 0001h
jmp int_emu
new_02 :
push 0002h
jmp int_emu
new_03 :
push 0003h
jmp int_emu
new_04 :
push 0004h
jmp int_emu
new_05 :
push 0005h
jmp int_emu
new_06 :
push 0006h
jmp int_emu
new_07 :
push 0007h
jmp int_emu
new_08 :
push 0008h
jmp int_emu
new_09 :
push 0009h
jmp int_emu
new_0a :
push 000ah
jmp int_emu
new_0b :
push 000bh
jmp int_emu
new_0c :
push 000ch
jmp int_emu
new_0d :
push 000dh
jmp int_emu
new_0e :
push 000eh
jmp int_emu
new_0f :
push 000fh
jmp int_emu
new_10 :
push 0010h
jmp int_emu
new_11 :
push 0011h
jmp int_emu
new_12 :
push 0012h
jmp int_emu
new_13 :
push 0013h
jmp int_emu
new_14 :
push 0014h
jmp int_emu
new_15 :
cmp ah,87h
jnz L3
push bp
mov bp,sp
add bp,02h
push eax
push ebx
push ecx
push edx
push edi
push esi
mov ebx,ss:[bp+14h]
shl ebx,04h
and esi,0000ffffh
add ebx,esi
mov ax,0010h
mov ds,ax
mov es,ax
mov esi,ds:[ebx+12h]
mov edi,ds:[ebx+1ah]
and esi,00ffffffh
and edi,00ffffffh
or cx,cx
jz L2
L1 :
mov ax,ds:[esi]
mov es:[edi],ax
add esi,02h
add edi,02h
loop L1
L2 :
pop esi
pop edi
pop edx
pop ecx
pop ebx
pop eax
pop bp
iretd
L3 :
push 0015h
jmp int_emu
new_16 :
push 0016h
jmp int_emu
new_17 :
push 0017h
jmp int_emu
new_18 :
push 0018h
jmp int_emu
new_19 :
push 0019h
jmp int_emu
new_1a :
push 001ah
jmp int_emu
new_1b :
push 001bh
jmp int_emu
new_1c :
push 001ch
jmp int_emu
new_1d :
push 001dh
jmp int_emu
new_1e :
push 001eh
jmp int_emu
new_1f :
push 001fh
jmp int_emu
new_20 :
push 0020h
jmp int_emu
new_21 :
push 0021h
jmp int_emu
new_22 :
push 0022h
jmp int_emu
new_23 :
push 0023h
jmp int_emu
new_24 :
push 0024h
jmp int_emu
new_25 :
push 0025h
jmp int_emu
new_26 :
push 0026h
jmp int_emu
new_27 :
push 0027h
jmp int_emu
new_28 :
push 0028h
jmp int_emu
new_29 :
push 0029h
jmp int_emu
new_2a :
push 002ah
jmp int_emu
new_2b :
push 002bh
jmp int_emu
new_2c :
push 002ch
jmp int_emu
new_2d :
push 002dh
jmp int_emu
new_2e :
push 002eh
jmp int_emu
new_2f :
push 002fh
jmp int_emu
new_30 :
push 0030h
jmp int_emu
new_31 :
push 0031h
jmp int_emu
new_32 :
push 0032h
jmp int_emu
new_33 :
push 0033h
jmp int_emu
new_34 :
push 0034h
jmp int_emu
new_35 :
push 0035h
jmp int_emu
new_36 :
push 0036h
jmp int_emu
new_37 :
push 0037h
jmp int_emu
new_38 :
push 0038h
jmp int_emu
new_39 :
push 0039h
jmp int_emu
new_3a :
push 003ah
jmp int_emu
new_3b :
push 003bh
jmp int_emu
new_3c :
push 003ch
jmp int_emu
new_3d :
push 003dh
jmp int_emu
new_3e :
push 003eh
jmp int_emu
new_3f :
push 003fh
jmp int_emu
new_40 :
push 0040h
jmp int_emu
new_41 :
push 0041h
jmp int_emu
new_42 :
push 0042h
jmp int_emu
new_43 :
push 0043h
jmp int_emu
new_44 :
push 0044h
jmp int_emu
new_45 :
push 0045h
jmp int_emu
new_46 :
push 0046h
jmp int_emu
new_47 :
push 0047h
jmp int_emu
new_48 :
push 0048h
jmp int_emu
new_49 :
push 0049h
jmp int_emu
new_4a :
push 004ah
jmp int_emu
new_4b :
push 004bh
jmp int_emu
new_4c :
push 004ch
jmp int_emu
new_4d :
push 004dh
jmp int_emu
new_4e :
push 004eh
jmp int_emu
new_4f :
push 004fh
jmp int_emu
new_50 :
push 0050h
jmp int_emu
new_51 :
push 0051h
jmp int_emu
new_52 :
push 0052h
jmp int_emu
new_53 :
push 0053h
jmp int_emu
new_54 :
push 0054h
jmp int_emu
new_55 :
push 0055h
jmp int_emu
new_56 :
push 0056h
jmp int_emu
new_57 :
push 0057h
jmp int_emu
new_58 :
push 0058h
jmp int_emu
new_59 :
push 0059h
jmp int_emu
new_5a :
push 005ah
jmp int_emu
new_5b :
push 005bh
jmp int_emu
new_5c :
push 005ch
jmp int_emu
new_5d :
push 005dh
jmp int_emu
new_5e :
push 005eh
jmp int_emu
new_5f :
push 005fh
jmp int_emu
new_60 :
push 0060h
jmp int_emu
new_61 :
push 0061h
jmp int_emu
new_62 :
push 0062h
jmp int_emu
new_63 :
push 0063h
jmp int_emu
new_64 :
push 0064h
jmp int_emu
new_65 :
push 0065h
jmp int_emu
new_66 :
push 0066h
jmp int_emu
new_67 :
push 0067h
jmp int_emu
new_68 :
push 0068h
jmp int_emu
new_69 :
push 0069h
jmp int_emu
new_6a :
push 006ah
jmp int_emu
new_6b :
push 006bh
jmp int_emu
new_6c :
push 006ch
jmp int_emu
new_6d :
push 006dh
jmp int_emu
new_6e :
push 006eh
jmp int_emu
new_6f :
push 006fh
jmp int_emu
new_70 :
push 0070h
jmp int_emu
new_71 :
push 0071h
jmp int_emu
new_72 :
push 0072h
jmp int_emu
new_73 :
push 0073h
jmp int_emu
new_74 :
push 0074h
jmp int_emu
new_75 :
push 0075h
jmp int_emu
new_76 :
push 0076h
jmp int_emu
new_77 :
push 0077h
jmp int_emu
new_78 :
push 0078h
jmp int_emu
new_79 :
push 0079h
jmp int_emu
new_7a :
push 007ah
jmp int_emu
new_7b :
push 007bh
jmp int_emu
new_7c :
push 007ch
jmp int_emu
new_7d :
push 007dh
jmp int_emu
new_7e :
push 007eh
jmp int_emu
new_7f :
push 007fh
jmp int_emu
new_80 :
push 0080h
jmp int_emu
new_81 :
push 0081h
jmp int_emu
new_82 :
push 0082h
jmp int_emu
new_83 :
push 0083h
jmp int_emu
new_84 :
push 0084h
jmp int_emu
new_85 :
push 0085h
jmp int_emu
new_86 :
push 0086h
jmp int_emu
new_87 :
push 0087h
jmp int_emu
new_88 :
push 0088h
jmp int_emu
new_89 :
push 0089h
jmp int_emu
new_8a :
push 008ah
jmp int_emu
new_8b :
push 008bh
jmp int_emu
new_8c :
push 008ch
jmp int_emu
new_8d :
push 008dh
jmp int_emu
new_8e :
push 008eh
jmp int_emu
new_8f :
push 008fh
jmp int_emu
new_90 :
push 0090h
jmp int_emu
new_91 :
push 0091h
jmp int_emu
new_92 :
push 0092h
jmp int_emu
new_93 :
push 0093h
jmp int_emu
new_94 :
push 0094h
jmp int_emu
new_95 :
push 0095h
jmp int_emu
new_96 :
push 0096h
jmp int_emu
new_97 :
push 0097h
jmp int_emu
new_98 :
push 0098h
jmp int_emu
new_99 :
push 0099h
jmp int_emu
new_9a :
push 009ah
jmp int_emu
new_9b :
push 009bh
jmp int_emu
new_9c :
push 009ch
jmp int_emu
new_9d :
push 009dh
jmp int_emu
new_9e :
push 009eh
jmp int_emu
new_9f :
push 009fh
jmp int_emu
new_a0 :
push 00a0h
jmp int_emu
new_a1 :
push 00a1h
jmp int_emu
new_a2 :
push 00a2h
jmp int_emu
new_a3 :
push 00a3h
jmp int_emu
new_a4 :
push 00a4h
jmp int_emu
new_a5 :
push 00a5h
jmp int_emu
new_a6 :
push 00a6h
jmp int_emu
new_a7 :
push 00a7h
jmp int_emu
new_a8 :
push 00a8h
jmp int_emu
new_a9 :
push 00a9h
jmp int_emu
new_aa :
push 00aah
jmp int_emu
new_ab :
push 00abh
jmp int_emu
new_ac :
push 00ach
jmp int_emu
new_ad :
push 00adh
jmp int_emu
new_ae :
push 00aeh
jmp int_emu
new_af :
push 00afh
jmp int_emu
new_b0 :
push 00b0h
jmp int_emu
new_b1 :
push 00b1h
jmp int_emu
new_b2 :
push 00b2h
jmp int_emu
new_b3 :
push 00b3h
jmp int_emu
new_b4 :
push 00b4h
jmp int_emu
new_b5 :
push 00b5h
jmp int_emu
new_b6 :
push 00b6h
jmp int_emu
new_b7 :
push 00b7h
jmp int_emu
new_b8 :
push 00b8h
jmp int_emu
new_b9 :
push 00b9h
jmp int_emu
new_ba :
push 00bah
jmp int_emu
new_bb :
push 00bbh
jmp int_emu
new_bc :
push 00bch
jmp int_emu
new_bd :
push 00bdh
jmp int_emu
new_be :
push 00beh
jmp int_emu
new_bf :
push 00bfh
jmp int_emu
new_c0 :
push 00c0h
jmp int_emu
new_c1 :
push 00c1h
jmp int_emu
new_c2 :
push 00c2h
jmp int_emu
new_c3 :
push 00c3h
jmp int_emu
new_c4 :
push 00c4h
jmp int_emu
new_c5 :
push 00c5h
jmp int_emu
new_c6 :
push 00c6h
jmp int_emu
new_c7 :
push 00c7h
jmp int_emu
new_c8 :
push 00c8h
jmp int_emu
new_c9 :
push 00c9h
jmp int_emu
new_ca :
push 00cah
jmp int_emu
new_cb :
push 00cbh
jmp int_emu
new_cc :
push 00cch
jmp int_emu
new_cd :
push 00cdh
jmp int_emu
new_ce :
push 00ceh
jmp int_emu
new_cf :
push 00cfh
jmp int_emu
new_d0 :
push 00d0h
jmp int_emu
new_d1 :
push 00d1h
jmp int_emu
new_d2 :
push 00d2h
jmp int_emu
new_d3 :
push 00d3h
jmp int_emu
new_d4 :
push 00d4h
jmp int_emu
new_d5 :
push 00d5h
jmp int_emu
new_d6 :
push 00d6h
jmp int_emu
new_d7 :
push 00d7h
jmp int_emu
new_d8 :
push 00d8h
jmp int_emu
new_d9 :
push 00d9h
jmp int_emu
new_da :
push 00dah
jmp int_emu
new_db :
push 00dbh
jmp int_emu
new_dc :
push 00dch
jmp int_emu
new_dd :
push 00ddh
jmp int_emu
new_de :
push 00deh
jmp int_emu
new_df :
push 00dfh
jmp int_emu
new_e0 :
push 00e0h
jmp int_emu
new_e1 :
push 00e1h
jmp int_emu
new_e2 :
push 00e2h
jmp int_emu
new_e3 :
push 00e3h
jmp int_emu
new_e4 :
push 00e4h
jmp int_emu
new_e5 :
push 00e5h
jmp int_emu
new_e6 :
push 00e6h
jmp int_emu
new_e7 :
push 00e7h
jmp int_emu
new_e8 :
push 00e8h
jmp int_emu
new_e9 :
push 00e9h
jmp int_emu
new_ea :
push 00eah
jmp int_emu
new_eb :
push 00ebh
jmp int_emu
new_ec :
push 00ech
jmp int_emu
new_ed :
push 00edh
jmp int_emu
new_ee :
push 00eeh
jmp int_emu
new_ef :
push 00efh
jmp int_emu
new_f0 :
push 00f0h
jmp int_emu
new_f1 :
push 00f1h
jmp int_emu
new_f2 :
push 00f2h
jmp int_emu
new_f3 :
push 00f3h
jmp int_emu
new_f4 :
push 00f4h
jmp int_emu
new_f5 :
push 00f5h
jmp int_emu
new_f6 :
push 00f6h
jmp int_emu
new_f7 :
push 00f7h
jmp int_emu
new_f8 :
push 00f8h
jmp int_emu
new_f9 :
push 00f9h
jmp int_emu
new_fa :
push 00fah
jmp int_emu
new_fb :
push 00fbh
jmp int_emu
new_fc :
push 00fch
jmp int_emu
new_fd :
push 00fdh
jmp int_emu
new_fe :
push 00feh
jmp int_emu
new_ff :
push 00ffh
jmp int_emu
int_emu :
push bp
mov bp,sp
add bp,04h
push eax
push ebx
mov ax,0010h ;
mov ds,ax ;
mov ax,ss:[bp+0ch] ;
sub ax,06h ;
mov ss:[bp+0ch],ax ;
xor eax,eax ;
xor ebx,ebx ;
mov ax,ss:[bp+10h] ;V86 下 IRET 要返回的位址
shl eax,04h ;
mov bx,ss:[bp+0ch] ;
add ebx,eax ;
mov ax,ss:[bp+00h] ;
mov ds:[ebx],ax ;
mov ax,ss:[bp+04h] ;
mov ds:[ebx+02h],ax ;
mov ax,ss:[bp+08h] ;
mov ds:[ebx+04h],ax ;
nop
xor ebx,ebx ;
mov bx,ss:[bp-02h] ;
shl ebx,02h ;
mov ax,ds:[ebx] ;IRETD後跳到何处执行
mov ss:[bp+00h],ax ;(查 0000:0000 的中断表)
mov ax,ds:[ebx+02h] ;
mov ss:[bp+04h],ax ;
mov eax,ss:[bp+08h]
or eax,00032000h
and eax,0fffffeffh
mov ss:[bp+08h],eax
pop ebx
pop eax
pop bp
add sp,02h
iretd
set_base :
mov cs:[di+02h],ax
shr eax,0010h
mov cs:[di+04h],al
mov cs:[di+07h],ah
ret
next :
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov bx,offset gdttab
add eax,ebx
mov di,offset gdtadds+02h
mov cs:[di],eax ;设定 gdtadds
NOP
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov di,offset gdttab+08h
call set_base ;设定 PRG Seg 的 Base
NOP
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov bx,offset tssltr
add eax,ebx
mov di,offset gdttab+18h
call set_base
NOP ;设定 TSSltr 的 Base
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov bx,offset tssjmp
add eax,ebx
mov di,offset gdttab+20h
call set_base
NOP ;设定 TSSjmp 的 Base
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov bx,offset buffer1
add eax,ebx
mov di,offset gdttab+28h
call set_base
NOP ;设定 Stack 的 Base
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,04h
mov bx,offset idttab
add eax,ebx
mov di,offset idtadds+02h
mov cs:[di],eax ;设定 idtadds
NOP
cli
lgdt fword ptr cs:gdtadds
lidt fword ptr cs:idtadds
mov eax,cr0
or al,01h
mov cr0,eax
mov bx,0018h
ltr bx
db 0eah,00h,00h,20h,00h ;根据TSS表可知跳到enter_v86
enter_v86 :
mov ax,0028h
mov es,ax
xor eax,eax
mov ax,code
push eax ;GS
push eax ;FS
push eax ;DS
push eax ;ES
push eax ;SS
mov ax,0f000h
push eax ;ESP
mov eax,00023000h ;设定VM=1 等级=3
push eax ;Eflag
xor eax,eax
mov ax,code
push eax ;CS
mov ax,offset return_dos
push eax ;EIP
clts ;将 387 切换成 32 位元模式
iretd ;回到 V86 (共弹出24h BYTE)
;-------------------------------------------------------------------------
; 下面的程式便是回到 V86 继续执行的程式
;-------------------------------------------------------------------------
return_dos :
sti
mov ax,cs
mov ds,ax
mov dx,offset next
add dx,0200h
int 27h
start endp
code ends
end start
;-------------------------------------------------------------------------
如何侦测现在是在真实模式下或保护模式呢 ,重点就在於 CR0 暂存器的 Bit0
是否为 ????1???? ,若为 ????1???? 则表示现在在保护模式 ,反之则为真实模式 ,不过如果要
执行 MOV EAX,CR0 这个指令必需要在特权等级才能执行 ,所以您要侦测这个位元的
话 ,可以使用 SMSW AX ,来读取 CR0 的低位元部份。
┌———————————————————————————————————┐
│ Soft Bugger 软体蛀虫 90:90/2 软体新技术的实行者 │
│ BBS:02-5955461 24HR ID:Werong Ho -- 软蛀 -- │
└———————————————————————————————————┘
Updated: 2006-12-26 Home / Index
本文转自

转载地址:http://rwiob.baihongyu.com/

你可能感兴趣的文章
11gR2批量操作EM性能监控报表集
查看>>
[转帖]广交会使用频率最高的英语
查看>>
职业经理人影响力自检手册(二)
查看>>
企业如何提好自己的内部需求?
查看>>
[分享]ERP实施工程师笔试题目
查看>>
看板管理概述(zt)
查看>>
IT审计中应注意的几个问题(zt)
查看>>
最美的七十个英语单词
查看>>
中国企业需要精益求精 (zt)
查看>>
第四章 计划工作概述
查看>>
物流基础知识(八)
查看>>
关于BPR和ERP的关系思考 (转载)
查看>>
写作必背200句
查看>>
职业经理人影响力自检手册(一)
查看>>
[HR规划]如何在中小企业进行人力资源规划(zt)
查看>>
ERP实施先要解决人的问题(zt)
查看>>
有效库存:供应链产业切肤之痛 (zt)
查看>>
李嘉诚给年青人提出的53条人生忠告(zt)
查看>>
第23课 企业信息资源规划系列讲堂之一
查看>>
第十七章 控制工作概述
查看>>