第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)
はーい
今日も痛い文が飛び出てきますよー
さっきの記事の最後に
「0Bは文字列リテラルのかたまりの中のアドレスじゃね」って
書いたわけですが
オブジェクトファイルに上のような変更を加えて
リンクしてみたんだ。
そしたら
(`・ω・´)
(※変更前の動作はこちら)
ね?
機械語でどこをどう変えたら
どうなっちゃうか分かっちゃうってのが
楽しいというか
念のためEXEファイルの中をメモ帳で開いてみましたが
「いやっほーい」のとこはちゃんと残ってました。
一度も使われていないリテラルであっても
オブジェクトファイルに残ってればそのままファイルサイズに‥‥ごくり
シンボルテーブルの見方をメモっとく。
00B 00000000 UNDEF notype External | MessageBoxA
00C 0000000B SECT2 notype Static | message
00B、00CってのはSymbol Indexかなぁー。textセクションの最後にあるテーブルでも使う。
00000000、0000000Bはシンボルテーブル‥じゃなかった、
シンボルテーブルの前に文字列定義してるかたまりがあったんだけど
その中のアドレス。多分。
というかMessageBoxAはまだリンクしてないのでUNDEFです(´・ω・`)
UNDEFは無条件で00000000になるのかしら?
SECT2は2番目のセクションと関係してますよーって意味?なのかしら?(´・ω・`)
2番目のセクションと言ったらtextかなぁー。。
notypeってなにそれおいしいのry
とりあえず他も全部notype(関数のStartだけ最後にかっこついてた)
MessageBoxAにかっこがついてないのはまだ関数かどうかも分からないから?
今はまだ詮索せんとこうと。
ExternalとかStaticとかは知らんがな。
Externalって「これからリンクする時外部にあるかもよー」って意味?
でもStartにもExternalついてるし(´・ω・`)
もう関数=External、アドレス=Staticでええわ。知らんがな(´・ω・`)
隊長!シンボルテーブルの1行の情報は構造体になっているものと思われます!
何だと!して、構造体の定義は?
知らんがな(´・ω・`)
バイナリの中の定義部分確認してみました。
(※messageの行の00を0Bに戻し忘れてたけどまあいっか)
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
はもちろんmessageのASCIIですよね。
そしたら
02 00 00 00
はSECT2、
03 00
はStaticを表す?
なーんか選択部分の直前の02 00が引っかかるんですよ。
2 → External
3 → Static
でいいのかなぁ(´・ω・`)知らんがな
なんか知らんがなばかりだけど暗中模索だから仕方ない‥‥orz
notypeということは当然0だろうけど、どこにあるんだろそんなデータ。
messageとNULL文字のすぐ後の4バイトはアレでしょ、
文字列のかたまりの中の、自身のデータが格納されているアドレス。
最近の若者言葉で言うところのRVAなのかしらー。
しかしRVAって無駄にかっこいい。
Tシャツ作ってもいいレベル。
ついでなのでExitProcess、MessageBoxAの定義部分も確認します。
なーんかどちらも文字列が入るべきところが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ファイルの最後の方にまとめられているみたい。
(´・ω・`)
難しいなぁー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のシンボルテーブルに該当する部分なわけです。
最初の6D~65のあたりはmessageというASCIIコード文字で、
0Bっていうのはさっきのアドレスっていうのは分かるんですが
0000002F REL32 00000000 C message
はーいmessage様御当選おめでとうございますそれではくじをもう一度―
のあたりの
0000002F
これをどこに書いてるのが分からないんですね。
‥‥
‥‥‥‥
‥‥‥‥‥‥‥‥
2F 00 00 00 0C 00 00 00 04 00
んん?あやしいぞ!?
なーんか、
ここが怪しい‥
臭う‥臭うぞ!
最後に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 32?32ビット整数でしょ?
どうして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日詰まりました。ていうか今日です。。
いろいろやってみてやっと分かりました。
要するに足し算ですね。いやー無知は罪だ。
WindowsやIntelの基礎知識さえ身に着けていないまま勉強を進めてるので
(というかその基礎知識を身につけるための資料すら見当たらない状態)
こうやって暗中模索ちうなわけで。
残りの
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