Was verhindert, dass ein Assembly-Programm das Betriebssystem zum Absturz bringt? [geschlossen]

17

Zuallererst bin ich ein Anfänger. Wenn diese Frage dumm klingt, weisen Sie bitte auf die falschen Annahmen hin.

Nach meinem Verständnis besteht die Aufgabe eines Betriebssystems darin, Hardware und Software zu verwalten, die auf dem Betriebssystem ausgeführt werden. Soweit ich weiß, können Sie mit Assembler-Programmen die Hardware fast direkt steuern. In einem Assembler-Programm kann man Daten in Register lesen und schreiben und Daten in RAM lesen und schreiben.

Wäre es angesichts dieser Freiheit, mit Registern und RAM zu arbeiten, nicht möglich, dass Assembler-Programme das Betriebssystem beeinflussen? Angenommen, ein Betriebssystem verwendet Register A, um wichtige Informationen zu speichern, und ich führe auf diesem Betriebssystem ein zusammengesetztes Programm aus. Wenn das Programm Junk-E-Mails erfolgreich in Register A schreibt, ist das Betriebssystem mit Sicherheit betroffen.

Fragen:

  1. Ist es möglich, mit Register A auf die oben beschriebene Weise zu verwechseln?

  2. Wenn nicht, was hindert Assembly-Programme daran, die vom Betriebssystem verwendeten Register zu ändern?

Fluss
quelle
13
clevere
Es gibt heute und in der Vergangenheit viele Computerarchitekturen, und es wurden viele Betriebssysteme entwickelt. Auf welche Architektur / welches Betriebssystem beziehen Sie sich genau? Auf einigen (alten) Architekturen gab es keine Möglichkeit, das Programm von dem zu stoppen, was es nach dem Start tat, das ist richtig. Moderne Hardware / Betriebssysteme haben jedoch Hardware-Tools eingebaut, die nur den Teil des Speichers für das Programm im "normalen" Modus (nicht als Superuser) zur Verfügung stellen. Außerhalb dieses Grenzwerts kann nicht auf den Speicher zugegriffen werden. Die Verwendung von Registern ist kostenlos, da das Betriebssystem keine nützlichen Informationen in Registern speichert, sondern nur im Speicher / auf der Festplatte.
cyclone125
2
In einem Mikroprozessor läuft Ihr Programm im "Benutzermodus", die Betriebssysteme laufen im "Systemmodus". Wenn ein Benutzermodusprogramm beispielsweise eine Halteanweisung ausführt, wird die Maschine nicht anhalten. Der Halt würde abgefangen und das Betriebssystem aufgerufen. In Bezug auf RAM würde das Betriebssystem eine Umgebung für das Benutzermodusprogramm einrichten, so dass das, was das Benutzerprogramm als RAM-Adresse X ansieht, über Speicherverwaltungshardware nicht wirklich die RAM-Adresse X sein würde.
George White
1
@flux Ich habe meinen Kommentar aktualisiert. Die Antwort wäre: Es gibt keine "allgemeine" Antwort auf Ihre Frage, da es verschiedene Computerarchitekturen / Betriebssysteme gibt / gab. Es kann auf verschiedene Arten sein.
cyclone125
2
... Vor langer Zeit habe ich rohen Maschinencode geschrieben. Ja ha !!! :-)
Russell McMahon

Antworten:

32

Am Ende sind alle Programme Maschinencode, unabhängig davon, ob die Ausgangssprache Assembler oder eine Hochsprache war.

Das Wichtigste ist, dass es Hardware- Mechanismen gibt, die die Möglichkeiten eines bestimmten Prozesses einschränken, einschließlich "Durcheinander" -Registern, die sich auf andere Programme oder das Betriebssystem auswirken können.

Dies begann mit einer einfachen Unterscheidung zwischen den Betriebsmodi "Benutzer" und "Supervisor" und hat sich seitdem zu einer Sicherheitsarchitektur mit mehreren "Privilegierungsringen" entwickelt.


