機械語初心者がアセンブラを作ってみる

機械語初心者がアセンブラを作ってみるだけのブログです。ひつまぶしひつまぶし

第8回 やっとここまでこきつけた

やっとキタ━━━━(゚∀゚)━━━━!!

 

アセンブリのニモニックを機械語に変換し

オブジェクトファイルに書き込むための

基幹部分が完成しました!

 

といっても

今は mov reg32, reg32 の部分だけ。

識別できるオペランドレジスタだけ。即値すら未実装です。

しかも定義されてるレジスタはeax~edxの4つだけ。

 

だけどこれからどんどん増やしていきます。

 

定数を目一杯定義した甲斐あって

ニモニック定義の追加がちょっと簡単になってます。

 

空行とコメントにも対応。

 

COFFフォーマットはまだです。

今は未だtextセクションの命令部分だけ。

 

例えば

次のアセンブリがあったとします。

 

; テストアセンブリ

 

mov eax,ecx

 

mov ebx,ecx; コメント

 

これをアセンブル(?)します。

 

C:\Users\***\Documents\mb\src>da

[ 3]  mov eax,ecx

[ 5]  mov ebx,ecx

 

        エラー: 0  警告:

 

(ファイル名の指定、警告は未実装。上2行はテストのための出力)

そしたらtest.objが生成されるので、

これをバイナリエディタで開いたら

 

8B C8 8B CB

 

やっとここまでできたよ

やったねたえちゃん!

 

とりま

死なない程度にばんがります。

 

その前に飽きそう

第7回 おやすみ

今日は

 

580円の弁当買って1100円払ったのに

420円しか返って来なかったので

 

