Stary Linux, który wysłałeś, próbował wykonać bardzo delikatne włamanie. Funkcja została określona następująco:
int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
long fs, long es, long ds,
long eip, long cs, long eflags,
unsigned long * esp, long ss)
Argumenty funkcji nie faktycznie reprezentują argumentów do funkcji (z wyjątkiem signr
), ale wartości, które wywołanie funkcji (a jądro obsługi przerwań/wyjątków napisane w montażu) Konserwy stos przed wywołaniem do_signal
. Instrukcja *(&eax) = -EINTR
służy do modyfikowania zachowanej wartości EAX na stosie. Podobnie instrukcja *(&eip) = old_eip -= 2
służy do modyfikowania adresu zwrotnego programu wywołującego. Po zwróceniu do_signal
handler wyskakuje pierwsze 9 "argumentów" ze stosu, przywracając je do nazwanych rejestrów. Następnie wykonuje instrukcję IRETD
, która wyrzuca pozostałe argumenty ze stosu i powraca do trybu użytkownika.
Nie trzeba dodawać, że ten hack jest niesamowicie niewiarygodny. Jest to zależne od kodu generującego kompilator dokładnie w taki sposób, w jaki oczekiwał. Dziwię się, że nawet pracował dla kompilatora GCC z tamtej epoki, wątpię, czy było to długo przed tym, zanim GCC wprowadziła optymalizację, która go zepsuła.
Czy możesz podać nam link do tego źródła jądra? lub dodaj pełną definicję funkcji (jeśli nie jest zbyt długa). –
Może to uniemożliwić kompilatorowi używanie rejestru dla eaxa i zmusić go do użycia pamięci na stosie. –
@ KlasLindbäck: Nice !!! Powinieneś go zapisać, ponieważ jest to prawdopodobnie poprawna odpowiedź (nazwa "eax" sugeruje, że jest to powód). –