9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IPFactoryAdvent Calendar 2019

Day 20

PEを理解したかったのでreadpeってものを作った

Last updated at Posted at 2019-12-19

はじめに

最近私は低レイヤーの勉強をしています.

ある時, IATがおかしいと実行時に怒られてしまいました.
私はその時, IATを直すことができなかったのでPEを理解したいと思い,
readpeを自作しようと思いました.

readpeELFフォーマットを見やすくするためのreadelf
PE版です.

今回実装したオプションは,
-h, -o, -Sです.

私は普段mingw-w64というコンパイラを使っているのですが,
それを使うとMicrosoftのドキュメントの説明と
異なる点があったため, Visual Studioのコンパイラを使いました.

PEとは

Windowsで使用される実行ファイルのファイルフォーマット
COFFとも呼ばれる

MS-DOS Header

前方互換をとるためのHeaderである

DOS Header

  • Sigunature

        0x5A4D(MZ)が格納されている
  • Pointer to PE Header (0x3C)

        PE Headerの先頭のアドレスが格納される

DOS Stub

MS-DOS上で実行するためのコード
通常の場合は処理されず, MS-DOSの場合のみに処理される

#ここから
それではreadpeについて説明したいと思います.
readpex86/x64に対応しています.

**ソースコード**はここから

hello_x86.exe

今回の解析対象はhello_x86.exeです.
コンパイル前のファイルは下記の通りです.

hello_x86.c
#include <stdio.h>

int main() {
    printf("Hello,World!\n");
    return 0;
}

これをcl hello_x86.c -o hello_x86コマンドでコンパイルします.

-h

COFF Headerを出力します.

これを見ることで, このファイルがいつコンパイルされたかなどの
基本的な情報がわかります.

このオプションでは見やすいようにするために,
フラグの部分を赤(1)と緑(0)で分けした.

キャプチャ.PNG

File Header
- **Machine**     どのマシーンを対象として作られているかを示す     基本的には0x8664(x64), 0x014C(x86)
  • NumberOfSections
        セクションの数

  • TimeDataStamp
        1970年1月1日00:00からの秒数
        ファイルが作成された日時を示す

  • PointerToSymbolTable
       

  • NumberOfSymbols
       

  • SizeOfOptionalHeader
        Optionalheaderのサイズ

  • Characteristics
        ファイルの特性を示すフラグ

  • IMAGE_FILE_RELOCS_STRIPPED(0x0001)

        ベース再配置情報が含まれないことを意味する

  • IMAGE_FILE_EXECUTABLE_IMAGE(0x0002)

        実行可能ファイルであることを意味する

  • IMAGE_FILE_LINE_NUMS_STRIPPED(0x0004)

        ファイルから行番号が削除される

  • IMAGE_FILE_LOCAL_SYMS_STRIPPED(0x0008)

        ファイルにシンボルテーブルが含まれない

  • IMAGE_FILE_AGGRESSIVE_WS_TRIM(0x0010)

        Windows2000以降は廃止された

  • IMAGE_FILE_LARGE_ADDRESS_AWARE(0x0020)

        2GBを超えるアプリのアドレスをサポートする

        x64の場合は既定でフラグが立っている

  • NULL(0x0040)

  • IMAGE_FILE_BYTES_REVERSED_LO(0x0080)

  • IMAGE_FILE_32BIT_MACHINE(0x0100)

        x86の場合のみにフラグが立つ

  • IMAGE_FILE_DEBUG_STRIPPED(0x0200)

        デバッグ情報を含まない

  • IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP(0x0400)

        リムーバブルメディアから実行するときに, スワップファイル上にコピーして実行する

  • IMAGE_FILE_NET_RUN_FROM_SWAP(0x0800)

        ネットワーク上から実行するときに, スワップファイル上にコピーして実行する

  • IMAGE_FILE_SYSTEM(0x1000)

  • IMAGE_FILE_DLL(0x2000)

        DLLファイルであるを意味する

  • IMAGE_FILE_UP_SYSTEM_ONLY(0x4000)

        単一のCPUのマシンでのみ実行可能である

  • IMAGE_FILE_BYTES_REVERSED_HI(0x8000)

-o

Optional Headerを出力します.