開発しません。(キリッ

 

素直に言うと、課題とか課題とか課題とか

 

(´・ω・`)

 

今朝、偶然見つけた資料置いてく

http://www.interq.or.jp/chubu/r6/reasm/PE_FORMAT/intro.html

 

ウィキペディアで見つけた。

第6回 そろそろ飽きてきた

のですが

アセンブラの開発を進めました。

 

隊長!mallocがありますぞ!ありますぞ!

 

mov r32 / rm32 というニモニック1つアセンブルするだけでも

たくさん構造体を定義して、

たくさんの処理を書かなければいけないので

もうほんと時間かかります(´・ω・`)

 

でもってこれのほとんどは

アセンブリを解析して構造体作って

ニモニックやレジスタを定義したconstの構造体配列を読み込んで

いろいろデータの整合性を確認して

機械語作りますよ

という部分なので

 

mov1つさえできれば後は

ニモニックやレジスタの定義を増やしながら

関数をちょこちょこ修正していくだけなので

 

ここを乗り越えられれば‥‥飽きるまでに。

 

蛇足ですが、Intelの 「64 and IA-32 Architectures Software Developer’s Manual」(以下インテルの○○)

406ページ目に2つのレジスタの組み合わせ方の説明発見。

movニモニックの機械語と合わせてハンドアセンブルしてみました。

 

例えば

mov ecx, eax

8B C8

になるとか。

これをアセンブラに任せられるようになりたい‥‥

 

のになかなかできないorz

 

 

今更なんだけど

mov  r32, rm32

mov  rm32, r32

の違いってなんだろう‥‥

r32は32ビットレジスタ

rm32はレジスタなのかIMMなのか分からない状態、でいいのかなぁ。

でもそうだとしたら

ディスティネーションオペランドレジスタなのかIMMなのか分からない状況って

どんなのかなぁって‥‥。

多分違うお(´・ω・`)

 

dumpbinしていちいち確かめるしか‥‥

第5回 資料を見つけた件

資料

 

キタ━━━━(゚∀゚)━━━━!!

キタ━━━━(゚∀゚)━━━━!!

キタ━━━━(゚∀゚)━━━━!!

 

むしろ

今まで何で気づかなかったっていうくらい。

 

COFF解析でネット検索してましたら

IMAGE_SYMBOL構造体が関係してるみたい

っていうことが分かりまして。

んで、それについてSDKのインクルードファイルを探してたら

winnt.hが引っかかったので

winnt.hを開いたんですよ。

 

//

// Symbol format.

//

 

typedef struct _IMAGE_SYMBOL {

    union {

        BYTE    ShortName[8];

        struct {

            DWORD   Short;     // if 0, use LongName

            DWORD   Long;      // offset into string table

        } Name;

        DWORD   LongName[2];    // PBYTE [2]

    } N;

    DWORD   Value;

    SHORT   SectionNumber;

    WORD    Type;

    BYTE    StorageClass;

    BYTE    NumberOfAuxSymbols;

} IMAGE_SYMBOL;

typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL;

 

は い 終 了

 

(´・ω・`)

 

どうして今まで気づかなかった

 

そのほかにもwinnt.hを漁ればいろいろ出てきそうです。

というかMSDNに構造体の説明が書いてなかったんですが

winnt.hの中に簡単な説明がありました!

しかも定数一覧まであるので

何を入れればいいのか大まかなことまでぱっちし。

ゆうべ迷ってたとこまで発見♪ 

 

#define IMAGE_SYM_CLASS_EXTERNAL            0x0002

#define IMAGE_SYM_CLASS_STATIC              0x0003

  

#define IMAGE_SYM_DTYPE_NULL                0       // no derived type.

#define IMAGE_SYM_DTYPE_POINTER             1       // pointer.

#define IMAGE_SYM_DTYPE_FUNCTION            2       // function.

#define IMAGE_SYM_DTYPE_ARRAY               3       // array.

  

資料が見つかってしまったので

COFFオブジェクトファイルの解析も順調に進みそうですし

そろそろアセンブラ作ろうかってことになったのですが

 

IntelのSoftware Developper's Manualっていうやつ

ニモニックやらオペランドやらの機械語

載って

いましたので

 

こっちのほうもありがたく頂戴させていただく

ことに

相成りました。

 

さらに

今まで使い道のわからなかった

ebxの主な?使い方まで

書いてあったので

ありがたくいただきました(`・ω・´)

 

winnt.hが見つかった以上、

開発が順調に進みそうです。

 

とりあえずmov reg/32 r/m32だけでも機械語に変換するプログラム作ってます。

それができたらシンボルテーブルも作って‥‥

 

おら わくわく するだ

第4回 COFFオブジェクトファイルの解析(2)

はーい

 

今日も痛い文が飛び出てきますよー

 

f:id:kmynews:20130515221058p:plain

 

さっきの記事の最後に

0Bは文字列リテラルのかたまりの中のアドレスじゃね」って

書いたわけですが

 

オブジェクトファイルに上のような変更を加えて

リンクしてみたんだ。

 

そしたら

 

 

f:id:kmynews:20130515221100p:plain


(`・ω・´)

 

(※変更前の動作はこちら)

 

f:id:kmynews:20130515221101p:plain


 

ね?

機械語でどこをどう変えたら

どうなっちゃうか分かっちゃうってのが

楽しいというか

 

念のためEXEファイルの中をメモ帳で開いてみましたが

「いやっほーい」のとこはちゃんと残ってました。

一度も使われていないリテラルであっても

オブジェクトファイルに残ってればそのままファイルサイズに‥‥ごくり

 

シンボルテーブルの見方をメモっとく。

 

00B 00000000 UNDEF  notype       External     | MessageBoxA

00C 0000000B SECT2  notype       Static       | message

 

00B00CってのはSymbol Indexかなぁー。textセクションの最後にあるテーブルでも使う。

000000000000000Bはシンボルテーブル‥じゃなかった、

シンボルテーブルの前に文字列定義してるかたまりがあったんだけど

その中のアドレス。多分。

というかMessageBoxAはまだリンクしてないのでUNDEFです(´・ω・`)

UNDEFは無条件で00000000になるのかしら?

SECT2は2番目のセクションと関係してますよーって意味?なのかしら?(´・ω・`)

2番目のセクションと言ったらtextかなぁー。。

notypeってなにそれおいしいのry

とりあえず他も全部notype(関数のStartだけ最後にかっこついてた)

MessageBoxAにかっこがついてないのはまだ関数かどうかも分からないから?

今はまだ詮索せんとこうと。

ExternalとかStaticとかは知らんがな。

Externalって「これからリンクする時外部にあるかもよー」って意味?

でもStartにもExternalついてるし(´・ω・`)

もう関数=External、アドレス=Staticでええわ。知らんがな(´・ω・`)

 

隊長!シンボルテーブルの1行の情報は構造体になっているものと思われます!

何だと!して、構造体の定義は?

 

知らんがな(´・ω・`)

 

 

f:id:kmynews:20130515221057p:plain


 

バイナリの中の定義部分確認してみました。

(※messageの行の000Bに戻し忘れてたけどまあいっか)

 

6D 65 73 73 61 67 65 00 00 00 00 00 02 00 00 00 03 00

 

のうち

 

6D 65 73 73 61 67 65 00

 

はもちろんmessageASCIIですよね。

そしたら

 

02 00 00 00

 

SECT2

 

03 00

 

Staticを表す?

なーんか選択部分の直前の02 00が引っかかるんですよ。

 

2 → External

3 → Static

 

でいいのかなぁ(´・ω・`)知らんがな

なんか知らんがなばかりだけど暗中模索だから仕方ない‥‥orz

 

notypeということは当然0だろうけど、どこにあるんだろそんなデータ。

messageNULL文字のすぐ後の4バイトはアレでしょ、

文字列のかたまりの中の、自身のデータが格納されているアドレス。

最近の若者言葉で言うところのRVAなのかしらー。

 

しかしRVAって無駄にかっこいい。

Tシャツ作ってもいいレベル。

 

f:id:kmynews:20130515221059p:plain


ついでなのでExitProcessMessageBoxAの定義部分も確認します。

なーんかどちらも文字列が入るべきところが00 00 00 00になってて、その後に04だとか10だとかあるわけなんですが、これはファイル最後の「ExitProcess」「MessageBoxA」関数名がまとまってるところがあって、そこのアドレスだと思いまし

1C@2DEのところが0にあたる?

第3回 COFFオブジェクトファイルの解析(1)

タイトルでは第回とか(1)とかつけてますが

本サイトは講座とかではなくただの日記なのであしからず

 

(前回までのあらすじ)

アセンブラEXEではなくOBJを出力することを思い出し

急遽OBJの解析にかかる僕だったが‥‥

 

  000000000000000B: 48 8D 15 00 00 00  lea         rdx,[message]

                    00

 

messageのアドレスはどこに書いてるの?

 

という話でしたが

心配なく

 

シンボルテーブルにありました

 

                                             Symbol  Symbol

 Offset      Type              Applied To   Index  Name

 --------    ----------------   -----------------  --------  ------

 0000000E  REL32             00000000         C  message

 

うーん。

(適宜スペースを調整してみた)

 

仮想アドレスがEのところに0があるけど

そこはmessageっていうシンボルを置く場所だからねー

って予約してるみたい。

 

ところでこのSymbol IndexのところがCになってるけど

これは適当につけてもいいのかなと思ったらそうじゃなくて

解析ファイルの最後のほう

 

COFF SYMBOL TABLE

000 00CDC627 ABS    notype       Static       | @comp.id

001 00000010 ABS    notype       Static       | @feat.00

002 00000000 SECT1  notype       Static       | .text

    Section length   4D, #relocs    7, #linenums    0, checksum        0

004 00000000 SECT2  notype       Static       | .data

    Section length   18, #relocs    0, #linenums    0, checksum        0

006 00000000 SECT3  notype       Static       | .debug$S

    Section length   7C, #relocs    0, #linenums    0, checksum        0

008 00000000 SECT4  notype       Static       | .drectve

    Section length   34, #relocs    0, #linenums    0, checksum        0

00A 00000000 UNDEF  notype       External     | ExitProcess

00B 00000000 UNDEF  notype       External     | MessageBoxA

00C 0000000B SECT2  notype       Static       | message

00D 00000000 SECT2  notype       Static       | caption

00E 00000000 SECT1  notype ()    External     | Start

 

にちゃっかり書いてありました。

めんどいω・`)

なぁー。

 

詳しい人には分かるかもしれないけど

シンボルテーブルはOBJファイルの最後の方にまとめられているみたい。

f:id:kmynews:20130515221055p:plain

 

ω・`)

