hur viktigt är det idag att se till att alla mina dll-filer har icke-motstridiga basadresser?

Raymond

20 januari, 2017

förr i tiden, en av de saker du uppmanades att göra var rebase dina DLL så att de alla hade nonoverlapping adressområden, därigenom undvika kostnaden för runtime omlokalisering. Är det fortfarande viktigt nuförtiden?

denna situation är en annan demonstration av hur det är viktigt för goda råd att komma med en motivering så att du kan berätta när det blir dåliga råd.

motiveringen för rebasing går så här: om en DLL laddas på sin föredragna basadress, kan bilden sökas in direkt från backing store utan att kräva några korrigeringar. Det betyder att sidorna kan delas mellan processer, eftersom varje process får en identisk kopia. (Naturligtvis slutar delningen när någon skriver till sidan och gör deras kopia annorlunda än den delade kopian.)

om en DLL inte kan laddas på sin föredragna adress, kommer bilden att flyttas, och hela den omplacerade DLL-filen stöds nu av sidfilen.1 Detta är en relativt dyr operation, eftersom DLL måste läsas från disk och fixas upp, och en åta sig laddning till sidfilen uppstår för att säkerställa att det finns utrymme att skriva de fasta sidorna. Dessutom, om två processer flyttar DLL och händer av en slump för att flytta dem till samma plats, försöker Windows NT inte dela de flyttade bilderna. Det kommer att finnas flera kopior i sidfilen.

kostnaden för denna dynamiska omlokalisering är vad rebasing försöker undvika. Låt oss kalla detta ” omlokalisering straff.”

ange ASLR.

ASLR gör att DLL-filerna laddas på pseudo-slumpmässiga adresser. Följaktligen kommer en DLL att laddas vid sin föredragna basadress endast i händelse av en förvånande slump.

Okej, så låt oss gå tillbaka till motiveringen för att se om det fortfarande gäller.

medför en DLL Som laddas bort från sin föredragna basadress en omplaceringsstraff? Om du tänker på det betyder ASLR att ingen DLL någonsin laddas på sin föredragna adress, men vi såg också att kärnan gör boende för detta så att DLL-filer som utsätts för ASLR fortfarande kan dela sidor, och det gör det utan att tvinga hela DLL att flyttas vid initial belastning. Så det finns ingen omlokaliseringsstraff i fallet där DLL flyttades av ASLR.

men vad händer om DLL flyttas av någon annan anledning? Det kan till exempel vara att den ASLR-valda basadressen inte är tillgänglig i processen, eftersom processen redan tilldelade något annat på den platsen. I så fall måste en traditionell omlokalisering ske, och du betalar omplaceringsstraffet.

Ah, men här är saken: när en DLL laddas, kommer ASLR att tilldela en basadress slumpmässigt bland de tillgängliga basadresserna som inte redan används.2 Så du kommer inte att komma in i scenariot “den ASLR-valda basadressen är inte tillgänglig” eftersom ASLR väljer DLL: s basadress bland basadressen som är tillgänglig.3

Okej, så du kan fortfarande komma in i en konfliktsituation, men du måste verkligen arbeta med det. Du kan till exempel ladda en DLL i en process och få en ASLR-tilldelad basadress. Du startar sedan en andra process, avsiktligt allokerar minne på den adressen (för att tvinga kollisionen) och laddar sedan DLL. I det här fallet kommer det att bli en omlokalisering eftersom du hukade på den plats där ASLR ville sätta DLL. Men det här är inte värre än vad du hade före ASLR: i pre-ASLR-världen skulle huk på en DLL: s föredragna basadress ha tvingat en omlokaliseringsstraff ändå.

så, låt oss se vad historien är. Att rebase eller inte rebase?

i närvaro av ASLR har rebasing dina DLLs ingen effekt eftersom ASLR kommer att ignorera din basadress ändå och flytta DLL till en plats för dess pseudo-slumpmässiga val.

Tänk på att även om rebasing inte har någon effekt skadar det inte heller.

om du är på ett system utan ASLR (antingen för att det föregår ASLR eller för att ASLR har inaktiverats av någon anledning), kommer rebasing att hjälpa till av traditionella skäl.

märk väl, system utan ASLR är verkligen svårt att hitta nuförtiden, så rebasing ger ingen fördel i den överväldigande majoriteten av fallen. Men i den försvinnande lilla andelen fall där du inte har ASLR, hjälper rebasing.

slutsats: det skadar inte att rebase, bara i fall, men förstår att utbetalningen kommer att vara extremt sällsynt. Bygg din DLL med /DYNAMICBASE aktiverad (och med /HIGHENTROPYVA för bra mått) och låt ASLR göra jobbet för att se till att ingen basadresskollision uppstår. Det kommer att täcka ganska mycket alla verkliga scenarier. Om du råkar falla i ett av de mycket sällsynta fallen där ASLR inte är tillgängligt, fungerar ditt program fortfarande. Det kan bara springa lite långsammare på grund av omplaceringsstraffet.

1 mer exakt läggs alla sidor som innehöll korrigeringar i sidfilen. Vi diskuterade denna finare punkt förra gången.

2 Okej, Det finns ett tredje fall, vilket är där ASLR helt enkelt har slut på basadresser. Men igen, detta är inte värre än vad du hade innan ASLR: om du får slut på basadresser, då är det varje man för sig själv. Varje gång en ny DLL laddas, måste kärnan scrounge runt för en tillräckligt stor bit av tillgängligt adressutrymme för att ladda DLL.

3 som ett resultat gör ASLR faktiskt ett bättre jobb för att undvika kollisioner än Manuell rebasing, eftersom ASLR kan se systemet som helhet, medan manuell rebasing kräver att du känner till alla dll-filer som laddas in i din process, och det är i allmänhet inte möjligt att samordna basadresser över flera leverantörer.

Raymond Chen

Följ

Leave a Reply