いろんなものはつながっている

組み込みOS自作入門(5)ELFフォーマットの展開

ELF形式の構造

ELF1

ELFヘッダ

ELF形式の先頭には16バイトの識別領域がある。マジックナンバとよばれるもの。ELFフォーマット先頭4バイトは必ず0x7f 0x45 0x4c 0x46となっている。そのほか識別情報には32ビットor64ビットの区別、エディアン、OS種別などが含まれている。

識別情報の後はファイルのサイズやアドレスに関する情報がならんでいる。エントリポイントのアドレスやセクションヘッダーテーブルの位置が書かれている。最後に書いてあるSection header string table indexは、セクション名がまとめて書かれているセクションのインデックス番号が書かれている。

セクション・ヘッダ・テーブル

セクション情報が書かれている。セクション名、セクションのタイプ、セクションのアドレス、セクションのファイル内での位置等が書かれている。.strtabというセクションにはセクション名がまとめて書かれている。

プログラム・ヘッダ・テーブル

セグメント情報が書かれている。セグメントのタイプにはメモリにロードされるもの、動的リンク情報、などの種別がなされている。アドレス関係では、ファイルでのセグメントの位置、メモリ上での物理アドレス、仮想アドレスの情報がある。あと、ファイル上でのサイズとメモリ上でのサイズもある。ファイル上でのサイズ≠メモリ上でのサイズとなるのは初期値のない静的変数のセクションBBS領域などでありえる。

プログラム・ヘッダによるメモリ展開

特定のフォーマットを解析するためには、各ヘッダに対応する構造体を定義して該当アドレスを構造体のポインタにキャストすることでフォーマット内のパラメータを参照することができる。

本のなかでELF形式ファイルのヘッダをのぞいていたように、Windowsの実行形式ファイルのヘッダーをちょっとのぞいてみた。Windowsの実行形式ファイルはもともとUNIXでの利用に由来をもつCOFF(Common Object File Format))形式をベースに設計されたPE(Portable Executable)とよばれるもの。COFFヘッダのまえにMS-DOS互換ヘッダー、MS-DOS用スタブがある。WindowsファイルフォーマットをあらわすマジックナンバのMZはPE形式を設計した人のイニシャルだそうだ。

ELF2
さしあたり、マジックナンバのMZとシグニチャのPE、あとファイルの作成日をみてみることにした。MS-DOS互換ヘッダやCOFFヘッダの構造体はwinnt.hに定義されているが関係のない要素はまとめた構造体を自分で定義した。

#include "stdafx.h"
#include "time.h"

typedef struct _MOS_DOS_HEADER {
	char MagicNum[2];
	char Dummy[58];
	long OffsetToPE;
} MOS_DOS_HEADER;

typedef struct _COFF_HEADER {
	char Signature[4];
	unsigned short TargetMachineType;
	unsigned short SectionNum;
	unsigned short TimeStamp[2];
	unsigned short OffsetToSymbolTable[2];
	unsigned short TableEntryNum[2];
	unsigned short SizeOfOptionHeader;
	unsigned short TypeOfFile;
} COFF_HEADER;

int main(int argc, char* argv[])
{
	// ファイルの先頭アドレスを取得する
	FILE* fp = fopen("C:\\temp\\wmplayer.exe", "r");
	if(fp == NULL) return -1;
	char c=fgetc(fp);
	char* pAddress = fp->_ptr;
	pAddress = pAddress - 1;

	// MOS-DOS互換ヘッダーをあらわした構造体にキャスト
	MOS_DOS_HEADER* pMS_DOS_HEADER = (MOS_DOS_HEADER*)(pAddress);
	long OffsetToPE = pMS_DOS_HEADER->OffsetToPE;
	printf("MagicNumber = %c%c\n", pMS_DOS_HEADER->MagicNum[0], pMS_DOS_HEADER->MagicNum[1]);

	// COFFヘッダーへのオフセット値を得て
	// COFFヘッダーをあらわした構造体にキャスト
	COFF_HEADER* pCOFF_HEADER = (COFF_HEADER*)(pAddress + OffsetToPE - 1);
	printf("Sinagure = %c%c\n", pCOFF_HEADER->Signature[0], pCOFF_HEADER->Signature[1]); 
	time_t* pTimeStamp = (time_t*)(pCOFF_HEADER->TimeStamp);
	struct tm *ts;
	ts = localtime(pTimeStamp);
	char buf[80];
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
    printf("TimeStamp=%s\n", buf);

	return 0;
}

ELF3

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク