mennyire fontos manapság annak biztosítása, hogy minden DLL-nek ne legyen ütköző báziscíme?

Raymond

január 20, 2017

a régi időkben, az egyik dolog, amit arra buzdítottak, hogy tegye meg a DLL-eket, hogy mindegyiknek ne legyen átfedő címtartománya, elkerülve ezzel a futásidejű áthelyezés költségeit. Ez ma is fontos?

ez a helyzet egy újabb demonstráció arról, hogy mennyire fontos, hogy a jó tanácsokhoz ésszerű indokok tartozzanak, így meg tudja mondani, mikor válik rossz tanácsgá.

az újraindítás indoklása a következő: Ha egy DLL-t a kívánt alapcímre töltenek be, akkor a kép közvetlenül a backing store-ból lapozható, javítás nélkül. Ez azt jelenti, hogy az oldalak megoszthatók a folyamatok között, mivel minden folyamat azonos példányt kap. (Természetesen a megosztás leáll, ha valaki ír az oldalra, és más másolatot készít a megosztott példánytól.)

ha egy DLL nem tölthető be a kívánt címre, akkor a kép áthelyezésre kerül, és a teljes áthelyezett DLL-t az oldalfájl támogatja.1 Ez egy viszonylag drága művelet, mivel a DLL-t lemezről kell olvasni és rögzíteni kell, és az oldalfájl elkötelezettsége merül fel annak biztosítása érdekében, hogy legyen hely a rögzített oldalak írására. Továbbá, ha két folyamat áthelyezi a DLL-t, és véletlenül áthelyezi őket ugyanarra a helyre, a Windows NT nem próbálja meg megosztani az áthelyezett képeket. Az oldalfájlban több példány lesz.

ennek a dinamikus áthelyezésnek az ára az, amit az újraindítás megpróbál elkerülni. Nevezzük ezt ” áthelyezési büntetésnek.”

írja be az ASLR-t.

az ASLR a DLL-eket pszeudo-véletlen címekre tölti be. Következésképpen a DLL csak meglepő véletlen egybeesés esetén töltődik be az előnyben részesített alapcímére.

Oké, menjünk vissza az indokláshoz, hogy lássuk, érvényes-e még.

áthelyezési büntetést von maga után az a DLL, amelyet a preferált alapcímtől távol töltenek be? Ha belegondolunk, az ASLR azt jelenti, hogy egyetlen DLL sem töltődik be a kívánt címre, de azt is láttuk, hogy a kernel ehhez szállást készít, így az ASLR-nek alávetett DLL-ek továbbra is megoszthatják az oldalakat, és ezt anélkül teszi, hogy a teljes DLL-t áthelyeznék a kezdeti terhelésnél. Tehát nincs áthelyezési büntetés abban az esetben, ha a DLL-t az ASLR áthelyezte.

de mi van, ha a DLL-t más okból áthelyezik? Például előfordulhat, hogy az ASLR által választott alapcím nem érhető el a folyamatban, mert a folyamat már kiosztott valami mást ezen a helyen. Ebben az esetben hagyományos áthelyezésre van szükség, és Ön fizeti az áthelyezési büntetést.

Ah, de itt van a dolog: amikor egy DLL betöltődik, az ASLR véletlenszerűen hozzárendel egy alapcímet a rendelkezésre álló alapcímek közül, amelyeket még nem használnak.2 tehát nem fog bejutni az “az ASLR által választott alapcím nem érhető el” forgatókönyvbe, mert az ASLR a rendelkezésre álló alapcím közül választja ki a DLL alapcímét.3

Oké, így még mindig konfliktushelyzetbe kerülhetsz, de tényleg dolgoznod kell rajta. Például betölthet egy DLL-t egy folyamatba, és kaphat egy ASLR-hez rendelt alapcímet. Ezután elindít egy második folyamatot, szándékosan lefoglalja a memóriát ezen a címen (az ütközés kényszerítéséhez), majd betölti a DLL-t. Ebben az esetben áthelyezés lesz, mert guggolt azon a helyen, ahol az ASLR a DLL-t akarta elhelyezni. De ez nem rosszabb, mint ami az ASLR előtt volt: az ASLR előtti világban, a DLL preferált alapcímére guggolva egyébként áthelyezési büntetést kényszerített volna.

tehát nézzük meg, mi a történet. Rebase vagy nem rebase?

ASLR jelenlétében a DLL-ek újraindítása nincs hatással, mert az ASLR egyébként figyelmen kívül hagyja az alapcímet, és áthelyezi a DLL-t egy pszeudo-véletlenszerű választott helyre.

ne feledje, annak ellenére, hogy az újratervezésnek nincs hatása, az sem árt.

ha ASLR nélküli rendszert használ (vagy azért, mert megelőzi az ASLR-t, vagy mert az ASLR-t bármilyen okból letiltották), akkor az újraindítás a hagyományos okokból segít.

ne feledje, hogy az ASLR nélküli rendszereket manapság nagyon nehéz megtalálni, így az újratervezés az esetek túlnyomó többségében nem jár haszonnal. De az esetek eltűnően kis százalékában, amikor nincs ASLR, akkor az újraindítás segít.

következtetés: nem árt az újrabázis, csak abban az esetben, de értsd meg, hogy a kifizetés rendkívül ritka lesz. Készítsd el a DLL-t /DYNAMICBASE engedélyezve (és /HIGHENTROPYVA – vel a jó méréshez), és hagyd, hogy az ASLR elvégezze a munkát annak biztosítására, hogy ne történjen báziscím-ütközés. Ez nagyjából lefedi az összes valós forgatókönyvet. Ha véletlenül azon Nagyon ritka esetek egyikébe esik, amikor az ASLR nem érhető el, akkor a program továbbra is működni fog. Lehet, hogy kissé lassabban fut az áthelyezési büntetés miatt.

1 pontosabban, a javításokat tartalmazó összes oldal az oldalfájlba kerül. Ezt a finomabbat már megbeszéltük a múltkor.

2 Oké, van egy harmadik eset, amikor az ASLR-nek egyszerűen elfogyott az alapcíme. De megint, ez nem rosszabb, mint ami az ASLR előtt volt: ha elfogy az alapcíme, akkor minden ember maga. Minden alkalommal, amikor egy új DLL betöltődik, a kernelnek meg kell keresnie egy elég nagy darab rendelkezésre álló címteret, amelybe betöltheti a DLL-t.

3 Ennek eredményeként az ASLR valójában jobb munkát végez az ütközések elkerülésében, mint a kézi újraindítás, mivel az ASLR a rendszer egészét képes megtekinteni, míg a kézi újraindításhoz ismernie kell az összes DLL-t, amely be van töltve a folyamatba, és általában nem lehetséges az alapcímek koordinálása több gyártó között.

Raymond Chen

Követ

Leave a Reply