MASM の数値と演算子

このトピックでは、Windows デバッグ ツールで Microsoft マクロ アセンブラー (MASM) 式構文を使用する方法について説明します。

デバッガーは、C++ 式と MASM 式の 2 種類の数値式を受け入れます。 これらの式はそれぞれ、入出力に関する独自の構文規則に従います。

各構文タイプが使用される場合の詳細については、「式の評価 および ? (式の評価)」を参照してください。

この例では、? コマンドは、MASM 式エバリュエーターを使用して命令ポインター レジスタの値を表示します。

0:000> ? @rip
Evaluate expression: 140709230544752 = 00007ff9`6bb40770

式エバリュエーターを MASM に設定します

.expr (式エバリュエーターの選択) を使用して、規定の式エバリュエーターが何であるかを確認し、それを MASM に変更します。

0:000> .expr /s masm
Current expression evaluator: MASM - Microsoft Assembler expressions

規定の式エバリュエーターが変更されたので、 ? (式の評価) コマンドを使用して MASM 式を表示できます。 次の使用例は、rip レジスタに 8 の 16 進数値を追加します。

0:000> ? @rip + 8
Evaluate expression: 140709230544760 = 00007ff9`6bb40778

レジスタ参照 @rip の詳細については、「レジスタ構文」を 参照してください。

デバッガー MASM 式の数値

MASM 式には、16、10、8、または 2 を使用して数値を入力できます。

n (基数の設定) コマンドを使用して、デフォルトの基数を 16、10、または 8 に設定します。 その後、プレフィックスのない数値はすべて、この基数で解釈されます。 0x プレフィックス (16 進数) 0n プレフィックス (10 進数) 0t プレフィックス (8 進数)、または 0y プレフィックス (2 進数) を指定することで、既定の基数をオーバーライドできます。

数値の後に h を追加して、16 進数を指定することもできます。 数字には大文字または小文字を使用できます。 たとえば、"0x4AB3"、"0X4aB3"、"4AB3h"、"4ab3h"、"4aB3H" は同じ意味を持ちます。

式のプレフィックスの後に数値を追加しない場合、数値は 0 として読み取られます。 そのため、0 を 0、プレフィックスの後に 0 を付け、プレフィックスのみを書き込むことができます。 たとえば、16 進数の "0"、"0x0"、および "0x" は同じ意味を持ちます。

16 進数の 64 ビット値は xxxxxxxx`xxxxxxxx 形式で入力できます。 また、グレーブ アクセント (`) を省略することもできます。 グレーブ アクセントを含める場合、 自動符号拡張 は無効になります。

この例では、10 進数、8 進数、およびバイナリ値を追加して 10 を登録する方法を示します。

