An Architecture-Agnostic Analysis Framework for Binary Executables
Total Page:16
File Type:pdf, Size:1020Kb
MENTALESE - An Architecture-Agnostic Analysis Framework for Binary Executables Dissertation zur Erlangung des Grades eines Doktor-Ingenieurs der Fakultät für Elektrotechnik und Informationstechnik an der Ruhr-Universität Bochum vorgelegt von Behrad Garmany geboren in Maschhad Bochum, November 2020 ii Gutachter: Prof. Dr. Thorsten Holz, Ruhr-Universität Bochum Zweitgutachter: Prof. Dr. Konrad Rieck, Technische Universität Braunschweig Tag der mündlichen Prüfung: 11. Februar 2021 Acknowledgements I am deeply grateful to my advisor Prof. Dr. Thorsten Holz for his support, guidance, and patience. He has given me the chance to pursue my interests in binary analysis and reverse engineering, which have been the focus of my studies for the past years. I would also like to thank Prof. Dr. Konrad Rieck for spending his valuable time for the review of this work. During my time at the chair of systems security, I had the chance and the pleasure to work with inspiring, collaborating, and hard working people to achieve common research goals. In particular, I would like to mention Martin Stoffel, Robert Gawlik, Jannik Pewny, Moritz Contag, Philipp Koppe, Benjamin Kollenda, Andre Pawlowski, Tim Blazytko, and Sebastian Vogl. Special thanks goes to Jannik Pewny who was spending his precious time to present our paper at the 34th Annual Computer Security Applications Conference whilst I was unable to travel, even though he was not part of the group of authors. Additionally, I would like to thank Cornelius Aschermann for inspiring talks and brainstorming discussions as well as a continuous reminder to keep going. I would also like to thank all other students who I had a great time with during my years at the chair. I want to express my gratitude to my friends Carsten Willems, Johannes Dahse, and Felix Schuster for their continuous support and encouragement to not lose track. My deepest gratitude goes to my parents and my sister for their unconditional love and support over all the years, encouraging me to pursue my passion. In the past three years I had the greatest luck to spend my life with my fiancé Verena who stood by my side and supported me with all my decisions. Abstract Static program analysis enables to reason about program behavior and its semantic properties without actually running the program. It enjoys a wealth of achievements based on decades of research. Unfortunately, it comes with some unpleasant computational drawbacks that stem from the problem that almost any interesting property to reason about is undecidable. Our field of research presented in this thesis, tackles a niche in the sector of program analysis which comes with the aspect of binary programs. At the end of each translation pipeline, it is the binary that is executed. Apparently, binary program analysis is the only choice when source code is not available. While it poses additional challenges that increase the complexity giving rise to more undecidable problems to deal with, it also has some pleasant properties which aid in the process of the analysis. Syntactic edge cases and language features, for instance are in a sense canonicalized, and many modules of a program are compiled into a single binary. The Internet of Things era has given rise to a high competition among companies that induced the use of commercial third party software that are usually shipped as binaries. A popular trend in third party code reuse incorporates more and more open source software which comes at risk. This era poses an additional interest in architecture agnostic tools that aid in the process of cross architecture binary analysis. Similarly to the interest for source code analyzers that concentrate on covering many languages, our interest concentrates on covering many architectures. This brings us to the first problem to be tackled—aside from the disassembly and control flow recovery— which comes with the choice of a proper intermediate language (IL). Ideally, the IL covers many architectures, has a small semantic footprint (small instruction set), and allows developing generic analyses that can be applied to all architectures. This thesis introduces Mentalese (language of thought), a framework for architecture agnostic analysis. The name is inspired by the philosophical hypothesis that assumes a language in which processes of thought take place. The way we approached binary analysis resembles in many ways this process. We discuss in this work our early steps to find a suitable IL and specify the design and the choices we made to build a framework that adds value to our field of binary analysis. The design of Mentalese, is concentrated to be scalable, flexible, accessible, and extensible. Based on our prototype we have developed tools that aided in the process of exploitation, cross architecture bug search, and bug detection. Zusammenfassung Die statische Code-Analyse ermöglicht das Ableiten von Aussagen über das Program- mverhalten und seine semantischen Eigenschaften ohne die tatsächliche Ausführung des Programms. Das Feld genießt einen Reichtum von Errungenschaften, die auf jahrzehntelanger Forschung beruhen. Leider ist mit der statischen Analyse das klassische Problem der Unentscheidbarkeit verknüpft, da fast jede interessante Eigenschaft nach der wir fragen eine nicht triviale und semantische Eigenschaft ist. Die Gesetzte der Berechenbarkeit erlauben kein Programm das für alle Programme eine solche Eigenschaft nachweisen kann. Die in dieser Dissertation vorgestellte Forschung nimmt eine Nische im Bereich der statischen Programmanalyse ein, dessen Anwendung sich auf binäre (aus- führbare) Programme fokussiert. Am Ende der Übersetzungspipeline des Quellcodes, ist es die Binärdatei, die auf der jeweiligen Maschine zu Ausführung kommt. Ist der Quellcode nicht verfügbar, so bleibt die binäre Analyse die einzige Wahl. Hierdurch wird die Analyse vor zusätzliche Herausforderungen gestellt, die wir in dieser Arbeit diskutieren. Allerdings hat die Analyse auf binärer Ebene auch Vorteile vorzuweisen. So werden syntaktische Strukturen und Sprachfeatures auf Maschinenebene kanonisiert. Auch werden viele Quellcode Module in eine einzige ausführbare Datei übersetzt, so dass das Programm im Gesamtkontext analysiert werden kann. Die Ära des Internets der Dinge (IOT) hat zu einer erhöhten Konkurrenz zwischen Unternehmen geführt, die vermehrt den Einsatz von kommerzieller Software von Drittanbietern induziert. Diese werden üblicherweise als ausführbare Binärdateien ausgeliefert. Ein beliebter Trend bei der Wiederverwendung von Drittanbietercode umfasst immer mehr die Einbindung von Open-Source-Software, die nicht ohne Risiko ist. Die Konsequenz ist ein Bedarf an architekturunabhängigen Tools, die den Prozess der architekturübergreifenden Binäranalyse ermöglicht. Dabei verfolgen wir, analog zum Trend kommerzieller Quellcodeanalysen, die ein möglichst breites Spektrum an Programmiersprachen abdecken, das Interesse möglichst viele Architeckturen abzudecken. Dies führt uns zu unserem ersten Problem, das neben dem Prozess des Disassemblierens und der Wiederherstellung des Kontrollflusses, die Wahl einer geeigneten Zwischensprache (intermediate language oder IL) in den Vordergrund stellt. Idealerweise deckt die IL viele Architekturen ab, hat einen kleinen Befehlssatz und ermöglicht die Entwicklung generischer Analysen, die auf alle Architekturen angewendet werden können. Bisherige Ansätze in der Forschung zur binären Analyse scheitern an der Skalierbarkeit und Stabilität. Diese Dissertation befasst sich mit unserer protoptypischen Implementierung von Mentalese (Sprache des Geistes), ein Framework für architekturunabhängige Analysen ausführbarer Programme. Der Name stammt von der philosophischen Hypothese ab, die von einer Sprache ausgeht, in der Denkprozesse stattfinden. Die Art und Weise, an der wir uns den Problemen der Binäranalyse nähern, entspricht in vielerlei Hinsicht diesem Prozess. Diese deklarative Art der Problemlösung ist eines der Konzepte von Mentalese. Das Design von Mentalese ist so konzipiert, dass es skalierbar, flexibel und leicht erweiterbar ist. Auf der Grundlage dieses Frameworks haben wir Tools entwickelt, die den Exploitation-Prozess unterstützen, eine architekturübergreifende Bug-Suche ermöglichen, sowie auch Bugs erkennen. Contents List of Figures xiii List of Tables xv List of Abbreviations xvii 1 Introduction 1 1.1 Binary Landscape . .3 1.2 Challenges . .4 1.3 Contributions . .5 2 Foundations 9 2.1 The VEX Intermediate Language . 11 2.2 Symbolic Execution: Steps with VEX . 14 2.2.1 Cross-Architecture Basic Block Semantics . 17 2.2.2 Path Extraction for Dynamic Hooks . 21 2.3 A suitable IL . 22 2.3.1 Dataflow Essentials . 26 2.3.2 Static Single Assignment . 28 3 Mentalese - A Binary Analysis Framework 37 3.1 From Datalog to Binary Analysis . 38 3.1.1 Datalog . 39 3.1.2 Knowledgebase: A Mental-IR ................ 41 3.2 Overview . 44 3.3 Frontend . 47 3.3.1 Stack Normalization . 48 3.3.2 SymIL Extensions . 50 3.3.3 Scopes . 51 3.4 Backend . 54 3.4.1 Transition Descriptors . 54 3.4.2 Pointer Analysis . 57 3.4.3 Flow-Sensitivity . 64 ix x Contents 3.4.4 Context-Sensitivity . 65 3.5 Analysis Derivatives . 69 3.5.1 Taint-Analysis . 69 3.5.2 Value Propagation . 74 3.5.3 Slicing . 75 3.6 Experimental Study: Pointer Analysis . 77 4 Towards Automated Generation of Exploitation Primitives for Web Browsers 87 4.1 Model and Assumptions . 89 4.2 Design . 93 4.2.1 Finding Sinks . 95 4.2.2 Program Paths . 96 4.2.3 Triggering Input . 102 4.2.4 Implementation Details . 103 4.3 Evaluation . 103 4.3.1