Hier ist ein sehr allgemeines Beispiel, um es etwas konkreter zu machen:

  • Im "Benutzermodus" kann ein Prozess nicht auf Speicher zugreifen, der seiner Prozess-ID nicht zugewiesen wurde. Speicher, der anderen Prozessen und dem Betriebssystem selbst zugewiesen ist, ist blockiert. Dies schließt die Werte von Registern ein, die von diesen anderen Prozessen verwendet werden. Dies wird von der MMU-Hardware erzwungen.

  • Daher kann ein Prozess im "Benutzermodus" nicht auf die MMU-Steuerregister zugreifen.

  • Und natürlich kann ein Prozess im "Benutzermodus" den Modus nur über einen sehr genau definierten Mechanismus in den "Supervisor-Modus" ändern, bei dem eine Betriebssystemfunktion aufgerufen wird.

Das Betriebssystem erhält die Kontrolle, wenn der Prozess versucht, eine dieser Regeln zu brechen. Sobald dies geschieht, kann das Betriebssystem den fehlerhaften Prozess einfach stoppen und nie mehr seine Anweisungen ausführen.

Dave Tweed
quelle
2
Wenn ich das richtig verstehe, meinen Sie: Einige Prozessoren haben "Benutzermodus" und "Supervisormodus". Das Betriebssystem wird im "Supervisor-Modus" ausgeführt und versetzt den Prozessor in den "Benutzermodus", um mein fiktives Assembly-Programm auszuführen. Im "Benutzermodus" gibt es Register und RAM-Adressen, auf die das Assemblerprogramm aufgrund eines absichtlichen Entwurfs der Hardware nicht zugreifen kann.
Flux
3
Grundsätzlich beschreibt diese Antwort moderne "i386-ähnliche" Architekturen mit MMU und Protected Mode. Allerdings gibt es viele alte (i8080, MOS 6502 usw.) sowie moderne, einfachere (AVR, ARM Cortex-M usw.) Architekturen, die diese Funktionen nicht bieten und für die eine Art von Betriebssystem verwendet wird (z. B. alte) CP / M, modernes FreeRTOS, ChibiOS usw.) Nichts kann das Programm davon abhalten, was es tut.
cyclone125
2
@Flux Die Architekturen von i386 (und höher) bieten Details zum Lernen. Die x86-Architektur verfügt nicht nur über Speicheradressen, die geschützt werden können, sondern auch über E / A-Adressen. (Für den Speicherzugriff werden unterschiedliche Anweisungen verwendet als für den E / A-Zugriff.) Der i386 + verfügt über drei Speicheradressen. Die segmentierte / selektorbasierte Adresse verwendet ein Selektorregister, das auf einen Tabelleneintrag (GDT oder LDT) verweist, um das Paar in eine einzelne lineare 32-Bit-Adresse abzubilden. Paging-Tabellen übersetzen dann die lineare 32-Bit-Adresse in eine physikalische 36-Bit-Adresse (P-II.). In beiden Übersetzungsschritten besteht ein Schutz.
jonk
4
@flux deine Zusammenfassung ist korrekt. Ein Programm in einem geschützten Speichersystem mit einem geeigneten Multitasking-Betriebssystem sollte nicht in der Lage sein, das System mit einer Reihe von Anweisungen zum Absturz zu bringen. Sogar ungültige - die landen bei einem speziellen Behandler.
pjc50
Obwohl es mehrere Ringe gibt (mindestens in x86), ist es sehr, sehr selten, dass mehr als zwei tatsächlich verwendet werden.
Wald
10

