Przechodzę przez MSIL i zauważam, że w MSIL jest wiele instrukcji nop .
Artykuł MSDN mówi, że nie podejmują żadnych działań i są używane do wypełniania miejsca, jeśli kod operacji jest załatany. Są używane znacznie częściej w kompilacjach do debugowania niż w kompilacjach wydań.
Wiem, że tego rodzaju instrukcje są używane w językach asemblera do wyrównywania późniejszych instrukcji, ale dlaczego nops MSIL są potrzebne w MSIL?
(Uwaga redaktora: przyjęta odpowiedź dotyczy NOP kodu maszynowego, a nie NOP MSIL / CIL, o które pierwotnie zadano pytanie).
Odpowiedzi:
NOP służą kilku celom:
źródło
Oto jak nops MSIL / CIL ( nie kod maszynowy x86
nop
) są używane przez debugowanie:Nops są używane przez kompilatory języków (C #, VB itp.) Do definiowania niejawnych punktów sekwencji. Informują one kompilator JIT, gdzie ma zapewnić możliwość odwzorowania instrukcji maszynowych z powrotem na instrukcje IL.
Wpis na blogu Ricka Byera na temat DebuggingModes.IgnoreSymbolStoreSequencePoints wyjaśnia kilka szczegółów.
C # umieszcza również instrukcje Nops po wywołaniu, tak aby lokalizacja witryny zwrotnej w źródle była wywołaniem, a nie wierszem po wywołaniu.
źródło
Zapewnia możliwość umieszczania w kodzie markerów opartych na wierszach (np. Punktów przerwania), w przypadku których kompilacja wydania nie wyemituje żadnych.
źródło
Może również przyspieszyć działanie kodu podczas optymalizacji pod kątem określonych procesorów lub architektur:
Procesory przez długi czas wykorzystują wiele potoków, które działają mniej więcej równolegle, więc dwie niezależne instrukcje mogą być wykonywane w tym samym czasie. Na prostym procesorze z dwoma potokami pierwszy może obsługiwać wszystkie instrukcje, podczas gdy drugi obsługuje tylko podzbiór. Ponadto między potokami występują przestoje, gdy trzeba czekać na wynik poprzedniej instrukcji, która nie jest jeszcze ukończona.
W takich okolicznościach dedykowany nop może wymusić następną instrukcję na konkretnym potoku (pierwszym lub nie pierwszym) i poprawić parowanie następujących instrukcji, tak aby koszt nop był więcej niż zamortyzowany.
źródło
Koleś! No-op jest niesamowity! Jest to instrukcja, która tylko pochłania czas. W mrocznych wiekach używałbyś go do mikroregulacji czasu w krytycznych pętlach lub, co ważniejsze, do wypełniania samomodyfikującego się kodu.
źródło
W jednym procesorze, dla którego pracowałem ostatnio (przez cztery lata), zastosowano NOP, aby upewnić się, że poprzednia operacja zakończyła się przed rozpoczęciem następnej. Na przykład:
wartość obciążenia do rejestru (trwa 8 cykli) nop 8 dodaj 1 do rejestru
Dzięki temu rejestr miał prawidłową wartość przed operacją dodawania.
Innym zastosowaniem było wypełnienie jednostek wykonawczych, takich jak wektory przerwań, które musiały mieć określony rozmiar (32 bajty), ponieważ adres dla wektora 0 był, powiedzmy, 0, dla wektora 1 0x20 i tak dalej, więc kompilator wstawił tam NOPy, jeśli potrzebne.
źródło
Mogą ich używać do obsługi edycji i kontynuowania podczas debugowania. Zapewnia debugerowi miejsce do pracy, aby zastąpić stary kod nowym bez zmiany offsetów itp.
źródło
Nieco niekonwencjonalnym zastosowaniem są slajdy NOP , używane w exploitach przepełnienia bufora.
źródło
50 lat za późno, ale hej.
Nopy są przydatne, jeśli ręcznie wpisujesz kod asemblera. Gdybyś musiał usunąć kod, nie mógłbyś przestać stosować starych kodów operacyjnych.
podobnie, możesz wstawić nowy kod, nadpisując jakiś opcode i przeskoczyć gdzie indziej. Tam umieszczasz nadpisane kody rozkazów i wstawiasz nowy kod. Kiedy będziesz gotowy, wskocz z powrotem.
Czasami trzeba było skorzystać z dostępnych narzędzi. W niektórych przypadkach był to tylko bardzo podstawowy edytor kodu maszynowego.
W dzisiejszych czasach w przypadku kompilatorów techniki te nie mają już żadnego sensu.
źródło
Jednym z klasycznych zastosowań jest to, że debugger może zawsze skojarzyć wiersz kodu źródłowego z instrukcją IL.
źródło
Na scenie łamania oprogramowania klasyczną metodą odblokowania aplikacji byłoby załatanie NOP linii, która sprawdza klucz, rejestrację lub okres czasu, czy tak dalej, aby nic nie robił i po prostu kontynuował uruchamianie aplikacji tak, jakby była zarejestrowana .
źródło
Widziałem również NOP w kodzie, który modyfikuje się, aby zaciemnić to, co robi jako symbol zastępczy (baaardzo stara ochrona przed kopiowaniem).
źródło
Jak powiedział ddaa, nops pozwala na uwzględnienie wariancji w stosie, więc kiedy nadpiszesz adres zwrotny, przeskakuje on na sanki nop (wiele nopsów z rzędu), a następnie poprawnie uderza w kod wykonywalny, zamiast przeskakiwać do niektórych bajt w instrukcji, który nie jest początkiem.
źródło
Pozwalają one linkerowi zastąpić dłuższą instrukcję (zwykle skok w dal) krótszą (skok krótki). NOP zajmuje dodatkowe miejsce - kodu nie można przesuwać, ponieważ uniemożliwiłoby to działanie innych skoków. Dzieje się to w czasie łącza, więc kompilator nie może wiedzieć, czy długi czy krótki skok byłby odpowiedni.
Przynajmniej jest to jedno z ich tradycyjnych zastosowań.
źródło
To nie jest odpowiedź na twoje konkretne pytanie, ale w dawnych czasach mógłbyś użyć NOP do wypełnienia pola opóźnienia gałęzi , jeśli nie udało ci się wypełnić go przydatną w inny sposób instrukcją.
źródło
Czy kompilatory .NET dopasowują dane wyjściowe MSIL? Wyobrażam sobie, że może to być przydatne do przyspieszenia dostępu do IL ... Ponadto rozumiem, że jest zaprojektowany jako przenośny, a na niektórych innych platformach sprzętowych wymagane są wyrównane dostępy.
źródło
Pierwszym zestawem, którego się nauczyłem, był SPARC, więc jestem zaznajomiony z gniazdem opóźnienia gałęzi, jeśli nie możesz go wypełnić inną instrukcją, zwykle instrukcją, którą zamierzałeś umieścić nad instrukcją gałęzi lub zwiększać licznik w pętlach, używasz a NOP.
Nie jestem zaznajomiony z crackingiem, ale myślę, że nadpisywanie stosu za pomocą NOP jest powszechne, więc nie musisz dokładnie obliczać, gdzie zaczyna się Twoja złośliwa funkcja.
źródło
Użyłem NOP do automagicznego dostosowania latencji zgromadzonej po wejściu do ISR. Bardzo przydatne do ustalenia czasu.
źródło
nop
będzie przydatny w ładunku exploita powodującym uszkodzenie pamięci. Oczywiścienop
jest podobniexchg eax, eax
źródło