難しいなぁーorz

 

ねーねー、

ところで解析の最初に書いてある

               F number of symbols

に、「シンボルの数は15個です」って

書いてあるわけなんだけど

 

上のシンボルテーブルで

Sectionで始まる行も含むってことでおk?

なの?

ほらCOFFの番号が飛んでるし。

 

いいのかなぁ‥‥

 

実はあのあとアセンブリをちょっと書き換えて

全く同じ引数でMessageBoxA関数を2回呼び出すようにしたので

もともとはシンボルテーブルのSymbol Indexがどこからきてるのか

調べるためでしたが

 

これのせいで話がややこしくなりました。

 

0000000E  REL32                      00000000         C  message

 00000015  REL32                      00000000         D  caption

 00000021  REL32                      00000000         B  MessageBoxA

 0000002F  REL32                      00000000         C  message

 00000036  REL32                      00000000         D  caption

 00000042  REL32                      00000000         B  MessageBoxA

 00000049  REL32                      00000000         A  ExitProcess

 

Symbol Indexはどこで決まってるのかとか

IDみたいな役割をするってのは分かったんですが

問題がこちら。

 

6D 65 73 73 61 67 65 00

0B 00 00 00 02 00 00 00 03 00

 

こちらがmessageのシンボルテーブルに該当する部分なわけです。