? @r10 + 0x10 + 0t10 + 0y10
Evaluate expression: 26 = 00000000`0000001a

デバッガー MASM 式のシンボル

MASM 式では、シンボルの数値はメモリ アドレスです。 シンボルが何を指すかに応じて、このアドレスはグローバル変数、ローカル変数、関数、セグメント、モジュール、またはその他の認識されたラベルのアドレスになります。

アドレスが関連付けられているモジュールを指定するには、シンボルの名前の前にモジュール名と感嘆符 (!) を含めます。 シンボルを 16 進数として解釈できる場合は、モジュール名と感嘆符、または単に感嘆符をシンボル名の前に含めます。 シンボルの認識の詳細については、「シンボルの構文とシンボルの照合」を参照してください。

クラスのメンバーを示すには、2 つのコロン (::) または 2 つのアンダースコア (__) を使用します。

シンボル名にグレーブ アクセント (`) またはアポストロフィ (') を使用するのは、シンボルの前にモジュール名と感嘆符を追加する場合のみです。

MASM 式の数値演算子

単項演算子を使用して、式の任意のコンポーネントを変更できます。 2 項演算子を使用して、任意の 2 つのコンポーネントを組み合わせることができます。 単項演算子は、二項演算子よりも優先されます。 複数の二項演算子を使用する場合、演算子は次の表に示す固定優先順位規則に従います。

いつでも括弧を使用して優先順位規則をオーバーライドできます。

MASM 式の一部がかっこで囲まれ、式の前に 2 つのアットマーク (@@) が表示される場合、式は C++ 式ルールに従って解釈されます。 2 つのアットマークと開き括弧の間にスペースを追加することはできません。 @@c++( ... ) または @@masm( ... )を使用して 式評価子 を指定することもできます。

算術計算を実行すると、MASM 式エバリュエーターはすべての数値とシンボルを ULONG64 型として扱います。

単項アドレス演算子では、DS がアドレスの既定のセグメントと見なされます。 式は、演算子の優先順位に従って評価されます。 隣接する演算子の優先順位が等しい場合、式は左から右に評価されます。

次の単項演算子を使用できます。

演算子 説明

+

単項プラス

-

単項マイナス

not

引数が 0 の場合は 1 を返します。 0 以外の引数に対して 0 を返します。

hi

上位 16 ビット

low

下位 16 ビット

by

指定したアドレスからの下位バイト。

$pby

物理アドレスを取得する点を除いて、 by と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。

wo

指定したアドレスの下位ワード。

$pwo

物理アドレスを取得する点を除いて、 wo と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。

dwo

指定したアドレスのダブルワード。

$pdwo

物理アドレスを取得する点を除いて、 dwo と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。

qwo

指定されたアドレスからのクワッドワード。

$pqwo

物理アドレスを取得する点を除いて、 qwo と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。

poi

指定したアドレスからのポインター サイズのデータ。 ポインター サイズは 32 ビットまたは 64 ビットです。 カーネル デバッグでは、このサイズは ターゲット コンピューターのプロセッサに基づいています。 したがって、ポインター サイズのデータが必要な場合は、 poi が最適な演算子です。

$ppoi

物理アドレスを取得する点を除いて、 poi と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。

次の例では、poi を使用してポインターを逆参照し、そのメモリ位置に格納されている値を確認する方法を示します。

まず、目的のメモリ アドレスを決定します。 たとえば、スレッド構造を見て、CurrentLocale の値を表示することを決定できます。

0:000> dx @$teb
@$teb                 : 0x8eed57b000 [Type: _TEB *]
    [+0x000] NtTib            [Type: _NT_TIB]
    [+0x038] EnvironmentPointer : 0x0 [Type: void *]
    [+0x040] ClientId         [Type: _CLIENT_ID]
    [+0x050] ActiveRpcHandle  : 0x0 [Type: void *]
    [+0x058] ThreadLocalStoragePointer : 0x1f8f9d634a0 [Type: void *]
    [+0x060] ProcessEnvironmentBlock : 0x8eed57a000 [Type: _PEB *]
    [+0x068] LastErrorValue   : 0x0 [Type: unsigned long]
    [+0x06c] CountOfOwnedCriticalSections : 0x0 [Type: unsigned long]
    [+0x070] CsrClientThread  : 0x0 [Type: void *]
    [+0x078] Win32ThreadInfo  : 0x0 [Type: void *]
    [+0x080] User32Reserved   [Type: unsigned long [26]]
    [+0x0e8] UserReserved     [Type: unsigned long [5]]
    [+0x100] WOW32Reserved    : 0x0 [Type: void *]
    [+0x108] CurrentLocale    : 0x409 [Type: unsigned long]

CurrentLocale は TEB の開始 0x108 を超えて配置されます。

0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108

poi を使用して、そのアドレスを逆参照します。

0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

返される値 409 は、TEB 構造体の CurrentLocale の値と一致します。

または、poi と括弧を使用して、計算されたアドレスを逆参照します。

0:000> ? poi(@$teb + 0x108)
Evaluate expression: 1033 = 00000000`00000409

by 演算子または wo 単項演算子を使用して、ターゲット アドレスからバイトまたはワードを返します。

0:000> ? by(0000008e`ed57b108)
Evaluate expression: 9 = 00000000`00000009
0:000> ? wo(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409

二項演算子

次の二項演算子を使用できます。 各セルの演算子は、下位のセルの演算子よりも優先されます。 同じセルの演算子は同じ優先順位であり、左から右に解析されます。

演算子 説明

*

/

mod (または %)

乗算

整数の除算

剰余 (余り)

+

-

追加

減算

<<

>>

>>>

左シフト

論理右シフト

算術右シフト

= (または ==)

<

>

<=

>=

!=

等しい

より小さい

より大きい

次の値以下

次の値以上

等しくない

(または &)

ビット演算子 AND

xor (または ^)

ビット演算子 XOR (排他的 OR)

または (または |)

ビット演算子 OR

<, >、 =、==、および != 比較演算子は、式が true の場合は 1、false の場合は 0 と評価されます。 1 つの等号 (=) は、二重等号 (==) と同じです。 MASM 式内で副作用や代入を使用することはできません。

無効な演算 (ゼロによる除算など) は、"オペランド エラー" として デバッガー コマンド ウィンドウに返されます。

== 比較演算子を使用して、戻り値が 0x409 と一致することをチェックできます。

0:000> ? poi(@$teb + 0x108)==0x409
Evaluate expression: 1 = 00000000`00000001

