cât de important este în zilele noastre să mă asigur că toate DLL-urile mele au adrese de bază neconflictuale?

Raymond

20 ianuarie, 2017

înapoi în a doua zi, unul dintre lucrurile pe care au fost îndemnați să facă a fost rebase DLL-uri, astfel încât toate au avut intervale de adrese nonoverlapping, evitând astfel costul de relocare runtime. Mai este important în zilele noastre?

această situație este o altă demonstrație a modului în care este important ca un sfat bun să vină cu o rațiune, astfel încât să puteți spune când devine un sfat rău.

rațiunea pentru rebasing merge astfel: dacă un DLL este încărcat la adresa de bază preferată, atunci imaginea poate fi paginată direct din magazinul de rezervă fără a necesita nicio remediere. Aceasta înseamnă că paginile pot fi partajate între procese, deoarece fiecare proces primește o copie identică. (Desigur, partajarea se oprește odată ce cineva scrie pe pagină și face copia lor diferită de copia partajată.)

dacă un DLL nu poate fi încărcat la adresa preferată, atunci imaginea va fi mutată, iar întregul DLL mutat este acum susținut de fișierul paginii.1 Aceasta este o operație relativ costisitoare, deoarece DLL-ul trebuie citit de pe disc și fixat, iar o taxă de comitere a fișierului paginii este suportată pentru a se asigura că există spațiu pentru a scrie paginile fixe. Mai mult, dacă două procese mută DLL-ul și se întâmplă printr-o coincidență să le mute în același loc, Windows NT nu încearcă să partajeze imaginile relocate. Vor exista mai multe copii în fișierul paginii.

costul acestei relocări dinamice este ceea ce rebasing încearcă să evite. Să numim aceasta ” pedeapsa de relocare.”

introduceți ASLR.

ASLR face ca DLL-urile să fie încărcate la adrese pseudo-aleatorii. În consecință, un DLL se va încărca la adresa de bază preferată numai în cazul unei coincidențe uimitoare.

bine, deci să ne întoarcem la rațiune pentru a vedea dacă se mai aplică.

un DLL încărcat departe de adresa de bază preferată suportă o penalizare de relocare? Dacă vă gândiți la asta, ASLR înseamnă că niciun DLL nu se încarcă vreodată la adresa preferată, dar am văzut, de asemenea, că nucleul face acomodări pentru acest lucru, astfel încât DLL-urile supuse ASLR să poată partaja în continuare pagini și face acest lucru fără a forța întregul DLL să fie mutat la încărcarea inițială. Deci, nu există nicio penalizare de relocare în cazul în care DLL-ul a fost mutat de ASLR.

dar dacă DLL-ul este mutat din alt motiv? De exemplu, s-ar putea ca adresa de bază aleasă de ASLR să nu fie disponibilă în proces, deoarece procesul a alocat deja altceva în acea locație. În acest caz, trebuie să aibă loc o relocare tradițională și plătiți pedeapsa de relocare.

Ah, dar iată chestia: când este încărcat un DLL, ASLR va atribui aleatoriu o adresă de bază dintre adresele de bază disponibile care nu sunt deja utilizate.2 deci, nu veți intra în scenariul” adresa de bază aleasă de ASLR nu este disponibilă”, deoarece ASLR alege adresa de bază a DLL dintre adresa de bază disponibilă.3

bine, deci încă poți intra într-o situație de conflict, dar trebuie să lucrezi cu adevărat la ea. De exemplu, puteți încărca un DLL într-un singur proces și puteți obține o adresă de bază atribuită ASLR. Apoi începeți un al doilea proces, alocați intenționat memoria la acea adresă (pentru a forța coliziunea) și apoi încărcați DLL-ul. În acest caz, va exista o relocare pentru că ați ghemuit pe locul în care ASLR a vrut să pună DLL. Dar acest lucru nu este mai rău decât ceea ce ați avut înainte de ASLR: în lumea pre-ASLR, ghemuirea pe adresa de bază preferată a DLL ar fi forțat oricum o penalizare de relocare.

deci, să vedem care este povestea. Pentru a rebase sau nu pentru a rebase?

în prezența ASLR, rebasing DLL-urile dvs. nu are niciun efect, deoarece ASLR va ignora adresa dvs. de bază oricum și va muta DLL-ul într-o locație a alegerii sale pseudo-aleatorii.

țineți minte, chiar dacă rebazarea nu are niciun efect, nici nu doare.

dacă sunteți pe un sistem fără ASLR (fie pentru că precede ASLR, fie pentru că ASLR a fost dezactivat din orice motiv), atunci rebazarea va ajuta, din motive tradiționale.

țineți minte, sistemele fără ASLR sunt foarte greu de găsit în zilele noastre, astfel încât rebazarea nu oferă niciun beneficiu în majoritatea covârșitoare a cazurilor. Dar, în acel procent vanishingly mic de cazuri în care nu aveți ASLR, apoi rebasing ajută.

concluzie: nu strică să re-bazezi, doar în caz, dar înțelegeți că plata va fi extrem de rară. Construiți DLL-ul cu /DYNAMICBASE activat (și cu /HIGHENTROPYVA pentru o bună măsură) și lăsați ASLR să facă munca de a se asigura că nu se produce nicio coliziune a adresei de bază. Asta va acoperi aproape toate scenariile din lumea reală. Dacă se întâmplă să cădeți într-unul dintre cazurile foarte rare în care ASLR nu este disponibil, atunci programul dvs. va funcționa în continuare. Doar poate rula un pic mai lent din cauza pedepsei de relocare.

1 mai precis, toate paginile care conțin remedieri sunt puse în fișierul de pagină. Am discutat acest punct mai fin data trecută.

3 ca urmare, ASLR face de fapt o treabă mai bună de a evita coliziunile decât rebazarea manuală, deoarece ASLR poate vizualiza sistemul în ansamblu, în timp ce rebazarea manuală necesită să cunoașteți toate DLL-urile care sunt încărcate în procesul dvs., iar coordonarea adreselor de bază între mai mulți furnizori nu este în general posibilă.

Raymond Chen

Urmați

Leave a Reply