最初の6D65のあたりはmessageというASCIIコード文字で、

0Bっていうのはさっきのアドレスっていうのは分かるんですが

 

0000002F  REL32                      00000000         C  message

 

はーいmessage様御当選おめでとうございますそれではくじをもう一度―

 

のあたりの

 

0000002F

 

これをどこに書いてるのが分からないんですね。

 

‥‥

‥‥‥‥

‥‥‥‥‥‥‥‥

 

2F 00 00 00 0C 00 00 00 04 00

 

んん?あやしいぞ!?

 

なーんか、

 

f:id:kmynews:20130515221056p:plain

 

ここが怪しい‥

臭う‥臭うぞ!

 

最後に04 00をつけてるのは区切りかな?

‥‥あああああああああああああああああああああああ

 

04 00はこれを表しているんじゃないかなーって。

(Symbol) Type : REL32

 

うーん

これ、正しいのかしら。。

 

世の中にはわからないことだらけです(´・ω・`)

仮定

仮定

仮定

仮定

仮定

 

裏付けましょうーっていうことで

 

.data

testdd WORD 4096

caption db "64びっと", 0

message db "いやっほーい", 0

.code

Start PROC

  sub    rsp, 28h     ; シャドウ領域、スタックをアライメントする

  mov    ax, testdd

  mov    rcx, 0

  lea    rdx, message

 

アセンブルしてdumpbin

どうだ?

 

00000007  REL32                      00000000         D  testdd

 

(´・ω・`)

(´・ω・`)(´・ω・`)

(´・ω・`)(´・ω・`)(´・ω・`)

 

‥‥あれ?

REL32ってREAL 3232ビット整数でしょ?

どうしてWORDでもこうなるの?

 

うーむ(´・ω・`)

 

と思ったら整数じゃなく実数だた

謎は深まるばかり。

 

浮動小数点数は通常64ビットだから

32ってことは単精度でしょうねー。

 

とりあえず04 00は単なる区切り文字だと思っときます。
ただ、シンボルテーブルだからにはTypeがどこかに書いているはずで、