Viele Multitasking-Betriebssysteme verwenden eine Datenstruktur, die als Process Control Block (PCB) bezeichnet wird, um das Problem des Überschreibens von Registern zu lösen. Wenn Sie Ihren Code ausführen, erstellt das Betriebssystem einen neuen Prozess, um den Überblick zu behalten. Die Platine enthält Informationen über Ihren Prozess und den Speicherplatz, der für den Inhalt des Registers vorgesehen ist. Angenommen, Prozess A wird derzeit auf dem Prozessor ausgeführt und Ihr Code wird gerade ausgeführt. Was passiert, wenn Sie Ihren Code ausführen?

  1. Die Statusdaten von Prozess A (Registerinhalt, Programmzähler usw.) werden auf die Leiterplatte kopiert.

  2. Die Statusdaten von Prozess B werden von seiner Platine in die CPU-Register kopiert

  3. Prozess B wird auf dem Prozessor ausgeführt, bis er beendet ist oder vorzeitig ausgeführt wird

  4. Die Statusdaten von Prozess B werden auf die Leiterplatte zurückkopiert

  5. Die Statusdaten von Prozess A werden zurück in die CPU kopiert und laufen weiter

Wenn das Betriebssystem als Prozess A ausgeführt wird, können Sie sehen, wie die Register gespeichert werden, bevor das Programm ausgeführt wird. Wenn Sie sie nach dem Beenden des Programms wieder in die CPU kopieren, werden Benutzerprogramme daran gehindert, mit den Vorgängen in anderen Prozessen in Konflikt zu geraten.

Um zu vermeiden, dass Benutzerprozesse über Betriebssystemdaten im Speicher schreiben, verwenden die meisten Plattformen die Speichersegmentierung. Grundsätzlich kann mithilfe des virtuellen Speichers der Adressraum, den ein Prozess sieht, einem beliebigen Bereich von physischen Adressen zugeordnet werden. Solange sich die physischen Speicherbereiche der Prozesse nicht überschneiden, ist es für einen Prozess unmöglich, die Daten eines anderen Prozesses zu überschreiben.

Natürlich machen verschiedene Betriebssysteme die Dinge anders, daher gilt dies nicht in jedem Fall. Auf den meisten Plattformen werden Betriebssystemprozesse in einem anderen Modus als Benutzerprozesse ausgeführt, und es gibt einige Schwierigkeiten.

jtst
quelle
4

Hängt davon ab, über welche Plattform Sie sprechen.

  • Bei einem einfacheren Prozessor führt der Prozessor nur die Anweisungen aus, die das Programm zur Ausführung auffordert.

  • Auf einem anspruchsvolleren Prozessor gibt es (mindestens) zwei Modi. In einem Modus tut der Prozessor, was das Programm anordnet. Im anderen Modus weigert sich der Prozessor selbst , bestimmte Anweisungen auszuführen.

Was hält ein Programm davon ab, das gesamte System zum Absturz zu bringen? Beim ersten Prozessortyp lautet die Antwort "nichts". Mit einem einfachen Prozessor kann ein einziges Schurkenprogramm tatsächlich das gesamte System zum Absturz bringen. Alle frühen 8-Bit-Heimcomputer und viele der 16-Bit-Heimcomputer fallen in diese Kategorie.

Auf einem modernen PC verfügt der Prozessor über "Schutz" -Hardware. Grundsätzlich wird das Betriebssystem in einem speziellen Modus ausgeführt, in dem es alles ausführen kann, wohingegen normale Programme in einem Modus ausgeführt werden, in dem der Prozessor nur bestimmte Aktionen zulässt (basierend auf den Einstellungen, die das Betriebssystem auf dem Prozessor konfiguriert hat). Sachen wie nur Zugriff auf bestimmte Register oder nur Zugriff auf bestimmte Speicherbereiche.

Es ist offensichtlich schlecht, wenn ein einziges Schurkenprogramm das gesamte System zum Absturz bringt. (Es gibt auch schwerwiegende Sicherheitsrisiken, wenn ein betrügerisches Programm auf die gewünschten Daten zugreift.) Um dies zu vermeiden, benötigen Sie zwei Dinge:

  1. Ein Prozessor, der tatsächlich über Schutzhardware verfügt (dh er kann so konfiguriert werden, dass die Ausführung bestimmter Anweisungen verweigert wird).

  2. Ein Betriebssystem, das diese Funktionen verwendet, um sich selbst zu schützen. (Es ist nicht gut, einen Chip mit Schutzschaltung zu haben, wenn das Betriebssystem ihn nie verwendet!)

