第2章 アセンブリ言語と OllyDBG の基本的な使い方
前へ 戻る
これから書かれていることはOllyの実践的な使い方ではなく、
アセンブラニーモニックの説明を初めとする基本的な使い方です。
・アセンブリ言語とは?
アセンブリ言語とはCPU(と言うかハード)レベルで動くプログラミング言語であり、CPUが理解する命令コードに対して1対1で対応する言語です。CPUが理解する命令コードというのは所謂マシン語であり、0と1の組み合わせからなる2進数の数字そのものです。実際には0と1の組み合わせ8文字を1BYTE(16進数)として1つの塊として処理しています。と言っても分かりづらいと思うので例を挙げると、16進数で90(2進数で10010000)はマシン語で「何もしない(正確にはEAXレジスタとEAXレジスタを入れ替えると言う意味の無い処理:従って処理自体には時間が必要になる)」という処理で、これはアセンブリ言語ではNOPというニーモニックに相当します。
アセンブリ言語自体は非常に簡単です。しかし、簡単すぎるために全体としては冗長的となり難しいというアンビバレンスを内包する言語でもあります
上述したように16進数で一つの塊となっているので以降では特別な場合を除いて16進数で話を進めます。
※EAXレジスタ…CPUは内部に演算データや計算結果などを一時的に保持しておく部分を持ち、これをレジスタと呼びます。EAXというのは汎用レジスタの一種で32ビットの大きさを持つレジスタ。詳しくはまぁ後述するので・・・
※ニーモニック…アセンブラにおける命令はニーモニックと呼ばれます。
・レジスタとは?
CPUが内部に持つ、演算データや計算結果などを一時的に保持しておくための領域で汎用レジスタ・フラグレジスタ・セグメントレジスタなど、いくつかの種類があります。
汎用レジスタにはEAX,EBX,ECX,EDX,EDI,ESI,EBP,ESPしかありません。それぞれ全て32ビットの領域を持ち、ESP以外ではEを取ると下位16ビットを指すようになります。と言ってもやはり分かりづらいと思うので例を挙げると
EAX=1234ABCD
である時、
AX=ABCD
と言うことです。
さらにXをLやHに変えると下位16ビットの中での下位,または上位8ビットを指す様になります。すなわち、
AL=CD
AH=AB
と言うことです。
他にも説明しなければいけないことは山ほどあるような気もしますが、そろそろニーモニックの説明に移ります。(こんな所で説明するより、実際に体感した方が覚えやすいし説明もしやすいので)
○MOV
書式:MOV
dest,src
srcの値をdestに転送するという意味です。
習うより慣れろと言うことで、 サンプルプログラムです。Ollyで開いてみましょう。(Toolからダウンロードできるはずです)
以下のような画面になると思います。
ここでOllyの基本的な使い方についての説明に入ります。ちなみに日本語化済みを前提として話を進めます。
インストーラーなんてものは無いので、ファイルを解凍すれば普通に使えます。起動後、exeファイルをドラッグ&ドロップしても開けますし、ファイル→開くからでも開けます。
ちなみにファイル→アタッチで現在実行中のモジュールが一覧表示され選ぶことでも開けます。ただし、今回のサンプルプログラムではMOVの説明のためのものなので実行してもすぐに終了してしまい、このアタッチによる方法では開けません。
と、言うわけでmov.exeを開くと下図のような画面が表示されているはずです。しかし、他にも色々とウィンドウがありますね?次はその辺の説明をします。まずは基本的な5つのウィンドウの説明です。まずは名前から、

