본문 바로가기

Debugging/Windows

Understanding of Address(Segmentation and Paging)

 

 

주소에는 다음과 같은 기준이 사용

  • Code
  • Stack
  • Data

 

Code의 몇 번지, Data의 몇 번지가 정확한 표현

Code, Stack, Data 별로 별도의 영역이 지정

 

Program을 동작(해석)하는 역할은 CPU(Microprocessor)가 담당하며, 해석되는 항목 중 하나가 Address

CPU 안에는 Address를 이해하기 위해서 몇 가지 Register가 위치 : CS(Code Segment), SS(Stack Segment), DS(Data Segment) Register

Address 표현 할 때는 Segment Register를 반드시 활용해야 함

CS의 0x1234 offset, SS의 0x5678 offset과 같은 표현이 정확한 주소 표현

어떤 Segment는 정의한 후 Base Address로부터 얼마나 떨어져 있는지 Offset으로 표현

 

 

위 그림은 실제로 CS:[1234]와 같은 문법으로 표현 → 이러한 표현 방식을 Segmentation

Segmentation 방식을 채택하는 목적은 Segment간 서로 다른 성격 때문에 Protected Mode를 사용하기 위함

예를 들어, Code Segment 영역을 넘어서는 위치로 Control을 변경하는 경우 제한

 

Segment에는 Base Address와 Size 정의가 필요

 

예를 들어, DS:[10]은 DS의 Base Address에 offset인 10을 더한 값이 실제 Address → 이를 Linear Address(선형 주소)라고 부름

DS:[offset] = DS의 Base Address + Offset = Linear Address

 

 

Windows의 사용 방식(x64 기준)

x64에서는 Offset 또한 64bit까지 표현 가능

문제는 CS, DS, SS + Offset(64bit) 를 계산한 값인 Linear Address도 64bit가 될 수 있는데 Windows는 Offset과 Linear Address가 모두 64bit를 선택

이 말인 즉슨, CS, DS, SS의 Base Address를 0x0으로 이용

즉, Offset과 Linear Address를 동일한 값으로 계산

CS, DS, SS가 아닌 다른 Segment Register들(FS, GS, ES)은 Base Address가 0x0이 아닐 수 있음

CS:[123456789ABCDEF0] = DS:[123456789ABCDEF0] = SS:[123456789ABCDEF0] = 123456789ABCDEF0(Linear Address)

 

※ 결국, Virtual Address는 Segmentation Unit을 통해 Linear Address로 해석되며, Windows의 경우에는 Segment의 Base Address를 0x으로 사용하기 때문에 Virtual Address와 Linear Address가 동일

 

예제) Segment Register와 종류 확인 방법

3: kd> r
rax=000000000003f801 rbx=ffff8f8035180180 rcx=0000000000000001
rdx=000000b000000000 rsi=0000000000000002 rdi=ffff8f8035190100
rip=fffff80751e79601 rsp=fffff88600c45748 rbp=0000000000000000
 r8=000000000000002a  r9=ffffd282297c6000 r10=0000000000000014
