一 CMOS介绍
CMOS(Complementary Metal-Oxide Semiconductor)是一种常见的半导体芯片技术,广泛用于各种微处理器和外设中。
在PC系统中,CMOS芯片主要用于实现实时时钟(RTC)和存储BIOS设置。CMOS内含有一小块SRAM芯片和电池,可以在系统断电时保持数据。
二 CMOS数据的读取
要读取CMOS中的数据,需要访问RTC及配置存储区指定的I/O端口。在IBM PC兼容机上,主要有以下几个I/O端口:
- 0x70 - RTC地址寄存器端口,写入要访问的RTC或CMOS内存地址
- 0x71 - RTC数据寄存器端口,读取或写入RTC的控制数据或CMOS内存单元的数据
- 0x72 - RTC控制寄存器端口,控制RTC及中断
- 0x73 - RTC状态寄存器端口,读取RTC及CMOS的状态
例如,要读取CMOS内存地址0x10处的数据:
- 向0x70端口写地址0x10
- 从0x71端口读数据,得到address 0x10处的内容
CMOS内存组织为128字节,低地址部分为RTC及状态寄存器,高地址部分存储BIOS配置信息。
通过直接访问这些I/O端口,我们可以在程序中读取CMOS配置数据,获取硬件信息。但需要注意CMOS访问是比较敏感的,如果不正确可能会导致系统问题。
DOS环境下的示例代码:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<dos.h>
typedef unsigned char BYTE;
typedef unsigned int WORD;
BYTE my_inp(BYTE port)
{
BYTE value;
__asm
{
mov al,port
out 70h,al
in al,71h
mov value,al
}
return value;
}
void my_outp(BYTE port,BYTE value)
{
__asm
{
mov al,port
out 0x70,al
mov al,value
out 0x71,al
}
}
void out_7071(BYTE port,BYTE value)
{
__asm
{
mov al,port
out 0x70,al
mov al,value
out 0x71,al
}
}
void main()
{
BYTE addr,data;
for(addr=0x0; addr<0xff; addr++)
{
data = my_inp(addr);
for(k=0x0; k<=0xf; k++)
{
printf(" %02x",k);
}
if(addr%16==0)
{
printf("\n");
printf("%02x",addr);
}
printf(" %02x",data);
}
}
读取出来的结果图
三 CMOS数据代表的含义
CMOS内存的组织格式如下:
- 低地址部分(0x00 - 0x7F)为RTC及状态控制寄存器:
- 0x00-0x0F: 用于RTC,包含时间日期等信息
- 0x10-0x2F: 状态控制和状态标志寄存器
- 0x30-0x3F: RTC控制寄存器
- 0x40-0x7F: 扩展RTC功能
- 高地址部分(0x80-0xFF)为BIOS配置数据:
- 0x80-0xF0: BIOS配置参数,可配置各种主板设定
- 0xF0-0xFF: 校验和及扩展BIOS数据区
具体一些重要的CMOS配置数据说明:
- 0x00-0x0B: 当前时间,分别是 秒 分 时 年 月 日 星期 年的最后两位
- 0x0C-0x0D: RTC状态控制
- 0x0E-0x0F: 诊断状态码
- 0x10-0x2D: 各种状态标志位
- 0x2E-0x2F: 校验和
- 0x14: 扩展内存大小
- 0x15: 基本内存大小
- 0x16: 其它内存大小
- 0x2D: 基本内存扩展
- 0x30: 复位代码
- 0x31: 系统复位跳转地址高8位
- 0x32: 系统复位跳转地址低8位
- 0x33: Checksum 校验和
- 0x34-0x3F: 扩展CMOS配置数据
4 清除CMOS密码
CMOS内存清除密码有两个方法:
1. 硬件跳线法
通过硬件暂时短接CMOS内存芯片上的 CLR_CMOS 引脚和地线,就可以重置CMOS的数据,从而清除密码。
2. 软件校验和法
利用CMOS内存的校验和机制可以实现软件清除密码:
CMOS地址0x10-0x2D存储了各种配置数据。
而0x2E-0x2F存储了0x10-0x2D区数据的校验和。
BIOS在启动时会计算一次0x10-0x2D的校验和,和0x2E-0x2F存储的校验和比较。
如果不匹配,则认为CMOS数据错误,重置CMOS为默认值。
也就是说我们可以通过修改0x10-0x2D区数据,导致校验和不匹配,进而达到重置CMOS清除密码的目的。
具体做法是:
- 读取0x2E-0x2F原始校验和
- 修改0x10-0x2D某字节数据,导致校验和变化
- 写入修改后的校验和到0x2E-0x2F
- 重启系统,BIOS会发现校验和错误,重置CMOS
这样就通过软件方法清除了CMOS密码。
debug
-O 70 2e
-O 71 00
-O 70 2f
-O 71 00