가상 주소를 실제 주소로 변환

대부분의 디버거 명령은 실제 주소가 아닌 가상 주소를 입력 및 출력으로 사용합니다. 그러나 실제 주소를 사용하는 것이 유용할 수 있는 경우가 있습니다.

가상 주소를 실제 주소로 변환하는 방법에는 !vtop 확장을 사용하고 !pte 확장을 사용하는 두 가지 방법이 있습니다.

Windows의 가상 주소에 대한 개요는 가상 주소 공간을 참조하세요.

!vtop을 사용하여 주소 변환

MyApp.exe 프로세스가 실행 중인 대상 컴퓨터를 디버깅하고 가상 주소 0x0012F980 조사한다고 가정합니다. 다음은 !vtop 확장과 함께 사용하여 해당 실제 주소를 결정하는 절차입니다.

!vtop을 사용하여 가상 주소를 실제 주소로 변환

  1. 16진수로 작업하고 있는지 확인합니다. 필요한 경우 N 16 명령을 사용하여 현재 베이스를 설정합니다.

  2. 주소의 바이트 인덱 스 확인 이 숫자는 가상 주소의 가장 낮은 12비트와 같습니다. 따라서 가상 주소 0x0012F980 바이트 인덱스가 0x980.

  3. !process 확장을 사용하여 주소의 디렉터리 베이스를 결정합니다.

    kd> !process 0 0
    **** NT ACTIVE PROCESS DUMP ****
    ....
    PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
     DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
        Image: MyApp.exe
    
  4. 디렉터리 베이스의 페이지 프레임 번호를 결정합니다. 3개의 후행 16진수 0이 없는 디렉터리 베이스일 뿐입니다. 이 예제에서는 디렉터리 베이스가 0x098FD000 페이지 프레임 번호가 0x098FD.

  5. !vtop 확장을 사용합니다. 이 확장의 첫 번째 매개 변수는 페이지 프레임 번호여야 합니다. !vtop의 두 번째 매개 변수는 해당 가상 주소여야 합니다.

    kd> !vtop 98fd 12f980
    Pdi 0 Pti 12f
    0012f980 09de9000 pfn(09de9)
    

    마지막 줄에 표시된 두 번째 숫자는 실제 페이지 시작의 실제 주소입니다.

  6. 페이지 시작 부분에 바이트 인덱스(0x09DE9000 + 0x980 = 0x09DE9980)를 추가합니다. 원하는 실제 주소입니다.

각 주소에 메모리를 표시하여 이 계산이 올바르게 수행되었는지 확인할 수 있습니다. !d\* 확장은 지정된 실제 주소에 메모리를 표시합니다.

kd> !dc 9de9980
# 9de9980 6d206e49 726f6d65 00120079 0012f9f4 In memory.......
# 9de9990 0012f9f8 77e57119 77e8e618 ffffffff .....q.w...w....
# 9de99a0 77e727e0 77f6f13e 77f747e0 ffffffff .'.w>..w.G.w....
# 9de99b0 .....

d* (Display Memory) 명령은 가상 주소를 인수로 사용합니다.

kd> dc 12f980
0012f980  6d206e49 726f6d65 00120079 0012f9f4  In memory.......
0012f990  0012f9f8 77e57119 77e8e618 ffffffff  .....q.w...w....
0012f9a0  77e727e0 77f6f13e 77f747e0 ffffffff  .'.w>..w.G.w....
0012f9b0  .....

결과는 동일하기 때문에 실제 주소 0x09DE9980 실제로 가상 주소 0x0012F980 해당한다는 것을 나타냅니다.

!pte를 사용하여 주소 변환

다시 말하지만, MyApp.exe 프로세스에 속하는 가상 주소 0x0012F980 조사하고 있다고 가정합니다. 다음은 !pte 확장과 함께 해당 물리적 주소를 결정하는 데 사용하는 절차입니다.

