用Windows终端仿真程序实现微机远程文件传送1.docx
《用Windows终端仿真程序实现微机远程文件传送1.docx》由会员分享,可在线阅读,更多相关《用Windows终端仿真程序实现微机远程文件传送1.docx(7页珍藏版)》请在冰豆网上搜索。
用Windows终端仿真程序实现微机远程文件传送1
用Windows终端仿真程序实现微机远程文件传送1
有些硬盘防拷贝是通过对硬盘FAT表中的簇链的检测来实现的,这与本文所推荐的方法原理一样,都是通过检测文件位置信息是否被改变来判断文件是否已被移动的。
但前者涉及到定位FAT表及文件所在目录等繁琐工作,而且还和硬盘型号及格式化信息有关,编程很不方便。
本文所介绍的方法则不然,它直接与操作系统打交道,取出操作系统内核中现成的数据,即利用DOS系统文件表(SYSTEMFILETABLE简称SFT)来实现防拷贝。
当您打开硬盘上的一个文件并移动读写指针时,DOS会时刻记录读写指针所对应的硬盘位置。
一个稍大些的文件在硬盘上要占用多个簇,这些簇并不是连续的,而是由操作系统一般按照“就近循环分配”原则为该文件分配的,这些簇的绝对簇号具有一定的随机性,在FAT表中形成一个簇链。
移动读写指针超过一个簇的大小时,则所对应的绝对簇号也要变化。
只要该文件没有被移动过(拷贝或整理硬盘),这些簇号就是固定的。
一旦该文件被移动了,根据DOS簇分配原则,这些对应的簇号就会改变。
由此,我们可以检查特定的文件指针所对应的绝对簇号是否改变了来判断该文件是否已被非法移动。
SFT是DOS在文件管理上的一个很重要的数据结构。
只要DOS开始引用一个文件或设备,它必然要建立一个SFT。
该表记录了文件设备名、目录特性、设备特性、文件大小和位置、DDPB(块设备)或设备驱动程序标题(字符设备)的地址,以及打开模式等有关文件的存储、访问和操作的管理信息。
其中有几项数据可以用来确定文件在硬盘上的位置,它们是:
文件读写指针所对应的绝对簇号,目录项的相对索引号(即目录项在目录扇区中的序号),目录项所在扇区的扇区号。
那么怎样利用这几项数据防拷贝呢?
这里所说的防拷贝是指可以拷贝但拷贝后的文件不能执行或不能被使用,包括数据文件和可执行文件。
若是可执行文件,则其本身包括一段检测代码,用以判断其本身是否已被非法移动。
若是数据文件,则在使用该数据文件的可执行文件中包括一段检测代码,来判断该数据文件是否已被非法移动。
当第一次将一个文件装入硬盘后,它所占有的硬盘的簇号已是固定的了。
这样我们就可以作一个加密程序,在该程序里,约定一个或多个秘密的值N,N1,N2…,然后将文件指针分别移动到N或N1,N2…,在SFT中取出那几项硬盘位置数据,再用约定的秘密算法加以运算,就得到了包含被加密文件位置信息的“钥匙”,将它存于另一个文件中或干脆附加在被加密文件的末尾。
在使用该文件的可执行文件的检测代码中,按同样的算法取得当前的“钥匙”,与先前保存的“钥匙”相比较,若相等,则说明文件没有被移动过,程序正常执行,否则,说明文件已不在先前的位置了,即已被非法移动过了,则程序异常执行。
我们先看看DOS系统中SFT的具体结构,系统有多个SFT,这个数目取决于文件中的FILES=N的N值。
在,,中,每个SFT的长度是3BH。
多个SFT形成SFT数组,并不是整个系统的所有SFT组成一个连续的大数组,而是可能有多个SFT数组,每个数组由一个控制块管理,它们之间由指针连接。
每个SFT数组的结构
偏移量长度说明
00HDWORD指向下一个SFT数组的指针
04HWORD本SFT数组内的SFT数目
06HnBYTEs由SFT组成的数组(n=本数组中SFT数目*每个SFT所占字节数)
我们还必须知道第一个SFT数组所在的地址。
这可由DOS功能调用52H先取得DOS的多重表指针,在多重表偏移量04H处即是一个长指针,它即指向第一个SFT数组的头部。
这样剩下的SFT数组的位置也就知道了。
每当DOS打开一个新文件时,DOS就从这些SFT数组中找一个空闲的SFT项,分配给该文件。
以后DOS就用此SFT控制访问该文件。
那么怎样确定一个刚打开的文件所对应的SFT项是SFT数组中的第几项呢?
我们利用文件句柄和文件句柄表。
每个进程都有一个文件句柄表,当我们打开一个文件时可得到该文件的句柄,它是一个整数,设为M,则在文件句柄表中的第M项即为该文件的SFT表项在SFT数组中的位置。
那么怎样找到文件句柄表呢?
我们先用DOS功能调用51H得到程序段前缀(PSP)的地址,在PSP偏移34H处即是指向该进程文件句柄表的双字指针。
附图给出怎样找一个已打开文件的SFT。
@@;附图@@
打开文件取得文件句柄是3,所对应的SFT的序号是6。
下面就给出一个可执行文件防拷贝的例子。
假设我们用C++语言编一个完成某一功能的程序,经过编译连接生成可执行文件,要对这个可执行文件实行硬盘防拷贝。
我们先编写一个设置“钥匙”的程序PUT-KEY,在该程序中按上述方法取得的“原钥匙”(它包含了初次装入硬盘时的位置信息),存于一个专用文件中(当然也可直接附加在的末尾,取时也到文件末尾去取),在中必须包含一段检测代码。
它也用PUT-KEY的方法取出自己的“当前钥匙”,与存于中的“原钥匙”比较,相等则说明文件还在原处,正常执行。
否则,说明正在执行的是被拷贝的副本,停止执行或异常执行。
这里,不用考虑“钥匙”的安全性,“钥匙”是可以公开的,只要取得“钥匙”的方法是保密的,非法拷贝者就无可奈何。
可以这样理解这个防拷贝方法:
可执行文件本身具有自锁性,在它每拷贝到一个新地点时就按文件位置上了一把新锁,当它执行时,它到一个固定的地方去取“钥匙”,打开本身的锁执行。
当它被移动后,可理解为锁换了(因为位置变了)。
用“原钥匙”打不开,所以“原钥匙”是可以公开的,就是用来设置“原钥匙”的。
当合法用户想把拷贝到一个新地方,只需运行一次就可以使用新的了。
所以必须由合法用户保管。
先编写一个取“钥匙”的子程序,放在文件中,在该子程序中,分别取目录项的相对索引号,目录项所在扇区的扇区号,文件指针所对应的绝对簇号。
采用相加的算法,形成“钥匙”。
这里只用了一个文件指针6000所对应的簇号,当然可以使用多个文件指针,采用更复杂的算法,如相乘、相除、异或、相减等。
所用的文件指针和所用的算法是保密的。
而算出的“钥匙”可以是公开的。
的内容如下(本文件用来被包含在和中)。
/*本子程序用来取filename的"当前钥匙"*/
unsignedlongcurentlocation-key(charfilename)
{
unsignedlongsecc;
intfilehandle;
inti,iii,jjj1,jjj2;
unsignedcharu-char=0;
unsignedintu-int=0;
unsignedlongu-long=0;
unsignedintoffst1,segmnt1,offst2,segmnt2;
voidpsp-ptrr;
unsignedcharfarptrr1,ptrr2;
FILEStream;
Stream=fopen(filename,"r+b");
if(Stream==NULL)
{cputs("openerror");exit
(1);}
filehandle=fileno(Stream);//取文件句柄;
fseek(Stream,6000,0);//将文件指针置于6000处;
fread(&i,2,1,Stream);//读一次,使DOS按此文件指针修正SFT;
asmpushes
asmmovah,51h
asmint21h//取程序段前缀(PSP)段地址;
asmmoves,bx
asmmovax,wordptres:
[52]//偏移量34H为文件句柄表(FHT)地址;
asmmovbx,ax
axmmovax,wordptres:
[54]
asmmoves,ax
asmaddbx,filehandle//文件句柄表中偏移filehandle处的一字节;
asmmoval,byteptres:
[bx]//为该文件的SFT在SFT数组中的序号;
asmxorah,ah
asmpopes
asmmoviii,ax//iii中存放文件的SFT在SFT数组中的序号;
asmpushes
asmmovah,52h//取DOS多重表指针;
asmint21h//es为段地址,bx为偏移量;
asmmovax,wordptres:
[bx+4]//多重表中偏移04H为第一个SFT数组控制块指针
;
asmmovoffst1,ax//offset1为第一个SFT数组控制块偏移量;
asmmovax,wordptres:
[bx+6]
asmmovsegmnt1,ax//segment1为第一个SFT数组控制块段地址;
asmmoves,segmnt1
asmmovbx,offst1
asmmovax,wordptres:
[bx]
asmmovoffst2,ax//offset2为第二个SFT数组控制块偏移量;
asmmovax,wordptres:
[bx+2]
asmmovsegmnt2,ax//segment2为第二个SFT数组控制块段地址;
asmmovax,wordptres:
[bx+4]
asmmovjjj1,ax//jjj1中存放第一个SFT数组的项数,一般为五
asmmoves,segmnt2//个(系统保留的五个常用文件的SFT);
asmmovbx,offst2
asmmovax,wordptres:
[bx+4]
asmmovjjj2,ax//jjj2中存放第二个SFT数组的项数,它一般等于
asmpopes//中FILES=N的N值减去第一个SFT
//数组中SFT项数jjj1;
ptrr1=(unsignedcharfar*)MK-FP(segmnt1,offst1+6);
//ptrr1指向第一个SFT数组中第一个SFT
Ptrr2=(unsignedcharfar*)MK-FP(segmnt2,offst2+6);
//ptrr2指向第二个SFT数组中第一个SFT
if(iii
#include
#include
#include
#include
#include""//将取钥匙子程序包函进来;
voidmain(intargc,char*argv[])//命令行上是待加密的文件名;
{
unsignedlongkey=0;
FILE*stream;
if(argc2)
{cputs("specifyafile");exit
(1);}
key=curentlocation-key(argv[1]);//取出文件当前“钥匙”;
stream=fopen("","w+b");//以写方式打开“钥匙”文件
t;
if(stream==NULL)
{cputs("can’topenfile");exit
(1);}
fwrite(&key,4,1,stream);//将当前“钥匙”(4字节)写入文件;
fclose(stream);
}
下面就是的内容:
#include
#include
#include
#include
#include
#include
#include
#include""//将取钥匙子程序包函进来;
//该程序main()函数
intmain()
{
//下面是一段检测代码,(可放在程序中必要的地方);
unsignedlongproto-key,curent-key;
FILE*Stream;
Stream=fopen("","rb");//以读方式打开“钥匙”文件;
if(Stream==NULL)//若因破坏而打不开则退出;
{cputs("openerror");exit
(1);}
fread(&proto-key,4,1,Stream);//取存放于文件中的“原钥匙”(4字节);
fclose(Stream);
curent-key=curentlocation-key("");//按同样的方法取“当前钥匙”;
if(curent-key!
=proto-key)//比较“当前钥匙”和“原钥匙”;
{
cputs("Thefilehasbeenmovedandisinvalid!
");exit
(1);
}
//若不相等,说明当前的文件位置与装入时的位置不同,//文件已经被移动过,这里可异常执行;
cputs("Thefileisvalid");//否则正常进行,完成程序的功能;
//以下是程序代码;
//...
//...
return0;
}//为了防跟踪,当打不开“钥匙”文件或发现文件已被移动过时,可不退出,而是
//异常执行;
以上程序用Borlandcc++编写,使用时,分别编译连接和
P形成和。
然后在DOS提示符下键入:
NO-COPY
就会得到openerror的信息,程序退出,这是因为还没有运行PUT-KEY来设置“钥匙”。
若先键入PUT-KEY 来为设置“钥匙”
再键入NO-COPY
则得到Thefileisvalid说明正常执行。
若将拷贝到其它目录再执行就会得到openerror的信息,程序退出。
若将一起拷贝到其它目录再执行
则得到Thefilehasbeenmovedandisinvalid!
若先在新目录运行PUT-KEY 来为新的设置“钥匙”
再运行新的NO-COPY
则得到Thefileisvalid说明正常执行。
若要对一个或多个数据文件加密,可对稍加修改,再在使用这些数据文件的可执行文件的原程序中加入检测代码即可。
若要修改加密算法或调整“钥匙”的取出方
法,则只需修改curentlocation-key()函数。