Sdílet prostřednictvím


Čísla a operátory MASM

Toto téma popisuje použití syntaxe výrazu MasM (Microsoft Macro Assembler) s nástroji pro ladění systému Windows.

Ladicí program přijímá dva různé druhy číselných výrazů: výrazy C++ a výrazy MASM. Každý z těchto výrazů se řídí vlastními pravidly syntaxe pro vstup a výstup.

Další informace o tom, kdy se jednotlivé typy syntaxe používají, najdete v tématu Vyhodnocení výrazů a ? (Vyhodnocení výrazu).

V tomto příkladu se jedná o ? příkaz zobrazí hodnotu registru ukazatele instrukce pomocí vyhodnocovače výrazů MASM.

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

Nastavte vyhodnocovač výrazů na MASM

Pomocí výrazu .expr (Zvolit vyhodnocovač výrazů) zjistěte, co je výchozí vyhodnocovač výrazů, a změňte ho na MASM.

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

Nyní, když byl výchozí vyhodnocovací výraz změněn, tlačítko ? (Vyhodnocení výrazu) příkaz lze použít k zobrazení výrazů MASM. Tento příklad přidá šestnáctkovou hodnotu 8 do registru rip.

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

Odkaz na @rip registr je podrobněji popsán v syntaxi registru.

Čísla ve výrazech MASM ladicího programu

Čísla můžete vložit do výrazů MASM v základu 16, 10, 8 nebo 2.

Pomocí příkazu n (Nastavit číselný základ) nastavte výchozí radix na 16, 10 nebo 8. Všechna nepředponová čísla se pak interpretují v této základně. Výchozí radix můžete přepsat zadáním předpony 0x (šestnáctkové), předpony 0n (desítkové), předpony 0t (osmičkové) nebo 0y předpony (binární).

Šestnáctková čísla můžete zadat také tak, že za číslo přidáte h . V číslech můžete použít velká nebo malá písmena. Například "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" a "4aB3H" mají stejný význam.

Pokud za předponu ve výrazu nepřidáte číslo, bude číslo čteno jako 0. Proto můžete napsat 0 jako 0, předponu následovanou 0 a pouze předponu. Například v šestnáctkové soustavě mají číslice "0", "0x0" a "0x" stejný význam.

Šestnáctkové 64bitové hodnoty můžete zadat ve formátu xxxxxxxx'xxxxxxxxxx . Můžete také vynechat přízvuk (`). Pokud zahrnete hrobový přízvuk, automatické rozšíření znaménka je zakázané.

Tento příklad ukazuje, jak přidat desetinnou, osmičkovou a binární hodnotu pro registraci 10.

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

Symboly ve výrazech MASM ladicího programu

Ve výrazech MASM je adresa paměti číselnou hodnotou jakéhokoliv symbolu. V závislosti na tom, na co symbol odkazuje, je tato adresa adresa globální proměnné, místní proměnné, funkce, segmentu, modulu nebo jakéhokoli jiného rozpoznaného popisku.

Pokud chcete určit, ke kterému modulu je adresa přidružená, uveďte název modulu a vykřičník (!) před název symbolu. Pokud lze symbol interpretovat jako šestnáctkové číslo, uveďte název modulu s vykřičníkem, nebo pouze samotný vykřičník před názvem symbolu. Další informace o rozpoznávání symbolů naleznete v tématu Syntaxe symbolů a Porovnávání symbolů.

K označení členů třídy použijte dvě dvojtečky (::) nebo dvě podtržítka (__).