!pte를 사용하여 가상 주소를 실제 주소로 변환

  1. 16진수로 작업하고 있는지 확인합니다. 필요한 경우 N 16 명령을 사용하여 현재 베이스를 설정합니다.

  2. 주소의 바이트 인덱 스 확인 이 숫자는 가상 주소의 가장 낮은 12비트와 같습니다. 따라서 가상 주소 0x0012F980 바이트 인덱스가 0x980.

  3. 프로세스 컨텍스트를 원하는 프로세스로 설정합니다.

    kd> !process 0 0
    **** NT ACTIVE PROCESS DUMP ****
    ....
    PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
        DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
        Image: MyApp.exe
    
    kd> .process /p ff779190
    Implicit process is now ff779190
    .cache forcedecodeuser done
    
  4. 가상 주소와 함께 !pte 확장을 인수로 사용합니다. 두 열에 정보가 표시됩니다. 왼쪽 열은 이 주소에 대한 PDE(페이지 디렉터리 항목)를 설명합니다. 오른쪽 열은 PTE(페이지 테이블 항목)를 설명합니다.

    kd> !pte 12f980
                   VA 0012f980
    PDE at   C0300000        PTE at C00004BC
    contains 0BA58067      contains 09DE9067
    pfn ba58 ---DA--UWV    pfn 9de9 ---DA--UWV
    
  5. 오른쪽 열의 마지막 행을 확인합니다. 표기법 "pfn 9de9"가 나타납니다. 0x9DE9 숫자는 이 PTE의 PFN( 페이지 프레임 번호 )입니다. 페이지 프레임 번호를 0x1000 곱합니다(예: 왼쪽으로 12비트 이동). 0x09DE9000 결과는 페이지 시작의 실제 주소입니다.

  6. 페이지 시작 부분에 바이트 인덱스(0x09DE9000 + 0x980 = 0x09DE9980)를 추가합니다. 원하는 실제 주소입니다.

이는 이전 메서드에서 가져온 것과 동일한 결과입니다.

직접 주소 변환

!ptovpte 확장은 가상 주소를 실제 주소로 변환하는 가장 빠른 방법을 제공하지만 이 변환도 수동으로 수행할 수 있습니다. 이 프로세스에 대한 설명은 가상 메모리 아키텍처의 세부 정보 중 일부에 대해 설명합니다.

메모리 구조는 프로세서 및 하드웨어 구성에 따라 크기가 달라집니다. 이 예제는 PAE(물리적 주소 확장)를 사용하도록 설정하지 않은 x86 시스템에서 가져옵니다.

0x0012F980 다시 가상 주소로 사용하면 먼저 직접 또는 .formats(숫자 형식 표시) 명령을 사용하여 이진 주소로 변환해야 합니다.

kd> .formats 12f980
Evaluate expression:
  Hex:     0012f980
  Decimal: 1243520
  Octal:   00004574600
  Binary:  00000000 00010010 11111001 10000000
  Chars:   ....
  Time:    Thu Jan 15 01:25:20 1970
  Float:   low 1.74254e-039 high 0
  Double:  6.14381e-318

이 가상 주소는 세 필드의 조합입니다. 비트 0~11은 바이트 인덱스입니다. 비트 12~21은 페이지 테이블 인덱스입니다. 비트 22~31은 페이지 디렉터리 인덱스입니다. 필드를 구분하면 다음이 있습니다.

0x0012F980  =  0y  00000000 00   010010 1111   1001 10000000

그러면 가상 주소의 세 부분이 노출됩니다.

  • 페이지 디렉터리 인덱스 = 0y0000000000 = 0x0

  • 페이지 테이블 인덱스 = 0y010010111 = 0x12F

  • 바이트 인덱스 = 0y100110000000 = 0x980

그런 다음 시스템에 대한 세 가지 추가 정보가 필요합니다.

  • 각 PTE의 크기입니다. PAE가 아닌 x86 시스템에서는 4바이트입니다.

  • 페이지의 크기입니다. 0x1000 바이트입니다.

  • PTE_BASE 가상 주소입니다. PAE가 아닌 시스템에서는 이 0xC0000000.

이 데이터를 사용하여 PTE 자체의 주소를 계산할 수 있습니다.

PTE address   =   PTE_BASE  
                + (page directory index) * PAGE_SIZE
                + (page table index) * sizeof(MMPTE)
              =   0xc0000000
                + 0x0   * 0x1000
                + 0x12F * 4
              =   0xC00004BC

PTE의 주소입니다. PTE는 32비트 DWORD입니다. 해당 내용을 검사합니다.

kd> dd 0xc00004bc L1
c00004bc  09de9067

이 PTE에는 0x09DE9067 값이 있습니다. 다음 두 필드로 구성됩니다.

  • PTE의 하위 12비트는 상태 플래그입니다. 이 경우 이러한 플래그는 0x067 같거나 0y0000001100111에 해당합니다. 상태 플래그에 대한 설명은 !pte 참조 페이지를 참조하세요.

  • PTE의 상위 20비트는 PTE의 PFN( 페이지 프레임 번호 )과 같습니다. 이 경우 PFN은 0x09DE9.

실제 페이지의 첫 번째 실제 주소는 PFN에 0x1000 곱한 것입니다(왼쪽 12비트 이동). 바이트 인덱스는 이 페이지의 오프셋입니다. 따라서 찾고 있는 실제 주소는 0x09DE9000 + 0x980 = 0x09DE9980. 이는 이전 메서드에서 얻은 것과 동일한 결과입니다.