 Diese beiden Forscher von der Rohr-Universität in Bochum haben in 2015 das erste Paper veröffentlicht. Meine Damen und Herren, eine warme Runde Applaus für die Vortragenden, die an der Rohr-Universität in Bochum ihre Arbeiten geschrieben haben. Vielen Dank für die Entschuldigung und fürs Kommen. Wir zeigen euch unseren Forschung im Bereich Micro-Code und hier sind auch noch unsere Beratenden in Bochum. Zwei der ersten Kleinen des Claimers. Die technischen Details in diesem Vortrag sind ziemlich spezifisch für AMD K10 Prozessoren. Die aktuellsten Prozessoren, auf denen das läuft, sind von 2013. Außerdem sind die meisten Sachen, die wir gefunden haben, durch Reverse Engineering gefunden. Das heißt, wenn ihr unsere Experimente erneut durchführen wollt, dann habt ihr das Risiko, weil es da wahrscheinlich unerwartetes oder undokumentiertes CPU-Ergebnis kommt. Zuerst wollen wir verstehen, was Micro-Code wirklich ist. Wir wollen einen kurzen Crash-Kurs für die Architektur der Architektur durchgehen. Wir wollen uns anschauen, ob das heckbar ist und am Ende wollen wir ein paar Demos zeigen. Zuallererst, was ist dieser Micro-Code überhaupt? Wenn das eure CPU ist, dann könnt ihr euch vorstellen, dass der Micro-Code ein kleiner Computer innerhalb der CPU ist, der die ganzen komplexen Funktionen, die wir hier besprechen, durchführt und wir werden darüber reden, wie wir damit umgehen können. Zuallererst möchte ich euch zeigen, was vor uns diskutiert wurde. Zum einen die AMD-Patente, die öffentlich verfügbar sind und die eine kurze Übersicht darüber geben, wie die Micro-Architektur im Detail implementiert ist. Dann gibt es Chip-Architekt, das ist eine Webseite, wo eine relativ detaillierter Artikel über die physikalische Platzierung von spezifischen Komponenten auf dem CPU-Chip auf dem Zidikon sind. Dann gibt es einen neuen Blockpost von 2004, ob der Ron X Post und der veröffentlicht zum allerersten Mal, dass Micro-Code updatebar ist und dass manche an DCPUs sogar Micro-Code akzeptieren, wenn er verodifiziert wurde und die Checksimme berechnet wurde. Und das war die erste Idee für unsere Forschung. Dann ist da eine Veröffentlichung, die hauptsächlich die Sicherheitsaspekte der Micro-Code Update diskutiert und sowohl für AMD als auch für Intel. Und dann gibt es die Arbeit von ARIGO. Es hat wahrscheinlich internes Wissen und veröffentlicht auch richtig coole Sachen über AMD Micro-Code. Jetzt, wo ihr wisst, was Micro-Code ist und was darüber schon an Vorarbeit geleistet wurde, wollen wir diskutieren, wofür das wirklich benutzt wird. Es wird für Instruktions-Decoding verwendet wird. Es wird benutzt, um CPU-Box zu fixen, die schon veröffentlichter Hardware sind. Und es wird für Exception-Handling verwendet, also für Ausnahmen in der Architektur. Wenn eine Division durch null ist, dann muss die CPU das erkennen und dann eine Ausnahme zum Betriebssystem weitergeben. Und das ist in Micro-Code implementiert. Außerdem wird Micro-Code benutzt, um Power-Management, also Strom-Management in der CPU durchzuführen und kann von den Herstellern benutzt werden, um sehr komplexe CPU-Features zu implementieren. Jetzt wissen wir, dass Micro-Code zum Instruktions-Decoden verwendet wird und jetzt wollen wir uns anschauen, wie das passiert. Die Architektur ist relativ komplex. Es ist ein Instruktions-Set mit unterschiedlicher Länge der Operanten und wir haben jetzt hier auch Beispiele, wo wir unterschiedlich viele benutzen. Üblicherweise ist es so, dass das erste Byte sagt, wie lange die Instruktion wirklich wird. Aber es gibt natürlich immer auch Ausnahmen für alles, z.B. Instruktionspräfekste, die die Entscheidung, wie lange das wird, auch noch hinterher beeinflussen können. Man kann die alle mitten an der Kopie kombinieren, um möglichst komplizierte Instruktionen zu erreichen. Es gibt auch Erweiterungen des Satzes. Hierbei haben wir z.B. Biskommerzahlen, Aditionen und Subtraktionen. Hier sieht man eine Instruktion, die hat verschiedene Operanten und die ist auch relativ kompliziert zu entschlüsseln und zu dekodieren. Das wird auch relativ kompliziert sein, die im CPUs auszuführen. Für die Komplexität braucht man am Ende einen kleinen Computer in unserer CPU, der das alles dekodiert für uns. Jetzt schauen wir uns noch kurz an, wie das dekodieren funktioniert. Hier haben wir z.B. eine x86 Anweisung auf der linken Seite. Das ist POP, die dereferenziert ein Register. Das wird dekodiert in mehrere Mikrocode-Operationen, also auch genannten Micro-Obs. Das sieht man hier auf der rechten Seite in der Folie. Zunächst lesen wir den obersten Eintrag auf dem Stack, laden das in ein temporäres Register und nachher wird dieses Register in die Adresse, wo ebx hinzeigt, gespeichert und danach wird der Basepoint dokumentiert. Das wir auch gerade noch gehört haben, ist, dass Microcode benutzt wird, um die CPUs selber zu upgraden, wenn Fehler passieren und die Dinge bereits ausgeliefert sind ins Feld. Das ist motiviert durch den berüchtigten Interpensium-Eftif-Bag, der 1990 war. Das Problem war, dass er unter gewissen BISCO-Operationen leicht abweigigere Resultate erzeugt hat. Und das Problem war, dass Intel dann die CPUs wirklich austauschen musste. Das wollten sie in der Zukunft vermeiden und deswegen haben sie so eine Upgrade-Möglichkeit mit eingebaut. Ein Beispiel dieses Jahr war, dass der Intel Kaby Lake Generation von Prozessoren ein Problem hatten, dass im Fall von Hyper-Fedding bestimmte Operationen so instabilem Verhalten geführt haben und auch zum Absturz geführt werden. Dann haben wir auf der AMD-Seite einige Bugs. Zum Beispiel 2008 gab es den Bug, dass zwei Einträge nicht zuverlässig gekäst werden konnten und das war auch im Microcode gefext worden hinterher. Jetzt relativ neu. Da gab es ein Problem in Ryzen, das ist die neuen Generation von Amtik. Das wurde auch durch Microcode hinterher berogen. Zwar mal uns die inneren Abläufe anschauen, wie das genau funktioniert, dass der Microcode eingebettet wird in die CPU. Wenn jetzt eine Operation ausgeführt wird auf der CPU, wird sie zuerst aus dem Speicher in die Caches geladen und dann zur Dekodierungs-Engine. Dort wird sie dann übersetzt in Microcode-Operationen, die möglicherweise umgeordnet werden, aber auf jeden Fall angeordnet in der Pipeline. Die Pipeline beschickt dann die ALUS, die Arithmetic Logic Units, also das sind die wirklich ausführenden kleinen Teile im CPU. Jetzt wollen wir uns den Dekoder mal genau anschauen. Am Anfang ist der Instruktionspuffer, der speichert einen Strom von Instruktionen, die dann weiterverarbeitet werden. Dann gibt es viele kleine Short-Dekoder, die verschiedene Zusammenpacken, verschiedene Operationen und ein größeres Paket für den Scheduler-Packen. Dann gibt es noch die Long-Dekoder, die die längere Operation übernimmt. Der nimmt komplexe x86 Instruktionen und schlüsst sie auf mehrere Micro-Operationen. Und dann gibt es noch den Vector-Dekoder, das ist der ganz auf der rechten Seite, das ist der, der die Micro-Code-Engine enthält. Das ist das, was die Übersetzung von großen x86 Micro-Operationen in kleine übersetzt und dabei die Übersetzung ausführt und in der Pipeline auch wieder anordnet. Und irgendwo müssten die gespeichert werden. Auf dem Chip ist ein Arbeitsspeicher der Micro-Code-ROM, wo dieser Micro-Code zwischengespeichert wird für die ganzen Micro-Programme. Und dann haben wir den Micro-Code-RAM, der während das läuft, den Micro-Code-Update aufbewahrt. Und dann gibt es noch viele weiteren Funktionen, damit das Ganze funktioniert. Zum Beispiel die Allitions-Unit, die den Programmsprecher erhöht und am wichtigsten für uns zumindest die Match-Register. Die beinhalten, oder sie führen dazu, dass wir Breakpoints im Micro-Code-ROM haben können. Und die können in unterschiedlichen Adressen eingerichtet werden und sobald so eine Adresse ausgeführt wird, wird der Control zurück zum Rahmen weitergenaltet werden, wo das Update gespeichert wird. Das ist notwendig, damit Updates überhaupt wirklich die Kontrolle von der CPU Instruktion bekommen kann. Zum Beispiel, wenn Inputs nicht aufgeräumt werden muss. Wie wird der Update von einem CPU wirklich geupdatet, z.B. das ist eine Kernel-Mode sein, dann muss der Match-Code-Update in den Arbeitsspeicher geladen werden, dann muss die virtuelle Adresse in einem spezifischen Register gespeichert werden und da der Match-Code-Update nicht nur in den Arbeitsspeicher geladen wird, dann ist es nicht persistent. Sobald die CPU zurückgesetzt wird, ist man wieder im initialen Zustand. So, das Match-Code-Update, der Teilformat sieht so aus. Es beinhaltet einen Header mit verschiedenen Feldern, State die Patch-ID in der Check-Summe und danach sind die ganzen Match-Register, wo der Inhalt für die jeweiligen Breakpoints gespeichert werden. Und dann folgt der Micro-Code. Der Micro-Code besteht aus oder ist organisiert in verschiedenen Trials und jeweils sind drei Micro-Operationen und ein Sequenzwort vorhanden. Die Micro-Ops sind Micro-Code Instruktionen, die Quake-Code, die Code ausführen und der Sequenzwort ist um den Kontrollfluss zu regulieren. Und jetzt müssen wir uns die Frage stellen, ist das hackbar? So, zwar, allererst lernen wir, ja, es ist updatebar. Wir haben Update-Triber in verschiedenen Biases und auch im Linux-Kandel. Das heißt, wir können die Prozederen, wir wissen die Prozederen, wie ein Update installiert werden kann. Wir haben die Micro-Updates vom Verkäufer, die durch Bias-Updates und auch über Coreboot veröffentlicht werden. Wir wissen, wie das Format, das High-Format aussieht und da sind Hinweise, dass es keine starke Kriptografie gibt, die Integrität überprüft oder beweist. Also, das ist ein Hackstump von einem dieser Updates. Ich möchte einfach nur mal kurz draufschauen. Hier können wir sehen, dass dieses Wert wieder und wieder vorkommt und hier, wenn wir mehr Werte uns anschauen, die auch wieder dieselben Werte sind, sehen wir Pattern. Das heißt, wir haben überhaupt keine starke Kriptografie, die hier angewendet wird. Außerdem haben wir gelernt, dass die CPU-modifizierte Updates akzeptiert, wenn die Check-Summer stand. Also, ja, wir können das hacken. Zu diesem Zeitpunkt müssen wir viele Micro-Updates automatisch erstellen und dadurch können wir dann die Änderung von der CPU beeinflussen. Dann können wir die Interna verstehen. Wir haben ein Framework erstellt, die verschiedene Notes beinhalten und jeder Note hat seinen eigenen X86-Betriebssystem. Das ist ein niedriger Neu, das heißt, wir verstehen alle und kontrollieren alle Instruktionen, die ausgeführt werden. Das Betriebssystem läuft auf Computern, die nur bei diesen AMD-Prozessoren, die diese AMD-Prozessoren benutzen. Die Notes werden mit Seriell an NRAS Preparation geschossen und wir benutzen die GPA Opins an den Reset- und Power-Switches auf dem Mainboard, um die Notes schnell neu starten zu können. Wenn die Notes zufälligen Micro-Code ausführen, dann hängen sie einfach und können sich nicht selber fangen. Darauf können wir dann über das Internet zugreifen, weil es nett ist. So sah es zu Hause aus, so sah es ein bisschen später und der Beta-Universität aus. Jetzt haben wir die ganzen Werkzeuge, die wir brauchen, um dies automatisiert zu testen. Wir haben das benutzt, um Heatmaps zu erstellen. Der Name ist ein bisschen falsch. Was wir sagen, wir meinen, was wir mit wärmer Karten der Heatmaps meinen. Es ist eine Übertragung von Micro-Code ROM-Adressen mit den zugehörigen x86 Instruktionen. Eine x86 Instruktion ist in Micro-Code implementiert und der Micro-Code ist in einer speziellen ROM-Adresse und die Karte erklärt uns, welche ROM-Adresse für welche x86 Instruktion verwendet wird. Die Heatmaps haben wir dadurch generiert, dass wir jede Micro-Code ROM-Adresse mit zu einer Adresse gehitscht haben und dann haben wir alle x86 Instruktionen durchgeführt. Also, wenn wir diese Heatmaps haben, können wir zuverlässig unsere eigenen Bits im Micro-Code ausführen. Dadurch, dass wir nur den entsprechenden Breakpoint-Register setzen zu einem bekannten Ort und können dann den zugehörigen x86 Instruktion ausführen. Dadurch wird die Kontrolle umgeleitet zu unserem eigenen Micro-Code Update. Da können wir einfach zufällige Bits hinschreiben und dann wird der einfach ausgeführt. Weil dort keine Dokumentation existiert, wie das Micro-Code Instruktion Set aufgebaut ist, mussten wir den analysieren mit einem Blackbox-Modell, weil es gibt dort keinen Compiler oder irgendwelche andere Dokumentationen dazu. Aber wir hatten ein gutes Oracle. Wir konnten dem einfach Input einfügen und den Output uns anschauen und die unterschiedlichen und dann konnten wir anschauen, was das bedeutet und wie es aufgebaut ist. Lasst uns jetzt mal kurz anschauen, wie so ein CPU Oracle aufgebaut ist. Allererst führen wir eine x86 Anweisung ein. Dann wird ein Initialerstatter hinzugefügt. Das sind ganz viele Werte in x86 Registern. Dann wird ein Micro-Code Update hinzugefügt, dass wir selber installiert haben. Das ist ein Match-Register, das zu einer entsprechenden Instruktion, die wir ausführen, gehört. Und die Micro-Operationen, die dort drin vorhanden sind und die mit zufälligen Bits befüllt sind, werden dann von der CPU ausgeführt. Anschließend kriegen wir einen Output-Status, der im Endeffekt den Start, den die CPU am Ende beinhaltet, ist darstellt. Häufig, wenn die CPU zufällige Bits als Micro-Code ausführt, stützt sie einfach ab. Und manchmal sehen wir keinen Unterschied zwischen dem Input-State und dem Output-State. Nach einigen Wochen des Boot-Forcing haben wir festgestellt, dass ein besonderer Bits-String existiert, der nicht die CPU zum Abschutz bringt und die die Änderungen am Input- und Output-State erzeugt. Das ist unser erster Versuch, um da eine weitere Analyse durchführen zu können. Jetzt wollen wir wissen, was dieser Bits-Stream im Endeffekt macht. Welche Operation führt dieser Bits-Stream durch und das näher anschauen zu können, haben wir angefangen, die einen Bit nach Bit im Bits-String, den wir gefunden haben, ein- und auszuschalten und hier enden wir Bits auf der rechten Seite und wir sehen, dass der Output wieder sich ändert. Und nach einigen Wechsel von Bits hin und her und wenn wir uns den Output anschauen, haben wir festgestellt, dass dieser Bits-String ein EA-Ax-Aditzierung darstellt auf Microcode-Level. Also jetzt konnten wir dieses Wissen anwenden, um eine kleine Datenbank zu erstellen von Obcode, Operanten und Feldern und hier können wir sehen, dass wir die Länge des Intimidiat-Updates vieles haben und es hier einführend konnten. Wenn wir jetzt andere Bits verändern, zum Beispiel Bits weiter hier links, dann bekommen wir anderen Output und wir wissen schon, welche Werte auf der rechten Seite Intimidiat sind und es ändert dann wieder aber anders. Und wenn wir uns den Binercode von den Inputs und Outputs anschauen, dann haben wir mehrere Überprüfungen festgestellt, dass wir ein X-Oder gefunden haben oder ein X-Oder. Nach weiteren Testen haben wir festgestellt, dass die Operations-Feld eine gewisse Länge hat. Die kann man jetzt hier sehen, operant. Und damit haben wir angefangen und wir haben unser Framework so benutzt, dass wir es automatisiert testen können und wo wir mehr oder weniger zufällig Bits ein- und ausgeschaltet haben und den Output so gefiltert haben, dass wir nur interessanten Output bekommen. Dass wir nur geringe Menge an Outputs bekommen. Interessante Output ist, die CPU stürzt dich ab, sie ändert ihr Verhalten, es ist noch ein bisschen zufälliges Geräusche, die da auch einkamen, herausfiltern und dann nach viel, viel Arbeit, kein Problem, wenn ihr es sich lesen könnt, sind wir zu diesem Ergebnis gekommen. Wir haben eine sehr große Liste von unterschiedlichen Operations-Feldern, die wir manchmal Register sind, oder Intermediates oder Größenfelder, ob Flags weiter geleitet werden oder nicht und so weiter. Eine andere Information, die wir herausfinden wollten, war, wie dieser Trials aufgebaut sind, die im ROM gespeichert sind, sind auf den ROM-Code aufgebaut und wie können wir nicht auslesen, wir wollten herausfinden, was sie machen. Zuallererst haben wir ein Breakpoint-Register benutzt an der bekannten Adresse, um Initialen Kontrolle zu bekommen, dann wird eine entsprechende x86 Instruktion ausführen, in der ersten Micro-Code ROM zu haben, dann wird unser Micro-Code im Update zurück zum Micro-Code ROM gesprungen, um genau dieser, zu genau der ROM-Adresse, die wir ausführen wollen, dann dienen wir eins zu der Adresse und benutzen diese Adresse für ein neues Match-Register, um zurück zu unserem Micro-Code RAM zu springen, zu unserem Update das Ergebnis ausgeben soll, dass wir den Input und Output-State uns anschauen können und hier wird nicht unser eigener, zufälliger Bitstream ausgeführt, sondern den Micro-Code-Trial, der im ROM gespeichert wird. Es gibt ein paar Probleme hierbei, zum einen der Micro-Code-ROM Trials könnten nur interne CPU-States verändern, die wir gar nicht sehen können und ein weiterer Nachteil ist, dass das Micro-Code-ROM Trials unter Umständen gar nicht ordentlich ausgeführt werden. Vielleicht springt es irgendwo anders im Micro-Code-ROM und dann haben wir die Kontrolle verloren, aber wir haben unseren Design, dass das egal ist und wir haben einen neuen Micro-Code-ROM in dieser Situation. So ziemlich spät in unserem Projekt haben wir uns dazu entschieden, es heraus zu versuchen, den Micro-Code-ROM von der CPU selber auszulesen und da haben wir ein Chip auseinander gebaut und eine einzelne Schicht transportiert und haben ein Foto davon gemacht, die wir jetzt sehen, hier in Grün ist die Micro-Code-ROM Bereiche. Sie sind relativ groß auf den CPU und wenn man sich genau genug ranzoomt mit einem elektronen Mikroskop heranzoomt und wenn wir uns noch weiter ranzoomen, können wir die weißen Punkte sehen, die den ein bisschen weiter links oder ein bisschen weiter rechts sind mit Ground oder mit der Versorgungsspannung verbunden und das bedeutet, dass diese spezifische Rommzelle entweder eine 1 oder eine 0 darstellt. Wir benutzen optische Schrifterkennung um die meisten dieser Bits herauszufinden und wir konnten nach einigem nachschauen, weil der physikalische Layout ein bisschen schief, das ist für unsere Softwareleute, konnten wir den Micro-Code-Instruktion dort finden und es ist immer noch relativ problematisch für uns, das genaue Mapping von dem physikalischen Layout zu den Micro-Code-ROM-Adressen herauszufinden. Jetzt gehen wir noch mal darüber, was wir bis jetzt herausgefunden haben. Wir haben diese Heatmaps erstellt, wir haben die Sprachsparationen gefunden, die sind aus dem Bereich der Logik, der Arithmetic und dem Branching. Wir können jetzt den X86-Programmszähler, also den Instruktions-Pointer schreiben und wir können den Control-Programm beeinflussen. Wir haben das Sequenzwort gefunden, mit dem wir die nächste Triade ausführen können. Das ist auch Sequenz-Complete, das heißt Sequenzvervollständigung, mit der man sagt, dass das vervollständigt ist und dann gibt es noch das man kann damit auch noch ohne Bedingung springen, dann haben wir die Ersetzungs-Engine gefunden, das ist etwas, mit dem man automatisch Operan, die in der Instruktion sind, in die Mikro-Code-Operationen schreiben, die IAX-Instruktion, also der Operant in der X86-Maco-Operation sind, werden dann einfach übersetzt in die, ebenfalls wieder in die IAX-Register auf dem Mikro-Code. Was wir jetzt machen wollen, ist das Ganze ein bisschen erweitern. Bis jetzt können wir nur die Logik einer X86-Instruktion ändern, durch ein setzendes Breakpoint, also das Registr, was wir aber machen wollten, ist, dass wir auch das Ganze erweitern können. Das können wir entweder tun, indem wir zurück in den Rom springen oder andere Triaden ausführen oder für einfache grundlegende Mikro-Operationen können wir auch grundlegende Logik selber ausführen. Also hier sind ein paar Beispiele. So, als wir das X86 Mikro-Code-Instructions haben, haben wir angefangen, unsere eigenen Mikro-Code-Operationen zu bauen. Das erste, was wir gemacht haben, ist eine simple Instrumentations-Folge, mit der wir im Mikro-Code zählen, wie oft eine X86-Instruktion ausgeführt wurde. Etwas anderes, was wir auch implementiert haben, ist ein kleines Framework, mit dem wir X86 Makro-Operationen nehmen können, uns reinhängen und danach andere Sachen ausführen, also quasi ein Hook. Was wir auch gemacht haben, ist ein remote ausführbare Mikro-Code-Attacken zu bauen. Wir können den Kontrollfluss zurückgeben im Mikro-Code. Wenn der Computer eine bestimmte Webseite besucht, können wir unsere Hintertür auslösen. Wir haben eine Beispiel-Webseite gebaut, mit der sie das ausführen können. Davon hatten wir zwei Versionen, eine mit ASM-JS, also Assembly-JS und die anderen mit WebAssembly. Was wir auch gemacht haben, ist Mikro-Code-Troyana zu bauen. Die sind noch schwerer zu finden. Die kriptografischen Mikro-Code-Troyana führen einen Nebenkanal ein, mit dem man den ECC-Mechanismus aushebeln kann und falsche Fehler einbauen. ECC korrigiert ja und führt man künstliche Fehler hinzu. Jetzt wollen wir uns einmal kurz ansehen, wie so ein Beispiel-Programm aussieht. Dieses Mikro-Code-Programm ist in unserer eigenen Mikro-Code-Register-Transfersprache angegeben, mit der wir das relativ effizient bauen können, ohne dass wir selber lange Textbausteine von Zeichen schreiben müssen. Das ist quasi ein Assembler. Was wir hier machen, ist, wir haben ein TN-D-Register, das ist intern, und verbrechen das mit dem Makro-Register AIX. Das ziehen wir voneinander ab und danach springen wir auf den Teil, wenn wir nicht den Pfad genommen haben. Das erste ist eine Befehlfolge, mit der wir Integer-Division durchführen und unten ist ein Beispiel, wo wir zurück in den Makro-Code-Rom springen. Wir setzen einfach nur die Befehlfolge auf, wir hucken uns rein und wenn sie fertig sind, dann springen wir wieder zurück in die Original-Triade. Das wird aber nur ausgeführt, wenn der AIX-Register mit dem T1-D-Register reinsteht. In diesem speziellen Fall incrementieren wir den Programmsäle um 1 und zählen den zum AIX-Programm-Counter hinzu. Das ist eine Mikro-Code mit der Tür, die AIX mit einem magischen Wert vergleicht und wenn der Wert gefunden wird, dann wird der Programmsäle um 1 hochgezählt. Das heißt, alle hinterherfolgenden Operationen werden alle etwas versetzt ausgeführt. Das ist ziemlich nützlich, aber immer noch recht einfach. Es gibt ja auch sehr viele Prozesse, die man mit dem AIX-Programm einsetzen, wo man gar keinen Micro-Code-Fehler braucht, also keinen Prozessor-Fehler, der vom Hersteller gemacht wurde. Das ist seinerweil Demo-Zeit. Das ist zuerst ein IPC dabei, der einen alten AMD CPU noch darstellt. Das ist einer von den CPUs, der im AIX-Programm bereits reingeladen ist in den CPU. Das ist nur eine Micro-Code-Hintertür. Das erste sind jetzt ein paar Werte, die als Träger funktionieren. Unten ist das das ausgeführte, denn das wird getriggert. Die eigentliche Magie passiert hier unten. Man sieht aus, was in einem Puffer steht, im Speicher. Das ist richtig, dass es in einer Sekundezeige ist. Du liest einfach nur Speicher und packst es in ein temporäres Register, und dann machst du ein bisschen Alp-Medik drauf. Dann implementierst du die eigentliche Semantik von einem Shift-Wide-Double, von der ASA, aber wenn der Trägerwerte nicht funktioniert, dann will man sauber rauskommen, oder das man Probleme macht. Sonst könnte man irgendwas stören auf dem System, das aufhält. Das heißt, hier muss man die Semantik einfach behalten, damit man nicht aufhält. Und jetzt wissen wir, ob wir jetzt triggern wollen oder nicht, und dann, was wir dann machen können, wir fügen noch ein paar Werte in den Register hinzu, oder modifizieren sie irgendwie. Jetzt setzen wir konditional erx auf 11. Das ist der syscall unter view. Dann setzen wir noch ein paar andere Register, dann müssen wir unseren Code aufrufen mit kontrollierten Argumenten. Das machen wir für ein paar weitere Register. Dann schreiben wir konditional den Programm-Counter mit dem, was wir übergeben. Und das kommt aus unserem JS-SSM-Depot. Das passiert nur, wenn ein Input für unsere Instruktion den magischen Counter überschreibt. Das ist jetzt unser Web-Esembler-Programm, das diese x86 Instruktion beinhaltet. Und wenn man sich das sich anschaut, dann haben wir ein Interrupt zum Kernel, sodass ein System-Call ausgeführt wird. Und den Buffer, aus dem wir lesen, ist hier zu sehen, und im Endeffekt sagen wir nur, hey, öffne uns einen Rechner. Und dies ist ein unmodifizierter Firefox, und ich habe keine Laie zu Code hinzugefügt. Und soweit ich weiß, ist es eine sichere Version. Wir drücken jetzt gleich die Rate. Wir haben ein Debugger eingeschossen, das heißt, wir brechen jetzt hier ab und in dem Debugger. Wir müssen ein bisschen warten, weil der EEPC nicht langsam ist, insbesondere, wenn man ein Firefox debugt. So werde es durch die Instruktion durchgehen, die Teile von Firefox sind, um an die richtige Adresse zu kommen. Und jetzt sind wir im Web-Assembly-Modul, das ich vorhin gezeigt habe. Das sind Sachen, die in Firefox läuft. Wir können beliebigen Codes ausführen, indem entsprechend der Web-Assembly hinzugefügt wird. Und wie wir sehen können, ist die Ausführung durch unseren Shift-Rechts-D-Operator und das, was wir wirklich verändert haben. Und wo ich es wirklich aufgepasst habe, ist, dass in unsere Konstante in einem Augmented-Figustel ist. Das heißt, unser Backdoor wird ausgeführt werden. Weil GDP gleich Kontrolle verliert, werde ich ein bisschen cheaten. Und ich weiß, dass wir 6,2 Tage bald springen. Darum erlede ich einfach 6. Und wir sind mitten in die Instruktion. Und wie ihr euch seht, machen wir die ganzen Sachen, die wir im Makro programmiert haben, um die ganzen Augmentregister auszustellen. Und um das mit dem Web-Assembly-Output vergleichen. Wie ich gesagt habe, das ist der Job 5. Jetzt auch diese beiden Opcodes hinten dran. Und wir haben genau diese Opcodes. Das ist einfach weiterführen. Ich hoffe, dass es nicht mehr so funktioniert. Natürlich nicht. Ich lasse nochmal ohne GDP laufen. Und wir haben uns an Taschenrechner. Wie ich schon gesagt habe, wir können auch replikraftische Hintertüren einbauen. Weil wir ein Reboot brauchen. Ich will das ein bisschen anders zeigen. Wir haben hier eine Standard-Signatur-Verifikation. Ja, eine geltige Signatur, weil alles in Ordnung ist. Aber jetzt werden wir die Hintertür schnell einfügen. Und unseren speziellen Kernel springen um diese Updates. Und während das neue bootet, will ich eine andere Demo kurz zeigen. Ich habe hier diese Konsole. Und die geht wirklich ins Script zu einem Raspberry Pi Schicken, der gerade im CCL sitzt. Und der wird mit der netteriellen Konsole mit einem entsprechenden MD-Note verbunden. Und das wird den Micacode ausführen, indem wir ihm sagen, was wir ausführen sollen. Und zuallererst sage ich, was passiert. Und wir sagen, hey, führt gar nichts aus. Und jetzt, was wir zeigen sollen, ist, dass EWP natürlich all in all ist. Weil ich habe nichts verändert. Und jetzt werde ich sagen, hey, lasst uns den Hook einfügen. Und... Auf einmal hat sich was geändert. Und was sich geändert hat, ist, dass dieser Micro-Code, den ich zur CPU geschickt habe. Und das einzige, was der macht, ist, dass die nächste 86 Institutionen, die ausgeführt werden soll, auf dem 6 speichern und dann zu einer speziellen Location springt. Und dieser spezielle Ort ist ganz weit hier. Das heißt, wir kriegen in X86 Controller ohne ein spezielles Programm zu schreiben. Es funktioniert einfach. Und das ist auch etwas, was wir machen können. Wir können Micacode Hooks einfügen und der EEPC ist jetzt gebotet. Das heißt, wir müssen noch schnell EF-VNC wieder einrichten. Einfach noch einen Sekunde warten. Wir sind wieder auf dem EEPC. Und wenn ein anderes Update installiert, dieses Update hat nicht die Firefox-Hintertür, aber anstatt dessen wollen wir die Krypto-Demo noch mal ausführen und auf einmal sagt es in valide Signature. Da wäre ein Fehler in die Berechnung und die kriptografische elliptische Kurvenberechnung eingeführt. Und damit können wir kriptografische Angriffe ausführen. Und noch passieren die Daten, was ich gemacht habe, ist ein kriptografischer Schwachstelle in eine andere Seite, die sich kriptografische Funktionen eingeführt habe. Und damit kann man kriptografischen Inhalt herausfinden. Und wir müssen nicht das Programm modifizieren. Und das in einem vormals vertrauenswürdigen Gerät. Und dazu bedeutet, dass wir jetzt ein Sicherheitsproblem haben. Man kann irgendein Update hinsenden. Ich habe es jetzt live gemacht, CPU geschickt und es hat es verstanden. Wir können eine Backdoor machen und wir können es wirklich nicht reparieren. Wir müssen eine kriptografische Natur auf der CPU hinzufügen. Natürlich kann man ein Hick fixen. Das ist einfach den Update, Michael, das muss man ausschalten. Im Endeffekt ist es nicht so schlimm, weil wir einen sehr starken Eingreifer-Motor haben. Das heißt, jemand muss ein Bios modifizieren, um etwas zu installieren. Also ist es normalerweise, weil es überhaupt kein Problem ist. Und zu guter Letzt, ja, Michael Codt kann es reverse-engineered werden und geändert werden. Und wenn ihr mehr darüber reden wollt dann schaut euch Sisi's View auf der Binary-Sicherheits-Assembly. Wir haben diesen E-PC dabei und auch einen alten K10, sodass ihr das selber hinschicken könnt. Außerdem haben wir einfach Sample-Updates und hat dem L-Datei auf GitHub gesendet, wo der Updatetreiber aufwanden ist, aber bitte seid sicher. Das kann dazu führen, dass die CPU kaputt geht. Also wir haben es selber nicht hingekriegt, aber ziemlich nah. Jetzt haben wir Zeit für Fragen aus dem Publikum. Wir haben auch einen Signalangel, der uns bereits gesagt hat, dass wir Fragen haben. Bevor wir zu den Fragen kommen, wenn ihr den Saal verlasst, ok, nun zum Signalangel. Mit der Frage aus dem Internet. Das ist ein Signalangel. Wir haben eine Frage, die ziemlich am Anfang vom Talkvorkommen ist. Ist es möglich, den Prozessor Physik zu beschädigen? Durch Malgecode? Habt ihr eine CPU mal wirklich kaputt gemacht? Wir haben bisher keine Kaputt gemacht, bis auf die eine, wo wir den Schutz oben gemacht haben. Klar, es ist wahrscheinlich möglich, haben wir ein bisschen noch nicht hingekriegt, aber das sein der AMD-Zaun als wäre es nicht möglich. Seitens gibt es ein Feature, was man anträgen kann, was wir noch nicht gefunden haben. Ist es möglich, aber wahrscheinlich eher nicht. Mikrofon 6. Ist es möglich, Performance-Problem mit Microcode zu fixen? Wir haben auch darüber nachgedacht. Zum Beispiel für Binärinstrumentierung könnte man Code emulieren, zum Beispiel wie es Walter macht oder man könnte es statisch instrumentieren, aber es hat alles Nachteile. Entweder das ist langsam oder es ist nicht vollständig. Also, Microcode-Projekt, eine Qual-performant, könnte eine relativ vorständige und performante Basis für Microcode-Institutierung sein, aber das Problem ist, im Moment ist es relativ limitiert und frei für neuere AMDs und für Interests der Code relativ schlossen. Vielleicht werden die Hersteller damit umgehen in Zukunft und dann könnte man das benutzen, um die Geschwindigkeit für solche Instrumentierungs-Frameworks zu beschleunigen. Es könnte auch dazu genutzt werden, um neue Instruktionen so zu fügen, aber ich bezweifle, dass es sehr viel schneller ist, als wenn wir es gleich hin, 68 Instruktionen bauen würden. Wir haben das schon mal benutzt, wir haben es auch schon mal versucht, wir haben damit Erfolg gehabt, aber der Verifizierungs-Mechanismus ist dort stärker. Wir haben noch keinen sehr tiefen Einblick genommen in diese Microcode-Updates von Intel. Wir haben das schon mal benutzt, wir haben das auch schon mal versucht, um das zu diskutieren. Kommt einfach mal vorbei bei unserer Assembly und dann können wir da drüber zusammen reden. Hallo. Sollte ich sagen, dass Microcode eher eine Riske-Architektur ist, eine Zisk-Architektur. Es gibt sehr irgendwelche Instruktionen, die ein Riske-Architektur eher nicht finden. Also die Frage ist, ist es risk-ähnlich? Ich kann dem zustimmen. Die Microcode-Instruktionen sind im größten Teil relativ simpel. Ein ganz interessantes Feature dabei ist, dass man einen drei operandenden Modus hat, also drei Register, die man übergeben kann, und man kann auch die Instruktionen von zwei Zierregister und nur einen Quellregister, was im Microcode nicht möglich ist. Aber es ist möglich im Microcode. Das ist relativ interessant. Danke. Woher wisst ihr, wie eine spezielle Instruktion, welchen Micro-Input-Point für eine Instruktion habt? Das ist eine sehr interessante Frage. Wir haben vorhin die Heatmaps gezeigt, die haben wir interpretiert, indem wir einen Breakpoint an jeder möglichen Microcode-Adresse gesetzt haben und alle möglichen Instruktionen probiert haben. Manchmal haben wir mehr als einen Hit gekriegt, weil eine Rom-Adresse nicht genug ist und die gesamte 86 Instruktionen zu implementieren. Aber wir haben acht Register, das heißt, wir können acht Breakpoints gleichzeitig setzen und die setzen wir dann auf verschiedene Stellen und schauen, an welche zuerst angeschlägt. So kommen wir dann Schrittwischen näher, welche Adresse das wirklich implementiert. Auf die Art haben wir dann auch die einen Sprung-Punkte gefunden. Ihr habt gesagt, dass Microcode-Updates nicht möglich ist. Das bedeutet, dass wenn ein vendor ein Microcode-Update herausfindet, dann ist es ein Programm, das in Bios hinzugefügt wird. Dann ist es ein Update, bei jedem Boot neu installieren soll. Die CPU-Hersteller veröffentlichen diese Updates natürlich nicht, aber sie geben sie den Mainboard-Hersteller und die machen das möglicherweise in Bios oder halt im UEFI. Und die enthalten dann die Microcode-Updates und die werden beim Boot geladen. Im Linux, der ist auch ein Microcode-Package, was ebenfalls Microcode-Updates auf jedem Boot durchführt und das habe ich auch geheitigt für meine Zecke. Das heißt, je nachdem wie es läuft, kriegst du es entweder von Bios oder von deinem Betriebssystem. Ich wollte fragen, abgesagt, dass es eventuell möglich ist, speziell Microcode-Updates installieren, um den Update-Mechanismus auszuschalten. Wie könnte man das machen? Wie würde man so etwas implementieren innerhalb von Libre-Boot und sicherstellen, dass der Microcode-Updates-Mechanismus sehr früh oder so früh wie möglich ausgeschaltet wird? Das wäre eigentlich relativ einfach zu bewerkstelligen. Das benötigt nun ein bisschen reverse Engineering Arbeit bei uns, aber durch die Hitnaps wissen wir schon relativ gut, wie der Update-Mechanismus wahrscheinlich funktioniert, weil, wenn man bei Backpoints dort setzt, kannst du keine Microcode-Updates-Mechanismen setzen. Das heißt, man müsste dann ein bisschen Arbeit machen, aber es wäre relativ einfach, ein Microcode-Updates-Mechanismus in Libre-Boot reinzubauen und dann relativ früh das auch wieder auszuschalten, dass man das nicht mehr benutzen kann. Kann man diesen Trick benutzen und die Geheimnisse zum Beispiel Schlüsse aus sicheren Inklaven herauszugeben oder ähnlichen Entitäten in der CPU? Wahrscheinlich eher nicht. Wir haben natürlich keine definitive Antwort, weil die Versionen der CPUs, die bei uns funktionieren, haben keine sicheren Klaren. Am Wasser wissen ist, dass man dieselben Rechte hat, wie der Code, der die angetriggert hat. Zum Beispiel bei der EMU. Dann wird der Microcode-Instruktion ebenfalls mit den EMU-Rechten gestartet. Er hat gesagt, dass ihr verschiedene Microcode ausprobiert habt. Wie viele Prozent der totalen, das ganze Platz, der dort vorhanden ist, die Situation, die noch nicht definiert sind, oder ist das alles fertig? Es ist sehr, sehr wahrscheinlich, dass wir nicht viele von den Instruktionen gefunden haben. Es gibt immer noch bestimmte Regionen in dem Microcode-Instruzonsatz, die wir noch nicht gefunden haben. Jedes Mal, wenn wir sie ansprechen, was die Anweisungen machen, wir können auch noch manche der Register beobachten, wir können interne Register zum Teil nicht anschauen und viele Anweisungen, die den internen Status der CPU verändern. Zum Beispiel Features ein- und ausschalten oder schneller oder langsamer Pfade für manche Sachen an- und ausschalten. Das können wir nicht wirklich beobachten und wir können nicht wissen, was der Bitstream oder die Instruktion tut. Und ja, sehr wahrscheinlich sind da ein Haufen Instruktionen drin, die wir nicht verstehen. Habt ihr darüber nachgedacht, ob es Wege gibt, wie man sagt, hey, mein Microcode hat eine Backdoor? Können wir das herausfinden, dass das der Fall ist? Ja. Während unserer Untersuchung davon haben wir uns noch keine Zeit gehabt, uns das anzuschauen. Aber wir haben das schon mal diskutiert und das ist eine wirklich gute Frage. Wenn man Microcode benutzt, um eine x86 Makro Instruktion zu hucken, dann hat man einen größeren Zeitversatz. Wenn man das genau messen würde, könnte man das feststellen und dass diese x86 Instruktion mehr tut, als sie es normal tun sollte. Aber es kommt auch darauf an, der Microcode macht nicht nur Dekodierung, sondern es wäre möglich, dass es trotzdem geht, dass man Trojaner dort versteckt, die man dann nicht finden könnte. Okay. Jetzt, wo wir Instruktionen wieder re-implementieren können, könnte man eine komplett andere Instruktion set implementieren? Klar könnte man machen. Das habe ich in den Verwandtenarbeitungen auch gezeigt, bei dem Truvas Talk von Narik, der macht so was. Ja, es geht. Wir sind immer noch nicht weit genug mit unserem Hintergrundwissen um das zu machen, aber wir glauben, dass er internes Wissen hat. Okay, zwei Fragen. Ich habe dir irgendeine Funktion gefunden, um ein paar Baxen x86 zu finden, auszuführen. Ich zeige dir mal, dass die Flieskommar-Zahlen-Unit, die haben wir gefunden, und wir haben auch ihre Muster gefunden, und es muss auch ein Weg geben, sie anzusprechen. Aber haben wir noch nicht. Zweite Frage beim Dekodieren. Gibt es da nicht so kurze Operationen, die ihr gezeigt habt? Werden die nicht auch durch diesen Code, sondern die Schortdekoder, die übersetzten einfache Anweisungen. Wir wissen, dass es einen Weg gibt, nicht Mikrokode-Übersetzte Instruktionen zu hocken. Sie sind auch nicht sicher, wir wissen zwar nicht, wie es geht, aber es geht. Hallo. Vielleicht habt ihr es gestartet, habt ihr mit Intel oder AMD darüber geredet, habt ihr mit zurückbekommen? Nein, wir haben Intel nicht angesprochen, aber wir haben mit AMD geredet. Die Arbeit ist auch auf Usenix veröffentlicht worden, und die haben 90 Tage gewartet, bevor wir die Ergebnisse rausgeschickt haben. Wir haben nach Feedback gefragt, und es ist wahrscheinlich so, dass sie in den neueren Versionen mehr oder weniger sichere Kryptomechanismen, die das verhindern in den neueren Architekturen. Das heißt, sie sind nicht wirklich interessiert daran. Großrunder Applaus für unsere Speaker, und damit verabschieden wir uns auch aus der Übersetzerkabine der X86 Architektur Übersetzend Waren