r11=0000000000000000 r12=ffffd2822a285100 r13=0000000000000000
r14=00000000915f8d00 r15=00000000915acea1
iopl=0         nv up di pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000002
nt!DbgBreakPointWithStatus+0x1:
fffff807`51e79601 c3              ret
 
3: kd> dg 0x10
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P  Lo 0000029b
 
0: kd> dg 18
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0018 00000000`00000000 00000000`00000000 Data RW Ac 0 Bg By P  Nl 00000493
 
0: kd> dg 2b
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
002B 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

 

CPU가 Memory와 주변장치를 읽고 쓸 수 있기 위해서는 Physical Address(=Real Address)가 필요

CPU 바깥 쪽을 접근하기 위해서는 Physical Address 사용

Virtual Address(=Linear Address)는 CPU 내에서만 사용되는 주소

 

그렇다면, Virtual Address(=Linear Address)가 어떻게 Physical Address로 변환되는지를 확인해야 함

이전 과정을 Segmentation이라고 불렀다면, Virtual Address → Physical Address로 변환하는 과정을 Paging이라고 부름

 

 

x64 에서는 64bit를 모두 Address로 해석할 수 없고, 48bit 까지만 해석 가능하며 나머지 16bit는 부호 확장 개념으로 사용

따라서, 64bit라고 하면, Address Range가 0000 0000 0000 0000 ~ FFFF FFFF FFFF FFFF

이를 구분하기 위해서 47번째 bit가 0이면 양수, 1이면 음수로 구분하여 관리

47번째 bit 까지 구분하면 Address Range는 다음과 같이 더 상세하게 구분

0x0000 0000 0000 0000 ~ 0x0000 7FFF FFFF FFFF : 47번째 bit가 0인 경우 → User Level Address Space

0xFFFF 8000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF : 47번째 bit가 1인 경우 → Kernel Level Address Space

※ Windows OS의 경우에는 Interlocked Opcode(CPU 수준의 동기화)를 지원하기 위해서 실제로는 44bit까지만 지원

 

간단한 예제)

Linear Address(Virtual Address)가 0x1234(16bit)인 경우,

 

실제 예제)

 

 

Page map level 4를 가리키는 CR3 Format 

https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html

 

※ ESXi OS인 VMKernel은 다를까?

ESXi OS인 VMKernel도 Windows OS와 다를 수 없다. 기존 x64 CPU Architecture 기반으로 동작하기 때문에 동일한 방식으로 이해할 수 없음

 

그렇다면, CPU(Microprocessor)는 왜 이렇게 Address 변환 과정을 가지는가?

  • 서로 다른 Process로부터 각자의 Physical Memory 보호 목적 : CR3 Register가 가리키는 Table 주소를 Process 별로 다르게 하여 각 Process 별 사용하는 Physical Memory 보호 

 

  • 실제 보유하는 Physical Memory 보다 더 큰 공간을 요구하는 Program을 동작시키기 위해서

 

 

PTE는 Page Table Entry로 Physical Memory의 Page Number를 획득하기 위해 사용하는 Entry

 

PTE 상세 Field

 

PTE 중 가장 중요한 Field는 Valid Field

Valid Field가 0이면 Page Fault Exception 발생, 사용되고 있는 PTE는 1

Page Frame Number의 경우에는 Windows가 별도로 관리하는 PFN Database에서 참조하여 PTE 구성

 

Process의 Memory 사용 현황 확인

VAD(Virtual Address Descriptor) 사용

1: kd> !process 0 1 notepad.exe
PROCESS ffff9f87130ac080
    SessionId: 2  Cid: 110c    Peb: bc6b7ee000  ParentCid: 0d8c
    DirBase: 55d1a000  ObjectTable: ffffcb83a638e540  HandleCount: 295.
    Image: notepad.exe
    VadRoot ffff9f8713b63090 Vads 122 Clone 0 Private 767. Modified 8. Locked 0.
    DeviceMap ffffcb83a465cb90
    Token                             ffffcb83a64c1770
    ElapsedTime                       00:01:36.761
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         298544
    QuotaPoolUsage[NonPagedPool]      17112
    Working Set Sizes (now,min,max)  (4994, 50, 345) (19976KB, 200KB, 1380KB)
    PeakWorkingSetSize                4921
    VirtualSize                       2101433 Mb
    PeakVirtualSize                   2101435 Mb
    PageFaultCount                    5096
    MemoryPriority                    FOREGROUND
    BasePriority                      8
    CommitCharge                      921
 
1: kd> .process ffff9f87130ac080
Implicit process is now ffff9f87`130ac080
WARNING: .cache forcedecodeuser is not enabled
 
