第5章 主要なニーモニックの説明 その 2
前へ 戻る
これから書かれていることはOllyの実践的な使い方ではなく、
アセンブラニーモニックの説明を初めとする基本的な使い方です。
それでは今回では残りの主要なニーモニックの説明に入ります。(その2)
ニーモニックのインデックスからサンプルプログラムがダウンロードできます。
書式:CALL dest
RETN
多くの場合、CALLでdestに飛んで、RETNで戻ってきます。
CALLはその次のアドレス(プロシージャ・リンク情報)をスタックに転送し、destにジャンプします。
RETNはスタックのアドレスにジャンプします。
00401000 >/$ E8
07000000 CALL
call.0040100C
; 40100Cをコール
00401005 |. 6A 00
PUSH 0
; /ExitCode = 0
00401007 \. E8 20000000 CALL
<JMP.&kernel32.ExitProcess> ;
\ExitProcess
0040100C /$ 55
PUSH EBP
; EBPを退避
0040100D |. 8BEC
MOV EBP,ESP
; EBPにESPを転送(ESPの退避)
0040100F |. 56
PUSH ESI
; ESIを退避
00401010 |. 57
PUSH EDI
; EDIを退避
00401011 |. A1 00304000 MOV EAX,DWORD PTR
DS:[403000]
; EAXに[403000]=401020を転送
00401016 |. E8 0E000000 CALL call.00401029
; 401029をコール
0040101B |. B8 01000000 MOV EAX,1
; 実行されない
00401020 |. 83C4 04 ADD
ESP,4
; スタックポインタを4足してポインタの補正
00401023 |. 5F
POP EDI
; 退避したEDIを戻す
00401024 |. 5E
POP ESI
; 退避したESIを戻す
00401025 |. 8BE5
MOV ESP,EBP
; 退避したESPを戻す
00401027 |. 5D
POP EBP
; 退避したEBPを戻す
00401028 \. C3
RETN
; 401005にリターン
00401029 /$ 50
PUSH EAX
; 401020をプッシュ
0040102A \. C3
RETN
; 401020にリターン(40101Bではない)
ここでちょっと説明です。F8はステップ実行なので、CALLでF8を使うとその中のプロシージャをまとめてすっ飛ばしますw CALLの中をトレースしたい時はF7(詳細ステップ実行)を使用しましょう〜。つまり今回は、F7だけ,もしくは401000と401016でF7を押せばその中も辿る事ができるって事です。
サンプルではCALLの次のアドレスに戻らない例を示していますが、まぁ稀なのであまり気にしなくてもいいですw
※プロシージャ…プログラム内で繰り返し出現する処理を行なうために、一連の命令を一つの手順としてまとめたもの。例えば、シリアルのチェックルーチン(入力したシリアルが正しいか誤りかを調べるプロシージャ)は起動時,入力時,制限項目の実行時など色々なケースで利用されます。このチェックをそれぞれのケースにおいてCALLで呼び出せば、その処理の記述は一回で済みます。
○SETX
書式:SETX dest
Xの条件に従いdestにビットをセットします。Xの条件はJXと同じなので割愛・・・
よく見かけるのはSETE(ZEROフラグが立っていたら)とSETNE(ZEROフラグが立っていなかったら)です。destはバイトレジスタか、メモリ参照が入ります。
00401000 >/$ E8
15000000 CALL
setx.0040101A
00401005 |. 83F8 00 CMP
EAX,0
; EAXと0を比較
00401008 |. 0F94C2
SETE DL ; DLにビットをセットする
0040100B |. E8 10000000 CALL
setx.00401020
00401010 |. 0F95C2
SETNE DL
; DLにビットをセットしない
00401013 |. 6A 00
PUSH 0
; /ExitCode = 0
00401015 \. E8 12000000 CALL
<JMP.&kernel32.ExitProcess>
; \ExitProcess
0040101A /$ A1 00304000 MOV EAX,DWORD PTR
DS:[403000]
0040101F \. C3
RETN
00401020 /$ A1 04304000 MOV EAX,DWORD PTR
DS:[403004]
00401025 |. A9 00000000 TEST EAX,0
; EAXと0を論理比較
0040102A \. C3
RETN
まぁこれは簡単でしょう〜w
○SHXとROX
書式:SHX
dest,cnt
SAX
dest,cnt
ROX
dest,cnt
destをcntの回数だけビットシフトするニーモニックです。
XにはRもしくはLが入り、それぞれ右ビットシフト,左ビッドシフトを意味します。
またCフラグのセットも行います。
それぞれの例として、10101010を1ビットシフトさせると以下のようになります。(8ビットの場合)
|
|
L |
Cフラグ |
|
R |
Cフラグ |
|||
|
SHX |
01010100 |
1 |
|
01010101 |
0 |
|||
|
SAX |
01010101 |
1 |
|
11010101 |
0 |
|||
|
ROX |
01010101 |
1 |
|
01010101 |
0 |
|||
つまり、最終的に押し出されたビットがCフラグにセットされ、1が押し出される場合、ROXでは最下段と最上段がつながっているようなシフトをします。SAXでは左ビットシフトではSHXと同じ挙動を示しますが、右ビットシフトの場合は最上位ビット(補数)を保持します。
○LEA
書式:LEA
dest,src
srcにはメモリ参照が入り、destに参照しているメモリのアドレスを転送します。
要するに、lea
dest,[addr]とすると、destにaddrを転送するってことです。いちいちサンプル作るほどの物でもないのでついでにw
00401000 >/$ B9
02000000
MOV ECX,2
; ECXに2をセット(ループカウンタみたいな物)
00401005 |> 83F9 02
/CMP ECX,2
; ECX値がエラーかどうかのチェック
00401008 |. 7F 0D
|JG SHORT shx.00401017
; エラーだったらジャンプして終了
0040100A |. 8D048D 00304000 |LEA EAX,DWORD PTR DS:[ECX*4+403000]
; 403000から12BYTE(3つ)のアドレステーブルを参照し、そのアドレスをEAXに転送
00401011 |. 8B00
|MOV EAX,DWORD PTR DS:[EAX]
; EAXの指定するアドレスの値(コール先)をEAXに転送
00401013 |. FFD0
|CALL EAX
; EAXをコール
00401015 |.^EB EE
\JMP SHORT shx.00401005
; ループ
00401017 |> 6A 00
PUSH 0
; /ExitCode = 0
00401019 \. E8 52000000 CALL
<JMP.&kernel32.ExitProcess> ;
\ExitProcess
0040101E . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
00401023 . D0E8
SHR AL,1
; ALを右に1ビット論理シフト
00401025 . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
0040102A . D0E0
SHL AL,1
; ALを左に1ビット論理シフト
0040102C . B8 32547698 MOV
EAX,98765432
; EAXに98765432を転送
00401031 . C1E8 08
SHR EAX,8
; EAXを右に1バイト論理シフト
00401034 . C1E8 10
SHR EAX,10
; EAXを右に2バイト論理シフト
00401037 . 49
DEC ECX
; ECXをデクリメント
00401038 . C3
RETN
00401039 . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
0040103E . D0F8
SAR AL,1
; ALを右に1ビット算術シフト
00401040 . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
00401045 . D0E0
SHL AL,1
; ALを左に1ビット算術シフト
00401047 . B8 32547698 MOV
EAX,98765432
; EAXに98765432を転送
0040104C . C1F8 08
SAR EAX,8
; EAXを右に1バイト算術シフト
0040104F . C1F8 10
SAR EAX,10
; EAXを右に1バイト算術シフト
00401052 . 49
DEC ECX
; ECXをデクリメント
00401053 . C3
RETN
00401054 . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
00401059 . D0C8
ROR AL,1
; ALを右に1ビットだけロケーショナルにシフト
0040105B . B8 AA000000 MOV EAX,0AA
; EAXに10101010bを転送
00401060 . D0C0
ROL AL,1
; ALを左に1ビットだけロケーショナルにシフト
00401062 . B8 32548709 MOV
EAX,9875432
; EAXに98765432を転送
00401067 . C1C0 10
ROL EAX,10
; EAXを左に2バイトだけロケーショナルにシフト
0040106A . 68 17104000 PUSH
shx.00401017
; 401017をスタックに転送して
0040106F . C3
RETN
; 401017にリターン
0040102Cのように2バイトのシフトを行うと、上位16ビットが下位16ビットに来るため、レジスタで指定(AXなど)することができるようになります。
ちょこっとだけプログラムを複雑にしてありますので、よくトレースして理解できるようにして下さいw
ちなみに、0040100A〜00401013はCALL [ECX*4+403000]と書いた方が一行で済んで短いんですが、LEAのためにかなり強引に盛り込んであるだけですw
サンプル最長記録達成・・・
サンプルプログラムの著作権とかは面倒なので放棄してます。好きに使ってもらって構いません。