このトピックでは、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 プレフィックス (バイナリ) を指定します。
数値の後に h を追加して、16 進数を指定することもできます。 数字には大文字または小文字を使用できます。 たとえば、"0x4AB3"、"0X4aB3"、"4AB3h"、"4ab3h"、"4aB3H" は同じ意味を持ちます。
式のプレフィックスの後に数値を追加しない場合、数値は 0 として読み取られます。 そのため、0 を 0、プレフィックスの後に 0 を付け、プレフィックスのみを書き込むことができます。 たとえば、16 進数の "0"、"0x0"、および "0x" は同じ意味を持ちます。
xxxxxxxx'xxxxxxxx 形式で 16 進数の 64 ビット値を入力できます。 また、墓のアクセント (') を省略することもできます。 グレーブ アクセントを含める場合、自動符号拡張は無効になります。
この例では、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 がアドレスの既定のセグメントと見なされます。 式は、演算子の優先順位に従って評価されます。 隣接する演算子の優先順位が等しい場合、式は左から右に評価されます。
次の単項演算子を使用できます。
| オペレーター | 意味 |
|---|---|
+ |
単項プラス |
- |
単項マイナス |
ない |
引数が 0 の場合は 1 を返します。 0 以外の引数に対して 0 を返します。 |
こんにちは |
上位 16 ビット |
低い |
下位 16 ビット |
作成者 |
指定したアドレスからの下位バイト。 |
$pby |
によって受け取る点を除き、物理アドレスに関しては同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。 |
wo |
指定したアドレスの下位ワード。 |
$pwo |
物理アドレスを受け取る点を除き、 wo と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。 |
dwo |
指定したアドレスの二重ワード。 |
$pdwo |
dwo と同じですが、物理アドレスを受け取る点が異なります。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。 |
qwo |
指定したアドレスのクアッドワード。 |
$pqwo |
物理アドレスを受け取る点を除き、 qwo と同じです。 既定のキャッシュ動作を使用する物理メモリのみを読み取ることができます。 |
ポイ |
指定したアドレスからのポインター サイズのデータ。 ポインター サイズは 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 (または &) |
ビットごとの 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 アドレスにある関数の戻り値として解釈します。 この戻り値が成功コードとして修飾される場合、 $fnsucc は TRUE を返します。 それ以外の 場合、$fnsucc は FALSE を返します。 戻り値の型が BOOL、bool、HANDLE、HRESULT、または NTSTATUS の場合、 $fnsucc 指定された戻り値が成功コードとして適格かどうかを正しく認識します。 戻り値の型がポインターの場合、 NULL 以外のすべての値は成功コードとして修飾されます。 その他の型の場合、成功は Flag の値によって定義されます。 フラグが 0 の場合、RetVal の 0 以外の値が成功します。 フラグが 1 の場合、RetVal の 0 の値が成功します。 |
$iment (アドレス) |
読み込まれたモジュール リストのイメージ エントリ ポイントのアドレスを返します。 Address は、ポータブル実行可能 (PE) イメージのベース アドレスを指定します。 エントリは、 Address が指定するイメージの 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 (List Loaded Modules コマンド) を使用して、対象領域のアドレスを決定します。
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 式におけるレジスタと Pseudo-Registers
MASM 式内でレジスタと擬似レジスタを使用できます。 すべてのレジスタと擬似レジスタの前にアット マーク (@) を追加できます。 アット マークにより、デバッガーは値にすばやくアクセスします。 この @ 記号は、最も一般的な x86 ベースのレジスタでは不要です。 その他のレジスタと擬似レジスタの場合は、アット マークを追加することをお勧めしますが、実際には必要ありません。 あまり一般的でないレジスタのアット マークを省略すると、デバッガーはテキストを 16 進数として解析し、次にシンボルとして、最後にレジスタとして解析しようとします。
ピリオド (.) を使用して、現在の命令ポインターを示すこともできます。 この期間の前に @ 記号を追加しないでください。 また、r コマンドの最初のパラメーターとしてピリオドを使用することはできません。 この期間は、 $ip 擬似レジスタと同じ意味を持ちます。
レジスタと擬似レジスタの詳細については、「 レジスタ構文 と Pseudo-Register 構文」を参照してください。
r register コマンドを使用して、 @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 式内で使用できます。 これらの式は、グレーブ アクセント (') を使用して囲む必要があります。 構文の詳細については、「 ソース行の構文」を参照してください。