为了帮助读者实际了解以上所介绍的一些概念,下面我们来分析一段在DOS实模式下直接读取4GB内存的代码。

通过该程序来分析CPU
的工作原理,揭开保护模式的神秘面纱,读者将会发现,保护模式其实与实模式一样简单和易于控制。
在此基础上用四五十行C
语言程序做到进出保护模式和在实模式之下直接访问整个4GB内存空间。
这个访问4GB内存的程序是在实模式下使用的,它只是让CPU中的不可见部分有4GB大小访问权限。
在进入保护模式(CR0成为1)后,如果段寄存器不发生变化的话,则一切和实模式一样。
所以CPU的保护位为1时,后面的代码依然可以执行,而不是死机状态。
同样的方法就不能用于分页,如果分页后的内存与不分页前时对于执行的地方发生不同,如分页的指令在内存0X12345处,分页后这个地方可能变成不存在,则计算机就只有出错重启。
对于这个问题,本人做过多次实验,屡试不爽。
2.4.1
程序的意义
此程序具有如下功能:
不需要在保护模式状态下就可以直接把386的4GB内存读出来;
利用此程序可直接在DOS中做物理设备的检测;
在DOS下,可根据此类方法将中断向量表移到任意位置,达到反跟踪或其他等目的。
2.4.2
程序代码
程序代码如下所示。
#include
<dos.h>
////////////////////////////////////////////////////////////////
//
Memory
be
//reloaded.
//
///////////////////////////////////////////////////////////////
unsigned
long
Base=0
//Limit=4G-1
0x00CF9200
Base=0
//Limit=4G-1
Size=4G
};
//Save
The
OldIDT[6]={0};
//NULL
The
pdescr_tmp[6]={0};
#define
KeyWait()
{while(inportb(0x64)&2);}
void
A20Enable(void)
{
KeyWait();
outportb(0x64,0xD1);
KeyWait();
outportb(0x60,0xDF);
//Enable
8042.
KeyWait();
outportb(0x64,0xFF);
KeyWait();
}
void
LoadFSLimit4G(void)
{
A20Enable();
//Enable
A20
//**************************************
//*
Disable
*
//**************************************
asm
{
CLI
any
//interrupts,
}
//Include
NMI.
//***************************************
//*
Load
*
//***************************************
asm
{
//The
pdescr_tmp[0],(3*8-1)
//MOV
word
GDTR
}
//**************************************
//*
Enter
*
//**************************************
//
Set
0x66,0x0F,0x22,0xC0
//MOV
Real
INTR
}
}
//With
can
FFFFh(Size=64K),
//then
Can
_AL;
}
/////////////////
Don't
<stdio.h>
/////////////////////////////////////////////////////////////
//打印出Address指向的内存中的数据
///////////////////////////////////////////////////////////
void
Dump4G(unsigned
j;
for(i=0;i<20;i++)
{
printf("%08lX:
",(Address+i*16));
for(j=0;j<16;j++)
printf("%02X
",ReadByte(Address+i*16+j));
printf("
");
for(j=0;j<16;j++)
{
if(ReadByte(Address+i*16+j)<0x20)
printf(".");
else
printf("%c",ReadByte(Address+i*16+j));
}
printf("\n");
}
}
main()
{
char
long
tmp;
LoadFSLimit4G();
printf("====Designed
Southern.1995.7.17====\n");
printf("Now
you
Memory.\n");
printf("Input
the
DUMP.\n");
printf("Press
Cuntinue
{
printf("-");
gets(KeyBuffer);
sscanf(KeyBuffer,"%lX",&tmp);
if(KeyBuffer[0]=='q')
break;
if(KeyBuffer[0]=='d')
Address+=(20*16);
else
Address=tmp;
Dump4G(Address);
}while(Address!=0);
return
0;
}
程序运行后,等用户从键盘输入一个字符。
当输入“Q”字符时,整个程序将退出,当输入“D”时,将在屏幕上显示一屏内存的数据,最左边为绝对地址,其后一列显示的是以十六进制位表示的内存的数据,后一列是数据所对应的ASCII码。


