MASM 번호 및 연산자

이 항목에서는 Windows 디버깅 도구를 사용하여 MASM(Microsoft Macro Assembler) 식 구문을 사용하는 방법을 설명합니다.

디버거는 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 식을 표시할 수 있습니다. 다음은 16진수 값 8을 rip 레지스터에 추가하는 예제입니다.

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

의 @rip 레지스터 참조는 레지스터 구문에 자세히 설명되어 있습니다.

디버거 MASM 식의 숫자

기본 16, 10, 8 또는 2의 MASM 식에 숫자를 넣을 수 있습니다.

n(숫자 기준 설정) 명령을 사용하여 기본 radix를 16, 10 또는 8로 설정합니다. 그런 다음, 접두사 없는 모든 숫자가 이 베이스에서 해석됩니다. 0x 접두사(16진수), 0n 접두사(10진수), 0t 접두사(8진수) 또는 0y 접두사(이진)를 지정하여 기본 radix를 재정의 할 수 있습니다.

숫자 다음에 h 를 추가하여 16진수를 지정할 수도 있습니다. 숫자 내에서 대문자 또는 소문자를 사용할 수 있습니다. 예를 들어 "0x4AB3", "0X4aB3", "4AB3h", "4ab3h" 및 "4aB3H"는 동일한 의미를 갖습니다.

식의 접두사 다음에 숫자를 추가하지 않으면 숫자가 0으로 읽혀집니다. 따라서 0을 0으로, 접두사 뒤에 0을, 접두사만 작성할 수 있습니다. 예를 들어 16진수에서 "0", "0x0" 및 "0x"는 동일한 의미를 갖습니다.

xxxx'xxxx 형식으로 16진수 64비트 값을 입력할 수 있습니다. 무덤 악센트(')를 생략할 수도 있습니다. 그레이브 악센트를 포함하면 자동 기호 확장 이 비활성화됩니다.

이 예제에서는 10을 등록하기 위해 10진수, 8진수 및 이진 값을 추가하는 방법을 보여줍니다.

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

디버거 MASM 식의 기호

MASM 식에서 기호의 숫자 값은 메모리 주소입니다. 기호가 참조하는 내용에 따라 이 주소는 전역 변수, 지역 변수, 함수, 세그먼트, 모듈 또는 기타 인식된 레이블의 주소입니다.

주소가 연결된 모듈을 지정하려면 모듈 이름과 느낌표(!)를 기호 이름 앞에 포함합니다. 기호를 16진수로 해석할 수 있는 경우 모듈 이름 및 느낌표 또는 느낌표만 기호 이름 앞에 포함합니다. 기호 인식에 대한 자세한 내용은 기호 구문 및 기호 일치를 참조하세요.

두 개의 콜론(::) 또는 두 개의 밑줄(__)을 사용하여 클래스의 멤버를 나타냅니다.

기호 앞에 모듈 이름과 느낌표를 추가하는 경우에만 기호 이름에 그레이브 악센트(') 또는 아포스트로피(')를 사용합니다.

MASM 식의 숫자 연산자

단항 연산자를 사용하여 식의 구성 요소를 수정할 수 있습니다. 이진 연산자를 사용하여 두 구성 요소를 결합할 수 있습니다. 단항 연산자는 이진 연산자보다 우선합니다. 여러 이진 연산자를 사용하는 경우 연산자는 다음 표에 설명된 고정 우선 순위 규칙을 따릅니다.

항상 괄호를 사용하여 우선 순위 규칙을 재정의할 수 있습니다.

MASM 식의 일부가 괄호로 묶이고 2개의 기호(@@)가 식 앞에 나타나는 경우 식은 C++ 식 규칙에 따라 해석됩니다. 두 기호와 여는 괄호 사이에 공백을 추가할 수 없습니다. @@c++( ... ) 또는 @@masm( ... )를 사용하여 식 계산기를 지정할 수도 있습니다.

