2016年7月10日日曜日

D言語でPEファイルヘッダをパースしてみた

今日もD言語やっていこうかと。

と言うわけで、作るもののネタが無いのでPEファイルのヘッダを解析してみる。
アルゴリズム的には、構造体作って、構造体にそのまま取り込んで、表示するだけなので
構造体をコピペすれば完成する代物。

ちょっとだけエイリアスを宣言してやる必要があるけど、やることはそれだけ。
とりあえず、x86バイナリと、x64バイナリに対応できればいいかなって感じ。

ちゃんと解析できてるかどうかの確認はIDA Freeあたりで試す。

D言語の std.File.rawReadは配列しか渡せないので、構造体をC言語みたいにポインタで渡すとか言う直感的な方法でなくて、戸惑ったけど、書き方が微妙に違うだけでほぼ同じだった。
D言語はいいぞ。ランタイムあたりが厄介者だけど、それはどうにかすればいい。

dmd -m32 PEHeaderAnalyzer.d
PEHeaderAnalyzer.exe PEHeaderAnalyzer.exe

実行結果こんな感じ
Machine: i386
applicationBits: 32
Subsystem: Windows CUI
ImageBase: 0x400000
BaseOfCode: 0x2000
SizeOFCode: 183296
AddressOfEntryPoint: 2565c
Absolute entry point: 42565c
SizeOfImage: 274432
IDAで答え合わせ。

※ 画像クリックで拡大可能

Machine: i386 と
ImageBase: 0x400000 はIDAでみると、問題なさそう。

BaseOfCode: 0x2000 も取り出せてる



エントリーポイントのアドレス(Absolute entry point) = ImageBase + AddressOfEntryPoint
ImageBase: 0x400000
AddressOfEntryPoint: 2565c
Absolute entry point: 42565c
合ってるっぽい。



かんたんでよい、きょうはここまで。

2016年7月9日土曜日

D言語ローレイヤ入門

D言語(ローレイヤ)入門していきます。

ぼく「D言語の最小ランタイムほしいよ~」
ぼく「uefi-dとか使ってみたけど構造体宣言できないし色々ダメ」
ぼく「UEFI AppをDでつくりたい、あわよくば・・・OSカーネルも」

というつぶやきをしたらプロから返事が帰ってきた。
Twitterつよい。


というわけで、minimal.zipを落として makeしてみた

minimal-d/object.d:1248: `_deh_beg' に対する定義されていない参照です
minimal-d/object.d:1249: `_deh_end' に対する定義されていない参照です
無いってさ!
ちなみに、object.dの1248行目と1249行目はこんな感じ。

        extern __gshared
        {
            /* Symbols created by the compiler and inserted into the object file
             * that 'bracket' the __deh_eh segment
             */
            void* _deh_beg;
            void* _deh_end;
        }

※object.d:すべてのクラスや構造体のベースになるクラスが入ったファイル。これがないとD言語の機能はもちろん、C言語で普通にできてた構造体の宣言すらできない(RTTI:実行時型情報が必須な言語の宿命(TypeInfo_Struct等が宣言されてないとリンカエラー))ので、大事。


見たとおり外部に宣言してある_deh_begと_deh_endを参照する ってな感じになってるし
もちろんコンパイラはそんなシンボルを生成してくれないしで、きっとD言語の仕様が微妙に変わったのかもしれない。

リンカスクリプトでEHテーブルセクションを定義した時にシンボルも定義すれば良いんだけど、それをやらなくてもできる方法があるので今回はそっちでやる。
ちなみに、EHテーブルセクション(セグメント)については、ここに書いてあった。
http://www.kmonos.net/alang/d/abi.html

例外ハンドラがたくさん書いてあるところ(GOTみたいな関数テーブル)っていう感じ。

先ず、CompilerDSOData構造体と_d_dso_registryって関数をみてみると
CompilerDSOData構造体には、_deh_beg、_deh_endの2つが居るけど
でもその構造体を引数にとってる、_d_dso_registry関数はそれらメンバに対して何も操作してない。
でも、引数をとってるからには、何かが入ってるはずなので、下のソースみたいに
もともと有った外部参照するところをコメントアウトする。
次に、普通にコメントアウトした変数と同名の変数の実体を宣言する。
さらに、宣言した変数に引数からもらった CompilerDSOData構造体の同名の変数の値を代入する。

これでリンカエラーは出なくなる。

じゃあ本当に直した部分は動くの?動きそうなの?
と言う疑問が湧いてきたので、一旦これでmakeコマンド叩いてみて、バイナリを生成して逆アセンブルしてみる。

動きそう、動かなそうの判断は、意図したデータ(EHテーブルセクションの開始位置と終了位置)
が入ってるか入ってないかで判断する。

各メモリアドレスの詳細


一応メモリアドレスがちゃんと有効なセクションを指してるのと、
構造体の順番と同じようにスタックにレイアウトされてるから問題なさそう。

C言語っぽい擬似コード




てわけで、きょうはこんなところで。