共用方式為


MASM 數位和運算符

本主題描述搭配 Windows 偵錯工具使用 Microsoft 宏組合器 (MASM) 表達式語法。

調試程式接受兩種不同類型的數值表達式:C++表達式和MASM運算式。 每個表達式都會遵循自己的輸入和輸出語法規則。

如需何時使用每個語法類型的詳細資訊,請參閱 評估表達式?(評估表示式)

在這裡範例中, ? 命令會使用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表達式。 本範例會將十六進位值 8 新增至撕裂緩存器。

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

的緩存器參考@rip會在 Register Syntax詳細說明。

調試程式MASM運算式中的數位

您可以將數位放在 BASE 16、10、8 或 2 的 MASM 運算式中。

使用 n (設定數位基底) 命令,將預設基數設定為 16、10 或 8。 然後,所有未取代的數字都會在此基底中解譯。 您可以指定 0x 前置詞(十六進位)、0n 前置詞(十進位)、0t 前置詞(八進位),或 0y 前置詞 (binary) 來覆寫預設的基數。

您也可以在數位後面加上 h 來指定十六進位數位。 您可以在數位中使用大寫或小寫字母。 例如,“0x4AB3”、“0X4aB3”、“4AB3h”、“4ab3h” 和 “4aB3H” 具有相同的意義。

如果您未在表達式中的前置詞後面加上數位,則數位會讀取為 0。 因此,您可以將 0 寫入為 0、前置詞後面接著 0,而且只寫入前置詞。 例如,在十六進位中,“0”、“0x0”和 “0x” 具有相同的意義。

您可以以 xxxxxxxx'xxxxxxxx 格式輸入十六進位 64 位值。 您也可以省略墳墓口音 (')。 如果您包含嚴重輔色, 則會停用自動符號延伸

此範例示範如何新增十進位、八進位和二進位值來註冊 10。

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

調試程式MASM表示式中的符號

在MASM表達式中,任何符號的數值都是其記憶體位址。 根據符號所參考的內容,此位址是全域變數、局部變數、函式、區段、模組或任何其他已辨識卷標的位址。

若要指定與地址相關聯的模組,請在符號名稱之前包含模組名稱和驚歎號 (!)。 如果符號可以解譯為十六進位數位,請在符號名稱之前包含模組名稱和驚嘆號,或只是驚歎號。 如需符號辨識的詳細資訊,請參閱 符號語法和符號比對

使用兩個冒號 (::) 或兩個底線 (__) 來指出類別的成員。

只有在您在符號前面新增模組名稱和驚嘆號時,才能在符號名稱中使用嚴重輔色 (') 或單引號 (')。

MASM 運算式中的數值運算元

您可以使用一元運算符來修改表達式的任何元件。 您可以使用二元運算符來合併任兩個元件。 一元運算符優先於二元運算元。 當您使用多個二進位運算符時,運算子會遵循下表所述的固定優先順序規則。

您一律可以使用括弧來覆寫優先順序規則。

如果MASM表達式的一部分以括弧括住,且在表達式前面出現兩個符號(@@),則表達式會根據 表達式規則C++解譯。 您無法在符號和左括弧之間新增兩個空格。 您也可以使用 @@c++( ... )@@masm( ... )來指定表示式評估工具

當您執行算術計算時,MASM 運算式評估工具會將所有數位和符號視為ULONG64類型。

一元位址運算元假設DS是位址的預設區段。 表達式的評估順序為運算符優先順序。 如果相鄰運算符的優先順序相等,則會從左至右評估表達式。

您可以使用下列一元運算子。

運算子 意義

+

一元加號

-

一元減號

not

如果自變數為零,則傳回 1。 傳回任何非零自變數的零。

你好

高16位

low

低16位

by

來自指定位址的低序位元組。

$pby

相同,不同之處在於它會採用實體位址。 只能讀取使用預設快取行為的實體記憶體。

來自指定位址的低序字組。

$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

使用 bywo 一元運算子,從目標地址傳回位元組或單字。

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,則為零。 單一等號 (=) 與雙等號 (==) 相同。 您無法在MASM運算式中使用副作用或指派。

無效的作業(例如除以零)會導致「操作數錯誤」傳回調試 程式命令視窗

我們可以使用 == 比較運算符來檢查傳回的值是否符合0x409。

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

MASM 運算式中的非數值運算元

您也可以在MASM運算式中使用下列其他運算符。

運算子 意義

$fnsucc(FnAddressRetValFlag

RetVal 值解譯為位於 FnAddress 位址之函式的傳回值。 如果此傳回值限定為成功碼,$fnsucc會傳回 TRUE。 否則,$fnsucc會傳回 FALSE

如果傳回類型為 BOOL、bool、HANDLE、HRESULT 或 NTSTATUS, $fnsucc 正確瞭解指定的傳回值是否限定為成功碼。 如果傳回類型是指針,NULL 以外的所有值都會限定為成功碼。 對於任何其他類型,成功是由 Flag 的值所定義。 如果 Flag 為 0,則 RetVal 的非零值會成功。 如果 Flag 為 1,則 RetVal零值為 success。

$iment (位址

傳回已載入模組清單中影像進入點的位址。 位址 指定可攜式可執行檔 (PE) 映像基位址。 在 Address 所指定影像的 PE 映像標頭中查閱影像進入點,以找到專案。

您可以將此函式用於模組清單中的這兩個模組,以及使用bu命令來設定未解析的斷點。

$scmp(“String1”, “String2”)

使用 strcmp C 函式,評估為 -1、0 或 1,例如 strcmp。

$sicmp(“String1”, “String2”)

評估為 -1、0 或 1,例如 stricmp Microsoft Win32 函式 。

$spat(“String”, “Pattern”)

根據字串是否符合模式,評估為 TRUEFALSE。 比對不區分大小寫。 模式 可以包含各種通配符和規範。 如需語法的詳細資訊,請參閱 字串通配符語法

$vvalid(位址長度)

判斷從 Address 開始的記憶體範圍,以及長度位元組的擴充是否有效。 如果記憶體有效, $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表示式中註冊和虛擬緩存器

您可以在 MASM 運算式中使用快取器和虛擬快取器。 您可以在所有快取器與虛擬快取器之前新增 at sign (@) 。 at 符號會使調試程式更快速地存取值。 最常見的 x86 型快取器不需要這個 @ 符號。 對於其他快取器和虛擬緩存器,建議您新增 at sign,但實際上並非必要。 如果您省略較不常見緩存器的正負號,調試程式會嘗試將文字剖析為十六進位數位,然後做為符號,最後做為緩存器。

您也可以使用句號 (.) 來指出目前的指令指標。 您不應該在此期間之前新增 @ 符號,而且不能使用句號做為 r 命令的第一個參數。 這個期間與虛擬緩存器$ip相同

如需緩存器和虛擬緩存器的詳細資訊,請參閱 註冊語法虛擬緩存器語法

使用 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:000>  ? NOT(($ip = .) AND ($ip = @rip) AND (@rip =. ))
Evaluate expression: 0 = 00000000`00000000

MASM 運算式中的源行號

您可以在 MASM 運算式中使用原始程式檔和行號表示式。 您必須使用嚴重輔色來括住這些表達式(『)。 如需語法的詳細資訊,請參閱 源行語法

另請參閱

MASM 運算式與C++表達式

混合表達式範例

C++數位和運算符

簽署延伸模組

? (評估表示式)