가상 메모리를 물리 메모리로 변환

일반적으로 가상 메모리를 물리 메모리로 변환해서 확인해야 할 경우가 거의 없지만 공부하는 차원에서 직접 Virtual address 를 physical address 로 변환하는 것을 Windbg 를 통해 확인해 보고자 합니다.

x86 system 을 기준으로 설명 합니다. x64 의 경우 내용이 좀 다르며 다음 번에 설명하기로 합니다.

Windows 에서는 Virtual address 를 관리하기 위해 page 라는 개념을 사용하는데 일반적인 경우 4KB 의 page 를 관리하게 됩니다. 하지만 Image 를 올리는 것과 같이 큰 Data 를 물리 메모리에 올릴때는 4MB ㅇ의 Large page 라는 것을 사용합니다.

 

일반 page 의 경우

virtual address 0xb742a310 을 기준으로 설명 합니다.

!pte 명령을 사용해서 virtual address 의 정보를 확인할 수 있습니다.

 

7: kd> !pte b742a310
               VA b742a310
PDE at   C0300B74        PTE at C02DD0A8
contains 00BA7963 contains 28857963
pfn ba7        -G-DA--KWEV    pfn 28857      -G-DA-KWEV

 

이 메모리의 내용을 확인해 보도록 하겠습니다.

7: kd> dd b742a310
b742a310  b742a3ac f7123166 b742a730 e51f7cd8
b742a320  00000080 b742a3cc 00000000 b742a2f3

 

자 이제부터 본격적으로 변환 작업을 진행 해 보도록 하겠습니다.

rm ff 명령을 사용해서 register mask 를 변환해서 모든 register 값을 볼 수 있도록 합니다.

kd> rm ff
Last set context:

 

r 명령으로 register 값을 확인 합니다. Page Directory 의 주소를 가지고 있는 cr3 레지스터의 값을 확인 합니다. 여기서는 0x3edb1000 입니다.

7: kd> r
Last set context:
eax=83000aec ebx=84d128d8 ecx=00000000 edx=83000ae4 esi=84d12830 edi=84d128a8
eip=8083df4c esp=b742a224 ebp=b742a264 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010246
fpcw=0000: rn 24 ------  fpsw=0000: top=0 cc=0000 --------  fptw=0000
fopcode=0000  fpip=0000:00000000  fpdp=0000:00000000
st0= 0.000000000000000000000e+0000  st1= 0.000000000000000000000e+0000
st2= 0.000000000000000000000e+0000  st3= 0.000000000000000000000e+0000
st4= 0.000000000000000000000e+0000  st5= 0.000000000000000000000e+0000
st6= 0.000000000000000000000e+0000  st7= 0.000000000000000000000e+0000
mm0=0000000000000000  mm1=0000000000000000
mm2=0000000000000000  mm3=0000000000000000
mm4=0000000000000000  mm5=0000000000000000
mm6=0000000000000000  mm7=0000000000000000
xmm0=0 0 0 0
xmm1=0 0 0 0
xmm2=0 0 0 0
xmm3=0 0 0 0
xmm4=0 0 0 0
xmm5=0 0 0 0
xmm6=0 0 0 0
xmm7=0 0 0 0
cr0=8001003b cr2=00000000 cr3=3edb1000
dr0=00000000 dr1=00000000 dr2=00000000
dr3=00000000 dr6=00000000 dr7=00000000 cr4=000006d9
nt!KeWaitForSingleObject+0x24f:
8083df4c 8919            mov     dword ptr [ecx],ebx  ds:0023:00000000=????????

 

찾고자 하는 virtual address 를 bit 단위로 쪼갭니다.

 

7: kd> .formats b742a310
Evaluate expression:
  Hex:     b742a310
  Decimal: -1220369648
  Octal:   26720521420
  Binary:  10110111 01000010 10100011 00010000
  Chars:   .B..
  Time:    ***** Invalid
  Float:   low -1.16013e-005 high -1.#QNAN
Double:  -1.#QNAN

 

Virtual address 값을 확인해 보면 다음과 같습니다.

 

1011011101 2DD Page Directory index
0000101010 2A Page Table Index
001100010000 310 Offset

 

CR3 에서 얻은 값으로 Page Directory index 로 물리 메모리 확인합니다. dd 는 메모리를 보여주는 명령이고 /p 는 physical memory 를 보여주는 것 입니다.

 

Page directory address + page directory index * size

7: kd> dd /p 3edb1000+2dd*4
3edb1b74  00ba7963 00ba8963 00ba9963 00baa963    !pte 명령의 결과중 첫 번째 Contains 에 있는 값과 동일합니다.
3edb1b84  00bab963 00bac963 00bad963 00bae963

 

가상 메모리에 동일 내용 들어 있는 것을 확인합니다.

7: kd> dd C0300B74
c0300b74  00ba7963 00ba8963 00ba9963 00baa963
c0300b84  00bab963 00bac963 00bad963 00bae963

 

ba7963 을 bit 단위로 확인하여 일반 page 인지 Large page 인지 확인 합니다.

 

7: kd> .formats 00ba7963
Evaluate expression:
  Hex:     00ba7963
  Decimal: 12220771
  Octal:   00056474543
  Binary:  00000000 10111010 01111001 01100011    PS Field가 set 되어 있지 않기 때문에 일반 page 로 4KB 단위
  Chars:   ..yc
  Time:    Fri May 22 19:39:31 1970
  Float:   low 1.71249e-038 high 0
  Double:  6.03786e-317

 