このHeaderは実行時に必要な情報がたくさん含まれています.

Optional Headerの中でもさらに3の主要な部分があります.
それを見やすくするために[--<header part>--]を付けました.

問題点として, これを出力した際にとても長くなってしまうので,
さらにオプションを増やして, header partごとに出力できるようにしたいです.

キャプチャ.PNG

Standard Fields

実行ファイルをロードする際に必要な情報が含まれている

Details
- **Magic**
    0x010Bの場合はx86, 0x020Bの場合はx64
    これからのサイズが変わる - **MajorLinkerVersion** - **MinorLinkerVersion**
    リンカーのバージョン - **SizeOfCode**
    実行可能なコードのサイズ - **SizeOfInitializedData**
    初期化済みのデータサイズ - **SizeOfUninitializedData**
    未初期化のデータサイズ - **AddressOfEntryPoint**
    実行を始めるEntry Pointのアドレス
    mainではない - **BaseOfCode**
    コード領域のベースアドレス - **BaseOfData**
    初期化済みのデータの開始アドレス
    x86のみが持っている

###Windows-Specific Fields

リンカーとローダに必要な情報が含まれている

Details
- **ImageBase**
    ファイルがロードされると望ましいアドレス
    EXEでは0x004000000, DLLでは0x10000000 - **SectionAlignment**
    メモリにロードされるときに各セクションの開始アドレスが`SectionAlignment`の倍数になる - **FileAlignment**
    ファイル内で各セクションの開始アドレスが`FileAlignment`の倍数になる - **MajorOperatingSystemVersion**
- **MinorOperatingSystemVersion**
    OSのバージョン - **MajorImageVersion**
- **MinorImageVersion**
    ファイルのバージョン - **MajorSubsystemVersion**
- **MinorSubsystemVersion**
    サブシステムのバージョン - **Win32VersionValue**
    今は使われていない - **SizeOfImage**
    ファイルをロードした際のメモリを占めるサイズ - **SizeOfHeaders**
    すべてのファイルヘッダーのサイズ - **CheckSum**
    ロード時にファイルを確認する時に使う - **Subsystem**
    ファイルのターゲットとなるサブシステム
    GUIなら0x02, CUIなら0x03 - **DllCharacteristics**
- IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA(0x0020)
    64bitのアドレス空間でASLRを有効
- IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE(0x0040)
    ASLRを有効 - IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY(0x0080)
    コードのデジタル署名を強制的にする - IMAGE_DLLCHARACTERISTICS_NX_COMPAT(0x0100)
    DEPが有効 - IMAGE_DLLCHARACTERISTICS_ NO_ISOLATION(0x0200)
    アプリケーションの分離を持たない - IMAGE_DLLCHARACTERISTICS_ NO_SEH(0x0400)
    構造化例外ハンドラーを持たない - IMAGE_DLLCHARACTERISTICS_ NO_BIND(0x0800)
    バインドできない - IMAGE_DLLCHARACTERISTICS_APPCONTAINER(0x1000)
    AppContainer 上で実行される必要がある - IMAGE_DLLCHARACTERISTICS_ WDM_DRIVER(0x2000)
    WDMドライバーであることを表す - IMAGE_DLLCHARACTERISTICS_GUARD_CF(0x4000)
    制御フローガードが有効である - IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE(0x8000)
    ターミナルサーバとの互換性がある - **SizeOfStackReserve**
    スタック領域として予約するサイズ - **SizeOfStackCommit**
    スタック領域としてコミットするサイズ - **SizeOfHeapReserve**
    ヒープ領域として予約するサイズ - **SizeOfHeapCommit**
    ヒープ領域として予約するサイズ - **LoaderFlags**
    今は使われていない - **NumberOfRvaAndSizes**
    `Data Directories`のサイズ

###Data Directories
上位の4バイトはアドレスを指していて, 下位4バイトはサイズを表している

