Delphi Programming / Object Pascal
[掲載 2014年05月25日] [更新 2014年06月09日] Delphi サンプルプログラム集
006_究極の選択 - アセンブリ言語と PE ヘッダ
動作確認等
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
006_Assembler_exe.zip [3,195 KB] 2014年06月09日版 (EXE 同梱)
2014年06月06日
DLL 内のエクスポート関数名の列挙のサンプルに,ファイルバージョン取得のコードを追加
究極の選択,それはアセンブリ言語を使用することです.
前のページで,実行時パッケージを使用して開発すると,実行ファイルのサイズが小さくなることを示しました.EXE のサイズを小さくする究極の方法は,アセンブリ言語を使用して,アセンブラを使用することです.
アセンブリ言語のニーモニック (ニモニック) と呼ばれる命令語は,コンピュータが直接理解可能な 0 と 1 の組み合わせである機械語に,ほぼ 1 対 1 に対応しています.無駄がありません.
本ページは,このアセンブリ言語を使用する開発に必要な環境についての記事です.また,EXE ファイルの内容に関するテストをしてみました.
本ページのサンプルのコードでは,64 ビット版の EXE や DLL の情報は正しく取得できないものがあります.64 ビット用の構造体は,32 ビット用とは異なる構造体があります.
32 ビットアプリケーションからでも,64 ビット版の EXE, DLL の情報は取得できます.読み込んだ EXE, DLL が 64 ビット版の場合は,64 ビット版用の構造体を使用するように修正,あるいはコードを追加する必要があります.
Delphi XE 以前の Delphi には,64 ビット用の構造体の定義はありません.
アセンブリ言語を使用して,アプリケーションを開発するには,コンパイラが必要です.Delphi 言語で書いたプログラムのコードからアプリを作成する,つまり,EXE を作成するには,Delphi のコンパイラを使用します.それと同じです.
アセンブリ言語で書いたプログラムコードをコンパイルするコンパイラを一般に,アセンブラと言っています.
ここでは,アセンブラを使用して,下図のようなダイアログを表示するプログラムを作成します.これ以上のことはやりません.興味ある方は,本ページの参考リンクの記事や参考書で調べたり,あるいはネットで検索してください.
図1
作成したアプリケーションの実行結果
01-01_ 開発に必要なアセンブラとリンカとライブラリ
今回は,Netwide Assembler (NASM) というアセンブラを使用します.これは,下の参考リンクのページから,[DWONLOAD] [2.11.04/] [Win32] の順にたどり,
nasm-2.11.04-win32.zip をダンロードして解凍しました.D ドライブに nasm というフォルダを作成して,そこに解凍しました.
この他にリンカとライブラリが必要です.
Delphi で開発していると,意識しなくても,コンパイルすると EXE ファイルができます.
一般的に,アセンブラの命令は,CPU の操作コードです.CPU が画面の操作やダイアログを表示する機能を持っているわけではありません.それらの機能は OS が提供しています.
プログラムのソースコードをコンパイルすると,オブジェクトファイルを生成します.そのオブジェクトファイルと,実行に必要なライブラリファイルをリンクさせて EXE ファイルを生成します.このライブラリファイルに,OS の機能を使用するため実際のコードがあります.
オブジェクトファイルとライブラリのリンクに必要なのがリンカです.
基本的なライブラリは OS が提供しています.そのため,リンカとライブラリ類も必要です.
今回は,Microsoft Visual Studio Express 2013 for Windows (以後,VS 2013) を使用しました.これにリンカとライブラリがあります.これの入手方法とインストール方法は [タイプライブラリの作成] の記事を参考にしてください.
図2
ダウンロードしたアセンブラ
図3
D:\nasm フォルダ内に解凍
NASM を解凍して,VS 2013 をイントールしたら,プログラムのコードを作成します.
メモ帳等のテキストエディタで,下のコードを入力して,hello2.asm という名前で保存します.今回は,D ドライブに 000 というフォルダを作成して,そこに保存しました.
コードの意味の説明は省略します.各自で調べてください.
図4
hello2.asm という名前で保存
copy code
global _WinMain@16
extern _MessageBoxA@16
section .text
_WinMain@16:
PUSH EBP
MOV EBP, ESP
PUSH 0
PUSH caption
PUSH msg
PUSH 0
CALL _MessageBoxA@16
MOV EAX, 2
MOV ESP, EBP
POP EBP
RET 16
section .data
caption:
db "テスト", 0
msg:
db `Win32 Application\r\nHello World!`, 0
コンパイルとリンクを実行するためのバッチファイルを作成しておくことにします.
下のコードをメモ帳等のテキストエディタで作成し,nasmbat.bat という名前で保存します.保存先は nasm.exe があるフォルダとします.今回のプログラムでは,user32.lib と msvcrt.lib というライブラリを使用します.そこで,これを追加しています.
nasm -f win32 %1.asm
link /OUT:%1.exe %1.obj user32.lib msvcrt.lib
図5
バッチファイルを作成して保存
準備ができたらコンパイルします.
[開発者コマンドプロンプト for VS2013] を管理者権限で起動します.起動したら,nasm.exe があるフォルダに移動します.そして,前項で作成したバッチファイルの引数に,作成したアセンブラのコードが書いてあるファイルを指定して,バッチファイルを実行します.今回の場合,コマンドラインは次のようになります.
図6
バッチファイルを実行
コンパイルとリンクに成功すると,次のように,Hello2.exe ができます.わずか 6 KB しかないアプリケーションとなっています.
フォルダ内の msvcr120.dll は,VS 2013 が提供している DLL で,作成したアプリの実行に必要な (再配布可能) DLL です.実行環境に VS 2013 がインストールされていれば必要ありません.
今回は VS 2013 で開発したので,msvcr120.dll が必要ですが,他のバージョンの Visual Studio を使用した場合は,別の DLL が必要となることがあります.
図7
Hello2.exe ができる
作成したアプリである Hello2.exe を起動すると,本ページの最初の図のようなダイアログが表示されることが確認できます.
タスクマネージャーで確認すると,確かに Hello2.exe (メモリ使用量 1,132 KB) となっていて,6 KB しかない EXE がメモリ上で展開しているこが分かります.VCL_Delphi_XE_32bit.exe (メモリ使用量 1,376 KB) は,Delphi XE で作成した,フォームが 1 つだけのアプリです.
確かに,アセンブリ言語を使用すれば,EXE のサイズが小さなアプリケーションを作成することができます.しかし,実用的なアプリケーションを開発するのは容易ではないでしょう.
図8
タスクマネージャで確認
作成した EXE の中身を見てみることにします.
1 と 0 の機械語では見にくいので,一般的には,16 進数の文字で表示することが行われています.その結果が下図です.一見すると,意味不明の記号の羅列に見えます.これをバイナリのダンプと言っています.
本サンプルのコードは,EXE のサイズが大きくなると,処理に時間がかかります.本格的に処理するのであれば,工夫が必要です.
遙か昔のプログラマは,このような値,実際には 1 と 0, あるいは 16 進数を,メモリやディスクに直接記録していきました.その後,アセンブラのような道具が開発され,更に Delphi のような総合開発環境が整備されていきました.
これらは,人類の知識と技術の蓄積が生み出した産物と言えるでしょう.
このようなバイナリダンプ表示のユーティリティ類は,ネット上でも入手できます.編集を可能にしたバイナリエディタと言うものもあります.
図9
設計時画面
図10
Hello2.exe のバイナリダンプ
16 進数文字でのダンプ表示は EXE だけとは限りません.下図は,'テスト' という文字列を保存したファイルを 16 進数表示したものです.
Shift-JIS の場合は,1 文字は 2 バイトです.したがって,全部で 6 バイトあります.一方,ユニコードである UTF-8 の場合は 12 バイトあることが分かります.
図11
文字列のバイナリダンプ
'テスト' という文字列の場合
上が SHIFT-JIS
下が UTF-8
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Panel1: TPanel;
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
OpenDialog1: TOpenDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
InitDir : String ;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'Courier New' ;
Memo1.Font.Size := 10 ;
Memo1.WordWrap := False;
Panel1.Font := Memo1.Font;
Memo2.Font := Memo1.Font;
Memo2.Lines.Clear;
Memo2.Lines.Add(' 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F' );
end ;
// =============================================================================
// ファイルのデータを16進バイナリダンプ
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
FileFullPath : String ;
FStream : TFileStream;
SL : TStringList;
BinArray : TBytes;
CntReadBytes : Integer;
StrLine : String ;
i : Integer;
begin
if InitDir = EmptyStr then begin
InitDir := ExpandFileName('../' );
end ;
OpenDialog1.InitialDir := InitDir;
if OpenDialog1.Execute then begin
Screen.Cursor := crHourGlass;
FileFullPath := OpenDialog1.FileName;
InitDir := ExtractFileDir(FileFullPath);
Panel1.Caption := ExtractFileName(FileFullPath);
Memo1.Clear;
Memo1.Update;
Memo1.Lines.BeginUpdate;
// ファイルストリームを生成
FStream := TFilestream.Create(FileFullPath, fmOpenread or fmShareDenyNone);
SL := TStringList.Create;
try
// バイト配列のサイズを設定
SetLength(BinArray, fStream.Size);
// バイト配列に読み出す
CntReadBytes := fStream.Read (BinArray[0 ], Length(BinArray));
StrLine := IntToHex(0 , 6 ) + ' ' + IntToHex(BinArray[0 ], 2 ) + ' ' ;
for i := 1 to CntReadBytes - 1 do begin
if (i mod 16 ) = 0 then begin
SL.Add(StrLine);
StrLine := IntToHex(i, 6 ) + ' ' ;
end else
if (i mod 8 ) = 0 then begin
StrLine := StrLine + ' ' ;
end ;
StrLine := StrLine + IntToHex(BinArray[i], 2 ) + ' ' ;
Application.ProcessMessages;
end ;
if StrLine <> '' then SL.Add(StrLine);
Memo1.Text := SL.Text;
finally
FStream.Free;
SL.Free;
end ;
Memo1.Lines.EndUpdate;
Screen.Cursor := crDefault;
end ;
end ;
end .
TMemoryStream を使用して,ファイルを読み込んで処理する場合は,例えば次のようにできます.
メモリからデータを 1 バイトづつ読み込んで処理しています.
処理速度も,使用するメモリ量も,上のコードの場合と大差ありません.いずれにしても,表示の処理に時間がかかります.本格的に処理するのであれば工夫が必要です.
copy code
// =============================================================================
// ファイルのデータを16進バイナリダンプ - TMemory Streamを使用する場合の例
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
FileFullPath : String ;
FStream : TMemoryStream;
SL : TStringList;
pStream : PByte;
StrLine : String ;
i : Integer;
begin
if InitDir = EmptyStr then begin
InitDir := ExpandFileName('../' );
end ;
OpenDialog1.InitialDir := InitDir;
if OpenDialog1.Execute then begin
Screen.Cursor := crHourGlass;
FileFullPath := OpenDialog1.FileName;
InitDir := ExtractFileDir(FileFullPath);
Panel1.Caption := ExtractFileName(FileFullPath);
Memo1.Clear;
Memo1.Update;
Memo1.Lines.BeginUpdate;
// メモリストリームを生成
FStream := TMemoryStream.Create;
SL := TStringList.Create;
try
// メモリストリームにファイルの内容を読み込み
FStream.LoadFromFile(FileFullPath);
// メモリに直接アクセスする
pStream := FStream.Memory;
StrLine := IntToHex(0 , 6 ) + ' ' + IntToHex(pStream^, 2 ) + ' ' ;
inc(pStream);
for i := 1 to FStream.Size - 1 do begin
if (i mod 16 ) = 0 then begin
SL.Add(StrLine);
StrLine := IntToHex(i, 6 ) + ' ' ;
end else
if (i mod 8 ) = 0 then begin
StrLine := StrLine + ' ' ;
end ;
StrLine := StrLine + IntToHex(pStream^, 2 ) + ' ' ;
inc(pStream);
Application.ProcessMessages;
end ;
if StrLine <> '' then SL.Add(StrLine);
Memo1.Text := SL.Text;
finally
FStream.Free;
SL.Free;
end ;
Memo1.Lines.EndUpdate;
Screen.Cursor := crDefault;
end ;
end ;
VS 2013 に DUMPBIN というプログラムが付属しています.これは,文字通り,バイナリダンプ用のプログラムです.実際には,バイナリダンプ以外にも,次項のサンプルの結果のような,EXE ファイルの他の情報も出力することができます.
VS 2013 の [開発者コマンドプロンプト for VS2013] を起動して ,作成した Hello2.exe のフォルダに移動します.そして,次のコマンを実行すると,dump.txt に結果が出力されます.
dumpbin /disasm /out:dump.txt Hello2.exe
図12
DUMPBIN を実行
下のリストが実行結果です.バイナリダンプの他に,アセンブリ言語の,CPU の命令語であるニモニックも出力されています.このように,バイナリからアセンブリ言語のコードを出力するのを,逆アセンブルと言っています.ニモニックの 1 行 1 行が機械語の命令に対応しています.
最初に書いたアセンブリのコードよりも非常に長いコードになっています.これは,元のソースコードをコンパイルした結果としての,ネイティブコードになっています.
このコードの左端の値は,EXE がメモリ上に展開する際のメモリのアドレスです.このアドレスは,物理的なメモリのアドレスではなく,プログラマから見たメモリ空間の「仮想アドレス」です.EXE 内での開始位置は,今回作成した Hello2.exe のバイナリダンプでは $000400 からです.この位置は,後述の PE ヘッダの情報から計算できます.
Delphi でプログラムの開発中,あるいはデバック中に,CPU ウィンドウで,このような表示を見たことがあるも知れません.
[備考]
下のコードは,俗に言う「コンパイラが吐き出したコード」です.EXE から元のソースコードを取得することは基本的にはできません.これはどの開発言語で作成した EXE でも同じです.
EXE を作成した開発言語のコードとの変換テーブル等を作成すれば可能かも知れませんが,個人的には意味がある作業とは考えられません.
以下のサイトに,Delphi 用の逆コンパイル (デコンパイル) ツールがあります.筆者は使用したことがありませんので,どこまで解析するのかは不明です.
.NET の開発言語には,中間コードを利用した逆コンパイル用のツールがあるようです.
リスト3
Hello2.exe を逆アセンブルした結果
EXE に記録されているのは,55 89 E5 6A 00 68 00 30 40 00 68 07 ... という値
copy code
Dump of file Hello2.exe
File Type: EXECUTABLE IMAGE
00401000: 55 push ebp
00401001: 89 E5 mov ebp,esp
00401003: 6A 00 push 0
00401005: 68 00 30 40 00 push 403000h
0040100A: 68 07 30 40 00 push 403007h
0040100F: 6A 00 push 0
00401011: E8 1A 00 00 00 call 00401030
00401016: B8 02 00 00 00 mov eax,2
0040101B: 89 EC mov esp,ebp
0040101D: 5D pop ebp
0040101E: C2 10 00 ret 10h
00401021: CC int 3
00401022: CC int 3
00401023: CC int 3
00401024: CC int 3
00401025: CC int 3
00401026: CC int 3
00401027: CC int 3
00401028: CC int 3
00401029: CC int 3
0040102A: CC int 3
0040102B: CC int 3
0040102C: CC int 3
0040102D: CC int 3
0040102E: CC int 3
0040102F: CC int 3
00401030: FF 25 9C 20 40 00 jmp dword ptr ds:[0040209Ch]
00401036: B8 4D 5A 00 00 mov eax,5A4Dh
0040103B: 66 39 05 00 00 40 cmp word ptr ds:[00400000h],ax
00
00401042: 74 04 je 00401048
00401044: 33 C0 xor eax,eax
00401046: EB 34 jmp 0040107C
00401048: 8B 0D 3C 00 40 00 mov ecx,dword ptr ds:[0040003Ch]
0040104E: 81 B9 00 00 40 00 cmp dword ptr [ecx+00400000h],4550h
50 45 00 00
00401058: 75 EA jne 00401044
0040105A: B8 0B 01 00 00 mov eax,10Bh
0040105F: 66 39 81 18 00 40 cmp word ptr [ecx+00400018h],ax
00
00401066: 75 DC jne 00401044
00401068: 33 C0 xor eax,eax
0040106A: 83 B9 74 00 40 00 cmp dword ptr [ecx+00400074h],0Eh
0E
00401071: 76 09 jbe 0040107C
00401073: 39 81 E8 00 40 00 cmp dword ptr [ecx+004000E8h],eax
00401079: 0F 95 C0 setne al
0040107C: 6A 02 push 2
0040107E: A3 48 30 40 00 mov dword ptr ds:[00403048h],eax
00401083: FF 15 80 20 40 00 call dword ptr ds:[00402080h]
00401089: 59 pop ecx
0040108A: 6A FF push 0FFFFFFFFh
0040108C: FF 15 18 20 40 00 call dword ptr ds:[00402018h]
00401092: 8B 0D 40 20 40 00 mov ecx,dword ptr ds:[00402040h]
00401098: A3 98 33 40 00 mov dword ptr ds:[00403398h],eax
0040109D: A3 9C 33 40 00 mov dword ptr ds:[0040339Ch],eax
004010A2: A1 6C 30 40 00 mov eax,dword ptr ds:[0040306Ch]
004010A7: 89 01 mov dword ptr [ecx],eax
004010A9: 8B 0D 44 20 40 00 mov ecx,dword ptr ds:[00402044h]
004010AF: A1 60 30 40 00 mov eax,dword ptr ds:[00403060h]
004010B4: 89 01 mov dword ptr [ecx],eax
004010B6: E8 7C 05 00 00 call 00401637
004010BB: E8 94 02 00 00 call 00401354
004010C0: 83 3D 28 30 40 00 cmp dword ptr ds:[00403028h],0
00
004010C7: 75 0C jne 004010D5
004010C9: 68 54 13 40 00 push 401354h
004010CE: FF 15 30 20 40 00 call dword ptr ds:[00402030h]
004010D4: 59 pop ecx
004010D5: E8 9D 05 00 00 call 00401677
004010DA: 83 3D 30 30 40 00 cmp dword ptr ds:[00403030h],0FFFFFFFFh
FF
004010E1: 75 09 jne 004010EC
004010E3: 6A FF push 0FFFFFFFFh
004010E5: FF 15 2C 20 40 00 call dword ptr ds:[0040202Ch]
004010EB: 59 pop ecx
004010EC: 33 C0 xor eax,eax
004010EE: C3 ret
004010EF: 68 57 16 40 00 push 401657h
004010F4: E8 29 05 00 00 call 00401622
004010F9: A1 68 30 40 00 mov eax,dword ptr ds:[00403068h]
004010FE: C7 04 24 5C 30 40 mov dword ptr [esp],40305Ch
00
00401105: FF 35 64 30 40 00 push dword ptr ds:[00403064h]
0040110B: A3 5C 30 40 00 mov dword ptr ds:[0040305Ch],eax
00401110: 68 54 30 40 00 push 403054h
00401115: 68 50 30 40 00 push 403050h
0040111A: 68 4C 30 40 00 push 40304Ch
0040111F: FF 15 84 20 40 00 call dword ptr ds:[00402084h]
00401125: 83 C4 14 add esp,14h
00401128: A3 58 30 40 00 mov dword ptr ds:[00403058h],eax
0040112D: 85 C0 test eax,eax
0040112F: 79 08 jns 00401139
00401131: 6A 08 push 8
00401133: E8 16 02 00 00 call 0040134E
00401138: 59 pop ecx
00401139: C3 ret
0040113A: E8 62 03 00 00 call 004014A1
0040113F: E9 00 00 00 00 jmp 00401144
00401144: 6A 14 push 14h
00401146: 68 38 21 40 00 push 402138h
0040114B: E8 60 05 00 00 call 004016B0
00401150: 33 F6 xor esi,esi
00401152: 89 75 E4 mov dword ptr [ebp-1Ch],esi
00401155: 89 75 E0 mov dword ptr [ebp-20h],esi
00401158: FF 15 8C 20 40 00 call dword ptr ds:[0040208Ch]
0040115E: 0F B7 D8 movzx ebx,ax
00401161: 89 75 FC mov dword ptr [ebp-4],esi
00401164: 64 A1 18 00 00 00 mov eax,dword ptr fs:[00000018h]
0040116A: 8B 50 04 mov edx,dword ptr [eax+4]
0040116D: 8B FE mov edi,esi
0040116F: BE 90 33 40 00 mov esi,403390h
00401174: 8B CA mov ecx,edx
00401176: 33 C0 xor eax,eax
00401178: F0 0F B1 0E lock cmpxchg dword ptr [esi],ecx
0040117C: 85 C0 test eax,eax
0040117E: 74 0B je 0040118B
00401180: 3B C2 cmp eax,edx
00401182: 75 F0 jne 00401174
00401184: 33 F6 xor esi,esi
00401186: 46 inc esi
00401187: 8B FE mov edi,esi
00401189: EB 03 jmp 0040118E
0040118B: 33 F6 xor esi,esi
0040118D: 46 inc esi
0040118E: 39 35 94 33 40 00 cmp dword ptr ds:[00403394h],esi
00401194: 75 0A jne 004011A0
00401196: 6A 1F push 1Fh
00401198: E8 B1 01 00 00 call 0040134E
0040119D: 59 pop ecx
0040119E: EB 3B jmp 004011DB
004011A0: 83 3D 94 33 40 00 cmp dword ptr ds:[00403394h],0
00
004011A7: 75 2C jne 004011D5
004011A9: 89 35 94 33 40 00 mov dword ptr ds:[00403394h],esi
004011AF: 68 C0 20 40 00 push 4020C0h
004011B4: 68 B0 20 40 00 push 4020B0h
004011B9: E8 E0 04 00 00 call 0040169E
004011BE: 59 pop ecx
004011BF: 59 pop ecx
004011C0: 85 C0 test eax,eax
004011C2: 74 17 je 004011DB
004011C4: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
004011CB: B8 FF 00 00 00 mov eax,0FFh
004011D0: E9 1D 01 00 00 jmp 004012F2
004011D5: 89 35 40 30 40 00 mov dword ptr ds:[00403040h],esi
004011DB: 39 35 94 33 40 00 cmp dword ptr ds:[00403394h],esi
004011E1: 75 1B jne 004011FE
004011E3: 68 AC 20 40 00 push 4020ACh
004011E8: 68 A4 20 40 00 push 4020A4h
004011ED: E8 B2 04 00 00 call 004016A4
004011F2: 59 pop ecx
004011F3: 59 pop ecx
004011F4: C7 05 94 33 40 00 mov dword ptr ds:[00403394h],2
02 00 00 00
004011FE: 85 FF test edi,edi
00401200: 75 09 jne 0040120B
00401202: 33 C0 xor eax,eax
00401204: B9 90 33 40 00 mov ecx,403390h
00401209: 87 01 xchg eax,dword ptr [ecx]
0040120B: 83 3D A0 33 40 00 cmp dword ptr ds:[004033A0h],0
00
00401212: 74 1B je 0040122F
00401214: 68 A0 33 40 00 push 4033A0h
00401219: E8 92 01 00 00 call 004013B0
0040121E: 59 pop ecx
0040121F: 85 C0 test eax,eax
00401221: 74 0C je 0040122F
00401223: 6A 00 push 0
00401225: 6A 02 push 2
00401227: 6A 00 push 0
00401229: FF 15 A0 33 40 00 call dword ptr ds:[004033A0h]
0040122F: A1 3C 20 40 00 mov eax,dword ptr ds:[0040203Ch]
00401234: 8B 30 mov esi,dword ptr [eax]
00401236: 89 75 E4 mov dword ptr [ebp-1Ch],esi
00401239: 8B 7D E0 mov edi,dword ptr [ebp-20h]
0040123C: 8A 0E mov cl,byte ptr [esi]
0040123E: 80 F9 20 cmp cl,20h
00401241: 77 3B ja 0040127E
00401243: 84 C9 test cl,cl
00401245: 74 04 je 0040124B
00401247: 85 FF test edi,edi
00401249: 75 33 jne 0040127E
0040124B: 8A 06 mov al,byte ptr [esi]
0040124D: 84 C0 test al,al
0040124F: 74 0A je 0040125B
00401251: 3C 20 cmp al,20h
00401253: 77 06 ja 0040125B
00401255: 46 inc esi
00401256: 89 75 E4 mov dword ptr [ebp-1Ch],esi
00401259: EB F0 jmp 0040124B
0040125B: 53 push ebx
0040125C: 56 push esi
0040125D: 6A 00 push 0
0040125F: 68 00 00 40 00 push 400000h
00401264: E8 97 FD FF FF call 00401000
00401269: A3 44 30 40 00 mov dword ptr ds:[00403044h],eax
0040126E: 83 3D 48 30 40 00 cmp dword ptr ds:[00403048h],0
00
00401275: 75 60 jne 004012D7
00401277: 50 push eax
00401278: FF 15 7C 20 40 00 call dword ptr ds:[0040207Ch]
0040127E: 80 F9 22 cmp cl,22h
00401281: 75 0C jne 0040128F
00401283: 33 C0 xor eax,eax
00401285: 85 FF test edi,edi
00401287: 0F 94 C0 sete al
0040128A: 8B F8 mov edi,eax
0040128C: 89 7D E0 mov dword ptr [ebp-20h],edi
0040128F: 0F B6 C1 movzx eax,cl
00401292: 50 push eax
00401293: FF 15 28 20 40 00 call dword ptr ds:[00402028h]
00401299: 59 pop ecx
0040129A: 85 C0 test eax,eax
0040129C: 74 04 je 004012A2
0040129E: 46 inc esi
0040129F: 89 75 E4 mov dword ptr [ebp-1Ch],esi
004012A2: 46 inc esi
004012A3: 89 75 E4 mov dword ptr [ebp-1Ch],esi
004012A6: EB 94 jmp 0040123C
004012A8: 8B 4D EC mov ecx,dword ptr [ebp-14h]
004012AB: 8B 01 mov eax,dword ptr [ecx]
004012AD: 8B 00 mov eax,dword ptr [eax]
004012AF: 89 45 DC mov dword ptr [ebp-24h],eax
004012B2: 51 push ecx
004012B3: 50 push eax
004012B4: E8 8F 00 00 00 call 00401348
004012B9: 59 pop ecx
004012BA: 59 pop ecx
004012BB: C3 ret
004012BC: 8B 65 E8 mov esp,dword ptr [ebp-18h]
004012BF: 8B 45 DC mov eax,dword ptr [ebp-24h]
004012C2: A3 44 30 40 00 mov dword ptr ds:[00403044h],eax
004012C7: 83 3D 48 30 40 00 cmp dword ptr ds:[00403048h],0
00
004012CE: 75 07 jne 004012D7
004012D0: 50 push eax
004012D1: FF 15 4C 20 40 00 call dword ptr ds:[0040204Ch]
004012D7: 83 3D 40 30 40 00 cmp dword ptr ds:[00403040h],0
00
004012DE: 75 0B jne 004012EB
004012E0: FF 15 24 20 40 00 call dword ptr ds:[00402024h]
004012E6: A1 44 30 40 00 mov eax,dword ptr ds:[00403044h]
004012EB: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
004012F2: E8 FE 03 00 00 call 004016F5
004012F7: C3 ret
004012F8: 55 push ebp
004012F9: 8B EC mov ebp,esp
004012FB: 8B 45 08 mov eax,dword ptr [ebp+8]
004012FE: 8B 00 mov eax,dword ptr [eax]
00401300: 81 38 63 73 6D E0 cmp dword ptr [eax],0E06D7363h
00401306: 75 25 jne 0040132D
00401308: 83 78 10 03 cmp dword ptr [eax+10h],3
0040130C: 75 1F jne 0040132D
0040130E: 8B 40 14 mov eax,dword ptr [eax+14h]
00401311: 3D 20 05 93 19 cmp eax,19930520h
00401316: 74 1B je 00401333
00401318: 3D 21 05 93 19 cmp eax,19930521h
0040131D: 74 14 je 00401333
0040131F: 3D 22 05 93 19 cmp eax,19930522h
00401324: 74 0D je 00401333
00401326: 3D 00 40 99 01 cmp eax,1994000h
0040132B: 74 06 je 00401333
0040132D: 33 C0 xor eax,eax
0040132F: 5D pop ebp
00401330: C2 04 00 ret 4
00401333: E8 F4 03 00 00 call 0040172C
00401338: CC int 3
00401339: 68 F8 12 40 00 push 4012F8h
0040133E: E8 EF 03 00 00 call 00401732
00401343: 59 pop ecx
00401344: 33 C0 xor eax,eax
00401346: C3 ret
00401347: CC int 3
00401348: FF 25 90 20 40 00 jmp dword ptr ds:[00402090h]
0040134E: FF 25 88 20 40 00 jmp dword ptr ds:[00402088h]
00401354: 33 C0 xor eax,eax
00401356: C3 ret
00401357: CC int 3
00401358: CC int 3
00401359: CC int 3
0040135A: CC int 3
0040135B: CC int 3
0040135C: CC int 3
0040135D: CC int 3
0040135E: CC int 3
0040135F: CC int 3
00401360: 55 push ebp
00401361: 8B EC mov ebp,esp
00401363: 8B 45 08 mov eax,dword ptr [ebp+8]
00401366: 33 D2 xor edx,edx
00401368: 53 push ebx
00401369: 56 push esi
0040136A: 57 push edi
0040136B: 8B 48 3C mov ecx,dword ptr [eax+3Ch]
0040136E: 03 C8 add ecx,eax
00401370: 0F B7 41 14 movzx eax,word ptr [ecx+14h]
00401374: 0F B7 59 06 movzx ebx,word ptr [ecx+6]
00401378: 83 C0 18 add eax,18h
0040137B: 03 C1 add eax,ecx
0040137D: 85 DB test ebx,ebx
0040137F: 74 1B je 0040139C
00401381: 8B 7D 0C mov edi,dword ptr [ebp+0Ch]
00401384: 8B 70 0C mov esi,dword ptr [eax+0Ch]
00401387: 3B FE cmp edi,esi
00401389: 72 09 jb 00401394
0040138B: 8B 48 08 mov ecx,dword ptr [eax+8]
0040138E: 03 CE add ecx,esi
00401390: 3B F9 cmp edi,ecx
00401392: 72 0A jb 0040139E
00401394: 42 inc edx
00401395: 83 C0 28 add eax,28h
00401398: 3B D3 cmp edx,ebx
0040139A: 72 E8 jb 00401384
0040139C: 33 C0 xor eax,eax
0040139E: 5F pop edi
0040139F: 5E pop esi
004013A0: 5B pop ebx
004013A1: 5D pop ebp
004013A2: C3 ret
004013A3: CC int 3
004013A4: CC int 3
004013A5: CC int 3
004013A6: CC int 3
004013A7: CC int 3
004013A8: CC int 3
004013A9: CC int 3
004013AA: CC int 3
004013AB: CC int 3
004013AC: CC int 3
004013AD: CC int 3
004013AE: CC int 3
004013AF: CC int 3
004013B0: 55 push ebp
004013B1: 8B EC mov ebp,esp
004013B3: 6A FE push 0FFFFFFFEh
004013B5: 68 58 21 40 00 push 402158h
004013BA: 68 09 17 40 00 push 401709h
004013BF: 64 A1 00 00 00 00 mov eax,dword ptr fs:[00000000h]
004013C5: 50 push eax
004013C6: 83 EC 08 sub esp,8
004013C9: 53 push ebx
004013CA: 56 push esi
004013CB: 57 push edi
004013CC: A1 38 30 40 00 mov eax,dword ptr ds:[00403038h]
004013D1: 31 45 F8 xor dword ptr [ebp-8],eax
004013D4: 33 C5 xor eax,ebp
004013D6: 50 push eax
004013D7: 8D 45 F0 lea eax,[ebp-10h]
004013DA: 64 A3 00 00 00 00 mov dword ptr fs:[00000000h],eax
004013E0: 89 65 E8 mov dword ptr [ebp-18h],esp
004013E3: C7 45 FC 00 00 00 mov dword ptr [ebp-4],0
00
004013EA: 68 00 00 40 00 push 400000h
004013EF: E8 7C 00 00 00 call 00401470
004013F4: 83 C4 04 add esp,4
004013F7: 85 C0 test eax,eax
004013F9: 74 54 je 0040144F
004013FB: 8B 45 08 mov eax,dword ptr [ebp+8]
004013FE: 2D 00 00 40 00 sub eax,400000h
00401403: 50 push eax
00401404: 68 00 00 40 00 push 400000h
00401409: E8 52 FF FF FF call 00401360
0040140E: 83 C4 08 add esp,8
00401411: 85 C0 test eax,eax
00401413: 74 3A je 0040144F
00401415: 8B 40 24 mov eax,dword ptr [eax+24h]
00401418: C1 E8 1F shr eax,1Fh
0040141B: F7 D0 not eax
0040141D: 83 E0 01 and eax,1
00401420: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
00401427: 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040142A: 64 89 0D 00 00 00 mov dword ptr fs:[00000000h],ecx
00
00401431: 59 pop ecx
00401432: 5F pop edi
00401433: 5E pop esi
00401434: 5B pop ebx
00401435: 8B E5 mov esp,ebp
00401437: 5D pop ebp
00401438: C3 ret
00401439: 8B 45 EC mov eax,dword ptr [ebp-14h]
0040143C: 8B 00 mov eax,dword ptr [eax]
0040143E: 33 C9 xor ecx,ecx
00401440: 81 38 05 00 00 C0 cmp dword ptr [eax],0C0000005h
00401446: 0F 94 C1 sete cl
00401449: 8B C1 mov eax,ecx
0040144B: C3 ret
0040144C: 8B 65 E8 mov esp,dword ptr [ebp-18h]
0040144F: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
00401456: 33 C0 xor eax,eax
00401458: 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040145B: 64 89 0D 00 00 00 mov dword ptr fs:[00000000h],ecx
00
00401462: 59 pop ecx
00401463: 5F pop edi
00401464: 5E pop esi
00401465: 5B pop ebx
00401466: 8B E5 mov esp,ebp
00401468: 5D pop ebp
00401469: C3 ret
0040146A: CC int 3
0040146B: CC int 3
0040146C: CC int 3
0040146D: CC int 3
0040146E: CC int 3
0040146F: CC int 3
00401470: 55 push ebp
00401471: 8B EC mov ebp,esp
00401473: 8B 45 08 mov eax,dword ptr [ebp+8]
00401476: B9 4D 5A 00 00 mov ecx,5A4Dh
0040147B: 66 39 08 cmp word ptr [eax],cx
0040147E: 74 04 je 00401484
00401480: 33 C0 xor eax,eax
00401482: 5D pop ebp
00401483: C3 ret
00401484: 8B 48 3C mov ecx,dword ptr [eax+3Ch]
00401487: 03 C8 add ecx,eax
00401489: 33 C0 xor eax,eax
0040148B: 81 39 50 45 00 00 cmp dword ptr [ecx],4550h
00401491: 75 0C jne 0040149F
00401493: BA 0B 01 00 00 mov edx,10Bh
00401498: 66 39 51 18 cmp word ptr [ecx+18h],dx
0040149C: 0F 94 C0 sete al
0040149F: 5D pop ebp
004014A0: C3 ret
004014A1: 55 push ebp
004014A2: 8B EC mov ebp,esp
004014A4: 83 EC 14 sub esp,14h
004014A7: 83 65 F4 00 and dword ptr [ebp-0Ch],0
004014AB: 83 65 F8 00 and dword ptr [ebp-8],0
004014AF: A1 38 30 40 00 mov eax,dword ptr ds:[00403038h]
004014B4: 56 push esi
004014B5: 57 push edi
004014B6: BF 4E E6 40 BB mov edi,0BB40E64Eh
004014BB: BE 00 00 FF FF mov esi,0FFFF0000h
004014C0: 3B C7 cmp eax,edi
004014C2: 74 0D je 004014D1
004014C4: 85 C6 test esi,eax
004014C6: 74 09 je 004014D1
004014C8: F7 D0 not eax
004014CA: A3 3C 30 40 00 mov dword ptr ds:[0040303Ch],eax
004014CF: EB 66 jmp 00401537
004014D1: 8D 45 F4 lea eax,[ebp-0Ch]
004014D4: 50 push eax
004014D5: FF 15 08 20 40 00 call dword ptr ds:[00402008h]
004014DB: 8B 45 F8 mov eax,dword ptr [ebp-8]
004014DE: 33 45 F4 xor eax,dword ptr [ebp-0Ch]
004014E1: 89 45 FC mov dword ptr [ebp-4],eax
004014E4: FF 15 0C 20 40 00 call dword ptr ds:[0040200Ch]
004014EA: 31 45 FC xor dword ptr [ebp-4],eax
004014ED: FF 15 10 20 40 00 call dword ptr ds:[00402010h]
004014F3: 31 45 FC xor dword ptr [ebp-4],eax
004014F6: 8D 45 EC lea eax,[ebp-14h]
004014F9: 50 push eax
004014FA: FF 15 14 20 40 00 call dword ptr ds:[00402014h]
00401500: 8B 4D F0 mov ecx,dword ptr [ebp-10h]
00401503: 8D 45 FC lea eax,[ebp-4]
00401506: 33 4D EC xor ecx,dword ptr [ebp-14h]
00401509: 33 4D FC xor ecx,dword ptr [ebp-4]
0040150C: 33 C8 xor ecx,eax
0040150E: 3B CF cmp ecx,edi
00401510: 75 07 jne 00401519
00401512: B9 4F E6 40 BB mov ecx,0BB40E64Fh
00401517: EB 10 jmp 00401529
00401519: 85 CE test esi,ecx
0040151B: 75 0C jne 00401529
0040151D: 8B C1 mov eax,ecx
0040151F: 0D 11 47 00 00 or eax,4711h
00401524: C1 E0 10 shl eax,10h
00401527: 0B C8 or ecx,eax
00401529: 89 0D 38 30 40 00 mov dword ptr ds:[00403038h],ecx
0040152F: F7 D1 not ecx
00401531: 89 0D 3C 30 40 00 mov dword ptr ds:[0040303Ch],ecx
00401537: 5F pop edi
00401538: 5E pop esi
00401539: 8B E5 mov esp,ebp
0040153B: 5D pop ebp
0040153C: C3 ret
0040153D: 83 3D 9C 33 40 00 cmp dword ptr ds:[0040339Ch],0
00
00401544: 74 03 je 00401549
00401546: 33 C0 xor eax,eax
00401548: C3 ret
00401549: 56 push esi
0040154A: 6A 04 push 4
0040154C: 6A 20 push 20h
0040154E: FF 15 58 20 40 00 call dword ptr ds:[00402058h]
00401554: 59 pop ecx
00401555: 59 pop ecx
00401556: 8B F0 mov esi,eax
00401558: 56 push esi
00401559: FF 15 18 20 40 00 call dword ptr ds:[00402018h]
0040155F: A3 9C 33 40 00 mov dword ptr ds:[0040339Ch],eax
00401564: A3 98 33 40 00 mov dword ptr ds:[00403398h],eax
00401569: 85 F6 test esi,esi
0040156B: 75 05 jne 00401572
0040156D: 6A 18 push 18h
0040156F: 58 pop eax
00401570: 5E pop esi
00401571: C3 ret
00401572: 83 26 00 and dword ptr [esi],0
00401575: 33 C0 xor eax,eax
00401577: 5E pop esi
00401578: C3 ret
00401579: 6A 14 push 14h
0040157B: 68 78 21 40 00 push 402178h
00401580: E8 2B 01 00 00 call 004016B0
00401585: 83 65 DC 00 and dword ptr [ebp-24h],0
00401589: FF 35 9C 33 40 00 push dword ptr ds:[0040339Ch]
0040158F: 8B 35 04 20 40 00 mov esi,dword ptr ds:[00402004h]
00401595: FF D6 call esi
00401597: 89 45 E4 mov dword ptr [ebp-1Ch],eax
0040159A: 83 F8 FF cmp eax,0FFFFFFFFh
0040159D: 75 0C jne 004015AB
0040159F: FF 75 08 push dword ptr [ebp+8]
004015A2: FF 15 60 20 40 00 call dword ptr ds:[00402060h]
004015A8: 59 pop ecx
004015A9: EB 65 jmp 00401610
004015AB: 6A 08 push 8
004015AD: E8 86 01 00 00 call 00401738
004015B2: 59 pop ecx
004015B3: 83 65 FC 00 and dword ptr [ebp-4],0
004015B7: FF 35 9C 33 40 00 push dword ptr ds:[0040339Ch]
004015BD: FF D6 call esi
004015BF: 89 45 E4 mov dword ptr [ebp-1Ch],eax
004015C2: FF 35 98 33 40 00 push dword ptr ds:[00403398h]
004015C8: FF D6 call esi
004015CA: 89 45 E0 mov dword ptr [ebp-20h],eax
004015CD: 8D 45 E0 lea eax,[ebp-20h]
004015D0: 50 push eax
004015D1: 8D 45 E4 lea eax,[ebp-1Ch]
004015D4: 50 push eax
004015D5: FF 75 08 push dword ptr [ebp+8]
004015D8: 8B 35 18 20 40 00 mov esi,dword ptr ds:[00402018h]
004015DE: FF D6 call esi
004015E0: 50 push eax
004015E1: E8 5E 01 00 00 call 00401744
004015E6: 83 C4 0C add esp,0Ch
004015E9: 8B F8 mov edi,eax
004015EB: 89 7D DC mov dword ptr [ebp-24h],edi
004015EE: FF 75 E4 push dword ptr [ebp-1Ch]
004015F1: FF D6 call esi
004015F3: A3 9C 33 40 00 mov dword ptr ds:[0040339Ch],eax
004015F8: FF 75 E0 push dword ptr [ebp-20h]
004015FB: FF D6 call esi
004015FD: A3 98 33 40 00 mov dword ptr ds:[00403398h],eax
00401602: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
00401609: E8 0B 00 00 00 call 00401619
0040160E: 8B C7 mov eax,edi
00401610: E8 E0 00 00 00 call 004016F5
00401615: C3 ret
00401616: 8B 7D DC mov edi,dword ptr [ebp-24h]
00401619: 6A 08 push 8
0040161B: E8 1E 01 00 00 call 0040173E
00401620: 59 pop ecx
00401621: C3 ret
00401622: 55 push ebp
00401623: 8B EC mov ebp,esp
00401625: FF 75 08 push dword ptr [ebp+8]
00401628: E8 4C FF FF FF call 00401579
0040162D: F7 D8 neg eax
0040162F: 59 pop ecx
00401630: 1B C0 sbb eax,eax
00401632: F7 D8 neg eax
00401634: 48 dec eax
00401635: 5D pop ebp
00401636: C3 ret
00401637: 56 push esi
00401638: 57 push edi
00401639: BE 28 21 40 00 mov esi,402128h
0040163E: BF 28 21 40 00 mov edi,402128h
00401643: EB 0B jmp 00401650
00401645: 8B 06 mov eax,dword ptr [esi]
00401647: 85 C0 test eax,eax
00401649: 74 02 je 0040164D
0040164B: FF D0 call eax
0040164D: 83 C6 04 add esi,4
00401650: 3B F7 cmp esi,edi
00401652: 72 F1 jb 00401645
00401654: 5F pop edi
00401655: 5E pop esi
00401656: C3 ret
00401657: 56 push esi
00401658: 57 push edi
00401659: BE 30 21 40 00 mov esi,402130h
0040165E: BF 30 21 40 00 mov edi,402130h
00401663: EB 0B jmp 00401670
00401665: 8B 06 mov eax,dword ptr [esi]
00401667: 85 C0 test eax,eax
00401669: 74 02 je 0040166D
0040166B: FF D0 call eax
0040166D: 83 C6 04 add esi,4
00401670: 3B F7 cmp esi,edi
00401672: 72 F1 jb 00401665
00401674: 5F pop edi
00401675: 5E pop esi
00401676: C3 ret
00401677: 56 push esi
00401678: 68 00 00 03 00 push 30000h
0040167D: 68 00 00 01 00 push 10000h
00401682: 33 F6 xor esi,esi
00401684: 56 push esi
00401685: E8 C6 00 00 00 call 00401750
0040168A: 83 C4 0C add esp,0Ch
0040168D: 85 C0 test eax,eax
0040168F: 75 02 jne 00401693
00401691: 5E pop esi
00401692: C3 ret
00401693: 56 push esi
00401694: 56 push esi
00401695: 56 push esi
00401696: 56 push esi
00401697: 56 push esi
00401698: E8 AD 00 00 00 call 0040174A
0040169D: CC int 3
0040169E: FF 25 34 20 40 00 jmp dword ptr ds:[00402034h]
004016A4: FF 25 38 20 40 00 jmp dword ptr ds:[00402038h]
004016AA: CC int 3
004016AB: CC int 3
004016AC: CC int 3
004016AD: CC int 3
004016AE: CC int 3
004016AF: CC int 3
004016B0: 68 09 17 40 00 push 401709h
004016B5: 64 FF 35 00 00 00 push dword ptr fs:[00000000h]
00
004016BC: 8B 44 24 10 mov eax,dword ptr [esp+10h]
004016C0: 89 6C 24 10 mov dword ptr [esp+10h],ebp
004016C4: 8D 6C 24 10 lea ebp,[esp+10h]
004016C8: 2B E0 sub esp,eax
004016CA: 53 push ebx
004016CB: 56 push esi
004016CC: 57 push edi
004016CD: A1 38 30 40 00 mov eax,dword ptr ds:[00403038h]
004016D2: 31 45 FC xor dword ptr [ebp-4],eax
004016D5: 33 C5 xor eax,ebp
004016D7: 50 push eax
004016D8: 89 65 E8 mov dword ptr [ebp-18h],esp
004016DB: FF 75 F8 push dword ptr [ebp-8]
004016DE: 8B 45 FC mov eax,dword ptr [ebp-4]
004016E1: C7 45 FC FE FF FF mov dword ptr [ebp-4],0FFFFFFFEh
FF
004016E8: 89 45 F8 mov dword ptr [ebp-8],eax
004016EB: 8D 45 F0 lea eax,[ebp-10h]
004016EE: 64 A3 00 00 00 00 mov dword ptr fs:[00000000h],eax
004016F4: C3 ret
004016F5: 8B 4D F0 mov ecx,dword ptr [ebp-10h]
004016F8: 64 89 0D 00 00 00 mov dword ptr fs:[00000000h],ecx
00
004016FF: 59 pop ecx
00401700: 5F pop edi
00401701: 5F pop edi
00401702: 5E pop esi
00401703: 5B pop ebx
00401704: 8B E5 mov esp,ebp
00401706: 5D pop ebp
00401707: 51 push ecx
00401708: C3 ret
00401709: 55 push ebp
0040170A: 8B EC mov ebp,esp
0040170C: FF 75 14 push dword ptr [ebp+14h]
0040170F: FF 75 10 push dword ptr [ebp+10h]
00401712: FF 75 0C push dword ptr [ebp+0Ch]
00401715: FF 75 08 push dword ptr [ebp+8]
00401718: 68 56 17 40 00 push 401756h
0040171D: 68 38 30 40 00 push 403038h
00401722: E8 3F 00 00 00 call 00401766
00401727: 83 C4 18 add esp,18h
0040172A: 5D pop ebp
0040172B: C3 ret
0040172C: FF 25 48 20 40 00 jmp dword ptr ds:[00402048h]
00401732: FF 25 94 20 40 00 jmp dword ptr ds:[00402094h]
00401738: FF 25 50 20 40 00 jmp dword ptr ds:[00402050h]
0040173E: FF 25 54 20 40 00 jmp dword ptr ds:[00402054h]
00401744: FF 25 5C 20 40 00 jmp dword ptr ds:[0040205Ch]
0040174A: FF 25 64 20 40 00 jmp dword ptr ds:[00402064h]
00401750: FF 25 68 20 40 00 jmp dword ptr ds:[00402068h]
00401756: 3B 0D 38 30 40 00 cmp ecx,dword ptr ds:[00403038h]
0040175C: 75 02 jne 00401760
0040175E: F3 C3 rep ret
00401760: E9 44 00 00 00 jmp 004017A9
00401765: CC int 3
00401766: FF 25 6C 20 40 00 jmp dword ptr ds:[0040206Ch]
0040176C: 55 push ebp
0040176D: 8B EC mov ebp,esp
0040176F: FF 15 1C 20 40 00 call dword ptr ds:[0040201Ch]
00401775: 6A 01 push 1
00401777: A3 8C 33 40 00 mov dword ptr ds:[0040338Ch],eax
0040177C: E8 23 01 00 00 call 004018A4
00401781: FF 75 08 push dword ptr [ebp+8]
00401784: E8 21 01 00 00 call 004018AA
00401789: 83 3D 8C 33 40 00 cmp dword ptr ds:[0040338Ch],0
00
00401790: 59 pop ecx
00401791: 59 pop ecx
00401792: 75 08 jne 0040179C
00401794: 6A 01 push 1
00401796: E8 09 01 00 00 call 004018A4
0040179B: 59 pop ecx
0040179C: 68 09 04 00 C0 push 0C0000409h
004017A1: E8 0A 01 00 00 call 004018B0
004017A6: 59 pop ecx
004017A7: 5D pop ebp
004017A8: C3 ret
004017A9: 55 push ebp
004017AA: 8B EC mov ebp,esp
004017AC: 81 EC 24 03 00 00 sub esp,324h
004017B2: 6A 17 push 17h
004017B4: E8 FD 00 00 00 call 004018B6
004017B9: 85 C0 test eax,eax
004017BB: 74 05 je 004017C2
004017BD: 6A 02 push 2
004017BF: 59 pop ecx
004017C0: CD 29 int 29h
004017C2: A3 70 31 40 00 mov dword ptr ds:[00403170h],eax
004017C7: 89 0D 6C 31 40 00 mov dword ptr ds:[0040316Ch],ecx
004017CD: 89 15 68 31 40 00 mov dword ptr ds:[00403168h],edx
004017D3: 89 1D 64 31 40 00 mov dword ptr ds:[00403164h],ebx
004017D9: 89 35 60 31 40 00 mov dword ptr ds:[00403160h],esi
004017DF: 89 3D 5C 31 40 00 mov dword ptr ds:[0040315Ch],edi
004017E5: 66 8C 15 88 31 40 mov word ptr ds:[00403188h],ss
00
004017EC: 66 8C 0D 7C 31 40 mov word ptr ds:[0040317Ch],cs
00
004017F3: 66 8C 1D 58 31 40 mov word ptr ds:[00403158h],ds
00
004017FA: 66 8C 05 54 31 40 mov word ptr ds:[00403154h],es
00
00401801: 66 8C 25 50 31 40 mov word ptr ds:[00403150h],fs
00
00401808: 66 8C 2D 4C 31 40 mov word ptr ds:[0040314Ch],gs
00
0040180F: 9C pushfd
00401810: 8F 05 80 31 40 00 pop dword ptr ds:[00403180h]
00401816: 8B 45 00 mov eax,dword ptr [ebp]
00401819: A3 74 31 40 00 mov dword ptr ds:[00403174h],eax
0040181E: 8B 45 04 mov eax,dword ptr [ebp+4]
00401821: A3 78 31 40 00 mov dword ptr ds:[00403178h],eax
00401826: 8D 45 08 lea eax,[ebp+8]
00401829: A3 84 31 40 00 mov dword ptr ds:[00403184h],eax
0040182E: 8B 85 DC FC FF FF mov eax,dword ptr [ebp+FFFFFCDCh]
00401834: C7 05 C0 30 40 00 mov dword ptr ds:[004030C0h],10001h
01 00 01 00
0040183E: A1 78 31 40 00 mov eax,dword ptr ds:[00403178h]
00401843: A3 7C 30 40 00 mov dword ptr ds:[0040307Ch],eax
00401848: C7 05 70 30 40 00 mov dword ptr ds:[00403070h],0C0000409h
09 04 00 C0
00401852: C7 05 74 30 40 00 mov dword ptr ds:[00403074h],1
01 00 00 00
0040185C: C7 05 80 30 40 00 mov dword ptr ds:[00403080h],1
01 00 00 00
00401866: 6A 04 push 4
00401868: 58 pop eax
00401869: 6B C0 00 imul eax,eax,0
0040186C: C7 80 84 30 40 00 mov dword ptr [eax+00403084h],2
02 00 00 00
00401876: 6A 04 push 4
00401878: 58 pop eax
00401879: 6B C0 00 imul eax,eax,0
0040187C: 8B 0D 38 30 40 00 mov ecx,dword ptr ds:[00403038h]
00401882: 89 4C 05 F8 mov dword ptr [ebp+eax-8],ecx
00401886: 6A 04 push 4
00401888: 58 pop eax
00401889: C1 E0 00 shl eax,0
0040188C: 8B 0D 3C 30 40 00 mov ecx,dword ptr ds:[0040303Ch]
00401892: 89 4C 05 F8 mov dword ptr [ebp+eax-8],ecx
00401896: 68 C8 20 40 00 push 4020C8h
0040189B: E8 CC FE FF FF call 0040176C
004018A0: 8B E5 mov esp,ebp
004018A2: 5D pop ebp
004018A3: C3 ret
004018A4: FF 25 70 20 40 00 jmp dword ptr ds:[00402070h]
004018AA: FF 25 74 20 40 00 jmp dword ptr ds:[00402074h]
004018B0: FF 25 78 20 40 00 jmp dword ptr ds:[00402078h]
004018B6: FF 25 00 20 40 00 jmp dword ptr ds:[00402000h]
Summary
1000 .data
1000 .rdata
1000 .reloc
1000 .text
04_ PE ヘッダ内の各構造体のメンバーの値を列挙
EXE や DLL の実行可能形式のファイルを PE ファイルと言っています.PE は Portable Executable の略です.PE ファイルのヘッダ部分が PE ヘッダということになります.
EXE のバイナリダンプをみると,一見意味のない数値の羅列ですが,PE ヘッダは複数の構造体で構成されています.詳細は参考リンクの記事で確認してください.
以下は,この PE ヘッダの情報を取得するサンプルです.まず,TFileStream でファイルストリームを作成します.そのストリームに,構造体を順番に読み込んで,各構造体のメンバーの値を取得します.
PE ヘッダの内容は,前項で説明した DUMPBIN でも取得することができます.
特定の構造体の,特定のメンバーの値だけを取得したい場合は,ImageNtHeader 関数を使用すると便利です.この関数の使用方法は,参考リンクの記事,または次項のサンプルを参考にしてください.
PE ヘッダからは,対象のファイルが 32 ビット版であるか 64 ビット版であるか,DLL か EXE かも知ることができます.また,GUI アプリかコンソールアプリであるかの情報も格納されています.
下の図は,今回作成した Hello2.exe の PE ヘッダ情報の取得結果です.
このサンプルは,32 ビット版の EXE, DLL 用のコードとなっています.
図13
設計時画面
図14
実行結果
上の図の最後の行の 6144 という値は,PE ヘッダの値から計算したファイルのサイズです.
一方,下の図のファイルのプロパティダイアログでも,ファイルのサイズが 6,144 バイトとなっていて,同じになっていることが確認できます.
図15
ファイルのプロパティダイアログでファイのサイズを確認
リスト4
PE ファイルのヘッダ部の情報を取得して表示
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Panel1: TPanel;
Button1: TButton;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
InitDir : String ;
procedure IMAGE_DOS_HEADER_Read(const Header: IMAGE_DOS_HEADER);
procedure IMAGE_NT_HEADERS_Read(const Header: IMAGE_NT_HEADERS);
procedure IMAGE_FILE_HEADER_Read(const Header: IMAGE_FILE_HEADER);
procedure IMAGE_OPTIONAL_HEADER_Read(const Header: IMAGE_OPTIONAL_HEADER);
procedure IMAGE_SECTION_HEADERS_Read(const Header: IMAGE_SECTION_HEADER);
procedure DisplayValueToMemo(CntChar: Integer; DigitValue: Integer;
DispText: String ; DispValue: Integer);
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses DateUtils;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'Courier New' ;
Memo1.Font.Size := 10 ;
Memo1.WordWrap := False;
Panel1.Caption := '' ;
end ;
// =============================================================================
// PEヘッダ内の各構造体のメンバーの値を列挙
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
FileFullPath : String ;
FStream : TFilestream;
DummyData : DWORD;
HInfo_DOS : IMAGE_DOS_HEADER;
HInfo_NTHEADER : IMAGE_NT_HEADERS;
HInfo_FILE : IMAGE_FILE_HEADER;
HInfo_OPTIONAL : IMAGE_OPTIONAL_HEADER;
HInfo_SECTION : IMAGE_SECTION_HEADER;
CountSections : Integer;
i : Integer;
MemPos : Integer;
EndSectionPos : Integer;
begin
if InitDir = EmptyStr then begin
InitDir := ExpandFileName('../' );
end ;
OpenDialog1.InitialDir := InitDir;
OpenDialog1.Filter := 'ファイル|*.exe;*.dll' ;
if OpenDialog1.Execute then begin
FileFullPath := OpenDialog1.FileName;
InitDir := ExtractFileDir(FileFullPath);
Memo1.Clear;
Memo1.Lines.BeginUpdate;
// ファイルストリームを生成
FStream := TFilestream.Create(FileFullPath, fmOpenread or fmShareDenyNone);
try
Memo1.Lines.Add('FileName : ' + ExtractFileName(FileFullPath));
Memo1.Lines.Add(' ' );
// IMAGE_DOS_HEADERの情報をHeaderInfo_DOSレコード型に読み込む
MemPos := FStream.Position;
FStream.Read (HInfo_DOS, SizeOf(HInfo_DOS));
Memo1.Lines.Add('IMAGE_DOS_HEADER ' );
Memo1.Lines.Add('[Memory Position]' + Format(' $%.8x' , [MemPos]));
Memo1.Lines.Add('[Size of Header]' + ' ' + IntToStr(SizeOf(HInfo_DOS)));
Memo1.Lines.Add('--------------------------------------------------------' );
IMAGE_DOS_HEADER_Read(HInfo_DOS);
// IMAGE_NT_HEADER部の先頭に移動するための位置移動
FStream.Seek(HInfo_DOS._lfanew, soFromBeginning);
// IMAGE_NT_HEADERSの情報を読み込む
MemPos := FStream.Position;
FStream.Read (HInfo_NTHEADER, SizeOf(HInfo_NTHEADER));
// その情報をTMemoに表示する
Memo1.Lines.Add(' ' );
Memo1.Lines.Add('IMAGE_NT_HEADER (PE HEADER)' );
Memo1.Lines.Add('[Memory Position]' + Format(' $%.8x' , [MemPos]));
Memo1.Lines.Add('[Size of Header]' + ' ' + IntToStr(SizeOf(HInfo_NTHEADER)));
Memo1.Lines.Add('--------------------------------------------------------' );
IMAGE_NT_HEADERS_Read(HInfo_NTHEADER);
// IMAGE_FILE_HEADERレコード型の先頭に移動
FStream.Seek(HInfo_DOS._lfanew, soFromBeginning);
FStream.Read (DummyData, SizeOf(DummyData));
// IMAGE_FILE_HEADERの情報を読み込む
MemPos := FStream.Position;
FStream.Read (HInfo_FILE, SizeOf(HInfo_FILE));
// その情報をTMemoに表示する
Memo1.Lines.Add(' ' );
Memo1.Lines.Add('IMAGE_NT_HEADER - IMAGE_FILE_HEADER' );
Memo1.Lines.Add('[Memory Position]' + Format(' $%.8x' , [MemPos]));
Memo1.Lines.Add('[Size of Header]' + ' ' + IntToStr(SizeOf(HInfo_FILE)));
Memo1.Lines.Add('--------------------------------------------------------' );
IMAGE_FILE_HEADER_Read(HInfo_FILE);
// セクション数を取得しておく
CountSections := HInfo_FILE.NumberOfSections;
// IMAGE_OPTIONAL_HEADER部の情報を読み込む
MemPos := FStream.Position;
FStream.Read ( HInfo_OPTIONAL, SizeOf(HInfo_OPTIONAL));
// その情報をTMemoに表示する
Memo1.Lines.Add(' ' );
Memo1.Lines.Add('IMAGE_NT_HEADER - IMAGE_OPTIONAL_HEADER' );
Memo1.Lines.Add('[Memory Position]' + Format(' $%.8x' , [MemPos]));
Memo1.Lines.Add('[Size of Header]' + ' ' + IntToStr(SizeOf(HInfo_OPTIONAL)));
Memo1.Lines.Add('--------------------------------------------------------' );
IMAGE_OPTIONAL_HEADER_Read(HInfo_OPTIONAL);
for i := 0 to CountSections - 1 do begin
// IMAGE_SECTION_HEADERの情報を読み込む
MemPos := FStream.Position;
FStream.Read (HInfo_SECTION, SizeOf(HInfo_SECTION));
// その情報をTMemoに表示する
Memo1.Lines.Add(' ' );
Memo1.Lines.Add('IMAGE_SECTION_HEADER - SECTION[' + IntToStr(i) + ']' );
Memo1.Lines.Add('[Memory Position]' + Format(' $%.8x' , [MemPos]));
Memo1.Lines.Add('[Size of Header]' + ' ' + IntToStr(SizeOf(HInfo_SECTION)));
Memo1.Lines.Add('--------------------------------------------------------' );
// その情報をTMemoに表示する
IMAGE_SECTION_HEADERS_Read(HInfo_SECTION);
end ;
// 最後ののセクションの最後の位置を計算
EndSectionPos := HInfo_SECTION.PointerToRawData + HInfo_SECTION.SizeOfRawData;
// 16進文字の表示にはIntToHeX関数も使用可能
Memo1.Lines.Add('--------------------------------------------------------' );
Memo1.Lines.Add('FileSize = $' + IntToHex(EndSectionPos, 8 )
+ ' (' + IntToStr(EndSectionPos) + ') bytes' );
finally
FStream.Free;
end ;
Memo1.Lines.EndUpdate;
end ;
end ;
// -----------------------------------------------------------------------------
// IMAGE_DOS_HEADER構造体の各メンバの値を取得して表示
// Windowsでは使用されていない
// Windowsで意味があるのは以下の2つのみ
//
// e_magic : DWORD MZというシグネチャ文字で,実行可能ファイルを意味する
// lfanew : LONG
// 新しい形式のヘッダへのファイル内オフセット
// 新しい形式のヘッダとはPE ファイルフォーマットならNTヘッダのこと
// NTヘッダがPEファイルの真のヘッダ
// -----------------------------------------------------------------------------
procedure TForm1.IMAGE_DOS_HEADER_Read(const Header: IMAGE_DOS_HEADER);
var
magic : WORD;
lfanew : Integer;
StrText : String ;
begin
magic := Header.e_magic;
lfanew := Header._lfanew;
// このシグネチャはIMAGE_DOS_SIGNATURE($5A4D = 'MZ'という定数がある
StrText := Char(Lo(magic)) + Char(Hi(magic));
Memo1.Lines.Add(Format('%-10s %-3s' , ['e_magic : ' , StrText]));
Memo1.Lines.Add(Format('%-10s $%.8x' , ['lfanew : ' , lfanew]));
end ;
// -----------------------------------------------------------------------------
// IMAGE_NT_HEADERS構造体の各メンバの値を取得して表示
// この構造体には,次の構造体が階層下にある
// IMAGE_FILE_HEADER
// IMAGE_OPTIONAL_HEADER(この中にIMAGE_DATA_DIRECTORY構造体がある)
// -----------------------------------------------------------------------------
procedure TForm1.IMAGE_NT_HEADERS_Read(const Header: IMAGE_NT_HEADERS);
var
Signature : DWORD;
StrText : String ;
begin
Signature := Header.Signature;
StrText := String (PAnsiChar(@Signature));
// 16進数はバイトオーダーがリトルリトルエンディアンになっているので注意
// このシグネチャはIMAGE_NT_SIGNATURE($00004550 = 'PE00'という定数がある
StrText := 'Signature : ' + StrText + ' (' + Format('$%.4x' , [Signature]) + ')' ;
Memo1.Lines.Add(StrText);
end ;
// -----------------------------------------------------------------------------
// PEのIMAGE_FILE_HEADER構造体の各メンバーの値を取得して表示
// -----------------------------------------------------------------------------
procedure TForm1.IMAGE_FILE_HEADER_Read(const Header: IMAGE_FILE_HEADER);
// ---------------------------------------------------------------------------
// UTC(世界協定時刻)とローカルとの時刻差を求める関数
// この差は分単位となっている
// 日本の場合は常に9:00:00となる
// ---------------------------------------------------------------------------
function UTCTimeDateTimeOffset: TDateTime;
var
tZone : TTimeZoneInformation;
begin
GetTimeZoneInformation(tZone);
Result := EncodeTime(ABS(tZone.Bias) div 60 , ABS(tZone.Bias) mod 60 , 0 , 0 );
end ;
// ---------------------------------------------------------------------------
const
IMAGE_FILE_MACHINE_IA64 = $0200 ;
IMAGE_FILE_MACHINE_AMD64 = $8664 ;
var
StrText : String ;
CntChars : Integer;
StrFmt : String ;
TempText : String ;
DateTime : TDateTime;
SL : TStringList;
i : Integer;
begin
CntChars := 20 ;
StrFmt := '%-' + IntTostr(CntChars) + 's : ' ;
// マシンのタイプ
StrText := 'Machine' ;
case Header.Machine of
IMAGE_FILE_MACHINE_I386 : TempText := 'IMAGE_FILE_MACHINE_I386' ;
IMAGE_FILE_MACHINE_IA64 : TempText := 'IMAGE_FILE_MACHINE_IA64' ;
IMAGE_FILE_MACHINE_AMD64 : TempText := 'IMAGE_FILE_MACHINE_AMD64' ;
IMAGE_FILE_MACHINE_R3000 : TempText := 'IMAGE_FILE_MACHINE_R3000' ;
IMAGE_FILE_MACHINE_R4000 : TempText := 'IMAGE_FILE_MACHINE_R4000' ;
IMAGE_FILE_MACHINE_R10000 : TempText := 'IMAGE_FILE_MACHINE_R10000' ;
IMAGE_FILE_MACHINE_ALPHA : TempText := 'IMAGE_FILE_MACHINE_ALPHA' ;
IMAGE_FILE_MACHINE_POWERPC : TempText := 'IMAGE_FILE_MACHINE_POWERPC' ;
else
TempText := 'Unknown' ;
end ;
Memo1.Lines.Add(Format(StrFmt, [StrText]) + TempText);
StrText := 'NumberOfSections' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.NumberOfSections);
StrText := 'TimeDateStamp' ;
DateTime := UnixToDateTime(Header.TimeDateStamp) + UTCTimeDateTimeOffset;
TempText := FormatDateTime('yyyy/mm/dd hh:nn:ss' , DateTime);
Memo1.Lines.Add(Format(StrFmt, [StrText]) + TempText);
StrText := 'PointerToSymbolTable' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.PointerToSymbolTable);
StrText := 'NumberOfSymbols' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.NumberOfSymbols);
// ファイルの属性値のフラグの組み合わせ
// DLLの時は,IMAGE_FILE_DLLがある
// EXEの時は,IMAGE_FILE_EXECUTABLE_IMAGEがある
StrText := 'SizeOfOptionalHeader' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.SizeOfOptionalHeader);
SL := TStringList.Create;
try
StrText := 'Characteristics' ;
if (IMAGE_FILE_RELOCS_STRIPPED and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_RELOCS_STRIPPED' );
if (IMAGE_FILE_EXECUTABLE_IMAGE and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_EXECUTABLE_IMAGE' );
if (IMAGE_FILE_LINE_NUMS_STRIPPED and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_LINE_NUMS_STRIPPED' );
if (IMAGE_FILE_LOCAL_SYMS_STRIPPED and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_LOCAL_SYMS_STRIPPED' );
if (IMAGE_FILE_AGGRESIVE_WS_TRIM and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_AGGRESIVE_WS_TRIM' );
if (IMAGE_FILE_LARGE_ADDRESS_AWARE and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_LARGE_ADDRESS_AWARE' );
if (IMAGE_FILE_BYTES_REVERSED_LO and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_BYTES_REVERSED_LO' );
if (IMAGE_FILE_32BIT_MACHINE and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_32BIT_MACHINE' );
if (IMAGE_FILE_DEBUG_STRIPPED and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_DEBUG_STRIPPED' );
if (IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP' );
if (IMAGE_FILE_NET_RUN_FROM_SWAP and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_NET_RUN_FROM_SWAP' );
if (IMAGE_FILE_SYSTEM and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_SYSTEM' );
if (IMAGE_FILE_DLL and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_DLL' );
if (IMAGE_FILE_UP_SYSTEM_ONLY and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_UP_SYSTEM_ONLY' );
if (IMAGE_FILE_BYTES_REVERSED_HI and Header.Characteristics) <> 0 then
SL.Add('IMAGE_FILE_BYTES_REVERSED_HI' );
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[0 ]);
StrText := '' ;
for i := 1 to SL.Count - 1 do begin
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[i]);
end ;
finally
FreeAndNil(SL);
end ;
end ;
// -----------------------------------------------------------------------------
// IMAGE_OPTIONAL_HEADER構造体の各メンバーの値を取得して表示
// -----------------------------------------------------------------------------
procedure TForm1.IMAGE_OPTIONAL_HEADER_Read(const Header: IMAGE_OPTIONAL_HEADER);
const
IMAGE_NT_OPTIONAL_HDR64_MAGIC = $020B ;
IMAGE_NT_OPTIONAL_HDR32_MAGIC = $010B ;
IMAGE_ROM_OPTIONAL_HDR_MAGIC = $0107 ;
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 ;
IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 ;
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 ;
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 ;
IMAGE_SUBSYSTEM_EFI_ROM = 13 ;
IMAGE_SUBSYSTEM_XBOX = 14 ;
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 ;
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = $0040 ;
IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = $0080 ;
IMAGE_DLLCHARACTERISTICS_NX_COMPAT = $0100 ;
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = $0200 ;
IMAGE_DLLCHARACTERISTICS_NO_SEH = $0400 ;
var
StrText : String ;
TempText : String ;
TempWord : WORD;
CntChars : Integer;
StrFmt : String ;
SL : TStringList;
ImageDir : TImageDataDirectory;
i : Integer;
begin
CntChars := 27 ;
StrFmt := '%-' + IntTostr(CntChars) + 's : ' ;
// バイナリの実行環境が32ビットか64ビットか等
StrText := 'Magic' ;
case Header.Magic of
IMAGE_NT_OPTIONAL_HDR32_MAGIC : TempText := 'IMAGE_NT_OPTIONAL_HDR32_MAGIC' ;
IMAGE_NT_OPTIONAL_HDR64_MAGIC : TempText := 'IMAGE_NT_OPTIONAL_HDR64_MAGIC' ;
IMAGE_ROM_OPTIONAL_HDR_MAGIC : TempText := 'IMAGE_ROM_OPTIONAL_HDR_MAGIC' ;
else
TempText := 'Unknown' ;
end ;
Memo1.Lines.Add(Format(StrFmt, [StrText]) + TempText);
StrText := 'MajorLinkerVersion' ;
DisplayValueToMemo(CntChars, 2 , StrText, Header.MajorLinkerVersion);
StrText := 'MinorLinkerVersion' ;
DisplayValueToMemo(CntChars, 2 , StrText, Header.MinorLinkerVersion);
StrText := 'SizeOfCode' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfCode);
StrText := 'SizeOfInitializedData' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfInitializedData);
StrText := 'SizeOfUninitializedData' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfUninitializedData);
StrText := 'AddressOfEntryPoint' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.AddressOfEntryPoint);
StrText := 'BaseOfCode' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.BaseOfCode);
StrText := 'BaseOfData' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.BaseOfData);
StrText := 'ImageBase' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.ImageBase);
StrText := 'SectionAlignment' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SectionAlignment);
StrText := 'FileAlignment' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.FileAlignment);
StrText := 'MajorOperatingSystemVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MajorOperatingSystemVersion);
StrText := 'MinorOperatingSystemVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MinorOperatingSystemVersion);
StrText := 'MajorImageVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MajorImageVersion);
StrText := 'MinorImageVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MinorImageVersion);
StrText := 'MajorSubsystemVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MajorSubsystemVersion);
StrText := 'MinorSubsystemVersion' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.MinorSubsystemVersion);
StrText := 'Win32VersionValue' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.Win32VersionValue);
StrText := 'SizeOfImage' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfImage);
StrText := 'SizeOfHeaders' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfHeaders);
StrText := 'CheckSum' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.CheckSum);
// アプリの特性
// Windowsアプリは,IMAGE_SUBSYSTEM_WINDOWS_GUI(2)
// コンソールアプリは,IMAGE_SUBSYSTEM_WINDOWS_CUI(3)
// デバイスドライバは,IMAGE_SUBSYSTEM_NATIVE(1)
StrText := 'Subsystem' ;
case Header.Subsystem of
IMAGE_SUBSYSTEM_UNKNOWN :
TempText := 'IMAGE_SUBSYSTEM_UNKNOWN' ;
IMAGE_SUBSYSTEM_NATIVE :
TempText := 'IMAGE_SUBSYSTEM_NATIVE' ;
IMAGE_SUBSYSTEM_WINDOWS_GUI :
TempText := 'IMAGE_SUBSYSTEM_WINDOWS_GUI' ;
IMAGE_SUBSYSTEM_WINDOWS_CUI :
TempText := 'IMAGE_SUBSYSTEM_WINDOWS_CUI' ;
IMAGE_SUBSYSTEM_OS2_CUI :
TempText := 'IMAGE_SUBSYSTEM_OS2_CUI' ;
IMAGE_SUBSYSTEM_POSIX_CUI :
TempText := 'IMAGE_SUBSYSTEM_POSIX_CUI' ;
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI :
TempText := 'IMAGE_SUBSYSTEM_WINDOWS_CE_GUI' ;
IMAGE_SUBSYSTEM_EFI_APPLICATION :
TempText := 'IMAGE_SUBSYSTEM_EFI_APPLICATION' ;
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER :
TempText := 'IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER' ;
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER :
TempText := 'IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER' ;
IMAGE_SUBSYSTEM_EFI_ROM :
TempText := 'IMAGE_SUBSYSTEM_EFI_ROM' ;
IMAGE_SUBSYSTEM_XBOX :
TempText := 'IMAGE_SUBSYSTEM_XBOX' ;
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION :
TempText := 'IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION' ;
else
TempText := 'Unknown' ;
end ;
Memo1.Lines.Add(Format(StrFmt, [StrText]) + TempText);
// DLLの特性に関する値(一般的には意味がないらしい)
StrText := 'DllCharacteristics' ;
TempWord := Header.DllCharacteristics;
SL := TStringList.Create;
try
if (TempWord and IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_NX_COMPAT) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_NX_COMPAT' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_NO_ISOLATION' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_NO_SEH) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_NO_SEH' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_NO_BIND) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_NO_BIND' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_WDM_DRIVER' );
if (TempWord and IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) <> 0 then
SL.Add('IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE' );
if SL.Count = 0 then SL.Add('Unknown' );
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[0 ]);
StrText := '' ;
for i := 1 to SL.Count - 1 do begin
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[i]);
end ;
finally
FreeAndNil(SL);
end ;
StrText := 'SizeOfStackReserve' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfStackReserve);
StrText := 'SizeOfStackCommit' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfStackCommit);
StrText := 'SizeOfHeapReserve' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfHeapReserve);
StrText := 'SizeOfHeapCommit' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfHeapCommit);
StrText := 'LoaderFlags' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.LoaderFlags);
StrText := 'NumberOfRvaAndSizes' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.NumberOfRvaAndSizes);
// IMAGE_DATA_DIRECTORY構造体の各メンバの値を取得して表示
// この構造体は配列
// 各種データのPEヘッダ(イメージベース)からの相対的な位置(RVA)と,
// そのデータのサイズがバイト単位で格納されている
CntChars := 32 ;
for i := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 do begin
ImageDir := Header.DataDirectory[i];
StrText := 'DataDirectory[' + IntToStr(i) + '].VirtualAddress' ;
DisplayValueToMemo(CntChars, 8 , StrText, ImageDir.VirtualAddress);
StrText := 'DataDirectory[' + IntToStr(i) + '].Size' ;
DisplayValueToMemo(CntChars, 8 , StrText, ImageDir.Size);
end ;
end ;
// -----------------------------------------------------------------------------
// IMAGE_SECTION_HEADER構造体の各メンバの値を取得して表示
// セクション数は,アプリケーションによって異なる
// ネイティブコード,リソース,デバッグ情報等の実際のデータの相対位置(RVA)
// データサイズ等がある
// -----------------------------------------------------------------------------
procedure TForm1.IMAGE_SECTION_HEADERS_Read(const Header: IMAGE_SECTION_HEADER);
const
IMAGE_SCN_NO_DEFER_SPEC_EXC = $00004000 ;
IMAGE_SCN_GPREL = $00008000 ;
IMAGE_SCN_ALIGN_128BYTES = $00800000 ;
IMAGE_SCN_ALIGN_256BYTES = $00900000 ;
IMAGE_SCN_ALIGN_512BYTES = $00A00000 ;
IMAGE_SCN_ALIGN_1024BYTES = $00B00000 ;
IMAGE_SCN_ALIGN_2048BYTES = $00C00000 ;
IMAGE_SCN_ALIGN_4096BYTES = $00D00000 ;
IMAGE_SCN_ALIGN_8192BYTES = $00E00000 ;
var
StrText : String ;
CntChars : Integer;
StrFmt : String ;
TempDWORD : DWORD;
SL : TStringList;
i : Integer;
Name : String ;
begin
CntChars := 20 ;
StrFmt := '%-' + IntTostr(CntChars) + 's : ' ;
// セクション名のバイト配列(ASCII文字列)
// バイト配列から文字列に変換
// PAnsiCharのままだと警告が表示されるので明示的にString型でキャスト
Name := String (PAnsiChar(@Header.Name));
Memo1.Lines.Add(Format(StrFmt, ['Name' ]) + Name);
StrText := 'VirtualAddress' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.VirtualAddress);
StrText := 'SizeOfRawData' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.SizeOfRawData);
StrText := 'PointerToRawData' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.PointerToRawData);
StrText := 'PointerToRelocations' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.PointerToRelocations);
StrText := 'PointerToLinenumbers' ;
DisplayValueToMemo(CntChars, 8 , StrText, Header.PointerToLinenumbers);
StrText := 'NumberOfRelocations' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.NumberOfRelocations);
StrText := 'NumberOfLinenumbers' ;
DisplayValueToMemo(CntChars, 4 , StrText, Header.NumberOfLinenumbers);
// セクションの特性を意味するフラグの組み合わせ
StrText := 'Characteristics' ;
TempDWord := Header.Characteristics;
SL := TStringList.Create;
try
if (TempDWord and IMAGE_SCN_TYPE_NO_PAD) <> 0 then
SL.Add('IMAGE_SCN_TYPE_NO_PAD' );
if (TempDWord and IMAGE_SCN_CNT_CODE) <> 0 then
SL.Add('IMAGE_SCN_CNT_CODE' );
if (TempDWord and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0 then
SL.Add('IMAGE_SCN_CNT_INITIALIZED_DATA' );
if (TempDWord and IMAGE_SCN_CNT_UNINITIALIZED_DATA) <> 0 then
SL.Add('IMAGE_SCN_CNT_UNINITIALIZED_DATA' );
if (TempDWord and IMAGE_SCN_LNK_OTHER) <> 0 then
SL.Add('IMAGE_SCN_LNK_OTHER' );
if (TempDWord and IMAGE_SCN_LNK_INFO) <> 0 then
SL.Add('IMAGE_SCN_LNK_INFO' );
if (TempDWord and IMAGE_SCN_LNK_REMOVE) <> 0 then
SL.Add('IMAGE_SCN_LNK_REMOVE' );
if (TempDWord and IMAGE_SCN_LNK_COMDAT) <> 0 then
SL.Add('IMAGE_SCN_LNK_COMDAT' );
if (TempDWord and IMAGE_SCN_NO_DEFER_SPEC_EXC) <> 0 then
SL.Add('IMAGE_SCN_NO_DEFER_SPEC_EXC' );
if (TempDWord and IMAGE_SCN_GPREL) <> 0 then
SL.Add('IMAGE_SCN_GPREL' );
if (TempDWord and IMAGE_SCN_MEM_PURGEABLE) <> 0 then
SL.Add('IMAGE_SCN_MEM_PURGEABLE' );
if (TempDWord and IMAGE_SCN_MEM_LOCKED) <> 0 then
SL.Add('IMAGE_SCN_MEM_LOCKED' );
if (TempDWord and IMAGE_SCN_MEM_PRELOAD) <> 0 then
SL.Add('IMAGE_SCN_MEM_PRELOAD' );
if (TempDWord and IMAGE_SCN_ALIGN_1BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_1BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_2BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_2BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_4BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_4BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_8BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_8BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_16BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_16BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_32BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_32BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_64BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_64BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_128BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_128BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_256BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_256BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_512BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_512BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_1024BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_1024BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_2048BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_2048BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_4096BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_4096BYTES' );
if (TempDWord and IMAGE_SCN_ALIGN_8192BYTES) <> 0 then
SL.Add('IMAGE_SCN_ALIGN_8192BYTES' );
if (TempDWord and IMAGE_SCN_LNK_NRELOC_OVFL) <> 0 then
SL.Add('IMAGE_SCN_LNK_NRELOC_OVFL' );
if (TempDWord and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then
SL.Add('IMAGE_SCN_MEM_DISCARDABLE' );
if (TempDWord and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
SL.Add('IMAGE_SCN_MEM_NOT_CACHED' );
if (TempDWord and IMAGE_SCN_MEM_NOT_PAGED) <> 0 then
SL.Add('IMAGE_SCN_MEM_NOT_PAGED' );
if (TempDWord and IMAGE_SCN_MEM_SHARED) <> 0 then
SL.Add('IMAGE_SCN_MEM_SHARED' );
if (TempDWord and IMAGE_SCN_MEM_EXECUTE) <> 0 then
SL.Add('IMAGE_SCN_MEM_EXECUTE' );
if (TempDWord and IMAGE_SCN_MEM_READ) <> 0 then
SL.Add('IMAGE_SCN_MEM_READ' );
if (TempDWord and IMAGE_SCN_MEM_WRITE) <> 0 then
SL.Add('IMAGE_SCN_MEM_WRITE' );
if SL.Count = 0 then SL.Add('Unknown' );
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[0 ]);
StrText := '' ;
for i := 1 to SL.Count - 1 do begin
Memo1.Lines.Add(Format(StrFmt, [StrText]) + SL[i]);
end ;
finally
FreeAndNil(SL);
end ;
end ;
// -----------------------------------------------------------------------------
// 指定文字数と指定桁数で数値を16進表示するメソッド
// CntChar : 表示文字数
// DigitValue : 16進数の表示桁数
// DispText : 表示文字
// DispValue : 16進数表示する値
// -----------------------------------------------------------------------------
procedure TForm1.DisplayValueToMemo(CntChar, DigitValue: Integer; DispText: String ;
DispValue: Integer);
var
StrFmt : String ;
begin
StrFmt := '%-' + IntToStr(CntChar) +'s : $%.' + IntTostr(DigitValue) + 'x' ;
Memo1.Lines.Add(Format(StrFmt,
[DispText, DispValue]) + ' (' + IntToStr(DispValue) + ')' );
end ;
end .
PE ヘッダの操作例です.PE ヘッダのセクション構造体は複数あります.この数はアプリケーションによって異なります.下表はセクション名の例です.
古い Delph では,ネイティブコードのセクション名が CODE となっているようです.
本サンプルは,DLL ファイル内のエクスポート関数名を列挙します.エクスポート関数は,外部から使用可能な関数のことです.エクスポート関数の情報は,.edata セクション構造体にあります.その構造体に,関数名が格納されている位置の情報があります.それを元に検索していきます.
ヘッダ内の情報の取得には,前項と同じ方法も使えますが,Windows API には,PE ヘッダを操作するための関数類があります.それらは ImageHlp.pas 内で定義されています.この中の ImageNtHeader と ImageRvaToVa という関数を使用しています.
ImageNtHeader 関数を使用すると,PE ヘッダの先頭ポインタが取得できます.そのためには,ファイルを読み込んだ時の先頭アドレスが必要です.これは,メモリマップドファイルを生成して取得しています.メモリマップドファイルは,ファイルハンドルから生成します.
TMemoryStream や TFileStream は,シーケンシャルなアクセスに向いていますが,メモリマップドファイルは,ランダムにメモリ内をアクセスするのに適しています.
サンプルでは,DLL のファイルバージョンも取得して表示していますが,この値は,エクスプローラでファイルのプロパティダイアログの [詳細] タブの [ファイルバージョン] の値と同じです.
本サンプルは,情報の取得ですが,情報を書き込むこともできます.必要性の有無はともかく,EXE 内を書き換えたり,別の EXE を挿入したりすることも可能です.そのためには,PE ヘッダのどこに,どのような情報が格納されているかという知識や,その取得方法が必要になります.
このサンプルは,32 ビット版の EXE, DLL 用のコードとなっています.
セクション名
内容
.text
ネイティブコード
.data
グローバル変数用の領域
.idata
インポート関数情報
.edata
エクスポート関数情報
.rsrc
リソース情報
.debug
デバック情報
.reloc
再配置情報
.tls
スレッドごとの情報変数に関する情報
図16
設計時画面
図17
Shell32.dll のエクスポート関数の一覧
File Version はファイルのバージョン
外部から使用可能な関数が 333 ある
Windows 7 U64(SP1) の場合
リスト5
DLL 内のエクスポート関数を列挙
DLL のファイルバージョンを文字列として取得して表示
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Panel1: TPanel;
Button1: TButton;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
InitDir : String ;
function ListExportDLLfunctionNames(FileHandle: THandle): Boolean;
function GetFileVersionString(FileName: string ): String ;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses ImageHlp;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'Courier New' ;
Memo1.Font.Size := 10 ;
Memo1.WordWrap := False;
Panel1.Font := Memo1.Font;
Panel1.Caption := '' ;
end ;
// =============================================================================
// DLL内のエクスポート関数名をリスト
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
FileFullPath : String ;
FileHandle : THandle;
begin
if InitDir = EmptyStr then begin
InitDir := 'C:\Windows\System32' ;
end ;
OpenDialog1.InitialDir := InitDir;
OpenDialog1.Filter := 'ファイル|*.exe;*.dll' ;
if OpenDialog1.Execute then begin
FileFullPath := OpenDialog1.FileName;
InitDir := ExtractFileDir(FileFullPath);
Memo1.Clear;
Memo1.Lines.BeginUpdate;
// 対象ファイルを読み出し専用で開き,そのハンドルを取得
FileHandle := CreateFile(PChar(FileFullPath),
GENERIC_READ,
FILE_SHARE_READ,
nil ,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0 );
if FileHandle = INVALID_HANDLE_VALUE then exit;
try
Panel1.Caption := ExtractFileName(FileFullPath);
// ファイルのバージョン文字列を取得
Memo1.Lines.Add('File Version : ' + GetFileVersionString(FileFullPath));
// エクスポート関数を列挙
ListExportDLLfunctionNames(FileHandle);
finally
CloseHandle(FileHandle);
end ;
Memo1.Lines.EndUpdate;
end ;
end ;
// -----------------------------------------------------------------------------
// 実際にDLL内のエクスポート関数名をリストする関数
// 引数はファイルのハンドル
//
// 32ビット版専用
// usesにImageHlpが必要
// -----------------------------------------------------------------------------
function TForm1.ListExportDLLfunctionNames(FileHandle: THandle): Boolean;
var
HeaderHandle : THandle;
HeaderPointer : Pointer;
pNTHeaders : PImageNtHeaders;
pExportTable : PImageExportDirectory;
NamesPointer : PNativeUInt;
FunctionName : PAnsiChar;
i : Integer;
StrText : String ;
begin
Result := False;
// メモリマップドファイル生成
// ファイルハンドルからファイルのマッピングオブジェクトを取得
HeaderHandle := CreateFileMapping(FileHandle, nil , PAGE_READONLY, 0 , 0 , nil );
if HeaderHandle = 0 then exit;
try
// メモリマップドファイルをアドレス空間にマップ
// 戻り値は開始アドレス
HeaderPointer := MapViewOfFile(HeaderHandle, FILE_MAP_READ, 0 , 0 , 0 );
if not Assigned(HeaderPointer) then exit;
try
// ヘッダのポインタ(アドレス)を取得
pNTHeaders := ImageNtHeader(HeaderPointer);
if not Assigned(pNTHeaders) then exit;;
// シグネチャ(PE)の文字を確認
if pNTHeaders.Signature <> IMAGE_NT_SIGNATURE then exit;
// エクスポートテーブルのアドレスを相対仮想アドレスから仮想アドレスに変換
pExportTable := ImageRvaToVa(
pNTHeaders,
HeaderPointer,
pNTHeaders.OptionalHeader.DataDirectory[0 ].VirtualAddress,
nil );
if not Assigned(pExportTable) then exit;
// 関数名が格納されている相対仮想アドレスを仮想アドレスに変換
// エクスポートテーブルの仮想アドレスから取得する
NamesPointer := ImageRvaToVa(pNTHeaders,
HeaderPointer,
Cardinal(pExportTable.AddressOfNames),
nil );
if not Assigned(NamesPointer) then exit;
Memo1.Lines.Add('Number of Functions : ' + IntToStr(pExportTable.NumberOfNames));;
Memo1.Lines.Add('--------------------------------------' );
// 関数名を順番に取得して表示
// FunctionNameの型はPAnsiString型にしておくこと
for i := 0 to pExportTable.NumberOfNames - 1 do begin
FunctionName := ImageRvaToVa(pNTHeaders, HeaderPointer, NamesPointer^, nil );
StrText := String (FunctionName);
Memo1.Lines.Add(FormatFloat('000#' , i + 1 ) + ' ' + StrText);
// 次の関数名が格納されているポインタ(アドレス)に移動
inc(NamesPointer);
end ;
finally
UnmapViewOfFile(HeaderPointer);
end ;
finally
CloseHandle(HeaderHandle);
end ;
Result := True;
end ;
// -----------------------------------------------------------------------------
// [ファイルのバージョン]の文字列を取得
// [ファイルのバージョン]は,ファイルのプロパティダイアログで表示される値
// 引数はファイルのフルパス名
// -----------------------------------------------------------------------------
function TForm1.GetFileVersionString(FileName: string ): String ;
var
dwHandle : Cardinal;
pInfo : Pointer;
InfoSize : DWORD;
pFileInfo : PVSFixedFileInfo;
iVer : array [0 ..3 ] of Cardinal;
begin
Result := '' ;
InfoSize := GetFileVersionInfoSize(PChar(FileName), dwHandle);
if InfoSize = 0 then exit;
GetMem(pInfo, InfoSize);
try
GetFileVersionInfo(PChar(FileName), 0 , InfoSize, pInfo);
VerQueryValue(pInfo, PathDelim, Pointer(pFileInfo), InfoSize);
iVer[0 ] := pFileInfo.dwFileVersionMS shr 16 ;
iVer[1 ] := pFileInfo.dwFileVersionMS and $FFFF ;
iVer[2 ] := pFileInfo.dwFileVersionLS shr 16 ;
iVer[3 ] := pFileInfo.dwFileVersionLS and $FFFF ;
Result := Format('%d.%d.%d.%d' , [iVer[0 ], iVer[1 ], iVer[2 ], iVer[3 ]]);
finally
FreeMem(pInfo, InfoSize);
end ;
end ;
end .
06_ EXE ( DLL ) のインポート関数名を列挙
EXE または DLL がインポートする関数名を列挙するサンプルです.
EXE や DLL は,当然ですが,ソースコード内の DLL や,Windows API の関数以外にも多くの関数をインポートして使用しています.それらの DLL 名と関数名を列挙します.
結果の図は,今回作成した Hello2.exe がインポートしている関数です.MessageBoxA はソースコードに書いた関数です.その他にも多くの関数を使用していることが分かります.
このサンプルは,32 ビット版の EXE, DLL 用のコードとなっています.
前項のエクスポート,このサンプルのインポートの他にも,いろいろなセクションテーブルがあり,その各々にセクションデータがあります.セクションデータの最後がファイルの末尾です.Delphi の場合は,最後はアプリケーションマニフェストの XML コードになっています.
このように,EXE や DLL はそれ自体が大きな構造体になっています.
リソースセクションのデータの取得や操作には,専用の Windows API があります.
図18
実行例
リスト6
EXE (DLL) がインポートしている関数を列挙
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Panel1: TPanel;
Button1: TButton;
Memo1: TMemo;
OpenDialog1: TOpenDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
InitDir : String ;
function ListImportDLLfunctionNames(FileHandle: THandle): Boolean;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses ImageHlp;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'Courier New' ;
Memo1.Font.Size := 10 ;
Memo1.WordWrap := False;
Panel1.Font := Memo1.Font;
Panel1.Caption := '' ;
end ;
// =============================================================================
// EXEまたはDLLがインポートしているDLLと関数名リスト
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
FileFullPath : String ;
FileHandle : THandle;
begin
if InitDir = EmptyStr then begin
InitDir := ExpandFileName('../' );
end ;
OpenDialog1.InitialDir := InitDir;
OpenDialog1.Filter := 'ファイル|*.exe;*.dll' ;
if OpenDialog1.Execute then begin
FileFullPath := OpenDialog1.FileName;
InitDir := ExtractFileDir(FileFullPath);
Memo1.Clear;
Memo1.Lines.BeginUpdate;
// 対象ファイルを読み出し専用で開き,そのハンドルを取得
FileHandle := CreateFile(PChar(FileFullPath),
GENERIC_READ,
FILE_SHARE_READ,
nil ,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0 );
if FileHandle = INVALID_HANDLE_VALUE then exit;
try
Panel1.Caption := ExtractFileName(FileFullPath);
ListImportDLLfunctionNames(FileHandle);
finally
CloseHandle(FileHandle);
end ;
Memo1.Lines.EndUpdate;
end ;
end ;
// -----------------------------------------------------------------------------
// 実際にインポートしているDLL名と関数名をリストする関数
// 引数はファイルのハンドル
//
// 32ビット版専用
// usesにImageHlpが必要
// -----------------------------------------------------------------------------
function TForm1.ListImportDLLfunctionNames(FileHandle: THandle): Boolean;
var
HeaderHandle : THandle;
HeaderPointer : Pointer;
pNTHeaders : PImageNtHeaders;
pImportTable : PImageImportDescriptor;
TableSize : Cardinal;
DLLName : PAnsiChar;
pThunkData : PImageThunkData;
pImportByName : pImageImportByName;
StrText : String ;
begin
Result := False;
HeaderHandle := CreateFileMapping(FileHandle, nil , PAGE_READONLY, 0 , 0 , nil );
if HeaderHandle = 0 then exit;
try
HeaderPointer := MapViewOfFile(HeaderHandle, FILE_MAP_READ, 0 , 0 , 0 );
if not Assigned(HeaderPointer) then exit;
try
pNTHeaders := ImageNtHeader(HeaderPointer);
// シグネチャ(PE)の文字を確認
if pNTHeaders.Signature <> IMAGE_NT_SIGNATURE then exit;
// DLL名が格納されている構造体の先頭ポインタを取得
pImportTable := ImageDirectoryEntryToData(HeaderPointer,
False,
IMAGE_DIRECTORY_ENTRY_IMPORT,
TableSize);
// 以下でも同じ
// DLL名が格納されている構造体の先頭ポインタを取得
// pImportTable := ImageRvaToVa(
// pNTHeaders,
// HeaderPointer,
// pNTHeaders.OptionalHeader.DataDirectory[1].VirtualAddress,
// nil);
if not Assigned(pImportTable) then exit;
// DLL名が検出されなくなるまでループ
while pImportTable.Name <> 0 Do begin
DLLName := ImageRVAToVA(pNTHeaders,
HeaderPointer,
pImportTable.Name,
nil );
StrText := String (PAnsiChar(DLLName));
Memo1.Lines.Add(StrText);
Memo1.Lines.Add('---------------------------------' );
// 現在のDLLの関数名が格納されている構造体の先頭ポインタを取得
pThunkData := ImageRVAToVA(pNTHeaders,
HeaderPointer,
pImportTable.FirstThunk,
nil );
// 関数名が検出されなくなるまでループ
while pThunkData^._Function <> 0 Do begin
pImportByName := ImageRVAtoVA(pNTHeaders,
HeaderPointer,
Cardinal(pThunkData.AddressOfData),
nil );
StrText := String (PAnsiChar(@pImportByName.Name));
Memo1.Lines.Add(StrText);
// 次の関数名のポインタ(アドレス)に移動
Inc(pThunkData);
end ;
Memo1.Lines.Add('---------------------------------' );
Memo1.Lines.Add(' ' );
// 次のDLL名のポインタ(アドレス)に移動
Inc(pImportTable);
end ;
Memo1.Lines.Add('End of List' );
finally
UnmapViewOfFile(HeaderPointer);
end ;
finally
CloseHandle(HeaderHandle);
end ;
Result := True;
end ;
end .