首页 > 编程资源分享区 > C/C++源代码共享 > BAT文件转换为COM的程序
2006
05-26

BAT文件转换为COM的程序

众所周知,批处理文件具有编写和使用方便,占用内存少等独到的优点,特别是DOS 3.30以后的版本,又增加
了许多新的批命令,使批处理文件使用起来更得心应手。但批处理文件是用ASCII码存储的,这既是优点也是
缺点。当你编写好一个软件后,其中要用到批处理文件,则会出现泄密的现象。怎样把批处理文件编译为命
令文件,而得到一定程度的保密呢?

一、批处理文件(.BAT)转换为命令文件(.COM)的技术原理

DOS的功能调用4BH是执行装入一个外部程序,并有选择地执行之,使用起来比较麻烦。DOS还提供了一个调用
规则很简单的软中断2EH,可用之完成执行DOS内部和外部命令的要求。
2EH中断的调用规则:首先使用DOS功能调用4AH,开辟一个适当大小的缓冲区,然后,把DS:SI指向以命令串
长度为先导的,以回车(0DH)为后缀的待执行命令串,然后执行中断。在执行2EH之后,除CS外的所有寄存器均
被破坏,所以在执行中断调用之前,要把使用的寄存器保护起来,中断返回后再恢复之。
在批处理文件中,可以把命令等分成以下几类:①内部命令和外部命令,②标号,③注释,④条件语句,⑤转
移语句,⑥循环语句。
对第一类命令,可以直接使用2EH实现;对第二类命令,只需在适当的地方构造一个标号即可;对第三类命令
,在编译过程中,自动删除之;对第四类命令,要使用比较(CMP)与转移(JE,JNE等)来实现;对第五类命令,
使用无条件转跳语句(JMP)来实现;而循环语句,即FOR语句,可以把它当作DOS命令来使用,只是要把
“%%”符号改为”%”。
实现了以上的各类命令,再构造几各通用的子程序就可以完成BAT到COM文件的转换。需要构造的子程序有执行
2EH的子程序,执行DOS返回的子程序和获得DOS命令行参数的子程序等。

二、构造编译程序

要把BAT文件转换为COM文件,还需要有一个有效的编译程序,它主要把相应的BAT文件中相应的命令解译为汇
编程序码或机器码,形成有效的ASM文件或COM文件,最后完成BAT到COM的编译工作。
首先,将用2EH中断执行DOS命令的程序段用汇编语言编好,并汇编、连接为机器码,把这些机器码用C语言的
字符数组表示出来,作为生成命令文件的头部。
其次,是对批文件中所有命令的转换工作,按照上述技术原理中的要求,将所有批命令按2EH中断的调用规则
,转换为待执行命令串,写入命令文件的缓冲区。
最后,将构造好的命令文件,从缓冲区写到磁盘文件上,生成的命令文件是与批命令同名扩展名为COM的命令
文件。

三、程序的使用方法

该程序采用DOS命令行格式:
BAT2COM <文件名>
其中“文件名”是调试好的批处理文件,它必须写上扩展名(.BAT)。如果要批量编译批文件,可以执行如下的
DOS命令:
for %a in (*.bat) do bat2com %a

四、源程序清单
/*************************************************************/
/* 程序名称: BAT2COM.C 1.50 */
/* 作 者: 董占山 */
/* 完成日期: 1993,1995 */
/* 用 途: 将批处理文件(.bat)转换为命令文件(.COM) */
/* 编译方法: 用下列命令编译连接可以得到BAT2COM.COM: */
/* tcc -mt bat2com */
/* tlink c:\tc\lib\c0t+bat2com,bat2com,,c:\tc\lib\cs\lib /t */
/******************************************************* ******/

#include <stdio.h>
#include <string.h>

/* 生成命令文件的头部,包含调用2EH的机器指令 */
char bat2comhead[81] = {
0xBB,0×00,0×10,0xB4,0x4A,0xCD,0×21,0x0E,0x1F,0x2E,
0x8B, 0x0E,0×51,0×01,0xBE,0×51,0×01,0x8B,0xC6,0×50,
0x5B,0×51,0×8 3,0xC3,0×02,0x8B,0xF3,0×33,0xDB,0x8A,
0x1C,0×53,0×56,0x2E,0 x8C,0×16,0x4D,0×01,0x2E,0×89,
0×26,0x4F,0×01,0xCD,0x2E,0x0E ,0x1F,0x2E,0x8B,0×26,
0x4F,0×01,0x2E,0x8E,0×16,0x4D,0×01,0x 58,0x5B,0×59,
0×03,0xC3,0×50,0×83,0xE9,0×01,0×83,0xF9,0×00, 0×75,
0xCD,0xB8,0×00,0x4C,0xCD,0×21,0xC3,0×00,0×00,0×00,
0 x00};

