アセンブラとPEフォーマットとマシン語の注入

Last modified: 2005/07/28 10:37:34

はじめに

私は以前、任意のプログラムを他プロセスへ注入する「DLLインジェクション」のテクニックを紹介しました。このテクニックについての詳細は「常駐プログラム隠蔽テクニック」を参照してください。

さて、この「DLLインジェクション」は、任意のプログラムを現在実行中の他プロセスへ注入し、他プロセスの一部としてこちら側が用意したプログラムを実行させるテクニックでした。これはとても面白く、任意のプロセスの情報を取得するための手法としてはSetWindowsHookExと同じくらい強力であり、かつ、実行したいプロセスの隠蔽という目的においても利用できるものでした。しかし、これはあくまでも実行中のプロセスへ注入したわけであり、EXEファイル自体を書き換えたわけではありません。よって、例えば、そのプロセスが何かしらの理由で強制終了し、再度起動された場合、もう一度、任意のプログラムの注入処理をほどこさなければ、我々の望む動作は得られません。もちろん、このテクニックも利用価値は多々ありますが、今回はこの「任意のプログラムを他のプログラムへ注入する」という行為を、「EXEファイルの変更」という角度から見ていくことにします。

今回、私が使用する環境はWindowsXPです。なお、このテキストを読むにあたって、PEフォーマットとアセンブラについての知識が必須となります。

PEフォーマット

PEフォーマットとは、Win32のバイナリフォーマットであり「Portable Executable」の略です。WindowsのEXEファイルは、このファイル形式で作られています。このファイル形式の詳細は、「マシン語大研究」のページを参考にしてください。このテキストでは、PEフォーマットについて簡単に解説します。まずは以下のEXEファイルmsg.exeをダウンロードしてください。

./msg.exe

マシン語大研究(PEフォーマットの解説)

msg.exeをバイナリエディタで開くと、以下のようになっています。私はバイナリエディタに「Stirling」を使用しています。

Stirling

-----  msg.exe(抜粋)
00000000  4D 5A 6C 00 01 00 00 00 02 00 00 00 FF FF 00 00  MZl.............
00000010  00 00 00 00 11 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000020  57 69 6E 33 32 20 50 72 6F 67 72 61 6D 21 0D 0A  Win32 Program!..
00000030  24 B4 09 BA 00 01 CD 21 B4 4C CD 21 60 00 00 00  $...............
00000040  47 6F 4C 69 6E 6B 20 77 77 77 2E 47 6F 44 65 76  GoLink www.GoDev
00000050  54 6F 6F 6C 2E 63 6F 6D 00 00 00 00 00 00 00 00  Tool.com........
-----

アドレス「00000020」以降は「Win32 Program!\r\n$」という17バイトの文字列があるのが分かります。そして、アドレス「00000031」以降の「B4 09 BA 00 01 CD 21 B4 4C CD 21」は16ビット環境でのマシン語となっています。このマシン語をアセンブリ言語に変換すると以下のようになります。

-----
355C:0011  B409     MOV AH, 09
355C:0013  BA0001   MOV DX, 0100
355C:0016  CD21     INT 21
355C:0018  B44C     MOV AH, 4C
355C:001A  CD21     INT 21
-----

「AH = 09」は文字列出力のシステムコールです。そして、出力すべき文字列のアドレスはDXレジスタに格納するので、「355C:0100」にある文字列を出力することになります。さらに「AH = 4C」はプログラム終了のシステムコールなので、ここで16ビットプログラムは終了となります。

そして、「0000003C」から続く4バイトがPEフォーマットの先頭アドレスとなります。つまり、「60 00 00 00」がPEフォーマットの先頭アドレスとなります。

-----  msg.exe(抜粋)
00000060  50 45 00 00 4C 01 01 00 E9 65 E4 42 00 00 00 00  PE..L...........
00000070  00 00 00 00 E0 00 0F 01 0B 01 00 25 00 04 00 00  ...........%....
-----