1: kd> .thread ffff9f871310e080
Implicit thread is now ffff9f87`1310e080
 
## Start, End에 있는 값은 12bit(offset)을 제외한 Virtual Page Number
## 예를 들어서 Start가 17ec0이고 End가 17ec0인 경우 실제 Start Address는 17ec0 000이고, End Address는 17ec0 fff --> 이 경우는 총 1 Page를 의미
 
1: kd> !vad ffff9f8713b63090
VAD             Level         Start             End              Commit
ffff9f8712d384e0  6           17ec0           17ec0               1 Private      READWRITE         
ffff9f8713a21280  5           7ffe0           7ffe0               1 Private      READONLY          
ffff9f8713a21370  4           7ffe3           7ffe3               1 Private      READONLY          
ffff9f8713a21500  5         bc6b4e0         bc6b55f              20 Private      READWRITE         
ffff9f8713a21140  3         bc6b600         bc6b7ff              11 Private      READWRITE         
ffff9f8713a21a00  5         bc6b900         bc6b97f              20 Private      READWRITE         
ffff9f8712d36730  4         bc6b980         bc6b9ff              20 Private      READWRITE         
ffff9f8712d36a50  6         bc6ba00         bc6ba7f              20 Private      READWRITE         
ffff9f8712d38030  5         bc6bb00         bc6bb7f              20 Private      READWRITE         
ffff9f8713b62870  2        23857ec0        23857ecf               0 Mapped       READWRITE          Pagefile section, shared commit 0x10
...
ffff9f8713b65d90  4       7ffaeee10       7ffaeee3d               3 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\imm32.dll
ffff9f8713b63130  5       7ffaeee70       7ffaef05c              16 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\ntdll.dll
 
Total VADs: 122, average level: 6, maximum depth: 7
Total private commit: 0x304 pages (3088 KB)
Total shared commit:  0x15eb pages (22444 KB)

 

Virtual Address에 있는 Memory 내용 확인

 

PTE 찾기

※ PTE는 64bit

1: kd> !pte 17ec0000
                                           VA 0000000017ec0000
PXE at FFFF884422110000    PPE at FFFF884422000000    PDE at FFFF8844000005F8    PTE at FFFF8800000BF600 >>>
contains 8A00000004593867  contains 0000000000000000
pfn 4593      ---DA--UW-V  contains 0000000000000000
not valid
  
1: kd> dq FFFF8800000BF600
ffff8800`000bf600  81000000`5930a847 00000000`00000000
ffff8800`000bf610  00000000`00000000 00000000`00000000
ffff8800`000bf620  00000000`00000000 00000000`00000000
ffff8800`000bf630  00000000`00000000 00000000`00000000
ffff8800`000bf640  00000000`00000000 00000000`00000000
ffff8800`000bf650  00000000`00000000 00000000`00000000
ffff8800`000bf660  00000000`00000000 00000000`00000000
ffff8800`000bf670  00000000`00000000 00000000`00000000
 
1: kd> dt nt!_MMPTE ffff8800`000bf600 -r2
   +0x000 u                : <unnamed-tag>
      +0x000 Long             : 0x81000000`5930a847
      +0x000 VolatileLong     : 0x81000000`5930a847
      +0x000 Hard             : _MMPTE_HARDWARE >>>
         +0x000 Valid            : 0y1 >>>
         +0x000 Dirty1           : 0y1
         +0x000 Owner            : 0y1
         +0x000 WriteThrough     : 0y0
         +0x000 CacheDisable     : 0y0
         +0x000 Accessed         : 0y0
         +0x000 Dirty            : 0y1
         +0x000 LargePage        : 0y0
         +0x000 Global           : 0y0
         +0x000 CopyOnWrite      : 0y0
         +0x000 Unused           : 0y0
         +0x000 Write            : 0y1
         +0x000 PageFrameNumber  : 0y000000000000000001011001001100001010 (0x5930a)
         +0x000 ReservedForHardware : 0y0000
         +0x000 ReservedForSoftware : 0y0000
         +0x000 WsleAge          : 0y0001
         +0x000 WsleProtection   : 0y000
         +0x000 NoExecute        : 0y1
...

 

Physical Address로 변환 및 조회

※ Virtual Address에 있는 Memory 내용과 Physical Address에 있는 Memory 내용이 동일한 것을 확인 

[Virtual Address]
0000000017ec0 000
 
[Page Table Entry]
81000000`5930a847
 
[Physical Address]
12번째 bit부터 39번째 bit
아래 005930a
00`5930a 847(12bit)
 
00`5930a + Virtual Address의 12bit(000)
00`5930a000
 
1: kd> !db 00`5930a000
#5930a000 32 00 00 00 f8 3d 8d 60-28 81 a7 4a a4 28 f5 5e 2....=.`(..J.(.^
#5930a010 49 26 72 91 00 00 08 00-0b 00 00 00 54 00 65 00 I&r.........T.e.
#5930a020 78 00 74 00 20 00 45 00-64 00 69 00 74 00 6f 00 x.t. .E.d.i.t.o.
#5930a030 72 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 r...............
#5930a040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#5930a050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#5930a060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#5930a070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

 

 

'Debugging > Windows' 카테고리의 다른 글

Thread State Transition  (0) 2023.06.05
Registry  (0) 2023.05.16
Security  (0) 2023.05.03
Objects and Handles  (2) 2023.04.15
프로세스(EPROCESS, KPROCESS, PEB, HANDLE...) - (2)  (0) 2023.02.05