int totallength; /* 所生成文件的总长度 */
char buffer[10000]; /* 生成命令文件的缓冲区 */

/* 删除批命令中的无意义的前导空格函数 */
void removespace(str1)
char *str1;
{
unsigned int i=0;
char *str2;
str2=str1; /* str2指向str1的地址 */
if ((str1==’ ‘) && (i==0))
{
++str1; /* str1地址加1 */
movmem(str1,str2,strlen(str1)+1); /* 删除一个前导空格 */
removespace(str2); /* 递归调用此函数 */
}
}

/* 将批命令中的”%%”改为”%”的函数 */
void removedouble(str1)
char *str1;
{
unsigned int j,i=0;
char *str2;
str2=str1; /* str2指向str1的地址 */
if ((str1==’%') && (str1[++i]==’%'))
{
–i;
for (j=0;j<i;j++) {
++str1;++str2;
}
++str1;
movmem(str1,str2,strlen(str1) +1); /* 删除一个’%'字符 */
removedouble(str2); /* 递归调用此函数 */
}
}

/* 删除批命令中的”@”符号函数 */
void removeatchar(str1)
char *str1;
{
char *str2;
str2=str1; /* str2指向str1的地址 */
if (str1[0]==’@')
{
++str1;
movmem(str1,str2,strlen(str1)+1); /* 删除字符’@’ */
}
}

/* 转换所有的批命令,并写入缓冲区 */
void transfer(flnm)
char *flnm;
{
unsigned int i, cmnum=0;
char strlen1,ch,str1[256],*p,*cm;
FILE *txtfl;
if ((txtfl=fopen(flnm,”r”))==NULL) {
printf(“Input file is not found !”);
exit(0);
}
p = buffer; /* p指向缓冲区的开始地址 */
for (i=0;i<81;++i) *p++=bat2comhead; /* 将命令文件头写入缓冲区 */
ch = 0x0d; /* 回车符 */
totallength = 83; /* 命令文件头加2个字节的总长度 */
for (i=0;i<2;i++) p++; /* p指针相前移动2个字节 */
do {
fgets(str1,256,txtfl); /* 从批文件中读一条命令 */
removespace(str1); /* 删除前导空格 */
removedouble(str1); /* 将”%%”改为”%” */
removeatchar(str1); /* 删除”@”字符 */
strlen1 = strlen(str1); /* 计算命令串长度 */
if (strlen1>2) { /* 合法命令? */
++cmnum; /* 命令数加1 */
*p++ = strlen1-1; /* 把命令长度写入缓冲区 */
++totallength; /* 命令文件总长度加1 */
for (i=0;i<strlen1-1;++i) *p++ = str1; /* 将命令串写入缓冲区 */
totallength += strlen1-1; /* 命令文件总长度加上命令串长度 */
*p++=ch; /* 写入一个回车符 */
++totallength; /* 命令文件总长度加1 */
strcpy(str1,”"); /* 清除命令字符串内容 */
}
} while (!feof(txtfl)); /* 是文件尾吗 ? */
cm = &cmnum; /* 写入命令个数 */
buffer[81] = *cm++;
buffer[80] = *cm;
fclose(txtfl); /* 关闭文件 */
}

/* 将构造好的缓冲区内容写入命令文件 */
void writeBAT2COM(flnm)
char *flnm;
{
FILE *bfl;
unsigned int i;
char drive[3],dir[65],name[9],ext[5] ;
fnsplit(flnm,drive,dir,name,ext);
strcat(name,”.com”);
if ((bfl=fopen(name,”wb”))==NULL) { /* 建立并打开一个二进制文件 */
printf(“File does not opened !”);
exit(1);
}
fwrite(buffer,totallength,1,bfl); /* 写缓冲区的内容 */
/* for (i=0;i<totallength;++i) fprintf(bfl,”%c”,buffer); */
/* for (i=0;i<totallength;++i) fputc(buffer,bfl); */
fclose(bfl);
}

/* 帮助函数 */
void help()
{
printf(“\nSyntex : B2C Batch_filename”);
exit(0);
}

/* 主函数 */
main(argc,argv)
int argc;
char *argv[];
{
char flnm[80];
printf(“\nB2C Version 1.0 Copyright (c) 1993,94 Dong Zhanshan”);
switch (argc) {
case 1 : help();break;
case 2 : strcpy(flnm,argv[1]);break;
default: help();
}
transfer(flnm);
writeBAT2COM(flnm);
}


留下一个回复