V názvu symbolu používejte obrácený apostrof (`) nebo apostrof (') pouze v případě, že před symbol přidáte název modulu a vykřičník.

Číselné operátory ve výrazech MASM

Libovolnou komponentu výrazu můžete upravit pomocí unárního operátoru. Pomocí binárního operátoru můžete zkombinovat jakékoli dvě komponenty. Unární operátory mají přednost před binárními operátory. Při použití více binárních operátorů se operátory řídí pevnými pravidly priority, která jsou popsána v následujících tabulkách.

Pravidla priority můžete vždy přepsat pomocí závorek.

Pokud je část výrazu MASM uzavřená do závorek a před výrazem se zobrazí dva znakové znaky (@@), výraz se interpretuje podle pravidel výrazu jazyka C++. Nelze přidat mezeru mezi dva zavináče a levou závorku. Vyhodnocovač výrazů můžete také zadat pomocí @@c++( ... ) nebo @@masm( ... ).

Při provádění aritmetických výpočtů bude vyhodnocovací modul výrazů MASM považovat všechna čísla a symboly za ULONG64 typy.

Operátory unárních adres předpokládají, že DS je výchozím segmentem adres. Výrazy se vyhodnocují v pořadí podle priority operátoru. Pokud mají sousední operátory stejnou prioritu, výraz se vyhodnotí zleva doprava.

Můžete použít následující unární operátory.

Operátor Význam

+

Unární plus

-

Unární mínus

ne

Vrátí hodnotu 1, pokud je argument nula. Vrací nulu pro libovolné nenulové argument.

Ahoj

Vysoké 16 bitů

nízký

Nízké 16 bitů

od

Bajt s nízkým pořadím ze zadané adresy.

$pby

Stejné jako při výjimkou toho, že přebírá fyzickou adresu. Číst lze pouze fyzickou paměť, která používá výchozí chování ukládání do mezipaměti.

wo

Slovo s nízkým pořadím ze zadané adresy

$pwo

Stejné jako wo s tím rozdílem, že používá fyzickou adresu. Číst lze pouze fyzickou paměť, která používá výchozí chování ukládání do mezipaměti.

dwo

Dvojité slovo ze zadané adresy

$pdwo

Stejné jako dwo s tím rozdílem, že přebírá fyzickou adresu. Číst lze pouze fyzickou paměť, která používá výchozí chování ukládání do mezipaměti.

qwo

Čtyřslovné slovo ze zadané adresy

$pqwo

Stejné jako qwo s tím rozdílem, že přebírá fyzickou adresu. Číst lze pouze fyzickou paměť, která používá výchozí chování ukládání do mezipaměti.

Poi

Data o velikosti ukazatele ze zadané adresy. Velikost ukazatele je 32 bitů nebo 64 bitů. V ladění jádra je tato velikost založená na procesoru cílového počítače. Proto je poi nejlepším operátorem, pokud chcete data o velikosti ukazatele.

$ppoi

Stejné jako poi s tím rozdílem, že přebírá fyzickou adresu. Číst lze pouze fyzickou paměť, která používá výchozí chování ukládání do mezipaměti.

Příklady

Následující příklad ukazuje, jak pomocí příkazu poi dereferencovat ukazatel a zobrazit hodnotu uloženou na této paměťové adrese.

Nejprve určete adresu paměti, o kterou máte zájem. Můžeme se například podívat na strukturu vlákna a rozhodnout se, že chceme vidět hodnotu 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 se nachází na adrese 0x108 za začátkem TEB.

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

Pomocí poi dereferencujte tuto adresu.

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

Vrácená hodnota 409 odpovídá hodnotě CurrentLocale ve struktuře TEB.

Nebo použijte poi a závorky k dereferencování počítané adresy.

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

Použijte unární operátory by nebo wo k vrácení bajtu nebo slova z cílové adresy.

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

Binární operátory

Můžete použít následující binární operátory. Operátory v každé buňce mají přednost před operátory v dolních buňkách. Operátory v rámci stejné úrovně mají stejnou prioritu a jsou zpracovávány zleva doprava.

Operátor Význam

*

/

mod (nebo %)

Násobení

Celočíselné dělení

Modulo (zbytek)

+

-

Přidání

Odčítání

<<

>>

>>>

Posun vlevo

Logický pravý posun

Aritmetický pravý posun

= (nebo ==)

<

>

<=

>=

!=

Rovná se

Menší než

Je větší než

Menší nebo rovno

Větší nebo rovno

Nerovná se

a (nebo &)

Bitový operátor AND

xor (nebo ^)

Bitwise XOR (exkluzivní OR)

nebo (nebo |)

Bitový operátor OR

Operátory <, >, =, == a != se vyhodnotí jako 1, pokud je výraz pravdivý, nebo jako nula, pokud je výraz nepravdivý. Jedno rovnítko (=) je stejné jako dvojité rovnítko (==). Ve výrazu MASM nelze použít vedlejší efekty ani přiřazení.

Neplatná operace (například dělení nulou) má za následek, že je do příkazového okna ladicího programu vrácena "chyba Operandu".

Pomocí relačního operátoru == můžeme zkontrolovat, že vrácená hodnota odpovídá 0x409.

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

Nečíselné operátory ve výrazech MASM

Ve výrazech MASM můžete také použít následující další operátory.

Operátor Význam

$fnsucc(FnAddress, RetVal, Flag)

Interpretuje hodnotu RetVal jako návratovou hodnotu pro funkci, která je umístěna na adrese FnAddress . Pokud se tato návratová hodnota kvalifikuje jako kód úspěchu, $fnsucc vrátí hodnotu PRAVDA. V opačném případě $fnsucc vrátí hodnotu FALSE.

Pokud je návratový typ BOOL, bool, HANDLE, HRESULT nebo NTSTATUS, $fnsucc správně pochopí, zda zadaná návratová hodnota kvalifikuje jako kód úspěchu. Pokud je návratovým typem ukazatel, všechny jiné hodnoty než NULL jsou kvalifikovat jako kódy úspěchu. Pro jakýkoli jiný typ je úspěch definován hodnotou Příznak. Pokud je příznak 0, pak je nenulová hodnota RetVal považována za úspěch. Pokud je Flag 1, nulová hodnota RetVal znamená úspěch.

$iment (adresa)

Vrátí adresu vstupního bodu obrázku v seznamu načtených modulů. Adresa určuje výchozí adresu bitové kopie přenosného spustitelného souboru (PE). Položku najdete vyhledáním vstupního bodu obrazu v záhlaví PE obrazu, který je určen adresou Address.

Tuto funkci můžete použít pro oba moduly, které už jsou v seznamu modulů, a k nastavení nevyřešených zarážek pomocí příkazu bu .

$scmp("String1"; "String2")

Vyhodnotí se na hodnotu -1, 0 nebo 1, podobně jako strcmp, pomocí C funkce strcmp .

$sicmp("String1"; "String2")

Vyhodnotí se jako -1, 0 nebo 1, jako je funkce stricmp Microsoft Win32 .

$spat("String"; "Pattern")

Vyhodnotí se jako PRAVDA nebo NEPRAVDA v závislosti na tom, jestli řetězec odpovídá vzoru. Porovnávání nerozlišuje malá a velká písmena. Vzor může obsahovat různé zástupné znaky a specifikátory. Další informace o syntaxi naleznete v tématu Syntaxe se zástupnými znaky řetězce.

$vvalid(Adresa,Délka)

Určuje, zda je rozsah paměti, který začíná na adrese a má délku Length bajtů, platný. Pokud je paměť platná, $vvalid vyhodnotí hodnotu 1. Pokud je paměť neplatná, $vvalid vyhodnotí hodnotu 0.

Příklady

Následující příklad ukazuje, jak prozkoumat rozsah platné paměti kolem načteného modulu.

Nejprve určete adresu oblasti zájmu, například pomocí příkazu lm (List Loaded Modules command).


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

Pomocí $vvalid zkontrolujte rozsah paměti.

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

Pomocí $vvalid potvrďte, že tento větší rozsah je neplatným rozsahem paměti.

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

Jedná se také o neplatný rozsah.

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

Použijte not k vrácení nuly, když je rozsah paměti platný.

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

Pomocí $imnet se podívejte na vstupní bod COMCTL32, který jsme dříve použili k určení adresy příkazem lm. Začíná na 00007ff9'591d00000.

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

Rozmontujte získanou adresu, abyste prozkoumali kód vstupního bodu.

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

Ve výstupu je zobrazeno, že COMCTL32 je potvrzen jako vstupní bod tohoto modulu.

Registry a Pseudo-Registers ve výrazech MASM

V rámci výrazů MASM můžete použít registry a pseudoregistry. Před všechny registry a pseudoregistry můžete přidat znak at (@). Znak at způsobí, že ladicí program bude přistupovat k hodnotě rychleji. Toto znak @ není nutný pro nejběžnější registry založené na platformě x86. Pro jiné registry a pseudoregistry doporučujeme přidat znak zavináč, ale není to ve skutečnosti povinné. Pokud vynecháte zavináč pro méně běžné registry, ladicí program se pokusí analyzovat text jako šestnáctkové číslo, potom jako symbol a nakonec jako registr.

Můžete také použít tečku (.) k označení aktuálního instrukčního ukazatele. Před tímto obdobím byste neměli přidávat znak @ a nelze použít tečku jako první parametr příkazu r. Toto období má stejný význam jako $ip pseudoregistr.

Další informace o registrech a pseudoregistrech naleznete v tématu Syntaxe registrace a Pseudo-Register Syntaxe.

Pomocí příkazu r register zjistíte, že hodnota @rip registru je 00007ffb'7ed007770.

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

Stejnou hodnotu lze zobrazit pomocí funkce . klávesová zkratka tečky.

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

Pomocí tohoto výrazu MASM můžeme potvrdit, že všechny tyto hodnoty jsou ekvivalentní, a pokud ano, vrátí nulu.

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

Čísla řádků zdrojového kódu ve výrazech MASM

V rámci výrazů MASM můžete použít výrazy zdrojového souboru a čísel řádků. Tyto výrazy je nutné uzavřít pomocí hrobných přízvuků (`). Další informace o syntaxi naleznete v tématu Syntaxe řádku zdroje.

Viz také

Výrazy MASM vs. výrazy C++

Příklady smíšených výrazů

Čísla a operátory jazyka C++

Rozšíření podpisu

? (Vyhodnocení výrazu)