Virtuális – fizikai címfordítás Windows alatt x64-en II.

Az előző bejegyzésben megnéztük, hogy hogyan lehet egy folyamat virtuális címéhez megtalálni, hogy milyen fizikai cím tartozik hozzá. Most egy picit nézzük meg részletesebben hogyan megy a címfordítás, milyen adatstruktúrákat használ a kernel és az alatta levő hardver.

Az Intel Software Developer Manualban 3A-ban megtalálhatjuk, hogy hogyan működik a címfordítás x64-en. Négy szintű laptáblát használ a processzor:

image 

Jelenleg 48 bit van kihasználva a 64-ből. 4×9-et használnak arra, hogy megtaláljuk a keresett fizikai lapot a különböző szintű laptábla struktúrákkal (Page Map Level 4 – PML4, Page Directory Pointer – PDP, Page Directory – PD, Page Table – PT), a maradék 12 pedig a lapon belüli offset (4KB-os lapok használata esetén). Ugyanitt megtalálható, hogy az egyes táblákban az elemek hogyan épülnek fel. Itt most csak a PTE (Page Table Entry) szerkezetét másolom be:

image

Az utolsó 12 bit mindenféle státusz bit (Dirty, Accessed, User/Supervisor, Read/Write, Present, stb.), a 12-39 bitek pedig a fizikai lapot jelölik ki.

Nézzük akkor meg, hogy mit látunk ezekből egy kernel debuggerben Windowson. Először megnézem, hogy melyik folyamat kontextusában vagyunk a debugger elindítása után:

lkd> !process
PROCESS fffffa8004855560
    SessionId: 1  Cid: 0bbc    Peb: 7fffffd3000  ParentCid: 051c
    DirBase: 1e3a0000  ObjectTable: fffff8800faa0310  HandleCount:  99.
    Image: windbg.exe
    VadRoot fffffa8007e37340 Vads 95 Clone 0 Private 4378. Modified 163. Locked 1.

Kéne egy érvényes logikai cím ennek a folyamatnak a tartományában. Ha pl. megnézzük a folyamat részletes adatait, akkor ott kilistázza a folyamat szálait, és felhasználhatjuk, hogy mi volt azoknak a kezdőcíme:

lkd> !process fffffa8004855560
PROCESS fffffa8004855560
    SessionId: 1  Cid: 0bbc    Peb: 7fffffd3000  ParentCid: 051c
    DirBase: 1e3a0000  ObjectTable: fffff8800faa0310  HandleCount:  98.
    Image: windbg.exe
    VadRoot fffffa8007e37340 Vads 95 Clone 0 Private 4388. Modified 163. Locked 1.
    DeviceMap fffff8800887d6f0
    Token                             fffff88008470ab0
    ElapsedTime                       01:08:28.747
    UserTime                          00:00:02.964
    KernelTime                        00:00:00.156
    QuotaPoolUsage[PagedPool]         208280
    QuotaPoolUsage[NonPagedPool]      9232
    Working Set Sizes (now,min,max)  (9323, 50, 345) (37292KB, 200KB, 1380KB)
    PeakWorkingSetSize                9666
    VirtualSize                       118 Mb
    PeakVirtualSize                   119 Mb
    PageFaultCount                    27558
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      4753

        THREAD fffffa8007da2620  Cid 0bbc.0b28  Teb: 000007fffffde000 Win32Thread: fffff900c1f2f920 WAIT: (WrUserRequest) UserMode Non-Alertable
            fffffa8007ec60f0  SynchronizationEvent
        Not impersonating
        DeviceMap                 fffff8800887d6f0
        Owning Process            fffffa8004855560       Image:         windbg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      408493         Ticks: 10 (0:00:00:00.156)
        Context Switch Count      45544                 LargeStack
        UserTime                  00:00:01.435
        KernelTime                00:00:06.723
        Win32 Start Address 0x000000013f623888
        Stack Init fffffa6017236db0 Current fffffa60172368a0
        Base fffffa6017237000 Limit fffffa601722c000 Call 0
        Priority 10 BasePriority 8 PriorityDecrement 0 IoPriority 2 PagePriority 5
...

Van tehát egy címünk, nézzük meg mi van rajta:

