講座07 分岐処理を学ぶ

〜はじめに〜

前回、メッセージボックスの消去方法を紹介しましたが、今回はその延長である判定分岐処理のお話です。
ここを覚えれば、判定をひっくり返したり、無条件で通過させたりできるようになります。

〜早速ですが〜

次の逆アセンブルリストを見てください(右側は、自分が勝手に付けたコメントです)。
:00401058 51       push ecx        // 検索対象ドライブ名をスタック退避
:00401059 FF1504504000  call dword[00405004] // ドライブの種類取得用の命令
          ;;call KERNEL32.GetDriveTypeA
:0040105F 83F802     cmp eax, 00000002   // もしもeaxレジスタが数値 02
:00401062 7542      jne 004010A6     // でなければ分岐

これは、ディスクチェック解析のコンテンツで公開しているサンプルプログラムの一部分で、
「任意のドライブを検索し、それがどの種類か(HDD ? FLOPPY? CD? など)判定し、条件分岐する」
という処理を行っています。
一番上の命令でスタックというものを使用していますが、とりあえず置いておいて、
今回は、リストの下2行である「もしも…ならば(でなければ)分岐」という処理のみに
着目したいと思います。

もしも…を判定する cmp 命令

上のリストでは cmp eax, 00000002 という命令により、eaxレジスタが2か?を判定しています。
またまた出てきましたが、このレジスタというものは、高級言語で言う変数と同じ役割をするものです。
変数と言っても配列は使えませんし、eax,ebx,ecx,edi,esi…というように、種類も数えるほどしかありません。
ただ、4バイト使うときは [eax]、2バイト使うときは[ax]、1バイトなら[al]…というように、
データサイズによって名称が異なるという特徴があり、少々紛らわしかったりします。
(なお、4・2・1バイト時の名称をそれぞれ DWORD・WORD・BYTE と言います)
まぁ、ひとまずは数値が入っているものということを覚えておいてください。

分岐(ジャンプ)を行う命令 j**

リストでは jne 004010A6 となっていますが、jneとはJump Not Equalという意味です。
Jump(ジャンプ)、Not(否定)、Equal(等しい)…つまり、等しくなければジャンプです。
cmp命令の値を組み合わせることにより、eaxレジスタの値が2でなければジャンプ
という意味になります。
そしてそのジャンプ先は、jneの後の数値である 004010A6 です。
これで、eaxレジスタの値が2でなければアドレス 004010A6 の処理にジャンプとなるわけです。

で、もちろん、条件分岐用の命令にも色々あり、je(Jump Equal) 等しければ分岐、
jg(Jump Greater) 大きければ分岐、jl(Jump Less)小さければ分岐
…などなど、
さまざまな種類が用意されています。

分岐命令の共通性

命令の頭文字が j というのはもちろんですが、バイナリデータも共通性が高いです。
例えば、
:00401050 7505      jne 00401057
という命令がありますが、これをもしnotを取ったjeにすると…
:00401050 7405      je 00401057
全然別の分岐命令ですが、jgにすると…
:00401050 7F05      jg 00401057
もう分かりましたね。
これら分岐命令のバイナリデータは 7xyy というという形になっています。
xの部分の数値により、条件が変わる〜というわけです。

そして、yyの部分にはジャンプの「距離」が入ります。
例えば、アドレス 00401050 で 7x05 を実行すると、ジャンプ先は 00401057 ですが、
アドレス 00401100 で実行すると、ジャンプ先は 00401107 になります。
もしも 00401050 で 7x00 というようにジャンプ距離が0だと 00401052 になります。
つまり、yyの部分には「飛びたい距離 - 02」 の値が入るということですね。
(実際には、命令の実行されたアドレス+命令長(2バイト)の位置から分岐するからです)。

無条件分岐命令 jmp

今まで紹介したものには必ず「判定」というものがありました。
しかし、分岐命令には何も判定せずに強制的に分岐する jmp という命令があります。
これを使えば、cmp命令などに影響されずに目的のアドレスに飛ぶことができます。
バイナリデータは 7xyy ではなく EByy という形になっていますが、
yyの意味は判定分岐の場合と同じで、ジャンプの距離が入ります。

…ここで何かを思いついた人は、かなりゲーム改造のセンスがあります。
「もし、『CDが入っていたらジャンプ』という分岐命令をこれに書き替えたら…」
そう、これが「CDチェック解除」の最も基本的な理念です。
また、CDチェック解除以外にも様々な場面で使うこともできる、とても有効な手段です。

さいごに

と、盛り上がったところで今回はここまでです。
次回は、本格的に「CDチェック解除」と「判定分岐命令の変更方法」、
さらに「分岐命令の無効化」、と一通りの手法を紹介したいと思います。
それではっ

>>NEXT STEP