산술 계산을 수행할 때 MASM 식 계산기는 모든 숫자와 기호를 ULONG64 형식으로 처리합니다.

단항 주소 연산자는 DS를 주소의 기본 세그먼트로 가정합니다. 식은 연산자 우선 순위 순서로 평가됩니다. 인접 연산자의 우선 순위가 같으면 식이 왼쪽에서 오른쪽으로 평가됩니다.

다음 단항 연산자를 사용할 수 있습니다.

연산자 의미

+

단항 더하기

-

단항 빼기

not

인수가 0이면 1을 반환합니다. 0이 아닌 인수에 대해 0을 반환합니다.

hi

높은 16비트

낮은

낮은 16비트

by

지정된 주소의 낮은 순서 바이트입니다.

$pby

실제 주소를 사용하는 경우 를 제외하고 와 동일합니다. 기본 캐싱 동작을 사용하는 실제 메모리만 읽을 수 있습니다.

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으로 평가됩니다. 단일 등호(=)는 이중 등호(==)와 같습니다. MASM 식 내에서는 부작용 또는 할당을 사용할 수 없습니다.

잘못된 작업(예: 0으로 나누기)으로 인해 "피연산자 오류"가 디버거 명령 창으로 반환됩니다.

== 비교 연산자를 사용하여 반환된 값이 0x409 일치하는지 검사 수 있습니다.

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

MASM 식의 숫자가 아닌 연산자

MASM 식에서 다음 추가 연산자를 사용할 수도 있습니다.

연산자 의미

$fnsucc(FnAddress, RetVal, 플래그)

RetVal 값을 FnAddress 주소에 있는 함수의 반환 값으로 해석합니다. 이 반환 값이 성공 코드로 한정되면 $fnsuccTRUE를 반환합니다. 그렇지 않으면 $fnsucc FALSE를 반환 합니다.

반환 형식이 BOOL, bool, HANDLE, HRESULT 또는 NTSTATUS인 경우 $fnsucc 지정된 반환 값이 성공 코드로 적합한지 여부를 올바르게 이해합니다. 반환 형식이 포인터인 경우 NULL 이외의 모든 값은 성공 코드로 한정됩니다. 다른 형식의 경우 성공 은 플래그 값으로 정의 됩니다. 플래그가 0이면 RetVal의 0이 아닌 값이 성공합니다. 플래그가 1이면 RetVal 값이 성공입니다.

$iment(주소)

로드된 모듈 목록에서 이미지 진입점의 주소를 반환합니다. 주소 는 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)

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을 반환 하지 않습니다 .

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 식 내에서 레지스터 및 의사 레지스터를 사용할 수 있습니다. 모든 레지스터 및 의사 레지스터 앞에 at sign(@)을 추가할 수 있습니다. at 기호를 사용하면 디버거가 값에 더 빠르게 액세스할 수 있습니다. 이 @ 기호는 가장 일반적인 x86 기반 레지스터에는 필요하지 않습니다. 다른 레지스터 및 의사 레지스터의 경우 at 기호를 추가하는 것이 좋지만 실제로는 필요하지 않습니다. 덜 일반적인 레지스터에 대한 at 기호를 생략하면 디버거는 텍스트를 16진수로 구문 분석한 다음 기호로 구문 분석하고 마지막으로 레지스터로 구문 분석하려고 합니다.

마침표(.)를 사용하여 현재 명령 포인터를 나타낼 수도 있습니다. 이 기간 전에 @ 기호를 추가하면 안 되며 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이면 반환할 수 있습니다.

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

MASM 식의 원본 줄 번호

MASM 식 내에서 소스 파일 및 줄 번호 식을 사용할 수 있습니다. 엄중한 악센트(')를 사용하여 이러한 식을 묶어야 합니다. 구문에 대한 자세한 내용은 소스 줄 구문을 참조하세요.

추가 정보

MASM 식과 C++ 식 비교

혼합 식 예제

C++ 숫자 및 연산자

서명 확장

? (식 평가)