MASM 式の非数値演算子

MASM 式では、次の追加演算子を使用することもできます。

演算子 説明

$fnsucc(FnAddress, RetVal, Flag)

RetVal 値を FnAddress アドレスにある関数の戻り値として解釈します。 この戻り値が成功コードとして評価される場合、 $fnsuccTRUE を返します。 それ以外の場合、 $fnsuccFALSEを返します。

戻り値の型が BOOL、bool、HANDLE、HRESULT、または NTSTATUS の場合、 $fnsucc は指定された戻り値が成功コードとして適格かどうかを正しく認識します。 戻り値の型がポインターの場合、 NULL 以外のすべての値は成功コードとして評価されます。 その他の型の場合、成功は Flag の値によって定義されます。 フラグ が 0 の場合、 RetVal の 0 以外の値が成功となります。 フラグ が 1 の場合、 RetVal の 0 の値が成功となります。

$iment (アドレス)

読み込まれたモジュール リストのイメージ エントリ ポイントのアドレスを返します。 アドレス は、ポータブル実行可能 (PE) イメージのベース アドレスを指定します。 エントリは、 アドレス が指定するイメージの PE イメージ ヘッダー内のイメージ エントリ ポイントを検索することによって見つかります。

この関数は、モジュール リストに既に存在するモジュールの両方に使用でき、 bu コマンドを使用して、 未解決のブレークポイント を設定できます。

$scmp("String1", "String2")

strcmp C 関数を使用して、 strcmp のように、-1、0、または 1 と評価されます。

$sicmp("String1", "String2")

stricmp Microsoft Win32 関数のように、-1、0、または 1 と評価されます。

$spat("String", "Pattern")

文字列パターンと一致するかどうかに応じて TRUE または FALSE と評価されます。 照合では大文字と小文字は区別されません。 パターン は、さまざまなワイルドカード文字と指定子を含めることができます。 構文の詳細については、「文字列ワイルドカード構文」を参照してください。

$vvalid(Address, Length)

アドレス で始まり、 長さ バイトに対して拡張されるメモリ範囲が有効かどうかを判断します。 メモリが有効な場合、 $vvalid は 1 と評価されます。 メモリが無効な場合、 $vvalid は 0 と評価されます。

読み込まれたモジュールに関する有効なメモリの範囲を調査する方法を次に示します。

まず、たとえば lm (読み込まれたモジュールの一覧表示 コマンド) を使用して、対象領域のアドレスを決定します。


0:000> lm
start             end                 module name
00007ff6`0f620000 00007ff6`0f658000   notepad    (deferred)
00007ff9`591d0000 00007ff9`5946a000   COMCTL32   (deferred)        
...