So gut wie jedes moderne Desktop-Betriebssystem (Windows, Linux, Mac OS, BSD ...) kann als Betriebssystem im geschützten Modus bezeichnet werden, das auf einem Prozessor mit Schutzhardware ausgeführt wird. Wenn Sie auf einem 8-Bit-Mikrocontroller Embedded-Entwicklung betreiben, verfügt dieser wahrscheinlich über keine Schutzhardware. (Oder irgendein Betriebssystem, für diese Angelegenheit ...)

MathematicalOrchid
quelle
1

F. Was verhindert, dass ein Assembly-Programm das Betriebssystem zum Absturz bringt?

A. Nichts.

Viele sehr clevere Programmierer haben sich jedoch über die Jahre sehr bemüht, es immer schwieriger zu machen. Leider gibt es für jeden cleveren Programmierer viele, viele andere, die kreativer, ehrgeiziger und manchmal glücklicher sind als die cleveren. Jedes Mal, wenn ein cleverer Programmierer sagt, dass niemand etwas tun sollte, würde oder könnte, wird jemand einen Weg finden, dies zu tun. Microsoft Windows (als Beispiel) gibt es seit fast 35 Jahren, und wir haben immer noch BSoD (Blue Screens of Death). Dies sind nur Anweisungen, die das Betriebssystem zum Absturz gebracht haben.

Beginnen wir mit einer kleinen Terminologie. Alles, was auf einem Computer läuft, geschieht im Maschinencode. Das Bit, das die Tastenanschläge oder die Bewegung des Mauszeigers liest, das Bit, das die Farbe eines Pixels auf der Anzeige ändert oder ein Byte aus einer Datei liest, und das Bit, das berechnet, ob Ihre Kugel den Bösewicht trifft oder das Bit, das entscheidet Wenn Ihr Kreditkartenantrag akzeptiert wird, werden alle als Folge von Maschinencode-Anweisungen ausgeführt. Einige Arbeiten sind so häufig und werden so oft ausgeführt, dass es sinnvoll ist, die dazu erforderlichen Anweisungen zusammenzustellen und alle Personen diese Baugruppe verwenden zu lassen. Die Menge dieser Jobs, die es anderen ermöglichen oder helfen, den Computer zu nutzen, wird in der Regel als Betriebssystem bezeichnet, zwischen ihnen und anderen Programmen besteht jedoch kein grundsätzlicher Unterschied. Sie alle sind nur Sequenzen von Maschinencode-Anweisungen.

Was Betriebssysteme komplizierter macht (und daher zum Absturz neigt), ist, dass sie Dinge berücksichtigen müssen, über die Sie normalerweise nicht nachdenken müssen. Nehmen Sie die einfachsten Jobs als Beispiel. Ich möchte eine Nachricht an das Ende einer Datei schreiben. In einer höheren Sprache würden Sie etwa schreiben:

  with open("myFile.txt", "w+") as f:
      # do some really clever things
      f.write("Goodbye cruel world!")

Ignorieren wir alle Details darüber, wie auf die physischen Zustände zugegriffen und diese geändert werden oder wie sie als Bits und Bytes interpretiert werden oder wie diese Bytes zu und von dem Speicher und der CPU übertragen werden, und vertrauen wir darauf, dass alles, was von den Programmen des Betriebssystems verarbeitet wird hinter den Kulissen. Denken wir nur darüber nach, wie Sie an das Ende einer Datei anhängen. 1) Finden Sie heraus, wo sich das Ende der Datei befindet. 2) Schreiben Sie etwas an dieser Position. Was könnte möglicherweise falsch laufen? Eigentlich ziemlich viel. Denken Sie darüber nach, was sonst noch auf dem Computer passiert, während Sie clevere Dinge tun. Wenn irgendetwas anderes (einschließlich des Betriebssystems selbst) die Datei ändert, an der Sie gerade arbeiten, wird dieser wirklich einfache Job plötzlich sehr viel komplizierter. Die Datei ist länger, die Datei ist kürzer. Die Datei ist nicht mehr da. Die Festplatte ist voll.

Paul Smith
quelle