_tmain関数をコーディング(1/2)
int _tmain(int argc, _TCHAR* argv[]) { ///////////////////////////// // 必要なデータを初期化 ///////////////////////////// //コードセッションのサイズ int SizeOf_CodeSection; if(sizeof(NativeBuffer)%ALIGNMENT) SizeOf_CodeSection=sizeof(NativeBuffer) +(ALIGNMENT-sizeof(NativeBuffer)%ALIGNMENT); else SizeOf_CodeSection=sizeof(NativeBuffer); //インポートセクションのサイズ int SizeOf_ImportSection; SizeOf_ImportSection=ALIGNMENT; //データセクションのサイズ int SizeOf_DataSection; if(sizeof(InitBuffer)%ALIGNMENT) SizeOf_DataSection=sizeof(InitBuffer) +(ALIGNMENT-sizeof(InitBuffer)%ALIGNMENT); else SizeOf_DataSection=sizeof(InitBuffer); //コードセクションの開始位置 int Pos_CodeSection=EXE_HEADER_SIZE; //インポートセクションの開始位置 int Pos_ImportSection; Pos_ImportSection= Pos_CodeSection+ SizeOf_CodeSection; //データセクションの開始位置 int Pos_DataSection; Pos_DataSection= Pos_CodeSection+ SizeOf_CodeSection+ SizeOf_ImportSection; //インポートディレクトリテーブルを初期化 ImportDesc[0].OriginalFirstThunk= Pos_ImportSection+ (USE_DLL+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+ sizeof(szDllName); ImportDesc[0].TimeDateStamp=0; ImportDesc[0].ForwarderChain=0; ImportDesc[0].Name= Pos_ImportSection+ (USE_DLL+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR); ImportDesc[0].FirstThunk= ImportDesc[0].OriginalFirstThunk+ sizeof(LookupTable)+ sizeof(HintTable); //ルックアップテーブルを初期化 LookupTable[0]= Pos_ImportSection+ (USE_DLL+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+ sizeof(szDllName)+ sizeof(LookupTable);
EXEファイルのヘッダを生成するためには、あらかじめ各セクションデータの書き込み位置やサイズを知っておく必要があります。_tmain関数の先頭部分ではコードセクション、インポートセクション、データセクションのサイズおよび開始位置を計算します。
インポートセクションの内容は多少入り組んでいるので、ネイティブセクションやデータセクションなどのようにバイナリとしてデータを用意せず、きちんと構造体に値を書き込んでいきます。
//////////////////////////// // EXEファイルのヘッダ情報 //////////////////////////// IMAGE_DOS_HEADER ImageDosHeader; ImageDosHeader.e_magic= 0x5A4D; ImageDosHeader.e_cblp= 0x0090; ImageDosHeader.e_cp= 0x0003; ImageDosHeader.e_crlc= 0; ImageDosHeader.e_cparhdr= 4; ImageDosHeader.e_minalloc=0x0000; ImageDosHeader.e_maxalloc=0xFFFF; ImageDosHeader.e_ss= 0x0000; ImageDosHeader.e_sp= 0x00B8; ImageDosHeader.e_csum= 0x0000; ImageDosHeader.e_ip= 0x0000; ImageDosHeader.e_cs= 0x0000; ImageDosHeader.e_lfarlc= 0x0040; ImageDosHeader.e_ovno= 0x0000; ImageDosHeader.e_res[0]= 0; ImageDosHeader.e_res[1]= 0; ImageDosHeader.e_res[2]= 0; ImageDosHeader.e_res[3]= 0; ImageDosHeader.e_oemid= 0x0000; ImageDosHeader.e_oeminfo= 0x0000; ImageDosHeader.e_res2[0]= 0; ImageDosHeader.e_res2[1]= 0; ImageDosHeader.e_res2[2]= 0; ImageDosHeader.e_res2[3]= 0; ImageDosHeader.e_res2[4]= 0; ImageDosHeader.e_res2[5]= 0; ImageDosHeader.e_res2[6]= 0; ImageDosHeader.e_res2[7]= 0; ImageDosHeader.e_res2[8]= 0; ImageDosHeader.e_res2[9]= 0; ImageDosHeader.e_lfanew= 0x0100; //PEヘッダの位置
この構造体は昔からの名残であり、ほとんど意味を持ちません。しかしながら、EXEファイルの先頭に必ず存在することになっているので、きちんと定義しておきましょう。e_magicにEXEファイルのシグネチャである「MZ」が書き込まれる点、e_lfanewメンバにPEヘッダの先頭位置が書き込まれる点に注意してみると良いでしょう。
///////////////////////////////////////////// // PEヘッダ ///////////////////////////////////////////// IMAGE_NT_HEADERS ImagePeHdr; ImagePeHdr.Signature=IMAGE_NT_SIGNATURE; //マシンタイプ ImagePeHdr.FileHeader.Machine= IMAGE_FILE_MACHINE_I386; ImagePeHdr.FileHeader.NumberOfSections= 3; //セクション数 ImagePeHdr.FileHeader.TimeDateStamp= (DWORD)time(NULL); ImagePeHdr.FileHeader.PointerToSymbolTable= 0x00000000; ImagePeHdr.FileHeader.NumberOfSymbols= 0x00000000; ImagePeHdr.FileHeader.SizeOfOptionalHeader= IMAGE_SIZEOF_NT_OPTIONAL32_HEADER; ImagePeHdr.FileHeader.Characteristics= IMAGE_FILE_EXECUTABLE_IMAGE| IMAGE_FILE_32BIT_MACHINE| IMAGE_FILE_LINE_NUMS_STRIPPED| IMAGE_FILE_LOCAL_SYMS_STRIPPED; ImagePeHdr.OptionalHeader.Magic= 0x010B; ImagePeHdr.OptionalHeader.MajorLinkerVersion= 1; ImagePeHdr.OptionalHeader.MinorLinkerVersion= 0; //コードサイズ(.textのセッションサイズ) ImagePeHdr.OptionalHeader.SizeOfCode= sizeof(NativeBuffer); //データサイズ(.dataのセッションサイズ) ImagePeHdr.OptionalHeader.SizeOfInitializedData=sizeof(InitBuffer); //未初期化データのサイズ(なし) ImagePeHdr.OptionalHeader.SizeOfUninitializedData=0; ImagePeHdr.OptionalHeader.AddressOfEntryPoint= Pos_CodeSection; //.textのアドレス ImagePeHdr.OptionalHeader.BaseOfCode= Pos_CodeSection; //.dataのアドレス ImagePeHdr.OptionalHeader.BaseOfData= Pos_DataSection; //イメージベース ImagePeHdr.OptionalHeader.ImageBase= 0x00400000; //セクションアラインメント ImagePeHdr.OptionalHeader.SectionAlignment= ALIGNMENT; ImagePeHdr.OptionalHeader.FileAlignment= ALIGNMENT; ImagePeHdr.OptionalHeader.MajorOperatingSystemVersion=4; ImagePeHdr.OptionalHeader.MinorOperatingSystemVersion=0; ImagePeHdr.OptionalHeader.MajorImageVersion= 0; ImagePeHdr.OptionalHeader.MinorImageVersion= 0; ImagePeHdr.OptionalHeader.MajorSubsystemVersion=4; ImagePeHdr.OptionalHeader.MinorSubsystemVersion=0; ImagePeHdr.OptionalHeader.Win32VersionValue= 0; //すべてのイメージサイズ ImagePeHdr.OptionalHeader.SizeOfImage= EXE_HEADER_SIZE+ SizeOf_CodeSection+ SizeOf_ImportSection+ SizeOf_DataSection; //ヘッダサイズ ImagePeHdr.OptionalHeader.SizeOfHeaders= EXE_HEADER_SIZE; ImagePeHdr.OptionalHeader.CheckSum= 0; ImagePeHdr.OptionalHeader.Subsystem= IMAGE_SUBSYSTEM_WINDOWS_GUI; ImagePeHdr.OptionalHeader.DllCharacteristics= 0; ImagePeHdr.OptionalHeader.SizeOfStackReserve= 0x00100000; ImagePeHdr.OptionalHeader.SizeOfStackCommit= 0x00001000; ImagePeHdr.OptionalHeader.SizeOfHeapReserve= 0x00100000; ImagePeHdr.OptionalHeader.SizeOfHeapCommit= 0x00001000; ImagePeHdr.OptionalHeader.LoaderFlags= 0; ImagePeHdr.OptionalHeader.NumberOfRvaAndSizes= IMAGE_NUMBEROF_DIRECTORY_ENTRIES; //データ ディクショナリ ImagePeHdr.OptionalHeader.DataDirectory[0].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[0].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[1].VirtualAddress= Pos_ImportSection; //インポートテーブル ImagePeHdr.OptionalHeader.DataDirectory[1].Size=SizeOf_ImportSection; ImagePeHdr.OptionalHeader.DataDirectory[2].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[2].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[3].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[3].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[4].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[4].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[5].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[5].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[6].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[6].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[7].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[7].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[8].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[8].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[9].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[9].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[10].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[10].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[11].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[11].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[12].VirtualAddress= Pos_ImportSection+ (USE_DLL+1)*sizeof(IMAGE_IMPORT_DESCRIPTOR)+ 16*USE_DLL+ //DLL名 sizeof(LookupTable)+ //ルックアップテーブル sizeof(HintTable); //ヒント名(関数名)テーブル ImagePeHdr.OptionalHeader.DataDirectory[12].Size=sizeof(LookupTable); ImagePeHdr.OptionalHeader.DataDirectory[13].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[13].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[14].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[14].Size=0; ImagePeHdr.OptionalHeader.DataDirectory[15].VirtualAddress=0; ImagePeHdr.OptionalHeader.DataDirectory[15].Size=0;
このサンプルプログラムが生成するEXEファイルは、「.text」「.idata」「.sdata」という3つのセクションを保有します。セクション数が変わると、NumberOfSectionsメンバの値が変わります。
