Wspomniałem o „przepełnieniu bufora” w komentarzu do odpowiedzi Pythagrasa, prawdopodobnie powinienem wyjaśnić, co miałem na myśli. W języku C nie wystarczy wiedzieć, że bezpośrednia praca z pamięcią jest niebezpieczna - należy również zrozumieć dokładne sposoby jej niebezpieczeństwa. Naprawdę nie podoba mi się metafora „strzelania sobie w stopę” dla wszystkich tych przypadków - przez większość czasu to nie ty pociągasz za spust, ale często jest to aktor o interesach sprzecznych z twoim i / lub użytkownikami ” .
Na przykład w architekturze ze stosem malejącym (najpopularniejsze architektury pasują do tego rachunku - ogólnie x86 i ARM), gdy wywołasz funkcję, adres zwrotny funkcji zostanie umieszczony na stosie po zmiennych lokalnych zdefiniowanych w parametrze treść funkcji. Jeśli więc zadeklarujesz bufor jako zmienną lokalną i udostępnisz tę zmienną światu zewnętrznemu bez sprawdzania przepełnienia bufora, to tak:
void myFn(void) {
char buf[256];
gets(buf);
}
zewnętrzny użytkownik może wysłać ci ciąg znaków, który zastępuje adres zwrotny ze stosu - w zasadzie może zmienić pomysł programu na graf wywołań, który prowadzi do bieżącej funkcji. Użytkownik podaje więc ciąg znaków, który jest binarną reprezentacją kodu wykonywalnego dla twojej architektury, wystarczającą dopełnieniem, aby przepełnić stos myFn
, oraz dodatkowe dane, aby zastąpić adres zwrotny w myFn
celu wskazania kodu, który ci dał. Jeśli tak się stanie, to kiedy myFn
zwykle zwróci kontrolę nad swoim abonentem wywołującym, zamiast tego rozgałęzi się do kodu dostarczonego przez złośliwego użytkownika. Jeśli napiszesz kod C (lub C ++), który może być narażony na zaufanie niezaufanych użytkowników, musisz zrozumieć ten wektor ataku. Powinieneś zrozumieć, dlaczego przepełnienie bufora w stosunku do stosu jest często (ale nie zawsze) łatwiejsze do wykorzystania niż w przypadku stosu, i powinieneś zrozumieć, w jaki sposób układana jest pamięć w stosie (niekoniecznie zbyt szczegółowo, ale pomysł, że w danym malloc()
regionie znajdują się otaczające go struktury kontrolne, może pomóc zrozumieć, dlaczego twój program ulega awarii w innym malloc()
lub w free()
).
C udostępnia ci szczegółowe informacje o tym, jak działa twój komputer, i daje ci większą bezpośrednią kontrolę nad twoim komputerem, niż jakikolwiek inny język edytowany przez użytkowników w powszechnym użyciu. Z wielką mocą wiąże się wielka odpowiedzialność - tak naprawdę musisz zrozumieć te szczegóły niskiego poziomu, aby bezpiecznie i skutecznie pracować z C.