Windowsで使用されるインストールパッケージのファイル形式、Microsoft Installerというプログラムの元の名前に由来。プログラムのインストール、保存、削除に使用される
Category: Windows
EXEファイルのセクション
セクションにはデータサイズ、RVAなどが保存される
L ネイティブコード、リソース情報、デバッグ情報など
L 読み込み専用領域、再配置情報、インポート関数、エクスポート関数など
なるほど、ソースコードだけでなく、ソフトウェア一式ってイメージだな
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress: DWORD VirtualSize; } DWORD VirtualAddress; // セクションサイズ DWORD SizeOfRawData; // セクション位置 DWORD PointerToRawData; DWORD PointerToRelocations; //再配置エントリ情報 DWORD PointerToLinenumbers; //行番号 WORD NumberOfRelocations; //再配置エントリ WORD NumberOfLinenumbers; DWORD Characteristics; // セクション特性 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADERS;
Nameはセクション名
.text, .data, .idata, .edata, .rsrc, .debug, .reloc, .tls
.text, .data, .rsrcなどの各セクションはIMAGE_SECTION_HEADER構造体の後に配置。やっとか。
インポートは外部DLLと動作リンクを行う
リソースセクション(.rsrc)では、実行に直接関係ない特徴的なデータを管理
L データ型、ID、言語
結構気の遠くなるようなことやってるなー
あれ、でもメモリのポインタってC言語だとソースの中で指定するはずだけど、PointerToRawDataでIMAGE_SECTION_HEADER構造体で指定している?
それと、ネイティブコードのセクションは構造化されるのだろうか?それとも、1つのセクションに纏められるのだろうか?データ処理で考えると、.textセクション、.dataセクション、.rsrcセクションなど各セクション内部で構造化された方が効率的に見えるが。。
ああああ、メモリかー
EXEファイルのPEヘッダ
IMAGE_NT_HEADERS32に定義
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADER32, *PIMAGE_NT_HEADERS32;
PE headerにもSignature
4byte? 32bitOSを意志的している
IMAGE_FILE_HEADER構造体
typedef struct _IMAGE_FILE_HEADERS { WORD Machine; WORD NumberOfSections; DWORD TimeDataStamp; DWORD PointerToSymbols; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_NT_HEADERS;
Machineはそれぞれフラグがあう
unknown:0x0 あらゆるマシンタイプ
I386:0x14c Intel386以降
R3000: 0x162
R4000: 0x166 MIPS(r)リトルエンディアン
R10000: 0x168
….
NumberOfSections: 保持するセクション数
TimeDataStamp: 作成された日時
PointerToSymbols, NumberOfSymbols:シンボルテーブルの位置、数
SizeOfOptionalHeader: 構造体サイズ保持
Characteristics:ファイズ属性値
IMAGE_FILE_EXECUTABLE: 0x0002
IMAGE_FILE_LINE_NUMS_STRIPPED: 0x0004
…
IMAGE_OPTIONAL_HEADER32構造体も同様に定義される
Magic,MajorLinkerVersion, SizeOfCode, SizeOfInitializedData,
SizeOfInitializedData, SizeOfUnitializedData,AddressOfEntryPoint, BaseifCode, BaseOfData, ImageBase, …
IMAGE_DATA_DIRECTORY構造体はRVA, Size
PE Headerにはターゲットマシン、アライメント情報、セクション情報、メモリサイズ情報などが格納されており、OSがメモリにロードして実行する際に書き込まれる
OS側では書き込まれた内容を元にメモリで実行する
ツールを使用すればコンパイル時に自動生成される
第一印象項目が多いなと思ったが、exeファイルの共有フォーマットと考えると妥当か
EXEファイルの内部構造
Windowsの実行ファイルEXEファイルは、通常Visual C++, Visual Basic, Delphiなどのコンパイラが自動生成する
L ほとんどがデータサイズ、ファイル、メモリを指し示すオフセット値で構成されている
MS DOSはマイクロソフトが開発したパソコン用OS
sublimeで開くとバイナリコードでどのように書かれているかわかりません。
L x86に対応する機械語。アセンブラではない。
MZシグネチャはEXEファイルを裏付けるデータ
EXEファイルが動くマシン
– Intel 386以降(Windows)
– MIPS(r)
– Alpha AXP(tm)
– Motorola 68000
– Power PC
– 日立SH3, SH4
リソース箇所にデータを格納する
PEヘッダ(Portable Executable)
EXEファイルの先頭部分の情報
EXEファイルのロード方法
MicrosoftのOSが、MZシグネチャ、マシンタイプ、ネイティブコードなどの情報をもとにEXEファイルをメモリ上にロードして実行する
1. シグネチャ、マシンタイプを確認
2. EXEイメージをメモリ上にコピー
3. PEヘッダ記載データを元にEXEイメージの初期化
4. PEヘッダで指定されたスタートポイントからプログラム実行
なるほど、ディスクに保存したexeファイルをメモリ上に読み込んで、1行ずつ処理していくのね。
EXEファイルイメージは実行前にプロセスメモリの任意の場所にロードされる。メモリの先頭位置をイメージベースという。
RVA(Relative Virtual Address)とはイメージベースからの相対オフセット値
ファイルポインタで読み込み対象となるデータ位置を指定し、RVAでプロセスメモリ上のデータを指し示す
イメージベース + RVA = データアドレス
EXEファイル先頭
IMAGE_DOS_HEADER …MS-DOSで認識可能なデータフォーマット
MS-DOS用スタブ …ネイティブコードを保存できるスペース
NULL空間 … PEヘッダの先頭位置は8バイト境界
PEヘッダ
なるほど、*.exeと*.pkgではソースコードは一緒だけど単純に拡張子だけ異なるって訳ではないのね。当たり前か。
EXEファイルがMS-DOS用のヘッダやデータフォーマットということは、一つのソフトでもOSが変われば当然、ファイルの中身が違うってことですな。