Page Table Index 로 물리메모리 확인 두번째 Contains 에 있는 값과 동일합니다.

Page table address + page table index * size

7: kd> dd /p ba7000+2a*4
00ba70a8  28857963 00000000 00000000 00000000
00ba70b8  00000000 00000000 00000000 00000000

 

마지막으로 Offset 을 사용해서 물리 메모리 확인합니다.

page start address + offset

7: kd> dd /p 28857000+310
28857310  b742a3ac f7123166 b742a730 e51f7cd8
28857320  00000080 b742a3cc 00000000 b742a2f3

 

가상 메모리를 확인하여 동일함을 확인 합니다.

7: kd> dd b742a310
b742a310  b742a3ac f7123166 b742a730 e51f7cd8
b742a320  00000080 b742a3cc 00000000 b742a2f3

 

 

Large page

 

가상메모리 0x83002634 를 확인해 보고자 합니다.

!pte 명령을 통해 정보를 확인해 봅니다. 일반 페이지와는 다르게 LARGE PAGE 라고 나옵니다.

 

7: kd> !pte 83002634
               VA 83002634
PDE at   C0300830        PTE at C020C008
contains 030009E3      contains 00000000
pfn 3000       -GLDA--KWEV    LARGE PAGE pfn 3002

 

0x83002634 에 어떤 값이 있는지 확인해 봅니다.

 

7: kd> dd 83002634
83002634  02110201 03021103 11030211 02110301
83002644  04011102 11020211 01110403 02011104

 

0x83002634 를 Bit 단위로 쪼개 봅니다.

 

7: kd> .formats 83002634
Evaluate expression:
  Hex:     83002634
  Decimal: -2097142220
  Octal:   20300023064
  Binary:  10000011 00000000 00100110 00110100
  Chars:   ..&4
  Time:    ***** Invalid
  Float:   low -3.76597e-037 high -1.#QNAN
  Double:  -1.#QNAN

 

Large Page 이기 때문에 뒤의 22Byte 가 Offset 입니다.

1000001100 20C Page Directory Index
0000000010011000110100 2634 Offset

 

r 명령을 사용해서 cr3 register 값을 확인 합니다. 이전과 동일하게 3edb1000 입니다.

 

7: kd> r
Last set context:
eax=83000aec ebx=84d128d8 ecx=00000000 edx=83000ae4 esi=84d12830 edi=84d128a8
eip=8083df4c esp=b742a224 ebp=b742a264 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010246
fpcw=0000: rn 24 ------  fpsw=0000: top=0 cc=0000 --------  fptw=0000
fopcode=0000  fpip=0000:00000000  fpdp=0000:00000000
st0= 0.000000000000000000000e+0000  st1= 0.000000000000000000000e+0000
st2= 0.000000000000000000000e+0000  st3= 0.000000000000000000000e+0000
st4= 0.000000000000000000000e+0000  st5= 0.000000000000000000000e+0000
st6= 0.000000000000000000000e+0000  st7= 0.000000000000000000000e+0000
mm0=0000000000000000  mm1=0000000000000000
mm2=0000000000000000  mm3=0000000000000000
mm4=0000000000000000  mm5=0000000000000000
mm6=0000000000000000  mm7=0000000000000000
xmm0=0 0 0 0
xmm1=0 0 0 0
xmm2=0 0 0 0
xmm3=0 0 0 0
xmm4=0 0 0 0
xmm5=0 0 0 0
xmm6=0 0 0 0
xmm7=0 0 0 0
cr0=8001003b cr2=00000000 cr3=3edb1000
dr0=00000000 dr1=00000000 dr2=00000000
dr3=00000000 dr6=00000000 dr7=00000000 cr4=000006d9
nt!KeWaitForSingleObject+0x24f:
8083df4c 8919            mov     dword ptr [ecx],ebx  ds:0023:00000000=????????

 

cr3 레지스터에 있는 값인 Page directory address 를 사용해서 Page Table 위치를 찾습니다.

page directory + page directory index * size

 

7: kd> dd /p 3edb1000+20c*4
3edb1830  030009e3 034009e3 038009e3 03c009e3
3edb1840  040009e3 044009e3 048009e3 04c009e3

 

가상 메모리에 동일한 값이 있는지 확인 합니다.

7: kd> dd C0300830       
c0300830  030009e3 034009e3 038009e3 03c009e3
c0300840  040009e3 044009e3 048009e3 04c009e3

 

확인된 내용을 Bit 단위로 쪼개서 내용을 확인해 보니 Large page 로 설정되어 있습니다.

 

7: kd> .formats 030009e3
Evaluate expression:
  Hex:     030009e3
  Decimal: 50334179
  Octal:   00300004743
  Binary:  00000011 00000000 00001001 11100011    Large Page
  Chars:   ....
  Time:    Fri Aug 06 22:42:59 1971
  Float:   low 3.76272e-037 high 0
  Double:  2.48684e-316

 

물리 메모리 확인 PS field가 1로 설정되어 있기 때문에 직접 물리 메모리를 가리키는 것입니다. 즉 0x03000000 이 시작 주소 입니다.

Page 시작 address + offset

7: kd> dd /p 03000000 + 2634
03002634  02110201 03021103 11030211 02110301
03002644  04011102 11020211 01110403 02011104

 

Large page 의 처음에서 확인한 Virtual address 의 내용과 일치 합니다.