lkd> db 000000013f623888
00000001`3f623888  48 83 ec 28 e8 0b 05 00-00 48 83 c4 28 e9 62 fd  H..(.....H..(.b.
00000001`3f623898  ff ff cc cc cc cc cc cc-cc cc cc cc cc cc 66 66  ..............ff
00000001`3f6238a8  0f 1f 84 00 00 00 00 00-48 3b 0d 49 68 00 00 75  ........H;.Ih..u
00000001`3f6238b8  11 48 c1 c1 10 66 f7 c1-ff ff 75 02 f3 c3 48 c1  .H...f....u...H.
00000001`3f6238c8  c9 10 e9 89 05 00 00 cc-cc cc cc cc cc cc ff 25  ...............%
00000001`3f6238d8  a4 e0 f8 ff cc cc cc cc-cc cc ff 25 70 e0 f8 ff  ...........%p...
00000001`3f6238e8  cc cc cc cc cc cc ff 25-0c e0 f8 ff cc cc cc cc  .......%........
00000001`3f6238f8  cc cc ff 25 f8 df f8 ff-cc cc cc cc cc cc cc cc  ...%............

Ezt lehet később összehasonlításhoz felhasználni.

A !pte parancs megmutatja egy virtuális címhez tartozó laptábla bejegyzéseket:

lkd> !pte 000000013f623888
                                 VA 000000013f623888
PXE @ FFFFF6FB7DBED000     PPE at FFFFF6FB7DA00020    PDE at FFFFF6FB40004FD8    PTE at FFFFF680009FB118
contains 03C00000B1357867  contains 03B0000118A98867  contains 02800000D6DDA867  contains 02800000746FE025
pfn b1357      ---DA--UWEV  pfn 118a98     ---DA--UWEV  pfn d6dda      ---DA--UWEV  pfn 746fe      ----A--UREV

Látszik a négy hierarchia szint. A harmadik sorban a laptábla elemek virtuális címe található (ezek kernel módú címtartományban vannak, hogy más folyamat ne tudja módosítani). A negyedik sor a tartalmukat mutatja (ezek mind 64 bites elemek). Az egyes elemeket a fenti inteles kép alapján dekódolni is tudnánk, de ezt az utolsó sorban a WinDbg is megteszi nekünk. Kiírja mindig a következő szintű elem fizikai lapszámát (fizikai címet kell tartalmaznia, hisz éppen ezek végzik a címfordítást:), valamint a státusz biteket. Itt picit más sorrendben szerepelnek a bitek, de egy-az-egy megfeleltetés van a hardveres bitekkel (pl. itt a R/W bit a 2-es, míg az Intel doksiban az 1-es).

Ezek alapján tehát ehhez a virtuális címhez a 746fe számú memórialap tartozik. Ezen belül az eltolást ugye a virtuális cím utolsó 12 bitje adja meg, így a keresett fizikai cím a 746fe888. Ellenőrizzük is le:

lkd> !db 746fe888
#746fe888 48 83 ec 28 e8 0b 05 00-00 48 83 c4 28 e9 62 fd H..(.....H..(.b.
#746fe898 ff ff cc cc cc cc cc cc-cc cc cc cc cc cc 66 66 ..............ff
#746fe8a8 0f 1f 84 00 00 00 00 00-48 3b 0d 49 68 00 00 75 ........H;.Ih..u
#746fe8b8 11 48 c1 c1 10 66 f7 c1-ff ff 75 02 f3 c3 48 c1 .H...f....u...H.
#746fe8c8 c9 10 e9 89 05 00 00 cc-cc cc cc cc cc cc ff 25 ...............%
#746fe8d8 a4 e0 f8 ff cc cc cc cc-cc cc ff 25 70 e0 f8 ff ...........%p...
#746fe8e8 cc cc cc cc cc cc ff 25-0c e0 f8 ff cc cc cc cc .......%........
#746fe8f8 cc cc ff 25 f8 df f8 ff-cc cc cc cc cc cc cc cc ...%............

Telitalálat:)

Nézzük még meg, hogy mit tárol a Windows egy fizikai memórialapról. A PFN (Page Frame Number) adatbázisban különböző láncolt listákon tartja nyilván a lapok állapotát, ezekből a megfelelő elemet a !pfn parancs mutatja meg:

