以下のテキストを日本語に翻訳してください:
XCHG#
xchg A,B #指令用于将A和B的值互换
0x4013d8
にマウスを置くと、xor eax,eax
命令があります。ここでは、0x4013d8
アドレスの命令を変更するデモンストレーションを行います。メニューバーの「Edit-Patch program-Assemble」をクリックします。
次のウィンドウが表示されます。
変更する命令を入力すると、変更ができます。
xchg eax,esi
新しい命令を書き込んだ後、元の関数は中断されます。
0xc0
をNOP
に変更します。NOP(NO OPERATION)
命令は何もせず、何の操作も行いません。変更後の内容は次のとおりです。
上記の例では、1 バイトのみが関係しています。元のデータ型は db で、値は0xc0h
です。
しかし、変更後は関数が中断されているため、関数の開始アドレス 0x4013d8 で右クリックし、「Create function(関数の作成)」を選択します。
関数が作成されると、次のような内容になります。
IDA は前のloc_(通常の命令を示す)
をsub_(関数の開始点を示す)
に変更します。これにより、関数として再認識され、スペースキーを押してグラフビューに切り替えることができます。
再び XCHG 命令に注目します。EAX = 12345678、ESI = 55
と仮定すると、命令の実行後、EAX = 55、ESI = 12345678 になります。
PATCH
メニューには、すべての変更されたバイトを表示し、変更を元に戻すこともできる「PATCHED BYTES」機能があります。
xchg 命令は、レジスタの値と他のレジスタが指すメモリに格納された値を交換することもできます。
例えば、次の命令:xchg eax,[esi]
もし eax=55、esi=0x10000 であれば、プログラムは 0x10000 に格納された値を検索し、アドレスに書き込み権限がある場合は 55 を格納し、元の 0x10000 の値を eax に書き込みます。
4.3 スタック操作命令#
スタック(Stack)
は、関数の実行によって一時的に使用されるメモリ領域であり、メモリアクセスモードは先入れ後出し(FILO、FIRST IN LAST OUT)
です。これにより、データの格納と読み取りが行われます。
スタックの特徴は、最後にスタックに追加されたフレームが最初にスタックから取り出されることです(最も内側の関数呼び出しが最初に終了するため)。これは後入れ先出し
のデータ構造と呼ばれます。
スタックのデータ操作には 2 つの基本的な操作命令があります。
-
PUSH:オブジェクトをスタックのトップに保存します(プッシュ)
-
POP:スタックの最後に追加されたオブジェクトを取り出します。
-
いつでも、スタックのトップまたは最後にプッシュされたオブジェクトに対してのみ操作を行うことができます。
POP 操作は、スタックのトップに保存された最後のオブジェクトを取り出し、そのオブジェクトの下に(最後のプッシュ操作で保存された)オブジェクトを置きます。これにより、後続の操作が可能になります。
スタックは、メモリ領域の終了アドレスから始まり、高位(アドレス)から低位(アドレス)に割り当てられます。たとえば、メモリ領域の終了アドレスが 0x00001000 であり、最初のフレームが 4 バイトであると仮定すると、次に割り当てられるアドレスは 0x00000FFC から始まります。上記の図のようになります。
push 命令#
通常、32 ビットプログラムでは、PUSH は関数を呼び出す前にスタックにパラメータを渡すために使用されます。たとえば、上記の図の0x40104f
での命令です。PUSH 64
命令は 64(dword)をスタックのトップにプッシュし、PUSH EAX
命令は EAX の値をスタックにプッシュし、以前の 64(dword)の上に保存します。これにより、EAX の値がスタックのトップになります。
PUSH は定数以外にも、アドレスを操作することもできます。
文字列名の前にある OFFSET キーワードに注目してください。この命令は、この文字列または文字配列のアドレスをスタックにプッシュします。
文字列名をダブルクリックすると、次の図に移動します。
一般的に、C 言語のソースコードでは、文字配列は次のように定義されます:Char mystring[] = "Hello"
Dキー
を押すと、windowname
変数のデータ型が変更され、それを文字配列ではなく db またはバイトとして扱わないようにします。
変更後、このアドレスを参照するいくつかの命令が変更され、次の図のようになります。offset キーワードは、引数として 0x004020e7 アドレスが渡されることを保証しますが、アドレスに格納されているのはもはや文字配列ではなくバイトです。
命令全体はpush offset byte_4020E7
になります。byte_4020E7
の内容を検索すると、db 型に変更されていることがわかります。
Aキー
を押すと、ASCII 文字列に変換され、元の表示に戻ります。
他の単独のバイトとして表示されている文字列が見つかった場合は、同じ操作を行うことができます。文字列の開始地点を見つけてからA
キーを押すと、表示がより読みやすくなります。
次の内容:
A
キーを押すと、次の内容になります:
0x402110
でD
キーを押すと、amenu
文字列がバイトごとに分割されます。その後、A
キーを押して文字列を再結合します。
通常の文字列の例
X
キーを押して文字列の参照位置を検索します。
一般に、関数にパラメータを渡すときは、PUSH offset xxxxx
命令を使用して文字列のアドレスを関数に渡します。offset キーワードがない場合、渡されるのは0x402110
アドレスに格納されている内容であり、具体的なバイト55 4E 45 4D
が渡されます。ただし、API 関数はこのように動作しません。通常、ポインタまたは文字列の開始アドレスをパラメータとして受け取ります。
上記の命令では、DS: というマークは、プログラムがデータ領域(DS=DATA)のメモリに書き込むことを示しています。
pop 命令#
POP 命令は、スタックのトップに保存された値を読み取り、それを対象レジスタに転送します。次の図のように、POP EDI
はスタックのトップにある最初の値を読み取り、EDI レジスタに渡し、ESP の値を読み取った値の下に指し示し、それをスタックのトップとします。
テキスト検索で pop を検索すると、pop 命令の使用方法が変わらず、値を pop してアドレスに格納しないことがわかります。