ご覧の通り、アドレス「00000060」以降は「50 45」(文字列にすると「PE」)となっています。

さて、重要なのは、この「0000003C」から続く4バイトなので、例えば「0000003C」から続く4バイトを「40 00 00 00」に変更し、PEフォーマット部分も32バイト(20h)ずらし「00000040」から始めれば、msg.exeの「00000040から0000005Fまで」のデータは削除することが可能です。それは、この領域のデータ(文字列)をみても、リンカが意図的に付加したものだと分かります。

では、次に「00000000から0000001Fまで」のフォーマットをみていくことにします。

-----  msg.exe(抜粋)
00000000  4D 5A 6C 00 01 00 00 00 02 00 00 00 FF FF 00 00  MZl.............
00000010  00 00 00 00 11 00 00 00 40 00 00 00 00 00 00 00  ........@.......
-----
-----
0000h  2byte  4D 5A        「MZ」(固定)
0002h  2byte  6C 00        Number of bytes in last 512-byte page of executable
0004h  2byte  01 00        Total number of 512-byte pages
                           in executable (including the last page)
0006h  2byte  00 00        Number of relocation entries
                           再配置エントリ数
0008h  2byte  02 00        Header size in paragraphs
                           ヘッダのサイズ(16バイト単位)
000Ah  2byte  00 00        Minimum paragraphs of memory allocated
                           in addition to the code size
                           割り当てるメモリの最小値
000Ch  2byte  FF FF        Maximum number of paragraphs allocated
                           in addition to the code size
                           割り当てるメモリの最大値
000Eh  2byte  00 00        Initial SS relative to start of executable
                           スタックセグメントの初期値
0010h  2byte  00 00        Initial SP
                           スタックポインタの初期値
0012h  2byte  00 00        Checksum (or 0) of executable
                           チェックサム
0014h  4byte  11 00 00 00  CS:IP relative to start of executable (entry point)
                           プログラムのエントリーポイント
0018h  2byte  40 00        Offset of relocation table;
                           40h for new-(NE,LE,LX,W3,PE etc.) executable
                           プログラムの開始アドレス
