Uninitialized Variables
Podstawowe informacje
Podstawowym pomysłem tutaj jest zrozumienie, co dzieje się z niezainicjowanymi zmiennymi, ponieważ będą one miały wartość, która była już przypisana do pamięci. Przykład:
Funkcja 1:
initializeVariable
: Deklarujemy zmiennąx
i przypisujemy jej wartość, powiedzmy0x1234
. Ta czynność jest podobna do zarezerwowania miejsca w pamięci i umieszczenia w nim określonej wartości.Funkcja 2:
useUninitializedVariable
: Tutaj deklarujemy inną zmiennąy
, ale nie przypisujemy jej żadnej wartości. W języku C niezainicjowane zmienne nie są automatycznie ustawiane na zero. Zamiast tego zachowują wartość, która była ostatnio przechowywana pod ich adresem pamięci.
Gdy uruchamiamy te dwie funkcje sekwencyjnie:
W
initializeVariable
,x
otrzymuje wartość (0x1234
), która zajmuje określony adres pamięci.W
useUninitializedVariable
,y
jest deklarowane, ale nie otrzymuje wartości, więc zajmuje miejsce w pamięci bezpośrednio pox
. Ze względu na brak inicjalizacjiy
, kończy się "dziedziczeniem" wartości z tego samego miejsca w pamięci używanego przezx
, ponieważ jest to ostatnia wartość, która tam była.
To zachowanie ilustruje kluczowe pojęcie w programowaniu niskopoziomowym: Zarządzanie pamięcią jest kluczowe, a niezainicjowane zmienne mogą prowadzić do nieprzewidywalnego zachowania lub podatności na zagrożenia bezpieczeństwa, ponieważ mogą nieumyślnie przechowywać wrażliwe dane pozostawione w pamięci.
Niezainicjowane zmienne stosu mogą stwarzać kilka zagrożeń dla bezpieczeństwa, takich jak:
Ujawnienie danych: Wrażliwe informacje, takie jak hasła, klucze szyfrowania lub dane osobowe, mogą być ujawnione, jeśli przechowywane są w niezainicjowanych zmiennych, umożliwiając potencjalnie atakującym odczytanie tych danych.
Ujawnienie informacji: Zawartość niezainicjowanych zmiennych może ujawnić szczegóły dotyczące układu pamięci programu lub operacji wewnętrznych, pomagając atakującym w opracowywaniu ukierunkowanych exploitów.
Awarie i niestabilność: Operacje związane z niezainicjowanymi zmiennymi mogą prowadzić do niezdefiniowanego zachowania, co może skutkować awariami programu lub nieprzewidywalnymi wynikami.
Wykonywanie arbitralnego kodu: W określonych scenariuszach atakujący mogą wykorzystać te podatności, aby zmienić przebieg wykonania programu, umożliwiając im wykonanie arbitralnego kodu, który może obejmować zagrożenia związane z wykonaniem kodu zdalnego.
Przykład
Jak to działa:
Funkcja
initializeAndPrint
: Ta funkcja deklaruje zmienną całkowitąinitializedVar
, przypisuje jej wartość100
, a następnie drukuje zarówno adres pamięci, jak i wartość zmiennej. Ten krok jest prosty i pokazuje, jak zachowuje się zmienna zainicjowana.Funkcja
demonstrateUninitializedVar
: W tej funkcji deklarujemy zmienną całkowitąuninitializedVar
bez inicjalizacji. Gdy próbujemy wydrukować jej wartość, wynik może pokazać losową liczbę. Ta liczba reprezentuje dane, które wcześniej znajdowały się pod tym adresem pamięci. W zależności od środowiska i kompilatora, rzeczywisty wynik może się różnić, a czasami, dla bezpieczeństwa, niektóre kompilatory mogą automatycznie inicjować zmienne na zero, chociaż nie należy polegać na tym.Funkcja
main
: Funkcjamain
wywołuje obie powyższe funkcje sekwencyjnie, demonstrując różnicę między zmienną zainicjowaną i niezainicjowaną.
Przykład ARM64
To nie zmienia się w ARM64, ponieważ zmienne lokalne są również zarządzane na stosie, możesz sprawdzić ten przykład, gdzie to jest pokazane.
Last updated