初めに
MS-DOS上で動作するEXEファイルの構造を理解するために、今回はC言語を使ってEXEのバイナリを生成してみます。
Windows用のEXEファイルの先頭には、MS-DOS互換のMZヘッダ
が付いています。
このヘッダのおかげで、Windows用EXEをMS-DOS上で実行すると、以下のような文言が表示されます:
This program cannot be run in DOS mode.
前回の記事https://qiita.com/earthen94/items/acdaddaf36e44adffcd7
でも解説しましたが、当時はまだアセンブリの読み方が十分理解できていませんでした。
改めてバイナリを見直すと、EXEの中には文字列を出力するアセンブリ命令が機械語として組み込まれていることに気づきます。
EXEの生成
C:\Users\test\kaihatsu>gcc test.c -o test
C:\Users\test\kaihatsu>test.exe
test.c
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#pragma pack(push, 1) // 構造体の中身を0埋めしない
typedef struct {
uint16_t e_magic; // "MZ"
uint16_t e_cblp;
uint16_t e_cp;
uint16_t e_crlc;
uint16_t e_cparhdr;
uint16_t e_minalloc;
uint16_t e_maxalloc;
uint16_t e_ss;
uint16_t e_sp;
uint16_t e_csum;
uint16_t e_ip;
uint16_t e_cs;
uint16_t e_lfarlc;
uint16_t e_ovno;
uint8_t reserved[8];
uint16_t e_oemid;
uint16_t e_oeminfo;
uint8_t reserved2[20];
uint32_t e_lfanew;
} MZHeader;
#pragma pack(pop)
int main(void) {
FILE *f = fopen("hello.exe", "wb");
if(!f) return 1;
MZHeader hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.e_magic = 0x5A4D; // "MZ"
hdr.e_cblp = 0x0090; // 最後のページのバイト数(512単位)
hdr.e_cp = 0x0001; // 1ページ ファイル全体のページ数(512バイト単位)
hdr.e_cparhdr = 0x0004; // ヘッダは 64バイト (4*16)
hdr.e_sp = 0x00B8; // DOS標準の初期SP
hdr.e_ip = 0x0000; // 初期IP = 0
hdr.e_cs = 0x0000; // 初期CS = 0
hdr.e_lfarlc = 0x0040; // リロケテーブルのオフセット
// ヘッダを書き込む
fwrite(&hdr, sizeof(hdr), 1, f);
// ヘッダ後の位置 = e_cparhdr*16 バイト(64バイト)に合わせる
uint8_t padding[64 - sizeof(hdr)];
memset(padding, 0, sizeof(padding));
fwrite(padding, sizeof(padding), 1, f);
// コード部分(INT21h AH=9 で文字列出力)
uint8_t code[] = {
0x8C,0xC8, // mov ax, cs
0x8E,0xD8, // mov ds, ax
0xB4,0x09, // mov ah, 9
0xBA,0x10,0x00, // mov dx, 0x0010 ← 文字列のオフセット
0xCD,0x21, // int 21h
0xB8,0x4C,0x00, // mov ax, 4C00h
0xCD,0x21, // int 21h
// 文字列
'H','e','l','l','o',',',' ','D','O','S',' ','w','o','r','l','d','!','$'
};
fwrite(code, sizeof(code), 1, f);
fclose(f);
printf("hello_mz.exe has been generated.\n");
return 0;
}
動作確認
MS-DOS実機上で動かすとHello, DOS world!
と表示されました。
追記
実際にMASMでコンパイルしたEXEのヘッダを解析しました。
https://qiita.com/earthen94/items/359a55b8403a5fc21b47