001Ah  2byte  00 00        Overlay number (0h = main program)
001Ch  4byte  00 00 00 00  reserved?
                           多分予約語です(^^;。
-----

さて、ここまでのバイナリデータは、DOS用に用意されたプログラムです。つまりWindowsプログラムが実行できない環境でmsg.exeが実行された場合、標準出力に「Win32 Program!」と表示して、プログラムを終了するわけです。DOS用のデータであるため、Windows環境で実行する場合は、意味がありません。よってPEフォーマットの解説でも、よくこの部分の説明は省かれることが多いです。なぜなら、この部分はPEフォーマットというよりむしろMZフォーマットなので(笑)。というわけで、ここからがPEフォーマットの本番ということになります。ちなみにPE以前のデータ(00000000から0000005Fまで)をtest.comというようなCOMファイルとして作成し、コマンドプロンプトに「test.com」と入力すれば、ちゃんと実行されます。よかったら一度試してみてください。

./test.com

-----  test.com
00000000  4D 5A 6C 00 01 00 00 00 02 00 00 00 FF FF 00 00  MZl.............
00000010  00 00 00 00 11 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000020  57 69 6E 33 32 20 50 72 6F 67 72 61 6D 21 0D 0A  Win32 Program!..
00000030  24 B4 09 BA 00 01 CD 21 B4 4C CD 21 60 00 00 00  $...............
00000040  47 6F 4C 69 6E 6B 20 77 77 77 2E 47 6F 44 65 76  GoLink www.GoDev
00000050  54 6F 6F 6C 2E 63 6F 6D 00 00 00 00 00 00 00 00  Tool.com........
-----
-----  コマンドプロンプト
C:\nasm>test.com
Win32 Program!

C:\nasm>
-----

test.comの実行例

では、ここから本当のPEフォーマットを見ていくことにします。

-----  msg.exe(抜粋)
00000060  50 45 00 00 4C 01 01 00 E9 65 E4 42 00 00 00 00  PE..L...........
00000070  00 00 00 00 E0 00 0F 01                          ........
-----
-----  PEヘッダ
0060h  4byte  50 45 00 00  「PE\0\0」(固定)
0064h  2byte  4C 01        CPUタイプ(「4C 01」はIntel386以降)
0066h  2byte  01 00        セクション数
0068h  4byte  E9 65 E4 42  タイムスタンプ
006Ch  4byte  00 00 00 00  シンボルテーブルの位置(存在しなければ0)
0070h  4byte  00 00 00 00  シンボルテーブル内のエントリ数(存在しなければ0)
0074h  2byte  E0 00        オプションヘッダのサイズ
0076h  2byte  0F 01        ファイルの特性
-----
-----  msg.exe(抜粋)
00000070                          0B 01 00 25 00 04 00 00  ...........%....
00000080  00 00 00 00 00 00 00 00 00 10 00 00 00 10 00 00  ................
00000090  00 00 00 00                                      ....
-----
-----  オプションヘッダ(標準フィールド)
0078h  2byte  0B 01        識別子(実行ファイル「0B 01」、ROMイメージ「07 01」)
007Ah  1byte  00           リンカのメジャーバージョン
007Bh  1byte  25           リンカのマイナーバージョン
007Ch  4byte  00 04 00 00  コードセクションのサイズ
0080h  4byte  00 00 00 00  初期化されたデータセクションのサイズ(.data)
0084h  4byte  00 00 00 00  初期化されていないデータセクションのサイズ(.bss)
0088h  4byte  00 10 00 00  メモリ上のベースアドレス相対のプログラム開始アドレス
008Ch  4byte  00 10 00 00  メモリ上のベースアドレス相対のコードセクションの先頭アドレス
0090h  4byte  00 00 00 00  メモリ上のベースアドレス相対のデータセクションの先頭アドレス
-----
-----  msg.exe(抜粋)
00000090              00 00 40 00 00 10 00 00 00 02 00 00      ..@.........
000000A0  04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00  ................
000000B0  00 20 00 00 00 02 00 00 B9 FC 00 00 02 00 00 00  . ..............
000000C0  00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00  ................
000000D0  00 00 00 00 10 00 00 00
-----
-----  オプションヘッダ(Windowsフィールド)
0094h  4byte  00 00 40 00  メモリ上のベースアドレス
0098h  4byte  00 10 00 00  メモリ上に割り当てられるセクションのサイズ
009Ch  4byte  00 02 00 00  実行ファイルのセクションの単位
00A0h  2byte  04 00        OSのメジャーバージョン
00A2h  2byte  00 00        OSのマイナーバージョン
00A4h  2byte  00 00        実行ファイルのメジャーバージョン
00A6h  2byte  00 00        実行ファイルのマイナーバージョン
00A8h  2byte  04 00        サブシステムのメジャーバージョン
00AAh  2byte  00 00        サブシステムのマイナーバージョン
00ACh  4byte  00 00 00 00  予約語(常に0)
00B0h  4byte  00 20 00 00  プログラムが利用するメモリサイズ
00B4h  4byte  00 02 00 00  セクションデータの先頭アドレス
00B8h  4byte  B9 FC 00 00  チェックサム
00BCh  2byte  02 00        サブシステム(「02 00」はGUIで実行されるファイル)
00BEh  2byte  00 00        DLLの特性
00C0h  4byte  00 00 10 00  スタックのために予約された仮想メモリのサイズ
00C4h  4byte  00 10 00 00  実際に使われるスタックのサイズ
00C8h  4byte  00 00 10 00  ヒープ領域として予約された仮想メモリのサイズ
00CCh  4byte  00 10 00 00  実際に使われるヒープ領域のサイズ
00D0h  4byte  00 00 00 00  デバッグ用のフラグ
00D4h  4byte  10 00 00 00  データディレクトリ配列の数(8バイト単位)
-----
-----  msg.exe(抜粋)
000000D0                          00 00 00 00 00 00 00 00          ........
000000E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000000F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000150  00 00 00 00 00 00 00 00                          ........
-----
-----  データディレクトリ
(最初の4バイトはアドレス、最後4バイトはサイズ)
00D8h  8byte  00 00 00 00 00 00 00 00  エクスポートテーブルのアドレスとサイズ
00E0h  8byte  00 00 00 00 00 00 00 00  インポートテーブルのアドレスとサイズ
00E8h  8byte  00 00 00 00 00 00 00 00  リソーステーブルのアドレスとサイズ
00F0h  8byte  00 00 00 00 00 00 00 00  例外テーブルのアドレスとサイズ
00F8h  8byte  00 00 00 00 00 00 00 00  属性認証テーブルのアドレスとサイズ
0100h  8byte  00 00 00 00 00 00 00 00  再配置テーブルのアドレスとサイズ
0108h  8byte  00 00 00 00 00 00 00 00  デバッグデータの開始アドレスとサイズ
0110h  8byte  00 00 00 00 00 00 00 00  アーキテクチャ固有データのアドレスとサイズ
0118h  8byte  00 00 00 00 00 00 00 00  グローバルポインタレジスタの相対仮想アドレスとサイズ
0120h  8byte  00 00 00 00 00 00 00 00  TLSテーブルのアドレスとサイズ
0128h  8byte  00 00 00 00 00 00 00 00  ロードコンフィグレーションテーブルのアドレスとサイズ
0130h  8byte  00 00 00 00 00 00 00 00  バウンドインポートテーブルのアドレスとサイズ
0138h  8byte  00 00 00 00 00 00 00 00  インポートアドレステーブルのアドレスとサイズ
0140h  8byte  00 00 00 00 00 00 00 00  遅延インポート記述子のアドレスとサイズ
0148h  8byte  00 00 00 00 00 00 00 00  予約語(常に0)
0150h  8byte  00 00 00 00 00 00 00 00  予約語(常に0)
-----
-----  msg.exe(抜粋)
00000150                          2E 74 65 78 74 00 00 00          .text...
00000160  60 02 00 00 00 10 00 00 00 04 00 00 00 02 00 00  ................
00000170  00 00 00 00 00 00 00 00 00 00 00 00 20 00 50 60  ............ .P.
-----
-----  セクションヘッダ
0158h  8byte  2E 74 65 78  セクション名(ASCII)
              74 00 00 00
0160h  4byte  60 02 00 00  セクションサイズ
0164h  4byte  00 10 00 00  メモリ上のベースアドレスに相対なセクション先頭アドレス
0168h  4byte  00 04 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションサイズ
016Ch  4byte  00 02 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションの先頭アドレス
0170h  4byte  00 00 00 00  セクションの再配置エントリへのポインタ
0174h  4byte  00 00 00 00  セクションの行番号エントリへのポインタ
0176h  2byte  00 00        セクションの再配置エントリ数
0178h  2byte  00 00        セクションの行番号エントリ数
017Ch  4byte  20 00 50 60  セクションフラグ
-----

「00000180から00000200まで」のデータはセクション単位(アドレス009Ch以降の4バイトの値)にあわせるためにサイズを調整しているだけなので、すべて「00」となります。そして、実際に実行されるコードセクションのプログラムは、アドレス「00000200」から始まることになります。

-----  msg.exe(抜粋)
00000200  55 89 E5 81 EC 00 01 00 00 B8 47 65 74 50 89 45  ................
(省略)
-----

セクションデータ自体もサイズをセクション単位(アドレス009Ch以降の4バイトの値)の倍数にしなければならないので、実際のマシン語のサイズは260hバイトですが、「セクション単位(アドレス009Ch以降の4バイトの値)の倍数で表したセクションサイズ」は、400hバイトとなっています。つまり、「00000200から00000600」までがコードセクションとなります。ちなみにこのプログラムはコードセクションしかありませんが、通常のプログラムでは、データセクションやインポートセクションなど、他にも様々なものがあります。それらはまとめてセクションヘッダで定義され、コードセクションデータ以降に順番に追加されることになります。

EXEファイルへ任意のプログラムを追加する

PEフォーマットの解説に利用したプログラムmsg.exeは、ご覧の通りコードセクションのみで実現されています。「Wizard Bible vol.17」にて、まひんさんが「ウイルスプログラミングへの招待 〜インポートセクションを持たずにAPIを使う方法〜」という記事を書かれていますが、これを参考にして、コードセクションのみのプログラムを作成することができます。コンパイラはNASMとGOLINKを使います。

NASM

GOLINK

では、msg.exeのソースコードを見てください。

./msg.asm

-----  コマンドプロンプト
C:\nasm>nasmw -fwin32 msg.asm
C:\nasm>golink -entry main msg.obj
GoLink.Exe Version 0.25.4 - Copyright Jeremy Gordon 2002/4 - JG@JGnet.co.uk
Output file: msg.exe size: 1,536 bytes
C:\nasm>
-----

msg.exeの実行例

このプログラムは、実行するとMessageBoxを表示するだけの簡単なものです。ソースコードの解読にはPEフォーマットとアセンブリ言語の知識が必要です。では、このプログラムを任意のEXEファイルへ追加することにしましょう。ターゲットのEXEファイルは特に何でもよいのですが、今回は自前で用意しましょう。以下のプログラムをダウンロードしてください。

./hello.exe

このターゲットプログラムhello.exeに、msg.exeのコードセクションのプログラムを追加します。msg.exeのコードセクションは以下です。

-----  追加するマシン語(msg.exeのコードセクション)
00000200  55 89 E5 81 EC 00 01 00 00 B8 47 65 74 50 89 45 
00000210  CC B8 72 6F 63 41 89 45 D0 B8 64 64 72 65 89 45 
00000220  D4 B8 73 73 41 00 89 45 D8 B8 4C 6F 61 64 89 45 
00000230  BC B8 4C 69 62 72 89 45 C0 B8 61 72 79 41 89 45 
00000240  C4 B8 00 00 00 00 89 45 C8 B8 45 78 69 74 89 45 
00000250  AC B8 50 72 6F 63 89 45 B0 B8 65 73 73 00 89 45 
00000260  B4 B8 00 00 00 00 89 45 B8 B8 75 73 65 72 89 45 
00000270  9C B8 33 32 2E 64 89 45 A0 B8 6C 6C 00 00 89 45 
00000280  A4 B8 00 00 00 00 89 45 A8 B8 4D 65 73 73 89 45 
00000290  8C B8 61 67 65 42 89 45 90 B8 6F 78 41 00 89 45 
000002A0  94 B8 00 00 00 00 89 45 98 B8 47 65 74 41 89 85 
000002B0  7C FF FF FF B8 63 74 69 76 89 45 80 B8 65 57 69 
000002C0  6E 89 45 84 B8 64 6F 77 00 89 45 88 B8 57 69 7A 
000002D0  61 89 85 5C FF FF FF B8 72 64 20 42 89 85 60 FF 
000002E0  FF FF B8 69 62 6C 65 89 85 64 FF FF FF B8 20 76 
000002F0  6F 6C 89 85 68 FF FF FF B8 2E 31 39 00 89 85 6C 
00000300  FF FF FF B8 48 65 6C 6C 89 85 3C FF FF FF B8 6F 
00000310  21 20 54 89 85 40 FF FF FF B8 68 69 73 20 89 85 
00000320  44 FF FF FF B8 69 73 20 49 89 85 48 FF FF FF B8 
00000330  6E 6A 65 63 89 85 4C FF FF FF B8 74 20 43 6F 89 
00000340  85 50 FF FF FF B8 64 65 2E 00 89 85 54 FF FF FF 
00000350  8B 5D 04 81 E3 00 00 FF FF B9 05 00 00 00 66 81 
00000360  3B 4D 5A 74 12 81 EB 00 00 01 00 49 31 C0 39 C1 
00000370  75 EC E9 E4 00 00 00 8B 43 3C 01 D8 81 38 50 45 
00000380  00 00 75 E1 89 5D FC FC 8B 70 78 03 75 FC 81 C6 
00000390  18 00 00 00 AD 89 45 E8 AD 03 45 FC 89 45 E4 AD 
000003A0  03 45 FC 89 45 E0 AD 03 45 FC 89 45 DC 31 D2 8B 
000003B0  45 E0 8B 38 03 7D FC FC 31 C9 38 F2 75 08 8D 75 
000003C0  CC E9 03 00 00 00 8D 75 BC A6 75 07 80 3F 00 74 
000003D0  19 EB F6 41 3B 4D E8 7C 05 E9 7D 00 00 00 05 04 
000003E0  00 00 00 8B 38 03 7D FC EB D0 D1 E1 8B 75 DC 01 
000003F0  CE 31 C0 66 8B 06 C1 E0 02 8B 75 E4 01 C6 8B 3E 
00000400  03 7D FC 38 F2 75 07 89 7D EC FE C2 EB A1 89 7D 
00000410  F0 89 E8 2D 64 00 00 00 50 FF 55 F0 89 45 F8 89 
00000420  E8 2D 74 00 00 00 50 FF 75 F8 FF 55 EC 89 45 F4 
00000430  89 E8 2D 84 00 00 00 50 FF 75 F8 FF 55 EC FF D0 
00000440  89 C2 68 00 00 00 00 89 E8 2D A4 00 00 00 50 89 
00000450  E8 2D C4 00 00 00 50 52 FF 55 F4 89 EC 5D C3 00 
00000460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
....(省略)....
000005F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
-----

msg.exeのコードセクションは400h(1024)バイトあります。EXEファイル(hello.exe)に任意のプログラムを追加するためには、このマシン語をhello.exeのコードセクションの最初に追加し、しかもその後、もともとのhello.exeプログラムもちゃんと実行されるように配慮しなければなりません。そのためには、まず一番最後の「00」以降のデータをすべてNOP「90」に変換しましょう。これらはコードセクションをセクション単位(アドレス009Ch以降の4バイトの値)の倍数にするための追加データであるため、すべて「00」です。そして、さらに最後のマシン語命令である「C3」はret命令であり、KERNEL32.DLLへ処理を戻してしまうため、これもNOP「90」にします。

-----  変更前(00000450以降のデータ)
00000450  E8 2D C4 00 00 00 50 52 FF 55 F4 89 EC 5D C3 00 
00000460  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
....(省略)....
000005F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
-----
-----  変更後(00000450以降のデータ)
00000450  E8 2D C4 00 00 00 50 52 FF 55 F4 89 EC 5D 90 90 
00000460  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
....(省略)....
000005F0  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
-----

では、このコードセクションのデータ400hバイトをhello.exeのコードセクションの先頭に追加します。追加することによって、EXEファイル(hello.exe)に以下のような変化が起きます。

  1. コードセクションのサイズが変わる
  2. コードセクションの次に位置しているすべてのセクションのアドレスが変わる

よって、これらをPEフォーマットのデータに反映させなければなりません。では、ターゲットプログラムhello.exeのセクションヘッダをバイナリエディタで見てください。

-----  hello.exeのセクションヘッダ
0158h  8byte  2E 74 65 78  セクション名(ASCII)「.text」(コードセクション)
              74 00 00 00
0160h  4byte  E0 01 00 00  セクションサイズ
0164h  4byte  00 10 00 00  メモリ上のベースアドレスに相対なセクション先頭アドレス
0168h  4byte  00 02 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションサイズ
016Ch  4byte  00 02 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションの先頭アドレス
0170h  4byte  00 00 00 00  セクションの再配置エントリへのポインタ
0174h  4byte  00 00 00 00  セクションの行番号エントリへのポインタ
0176h  2byte  00 00        セクションの再配置エントリ数
0178h  2byte  00 00        セクションの行番号エントリ数
017Ch  4byte  20 00 50 60  セクションフラグ
0180h  8byte  2E 74 65 78  セクション名(ASCII)「.data」(データセクション)
              74 00 00 00
0188h  4byte  20 00 00 00  セクションサイズ
018Ch  4byte  00 20 00 00  メモリ上のベースアドレスに相対なセクション先頭アドレス
0190h  4byte  00 02 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションサイズ
0194h  4byte  00 04 00 00  セクション単位(アドレス009Ch以降の4バイトの値)の
                           倍数で表したセクションの先頭アドレス
0198h  4byte  00 00 00 00  セクションの再配置エントリへのポインタ
019Ch  4byte  00 00 00 00  セクションの行番号エントリへのポインタ
01A0h  2byte  00 00        セクションの再配置エントリ数
01A2h  2byte  00 00        セクションの行番号エントリ数
01A4h  4byte  40 00 30 C0  セクションフラグ
-----

0160h番目にセクションサイズがあります。また、0168h番目がセクション単位のサイズ、016Ch番目がセクション単位の先頭アドレスとなっています。よって、ターゲットのEXEファイルのこの部分を変更することで、OKだと考えられます。では、実際にhello.exeのバイナリを変更していきます。

まず、コードセクションのサイズを変更します。先頭に400h(1024)バイト追加したわけなので、hello.exeのアドレス「0169h」の「02」を「06」に変更します。さらにアドレス「0160h」のセクションサイズにも400hを加算しなければならないので、アドレス「0161h」の「01」を「05」に変更します。次にデータセクションのアドレスを変更します。アドレス「0194h」をみると、400h番目からデータセクションとなっているので、アドレス「0195h」の「04」を「08」に変更します。これで完了です。あとは、コードセクションの先頭(アドレス「0200h」)にさっき用意したマシン語を追加すれば、マシン語コードの追加は完了です。変更後のEXEファイルを保存し、実行すると、追加したマシン語コードが実行された後に、通常のプログラムが実行されます。

hello.exeの変更箇所

./hello.exe(変更後)

hello.exeの実行例

さて、今回は、hello.exeへの追加をバイナリエディタを使って手動で行いましたが、これを自動化したプログラムを作成すれば、すべてのEXEファイルに任意のプログラムを感染させることができます。これは一般的にいうコンピュータウイルスです。自分自身を他のEXEファイルへ感染させることによって、ウイルス自体の発見を難しくするわけです。EXEファイルに任意のプログラムを寄生させるテクニックなんて、ウイルスの作成にしか役に立たない気もしますが、このテクニック自体はとても興味深いものだと思います。ブラックか? ホワイトか? アンダーグラウンドか? オーバーグラウンド(?)か? といった括りに関係なく、こういった純粋な技術部分での話題はとても面白いものだと思いますので、興味を持たれた方は、ぜひいろいろと調べてみてください。

さいごに

さて、いかがだったでしょうか。本当はこの作成したマシン語を任意のEXEファイルへ追加してくれるプログラムも作る予定だったのですが、最近なぜかやるべきことが多く、なぜか忙しいのでちょっとそこまで手がまわりませんでした。申し訳ないです。またいつか気が向いた時に作ってみることにしますので、そしたらまたWBに投稿するのでよろしくお願いします(^^;。さて、最後になりましたが、ここまで読んでくれて本当にありがとうございます。

では、また会う日まで...


Copyright (C) 2003-2005 Kenji Aiko All Rights Reserved