それが書いてそうな場所が04 00以外にないんですよね‥‥。

 

とりあえず、まとめると

l  シンボルテーブルはファイルの最後にまとめられてる!

l  textセクションの最後に簡単なシンボルテーブルもとぎがある
textセクションのここにこのインデックスを挿入しますよっていう感じ)

 

ところで

解析結果の最後にあった

 

00A 00000000 UNDEF  notype       External     | ExitProcess

00B 00000000 UNDEF  notype       External     | MessageBoxA

00C 0000000B SECT2  notype       Static       | message

00D 00000000 SECT2  notype       Static       | caption

 

0000000Bは、

textセクションの中の位置ではなく

シンボルテーブルの中の位置かなぁ?(´・ω・`)

 

たくさんありすぎて1記事内ではとても書ききれない

それくらい謎が多いし、面白いことも多い

 

僕はそういうことに喜びを(略

第2回 メモリのアドレスとか

http://codezine.jp/article/corner/61

CodeZine連載「Windows実行ファイル「EXE」の謎に迫る」

こちらは

勉強の時に

非常に異常に役に立った資料です。

 

この資料が理解出来ればしめたものです。

僕の場合、9割は理解出来ました。残りの1割は‥‥うーん(汗

 

この資料で分からなかったところは

やっぱりこれですね、これ。

 

  000000014000100B: 48 8D 15 F9 1F 00  lea         rdx,[4000300Bh]

                    00

 

ようするに、lea rdx,機械語48 8D 15に置換できることがなんとなく予想出来ます。

では、F9 1F 00 00がどうして4000300Bhになるのでしょうか

というあたりで丸1日詰まりました。ていうか今日です。。

 

いろいろやってみてやっと分かりました。

要するに足し算ですね。いやー無知は罪だ。

WindowsIntelの基礎知識さえ身に着けていないまま勉強を進めてるので

(というかその基礎知識を身につけるための資料すら見当たらない状態)

こうやって暗中模索ちうなわけで。

残りの

 

  0000000140001020: E8 07 00 00 00     call        000000014000102C

  0000000140001027: E8 06 00 00 00     call        0000000140001032

  000000014000102C: FF 25 DE 0F 00 00  jmp         qword ptr [40002010h]

  0000000140001032: FF 25 C8 0F 00 00  jmp         qword ptr [40002000h]

 

も同じような理屈で、

要するにニモニックが終了した次のアドレスとの足し算ってわけですね。

上のcallの場合、140001025+00000007=14000102Cですねー。

次のニモニックの先頭のアドレスから足していくんですねー。

途中で足し算には気付いたものの、

自身のニモニック(この場合は140001020)に足すと思い込んで

答えが合わなくて3時間も悩んだ人がいるみたいです。

 

っと、.textセクションは解析が一番簡単なのでここでは重要じゃないか。

 

問題は、一番最初に挙げた資料URIにすら載ってないオブジェクトファイルの内容についてです。

 

そもそもアセンブラは直接EXEを出力するわけではなく

COFFフォーマット(よく知らん)のオブジェクトファイルを出力するそうで。

 

なので、アセンブラで作ったオブジェクトファイルが

マイクロソフトlink.exeでリンクできるようになるっていうのを

まず目標にします。

 

リンカは後から作るのでEXEファイルの解析は後でしなきゃいけないのに

真っ先に解析しちゃったお(´・ω・`)

ドジっちゃったお(´・ω・`)

 

さてオブジェクトファイルをdumpbinするお(`・ω・´)

 

  000000000000000B: 48 8D 15 00 00 00  lea         rdx,[message]

                    00

 

(`・ω・´)

( ゚д゚)

(´・ω・`)

 

今度はmessageのアドレスすら書いてないじゃないですかやだー

 

やだー

 

やだー‥‥

 

一難去ってまた一難ってのはこのことですね‥‥。

とりあえずオブジェクトファイルは資料もないので自分で頑張ってdumpbin読むしか‥‥

 

orz