lkd> !pfn 746fe 
    PFN 000746FE at address FFFFFA80015D4FA0
    flink       0000039F  blink / share count 00000001  pteaddress FFFFF88009E9EDD0
    reference count 0001    used entry count  0000      Cached    color 0   Priority 6
    restore pte FA8003E34B080460  containing page        074D91  Active      P      
      Shared         

Látszik, hogy ez egy megosztott lap, ami jelenleg aktív, azaz legalább egy folyamat munkakészletében szerepel.

Címfordítás kézzel

Zárásként még végezzük el a címfordítást kézzel a !pte és !vtop parancsok segítsége nélkül. A 000000013f623888 virtuális címet akarjuk fizikai címmé fordítani, ehhez írjuk fel bináris formában:

lkd> .formats 000000013f623888
Evaluate expression:
  Hex:     00000001`3f623888
  Decimal: 5358368904
  Binary:  00000000 00000000 00000000 00000001 00111111 01100010 00111000 10001000

Ezek alapján az egyes index értékek, amiket majd használni kell:

  • offset: 100010001000
  • PTE:    000100011
  • PDE:    111111011
  • PPE:    000000100 (ez az Intel doksiban a PDPE)
  • PXE:    000000000 (ez az Intel doksiban a PML4E)

A folyamathoz tartozó PML4 legelső elemét a folyamat struktúra BaseDir mezője tartalmazza, ez az aktuális folyamat esetén 1e3a0000. Ehhez kell hozzáadni a virtuális címből származó indexet, mely jelen esetben 000000000, így az eredmény 1e3a0000. Ez egy fizikai cím, és az ezt követő 64 bitre vagyunk kíváncsiak (a !dq 64 bites szavakat jelenít meg, az L1 pedig azt mondja, hogy csak az elsőt írja ki):

lkd> !dq 1e3a0000 L1
#1e3a0000 03c00000`b1357867

(ha ezt most gyorsan összehasonlítjuk a !pfn kimenetével, akkor látjuk, hogy jó nyomon vagyunk)

Ez a PML4 bejegyzése, ami megmutatja azt a PDP táblát, amit használnunk kell a következő indexszel. Már tudjuk, hogy a 12-39 bitek tartalmazzák a PFN-t, így a megfelelő PDP tábla kezdete a b1357000 címen található.

lkd> !dq 0xb1357000
#b1357000 05a00001`1aa1b867 01900000`d73e1867
#b1357010 00000000`00000000 00000000`00000000
#b1357020 03b00001`18a98867 00000000`00000000
#b1357030 00000000`00000000 00000000`00000000
#b1357040 00000000`00000000 00000000`00000000
#b1357050 00000000`00000000 00000000`00000000
#b1357060 00000000`00000000 00000000`00000000
#b1357070 00000000`00000000 00000000`00000000

Itt sorakoznak a bejegyzések egymás mellett, látszik, hogy jelenleg nincs még túl sok kitöltve. Nekünk a 4-edik kell (100 decimális számrendszerben 4), azaz a keresett bejegyzés a 03b00001`18a98867. Ebből a virtuális címhez tartozó PD tábla PFN-je 118098.

Számoljuk ki ebből és a PDE indexből a PDE címét, és nézzük meg a tartalmát:

kd> ? 118a98 * 0x1000 + 0y111111011 * 8
Evaluate expression: 4708732888 = 00000001`18a98fd8
lkd> !dq 118a98fd8 L1
#118a98fd8 02800000`d6dda867

A ? kiértékeli a mögötte lévő kifejezést. Először kiszámoltuk a címet a PFN-ből, majd hozzáadtuk az index * 8-at (mivel egy bejegyzés 8 byte hosszú). A 0x hexa számot jelöl, a 0y binárisat. A kapottak alapján a PT címe: d6dda

lkd> ? d6dda000 + 8 * 0y000100011
Evaluate expression: -690118376 = ffffffff`d6dda118
lkd> !dq d6dda118 L1
#d6dda118 02800000`746fe025

Ez pedig már a fizikai lap címe, ehhez már csak az offsetet kell hozzáadni. Az eredmény: 746fe888. Tökéletes, az elején a !pte parancs segítségével is ezt kaptuk, úgyhogy nem számoltuk el.

Nem is olyan ördöngösség ez, a megfelelő leírásokkal és egy kernel debuggerrel végig lehet követni a címfordítás menetét:-)

Advertisements
Kategória: Opre | Közvetlen link a könyvjelzőhöz.

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s