关于CMOS加密一问题,特引用易伟一文以C语言为例进行讨论:
CMOS有一个特点,就是关机后其中的信息不会丢失,除非电池没电或者人为使其受到破坏。
而且正常的DOS操作无法涉及到它,具有非常好的隐蔽性。在计算机系统中要实现CMOS的读写
可以通过70H和71H两个I/O(输入输出)端口来操作。端口70H是一个字节的只写端口,可以
用它来设置在CMOS中读取数据的位置。71H用来读写由70H所设置的CMOS读取位置上的数据。
因此,我们可以用程序来实现任意一个CMOS单元的读写,自然也就可以利用CMOS来进行加解密了。
如果想使软件只在固定的机器上运行,可以在安装软件时将CMOS数据中第10H至2DH字节(因为00H
至0FH字节的数据随时可能改变)读出,写入某一个磁盘文件,再在软件的主执行程序中加入检查配置
是否改变的程序段,如检查发现不正确则拒绝执行。逐个字节检查的方法最准确,但是太麻烦,通常
我们只需检查第10H至2DH字节的和便可以满足要求。下面用C语言给出实现这一操作的程序。其它语言
的实现与此类似,只是访问I/O端口的指令和函数不同而已。
在安装程序中加入以下程序段,可以将CMOS中第10H至2DH字节的数据之和写入文件USER_ID.CHK。
#include ″stdio.h″
main()
{
unsigned int i,cmosnumsum=0;
FILE ?fp;
for(i=0x10;i<=0x2d;i++)/?求得安装软件的机器的CMOS中10H至2DH字节的
和?/
{ outportb(0x70,i);
cmosnumsum+=inportb(0x71);
}
if((fp=fopen(″user_id.chk″,″wb″))==NULL)/?打开记录数据的文件 ″
USER_ID
{ printf(″Write error!/07″);
exit(0);
}
printf(″/n%d/n″,cmosnumsum);
fwrite(&cmosnumsum,2,1,fp);
fclose(fp);
}
在软件主执行程序中加入以下程序段,可以将CMOS中第10H至2DH字节的数据和与记载于
文件“USER_ID.CHK”中的数据进行比较,判断是否符合。
#include ″stdio.h″
main()
{ unsigned int i,cmosnumsum=0;
unsigned int filenum;
FILE ?fp;
for(i=0x10;i<0x2d;i++)/?求得软件运行的机器的CMOS中10H至2DH字节的和?/
{ outportb(0x70,i);
cmosnumsum+=inportb(0x71);
}
if((fp=fopen(″user_id.chk″,″rb″))==NULL)/?打开记录CMOS数据的文件?/
{ printf(″System error!/07″);
exit(0);
}
fread(&filenum,2,1,fp);/?读入记录在文件上的CMOS数据?/
printf(″/n%d/t%d/n″,cmosnumsum,filenum);
if(filenum!=cmosnumsum)/?将当前CMOS中的数据与文件中的数据进行比较?
?是否相同?相同则允许运行?/
{ printf(″Your config was changed , please re-run install.exe !/07″);
exit(0);
}
else
{printf(″Your system is right ! /07Congratulations !/07″);
}
fclose(fp);
}
下面,让我们来看看AV95的自动记录使用次数的功能是如何干得堂而皇之而又不为人知的。
在CMOS的数据结构中,第1BH至2DH字节保留未用。嘿嘿,正好让我们动点手脚。我们可以
将数据随意地写到这里而不用担心会被通知犯规并被扣除“信用点”,至于写些啥,当然是用
来记录你的劳动成果被免费使用的次数,也可以是版权信息、密码等。在CMOS的数据结构中,
第34H至7FH字节也是保留未用的,但这里不能乱写,许多BIOS厂家使用这里留下自己的版权信息
或者密码。
在CMOS中,第2EH和2FH两个字节存放的是第10H至2DH单元中的数据之和,高位在前,低位在后。
在系统自检时,BIOS还要检测该两处的值是否等于10H至2DH字节的数据之和。如果不等,则认为
CMOS出错,停止引导,提示出错及按〈F1〉进行修改。所以,我们在进行CMOS的操作时一定要保证
这两个字节的正确。最稳妥的解决方案是:建立一个2FH-10H+1=20H即32个字节的数组(注意,
不是128字节,因为00H至09H是系统实时钟,读出后再写回会使其走时不?0H至2FH字节的数据依次读入,
修改某些字节后将前30个元素和的高位赋给数组的第30号元素,低位赋给数组的第31号元素,再将数组
写回到CMOS。
下面的程序段可以实现这个操作,将其加入到你的程序中,便可以记录使用的次数。该程序段利用
CMOS中第25H字节记录使用次数,每使用一次使其减1,并使用CMOS中第26H字节记录是否为首次使用。
若26H处为0并且25H为0,则为首次使用,将剩余使用次数29记入25H处,并将26H处置1。若26H处为0并且25H处
为小于30大于0的值,则将25H处减1,显示剩余使用次数;若26H为1且25H为0,则认为使用次数已经用尽,
给出提示,结束运行。
#define NEVER 2/?定义第一次使用的标志量?/
#define OVER 0/?定义可以使用的标志量?/
#define ENABLE 1/?定义使用次数已尽的标志量?/
main()
{
unsigned char data[32];
unsigned int bytesum=0;
unsigned char k=0;
unsigned int i=0;
clrscr();
for(i=0x10;i<=0x2f;i++)
{ outportb(0x70,i);
data[i-0x10]=inportb(0x71);
}
bytesum=0;
for(i=0x10;i<=0x2d;i++)
{ bytesum+=data[i-0x10];
}
printf(″/nThese are CMOS data without changed:/nsum 10h--2dh:%x/n″,bytesum);
for(i=0x10;i<=0x2f;i++)printf(″%x/t%x/t″,data[i-0x10],i);
printf(″Press any key to chang seek 25h ....../n″);
getch();
if((data[0x25-0x10]<30)&&(data[0x25-0x10]>0)&&(data[0x26-0x10]==1))
k=ENABLE;
if((data[0x25-0x10]<=0)&&(data[0x26-0x10]==1))
k=OVER;
if((data[0x25-0x10]==0)&&(data[0x26-0x10]==0))
k=NEVER;
switch(k)
{ case 1:
{ data[0x25-0x10]-=1;
printf(″/nThis is %dth time ...... last %d times !/n/07″,30-data[0x25-0x10],data[0x25-0x10]);
break;
}
case 0:
{ printf(″/nYour times is over ! Please register !/n/07″);
break;
}
case 2:
{ data[0x25-0x10]=29;
data[0x26-0x10]=1;
printf(″/nThis is the first time ...... last 29 times !/n/07″);
break;
}
}
bytesum=0;
for(i=0x10;i<=0x2d;i++)
{ bytesum+=data[i-0x10];
}
data[0x2e-0x10]=bytesum>>8;
data[0x2f-0x10]=bytesum<< 8 >>8;/?利用位运算将和赋给相应的数组元素 /
printf(″/nThese are had changed CMOS data which is in momorey:/nsum
10h--2dh:%x/n″,bytesum);
for(i=0x10;i<=0x2f;i++)printf(″%x/t%x/t″,data[i-0x10],i);
printf(″Press any key to write back to CMOS !/n″);
getch();
for(i=0x10;i<=0x2f;i++)
{ outportb(0x70,i);
outportb(0x71,data[i-0x10]);
}
printf(″/nDATA WRITED BACK TO CMOS !!!/n/07/07/07″);
for(i=0x10;i<=0x2f;i++)
{ outportb(0x70,i);
data[i-0x10]=inportb(0x71);
}
bytesum=0;
for(i=0x10;i<=0x2d;i++)
{ /?此处可以加上你的软件的主要内容了?/
bytesum+=data[i-0x10];
}
printf(″/nThese are had changed CMOS data in CMOS:/nsum 10h--2dh:
%x/n″,bytesum);
for(i=0x10;i<=0x2f;i++)printf(″%x/t%x/t″,data[i-0x10],i);
printf(″Press any key to over ......″);
getch();
}
此程序对于在CMOS中将硬盘参数设置为AUTO的机器无效,因为每次机器重新启动自动检测硬盘时,
就将CMOS数据更新了。
一个子儿都没有?