メモリ範囲をチェックするには、$vvalid を使用します。

0:000> ? $vvalid(0x00007ff60f620000, 0xFFFF)
Evaluate expression: 1 = 00000000`00000001

$vvalid を使用して、この大きな範囲が無効なメモリ範囲であることを確認します。

0:000> ? $vvalid(0x00007ff60f620000, 0xFFFFF)
Evaluate expression: 0 = 00000000`00000000

これも無効な範囲です。

0:000> ? $vvalid(0x0, 0xF)
Evaluate expression: 0 = 00000000`00000000

メモリ範囲が有効な場合は、ゼロを返さ ない を使用します。

0:000> ? not($vvalid(0x00007ff60f620000, 0xFFFF))
Evaluate expression: 0 = 00000000`00000000

$imnet を使用して、先に lm コマンドを使用してアドレスを特定した COMCTL32 のエントリ ポイントを確認します。 00007ff9'591d0000 から始まります。

0:000> ? $iment(00007ff9`591d0000)
Evaluate expression: 140708919287424 = 00007ff9`59269e80

返されたアドレスを逆アセンブルして、エントリ ポイント コードを調べます。

0:000> u 00007ff9`59269e80
COMCTL32!DllMainCRTStartup:
00007ff9`59269e80 48895c2408      mov     qword ptr [rsp+8],rbx
00007ff9`59269e85 4889742410      mov     qword ptr [rsp+10h],rsi
00007ff9`59269e8a 57              push    rdi

COMCTL32 が出力に表示され、これがこのモジュールのエントリ ポイントであることを確認します。

MASM 式のレジスタと擬似レジスタ

MASM 式内でレジスタと疑似レジスタを使用できます。 すべてのレジスタと擬似レジスタの前に記号 (@) を追加できます。 この記号により、デバッガーは値にすばやくアクセスします。 この @ 記号は、最も一般的な x86 ベースのレジスタでは不要です。 その他のレジスタと擬似レジスタの場合は、記号を追加することをお勧めしますが、実際には必要ありません。 あまり一般的でないレジスタの記号を省略すると、デバッガーはテキストを 16 進数として解析し、次に記号として、最後にレジスタとして解析しようとします。

ピリオド (.) を使用して、現在の命令ポインターを示すこともできます。 このピリオドの前に @ 記号を追加しないでください。さもないと、 r コマンドの最初のパラメーターとしてピリオドを使用することができません。 このピリオドは、 $ip 擬似レジスタと同じ意味を持ちます。

レジスタと擬似レジスタの詳細については、「レジスタ構文 」および「擬似レジスタ構文」を参照してください。

r レジスタ コマンドを使用して、 @rip レジスタの値が 00007ffb'7ed00770 であることを確認します。

0:000> r
rax=0000000000000000 rbx=0000000000000010 rcx=00007ffb7eccd2c4
rdx=0000000000000000 rsi=00007ffb7ed61a80 rdi=00000027eb6a7000
rip=00007ffb7ed00770 rsp=00000027eb87f320 rbp=0000000000000000
 r8=00000027eb87f318  r9=0000000000000000 r10=0000000000000000
r11=0000000000000246 r12=0000000000000040 r13=0000000000000000
r14=00007ffb7ed548f0 r15=00000210ea090000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffb`7ed00770 cc              int     3

を使用して同じ値を表示することができます。 ピリオドのショートカット。

0:000> ? .
Evaluate expression: 140718141081456 = 00007ffb`7ed00770

これらの値がすべて等価であることを確認でき、また、等価である場合は、この MASM 式を使用して 0 を返すことができます。

0:000>  ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000

MASM 式のソース行番号

ソース ファイルと行番号の式は、MASM 式内で使用できます。 これらの式は、グレーブ アクセント (') を使用して囲む必要があります。 構文の詳細については、「ソース行の構文」を参照してください。

関連項目

MASM 式 vs. C++ 式

混在する式の例

C++ の数値と演算子

署名拡張機能

? (式の評価)