まぁこんな感じです。
それぞれのウィンドウの簡単な説明としては
○逆アセンブラウィンドウ
一番重要なウィンドウです。実行ファイルの逆アセンブラの結果の一覧が表示されています。
○インフォメーションウィンドウ
逆アセンブラウィンドウにおける選択行の情報が表示されています。
○ダンプウィンドウ
メモリーの内容が表示されています。
○レジスタウィンドウ
CPUのレジスタの値が表示されています。
○スタックウィンドウ
スタック情報の表示場所。主にリターンアドレスやAPIの引数などなどが表示されています。
と、言っても分かりづらいと思うので実際に使いながら内容を覚えるのが一番です。使う上で名称なんて関係ないしねぇ〜
と、言うことで実際に使ってみましょう。今現在レジスタウィンドウのEAXには0が格納されているはずです。
00401000> /$ B8 01000000 MOV EAX,1
; EAXに1を転送
00401005 |. B8 FFFFFFFF MOV EAX,-1
; EAXに-1(FFFFFFFF)を転送
0040100A |. 66:B8 1111 MOV
AX,1111
; EAX下位16ビットに1111を転送
0040100E |. B0 CD MOV AL,0CD
; AX下位8ビットにCDを転送
00401010 |. B4 AB
MOV AH,0AB
; AX上位8ビットにABを転送
00401012 |. 8BD8
MOV EBX,EAX
; EBXにEAXを転送
00401014 |. B8 00304000 MOV
EAX,mov.00403000
; EAXに403000を転送
00401019 |. C700 78563412 MOV DWORD PTR
DS:[EAX],12345678 ; EAXの指定するメモリアドレスに12345678を転送
0040101F |. 6A 00
PUSH 0
; /ExitCode = 0
00401021 \. E8 00000000 CALL
<JMP.&kernel32.ExitProcess> ;
\ExitProcess
F8を押してみましょう。選択行が一つ移動したと思います。それと同時にEAXには1が格納されたはずです。F8でステップ実行なんていうことができちゃうわけです。通常exeを実行したらノンストップで走り続けますが各コードの処理を1行ずつ確認できるのがリアルタイムデバッガの特徴です。ちなみにF9を押せば普通に実行されます。ためしにF9を押してみましょう。ハイ、終了しました。ExitProcessというのが処理を終えるためのAPIです。APIに関しては詳しくは後述するつもりですが簡単に言うと、多くのソフトウェアが共通して利用する機能は、OSやミドルウェアなんかの形でまとめて提供されていて、ソフト自体は規約に従ってその機能を「呼び出す」だけで、製作者がプログラミングすることなくその機能を利用したソフトウェアを作成することができるというものです。例えばMessageBoxと言うAPIを使えばあの見慣れたメッセージボックスを簡単に表示することができるわけです。
話が脱線した気もするので戻します。解析→再スタート(もしくはCtrl+F2)を選んでもう一度読み込みましょう。F8でステップ実行しながらレジスタの挙動を見てください。movの使い方が大体分かるかと思います。
00401019 が分からない? う・・・できれば避けて通りたかったのですが説明します。00401019 を実行する前にダンプウィンドウで403000行を表示してみましょう。表示の仕方はダンプウィンドウを選択してCtrl+Gで403000と入力すればOKです。(と言うかロード時に開いてるけど・・・一応説明と言うことでw)
ひたすら00が並んでいるかと思います。じゃあ 00401019 を実行してみましょう。ハイ、何か入りました。
00403000 78 56 34
12 xV4
なんて感じになってると思います。「あれ〜逆じゃん」と思う人もいると思いますがこれはCPUのデータ格納方式によるものです。まぁこういうものだと思ってしまうのが一番楽なのですが一応補足程度の説明を・・・
x86系のCPUではリトルエイディアンと呼ばれるデータ格納方式を採用しており、例えば AB CD
を格納しようとすると逆の CD AB となります。これ以上説明の仕様が無いので・・・こういうものだ!ということで覚えておいてください。ちなみに大事です。おまけを付けると逆ではなく順に格納する方式をビッグエイディアンと呼びます。ちなみにエイディアンというのはCPUが2BYTE以上のデータを扱う際の格納方式のことです。(1BYTEじゃ順も逆も無いからねぇ〜)
C言語をやったことがある人ならポインタを思い浮かべていただければ理解しやすいと思います。
ちなみにDWORDと言うのは32ビットの領域を意味します。MOV DWORD PTR
DS:[EAX],12345678は「EAXの指定する32ビットのメモリ領域に12345678を転送する」のような意味にとってもらえればいいと思います。なお、16ビットはWORD,8ビットはBYTEと呼びます。それぞれ次のような書式です。
MOV WORD PTR
DS:[EAX],1234
MOV BYTE PTR
DS:[EAX],12
00401019 |. C700 78563412 MOV DWORD PTR
DS:[EAX],12345678の行をダブルクリックしてコードを上記のように書き換えてみてください。その際は「余ったバイトをNOPで埋める」にチェックを入れておくのを忘れないように。そしてF8でステップ実行させてその処理を追ってみればその働きは分かると思います。
書き換えたコードはあくまでメモリレベルで書き換えただけなので、そのままでは実行ファイルに反映されることはありません。書き換え後のファイルを作成したい場合は
右クリック → 実行ファイルへコピー →全ての変更箇所 →
全てコピー →表示されたウィンドウで右クリック → ファイル保存
でできます。
・今頃ですが・・・-1がレジスタではFFFFFFFFとなっていることについて。
16進数などで正の整数のみを使って負数を表す場合、2の補数と言われるものを利用します。これは簡単に言うと上位1ビットが0なら正,1なら負を表すということです。例えばFFFFFFFFは2進数では111111111 11111111 11111111 1111111です。この一番左のビットは1になっていますね。ここから減れば減るほど負数の絶対値は大きくなります(値は小さくなる)。
有名な話としては「正→負の変換はビットを反転させて1を足せ」というのがあります。ビットを反転と言うのは0なら1に、1なら0に変換するということです。0001は2進数で00000000 00000001ですからビットを反転させると、11111111 11111110になります。これに1を足せば、11111111 11111111になり-1になると言うことですね。
ということでOllyとアセンブラの基本的な部分には触れたと言うことで、第一回目は終了です。
ちなみにサンプルプログラムはアセンブラで管理人が自作したものです。アセンブラの特徴はそのファイルサイズの小ささでしょう。2,560
バイトしかありま せん。ファイルサイズは2,560
バイトです。逆アセンブラコードを見れば分かるように全く無駄がありません。
サンプルプログラムの著作権とかは面倒なので放棄してます。好きに使ってもらって構いません。