Details
- **Export Table**
    エクスポート情報(.edata) - **Import Table**
    インポート情報(.idata) - **Resouce Table**
    リソース(.rsrc) - **Exception Table**
    例外情報(.pdata) - **Certificate Table**
    セキュリティ情報 - **Base Relocation Table**
    再配置情報(.reloc) - **Debug**
    デバッグ情報(.debug) - **Architecture**
    今は使われていない - **Global Ptr**
    グローバルポインター
    構造体サイズは0 - **TLS Table**
    TLS情報(.tls) - **Load Config Table**
    ロード構成情報 - **Bound Import**
    バインドされたインポート情報 - **IAT**
    インポートアドレステーブル - **Delay Import Descriptor**
    遅延インポート情報 - **CLR Runtime Header**
    .NETメタデータ(.cormeta) - **Reserved, must be zero**
    今は使われていない

-S

Section Headerを出力します.

これを見ることで, 各セクションの位置や,
読み込み可能や書き込み可能などのフラグがわかります.

格子状にすることで見やすくなっています.
charactorisicsの部分が見にくいのですがいい方法が思い浮かばなかったため,
とりあえずはそのままにしました.

キャプチャ.PNG

Section Header
- **Name**
    ASCIIで8バイト使う
    余ると0x00が入る - **VirtualSize**
    メモリにロードされた時に, このセクションがどれだけ占めるサイズ - **VirtualAddress**
    メモリにロードされた時に, このセクションが配置されるアドレス - **SizeOfRawData**
    ファイル内でのこのセクションサイズ - **PointerToRawData**
    ファイル内でこのセクションのアドレス - **PointerToRelocations** - **PointerToLinenumbers** - **NumberOfRelocations** - **NumberOfLinenumbers**
    PEでは使われない - **Charactorisics** - IMAGE_SCN_CNT_CODE (0x00000020)
    実行可能コードを含んでいる - IMAGE_SCN_CNT_INITIALIZED_DATA (0x00000040)
    初期化済みのデータが含まれている - IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x00000080)
    未初期化済みのデータが含まれている - IMAGE_SCN_LNK_INFO (0x00000200)
    コメントやその他のデータを含まれている
    .drectveセクションにある
    オブジェクトファイルにのみ有効 - IMAGE_SCN_LNK_REMOVE (0x00000800)
    リンク時にイメージから取り除かれる
    オブジェクトファイルにのみ有効 - IMAGE_SCN_LNK_COMDAT (0x00001000)
    COMDATデータが含まれる
    オブジェクトファイルにのみ有効 - IMAGE_SCN_GPREL (0x00008000)
    グローバルポインターを介して参照するデータがある - IMAGE_SCN_ALIGN_1BYTES (0x00100000) - IMAGE_SCN_ALIGN_2BYTES (0x00200000) - IMAGE_SCN_ALIGN_4BYTES (0x00300000) - IMAGE_SCN_ALIGN_8BYTES (0x00400000) - IMAGE_SCN_ALIGN_16BYTES (0x00500000) - IMAGE_SCN_ALIGN_32BYTES (0x00600000) - IMAGE_SCN_ALIGN_64BYTES (0x00700000) - IMAGE_SCN_ALIGN_128BYTES (0x00800000) - IMAGE_SCN_ALIGN_256BYTES (0x00900000) - IMAGE_SCN_ALIGN_512BYTES (0x00A00000) - IMAGE_SCN_ALIGN_1024BYTES (0x00B00000) - IMAGE_SCN_ALIGN_2048BYTES (0x00C00000) - IMAGE_SCN_ALIGN_4096BYTES (0x00D00000) - IMAGE_SCN_ALIGN_8192BYTES (0x00E00000)
    オブジェクトファイルにのみ有効 - IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000)
    拡張再配置が含まれている - IMAGE_SCN_MEM_DISCARDABLE (0x02000000)
    必要に応じて破棄できる - IMAGE_SCN_MEM_NOT_CACHED (0x04000000)
    メモリ上でキャッシュできない - IMAGE_SCN_MEM_NOT_PAGED (0x08000000)
    メモリ上でページングできない - IMAGE_SCN_MEM_SHARED (0x10000000)
    メモリ上で共有できる - IMAGE_SCN_MEM_EXECUTE (0x20000000)
    実行可能 - IMAGE_SCN_MEM_READ (0x40000000)
    読み込み可能 - IMAGE_SCN_MEM_WRITE (0x80000000)
    書き込み可能

##まとめ
今回の学習により, 自分でPEを解析することができると思います.
次はPackerを作りたいと思います.

##参考

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?