Создание com-файла.
Если поинтересоваться тем, что лежит внутри исполняемого файла формата com, можно столкнуться с определенными трудностями. Во многих книгах по ассемблеру предлагается определенным образом составить ассемблерную программу, а затем обработать ее программкой exe2bin.exe, которую можно найти в системном каталоге DOS. Но я в своих виндусовских машинах нигде такую программку не нашел.
Покопавшись в статьях в интернете, я в конце концов составил представление о том, как устроен файл com. А он может быть устроен так.
С самого начала идут машинные команды. Последними выполняемыми командами могут быть
MOV 4c00h
INT 21h
Они заканчивают выполнение программы. Их машинный вид (как мы видим их в com-файле):
B8 00 4C
CD 21
Данные же можно поместить в конце. Например, сразу после последних исполняемых команд, приведенных выше.
Приведем фрагмент, где нам могут понадобиться данные. Это, для примера, вывод строки на экран. Строка должна заканчиваться знаком доллара (код 24h). Сам этот знак на экран не выводится.
Ассемблерные команды для вывода строки:
MOV ah,09h
MOV dx, OFFSET Mes
INT 21h
Что это за OFFSET и Mes? Mes это переменная. А OFFSET фактически означает, что нам нужно смещение этой переменной. Относительно чего? Сейчас разберемся.
Все заработает, если вместо OFFSET Mes мы подставим число, которое будет равно смещению наших данных, но не от начала файла, а от начала файла плюс 100h (то-есть плюс 256 в десятичной форме).
То-есть если данные начинаются с 12-го байта (нумерация с нуля), то команда будет иметь такой вид:
MOV ah,09h
MOV dx, 256+12
INT 21h
А в машинной форме:
B4 09
BA 0C 01
CD 21
Старший и младший байты смещения здесь поменяны местами (так нужно).
В связи со всем этим может оказаться полезной программка, которая создает com-файл из текстового файла. В каждой строке текстового файла байт машинной команды в шестнадцатиричной форме. Причем записано все так, как принято в языке C (с префиксом 0x).
Например, содержимое файла может быть таким:
0x90
0xB8
0x0
0x0
0x8B
0xD0
0x3B
0xC2
0x74
0xe6
0xB4
0x09
0xBA
0x3b
0x01
0xCD
0x21
0xB4
0x09
0xBA
0x42
0x01
0xCD
0x21
0xB8
0x0
0x4C
0xCD
0x21
0x30
0x31
0xD
0xA
0x24
0x30
0x31
0x31
0x31
0xD
0xA
0x24
0x30
0x30
0xD
0xA
0x24
Приведу текст программы на языке C (она воспримет команды из файла Pr.txt и создаст файл Prog.com):
#include <stdio.h>
#include <stdlib.h>
#include "Str_ex.h"
#include "QnS.h"
char End[3]; /* Это конец строки в текстовом файле */
/*******************/
void main(void)
{
int j=1;
int R;
long Res;
short iRes;
FILE *f1;
End[0]=13;
End[1]=10;
End[2]=0;
char dest[200];
char D[10];
char *pD;
/*sprintf(dest,"%d",sizeof(short));
WrStr("Result.txt",End,dest,1);*/ /* Result=2*/
pD=&D[0];
f1=fopen("Prog.com","wb");
if(f1==NULL)
{
return;
}
while(j>0)
{
R=FindStrN("Pr.txt",End,dest,100,j);
j++;
if(R<0)
{
*dest=0;
/*WrStr("Lexema.txt",End," THE END! ",1);*/
break;
}
else
{
/*WrStr("Lexema.txt",End,Lex,1);*/ /* В тестовых целях
пишем в файл */
Res=strtol(dest,NULL,0);
iRes=(short)Res;
pD=(char *)&iRes;
fputc(*pD,f1);
/*fputc(*(pD+1),f1);*/
};
}
fclose(f1);
return;
}
Это программа из проекта в папке PrCom2 для Visual C++ 5.0 (Смотреть). Здесь используется функция FindStrN из моей библиотеке для чтения строки с определенным номером из текстового файла. «Скорострельность» данного алгоритма далеко не оптимальна, но здесь нам важен принцип. В дальнейшем я также часто буду использовать свои функции.
Итак, если мы каким-либо образом (например скомпилировав «вручную») узнали машинные коды интересующего нас DOSовского приложения и занесли их в файл Pr.txt, то с помощью вышеописанной программы мы получим исполняемый com-файл.