Malware-Analyse und Reverse Engineering. 4: Startup Prof. Dr. Michael Engel

Ähnliche Dokumente
U23 - Shellcode. Twix Chaos Computer Club Cologne. Motivation Einstieg Der erste Shellcode Nullbytes, NOP Slides

U23 Assembler Workshop

U23 Assembler Workshop

Systemprogrammierung

Karlsruher Institut für Technologie

Übung zu Betriebssysteme

2Binden 3. und Bibliotheken

Programmiertechnik. Teil 4. C++ Funktionen: Prototypen Overloading Parameter. C++ Funktionen: Eigenschaften

Übung zu Betriebssysteme

7 Laufzeit-Speicherverwaltung

Vorlesung: Rechnerstrukturen, Teil 2 (Modul IP7)

Unterprogramme. Unterprogramme

Betriebssysteme Teil 3: Laufzeitsystem für Programme

U7 POSIX-Prozesse U7 POSIX-Prozesse

Typ : void* aktuelle Parameter Pointer von beliebigem Typ

Kompilierung eines Programmes. Mnemonics, ld, GCC, AS

Rechnern netze und Organisatio on

Maschinencode Dateiformat und Stackframes

Übungen zu Softwaresysteme I Jürgen Kleinöder Universität Erlangen-Nürnberg Informatik 4, 2004 K-Uebung9.fm

G 5. Übung. G-1 Überblick. Besprechung 3. Aufgabe. Infos zur Aufgabe 5: fork, exec. Rechenzeiterfassung. Ü SoS I G.1

Exploit-Entwicklung mit Python

Systemnahe Programmierung in C Übungen Jürgen Kleinöder, Michael Stilkerich Universität Erlangen-Nürnberg Informatik 4, 2011 U7.fm

Technische Informatik I Übung 3: Assembler

Einführung in die Programmiersprache C

Datenstrukturen, Alignment Stack Prozeduraufruf, Parameterübergabe und -rückgabe (Calling Conventions) Leaf procedures

Übung 1 - Betriebssysteme I

2. Aufgabenblatt Musterlösung

Einführung in die Programmiersprache C

Assembler Unterprogramme

Technische Informatik 1 Übung 2 Assembler (Rechenübung) Georgia Giannopoulou (ggeorgia@tik.ee.ethz.ch) 22./23. Oktober 2015

Übungsblatt 10 (Block C 2) (16 Punkte)

Informatik I (D-ITET)

Informatik II Übung 05. Benjamin Hepp 3 April 2017

ERA-Zentralübung Maschinenprogrammierung

Repetitorium Programmieren I + II

Betriebssysteme. Tafelübung 2. Thread-Synchronisation. Olaf Spinczyk.

Maschinensprache. 2.5 x86 Speicherzugriff. Universität Mannheim

Technische Informatik I - HS 18

Rechnernetze und -Organisation. Teil B 2012 Tomislav Nad Karl C. Posch

Besprechung Aufgabe 1: Prozesse verwalten Fortsetzung Grundlagen C-Programmierung Aufgabe 2: Threadsynchronisation

Rechnernetze und Organisation

Rechnerne etze und -O Organisatio on

Rechnernetze und -Organisation. Teil B (30. März 2011) 2011 Michael Hutter Karl C. Posch

Einführung in die Programmierung mit C++

Einführung. Übungen zur Vorlesung Virtuelle Maschinen. Stefan Potyra. SoSe 2009

Buffer Overflow 1c) Angriffsstring: TTTTTTTTTTTTTTTT (16x) Beachte: Padding GCC-Compiler Zusatz: gcc O2 verhindert hier den Angriff (Code Optimierung)

Informatik II Übung 5

PThreads. Pthreads. Jeder Hersteller hatte eine eigene Implementierung von Threads oder light weight processes

Zeiger vom Typ void* benötigen weniger Speicher als andere Zeiger, da bei anderen Zeigertypen zusätzlich die Größe gespeichert werden muss.

4.4 Prozesse. H. Weber, HS RM SS 2010 Systemprogrammierung Kap. 4.4 Seite 1 von 22

PROGRAMMIEREN MIT UNIX/LINUX-SYSTEMAUFRUFEN

Malware-Analyse und Reverse Engineering. 13: Rückblick über das Semester Prof. Dr. Michael Engel

Übungen zur Vorlesung Systemsicherheit

Einführung Sprachfeatures Hinweise, Tipps und Styleguide Informationen. Einführung in C. Patrick Schulz

Fallbeispiel Unix. Betriebssysteme. Hermann Härtig TU Dresden

Buffer Overflow. Denis Graf, Tim Krämer, Konstantin Schlese. Universität Hamburg Fachbereich Informatik. 6. Januar 2013

Informatik I (D-MAVT)

Assembler - Adressierungsarten

Homogene Multi-Core-Prozessor-Architekturen

Informatik II - Tutorium 5

Assembler. Dr.-Ing. Volkmar Sieh. Department Informatik 4 Verteilte Systeme und Betriebssysteme Friedrich-Alexander-Universität Erlangen-Nürnberg

Einleitung Grundlagen Erweiterte Grundlagen Zusammenfassung Literatur. C: Funktionen. Philip Gawehn

6 Speicherorganisation

Praxis der Programmierung

Übungen zu Systemnahe Programmierung in C (SPiC) Inhalt. Moritz Strübe, Rainer Müller (Lehrstuhl Informatik 4) Sommersemester 2014

Fallbeispiel Unix. Betriebssysteme. Hermann Härtig TU Dresden

Grundlagen der Informatik III Wintersemester 2010/ Vorlesung Dr.-Ing. Wolfgang Heenes

Selbststudium Informationssysteme - H1102 Christian Bontekoe & Felix Rohrer

Oliver Höftberger. 20. Oktober 2014

Variablen. Deklaration: «Datentyp» «Variablenname» Datentyp bestimmt Größe in Bytes: sizeof Beispiel: long int v; Größe: 4 Bytes

Heap vs. Stack vs. statisch. 6 Speicherorganisation. Beispiel Statische Variablen. Statische Variablen

6 Speicherorganisation

Threads. Foliensatz 8: Threads Folie 1. Hans-Georg Eßer, TH Nürnberg Systemprogrammierung, Sommersemester 2015

Übungsblatt 10 (Block C 2) (16 Punkte)

Übungspaket 25 Kommandozeilenargumente

Grundlagen zur Assemblerprogrammierung unter SPIM im Sommersemester Lorenz Schauer Mobile & Verteilte Systeme

Mikrocomputertechnik. Unterprogramm

Heap vs. Stack vs. statisch. 6 Speicherorganisation. Beispiel Statische Variablen. Statische Variablen

Tafelübung zu BS 2. Threadsynchronisation

Verwendung Vereinbarung Wert einer Funktion Aufruf einer Funktion Parameter Rekursion. Programmieren in C

Überblick: Teil D Betriebssystemabstraktionen

6. Intel IA-32 Prozessoren Aufbau und Adressierungsarten

x86 Assembler Praktische Einführung Sebastian Lackner Michael Müller 3. Juni 2013

Michael Dienert. 8. Dezember 2016

Adressierungsarten des 6809 (Forts.)

Vorbemerkungen Einführung Buffer Heap vs. Stack Sicherheit Literatur. Umgang mit Buffern. Stefan Bruhns

Vorlesung Rechnerarchitektur

Eine Mini-Shell als Literate Program

Programmierung und Angewandte Mathematik

Was ist ein Prozess?

Übung Rechnerstrukturen. Aufgabenblatt 10 Ausgabe: , Abgabe: :00. Aufgabe 10.1 (Punkte 25) Gruppe Matrikelnummer(n)

C++ Teil 12. Sven Groß. 18. Jan Sven Groß (IGPM, RWTH Aachen) C++ Teil Jan / 11

Nachname: Vorname: Matr.-Nr.: Punkte: 1. Aufgabe: ( / 25 Pkt.) Gegeben ist das folgende Struktogramm zur Berechnung von sin(x) mit Hilfe einer Reihe.

Transkript:

Malware-Analyse und Reverse Engineering 4: Startup 6.4.2017 Prof. Dr. Michael Engel

Überblick (heute) Themen: Prozesserzeugung in Linux: fork und exec Linker und Einsprungpunkt Funktionsaufrufe und Parameterübergabe Stackframes MARE 04 Startup 2

Prozesserzeugung in Linux Zweistufiger Ablauf: Prozess erzeugt identische Kopie ( Kindprozess ) von sich selbst Systemaufruf fork() Erzeugt Kopie des Adressraums Kindprozess überschreibt eigenen Adressraum mit Code & Daten eines anderen Programms: Systemaufruf exec() MARE 04 Startup 3

Ablauf von fork (1) pid=25.data.text Stack Ressourcen Prozesszustand Dateien Unix-Kernel MARE 04 Startup 4

Ablauf von fork (2) pid=25.data.text Stack Ressourcen Prozesszustand Dateien < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 5

Ablauf von fork (3) pid=25.text.data Stack Prozesszustand < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Dateien Ressourcen pid26 ist Kopie von Prozess mit pid25, beide in fork()! pid=26.text.data Stack Prozesszustand < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 6

Ablauf von fork (4) pid25 und pid26 kehren aus fork zurück. Unterschied: Rückgabewert! pid=25.data.text Stack Prozesszustand Ressourcen pid=26.data.text Stack Prozesszustand Dateien < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); cpid=26 cpid=0 < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 7

Ablauf von fork (5) pid25 überspringt if()-block, pid26 führt ihn aus pid=25.data.text Stack Prozesszustand Ressourcen pid=26.data.text Stack Prozesszustand Dateien < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); cpid=26 cpid=0 < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 8

Ablauf von fork (6) pid25 wartet auf Ende von pid26, pid26 führt exit(0) aus und beendet sich pid=25.data.text Stack Prozesszustand Ressourcen pid=26.data.text Stack Prozesszustand Dateien < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); cpid=26 cpid=0 < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 9

Ablauf von fork (7) pid26 ist beendet und aus Speicherentfernt, pid25 beendet sein Warten auf Ende von pid26 pid=25.data.text Stack Prozesszustand Ressourcen pid=26 Dateien.text.data Stack Prozesszustand < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); cpid=26 cpid=0 < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 10

Funktion von exec() Ersetzen des Speicherinhaltes des aktuellen Prozesses durch die Sektionen einer anderen ausführbaren Datei (Parameter von exec) Einzige Methode, neue Programme zu starten...da fork() nur Kopie des aufrufenden Prozesses erzeugt Kernel öffnet ausführbare Programmdatei ELF-Lader lädt Text- und Datensektionen ld.so lädt evtl. shared libraries Stack, Heap, BSS werden neu angelegt Neues Programm wird am Einsprungpunkt gestartet MARE 04 Startup 11

Ablauf von exec (1) Kindprozess ist in Ausführung des if()-blocks Ressourcen pid=26.data.text Stack Prozesszustand Dateien cpid=0 < > int cpid=fork(); if (cpid==0) <child code> exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 12

Ablauf von exec (2) In if-block wird Systemaufruf exec() aufgerufen Ressourcen pid=26.data.text Stack Prozesszustand Dateien cpid=0 < > int cpid=fork(); if (cpid==0) exec( foo ); exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 13

Ablauf von exec (3) Kernel entsorgt Speicherinhalt von pid26 Ressourcen pid=26.data.text Stack Prozesszustand Dateien cpid=0 < > int cpid=fork(); if (cpid==0) exec( foo ); exit(0); <parent code> wait(cpid); Unix-Kernel MARE 04 Startup 14

Ablauf von exec (4) Kernel öffnet und lädt ausführbare Datei foo von Dateisystem Ressourcen pid=26 Dateien Unix-Kernel foo MARE 04 Startup 15

Ablauf von exec (5) Speichervon pid26 durch Sektionen von foo ersetzt, startet von vorne Ressourcen pid=26.data.text Stack Prozesszustand Dateien <erste Zeile von foo> exit(0); Unix-Kernel foo MARE 04 Startup 16

Starten des neuen Programms nach exec() Wo startet mit fork() neu erzeugter Prozess? Ist identische Kopie des Elternprozesses Fortsetzung nach Rückkehr aus fork()-aufruf Wo startet ein neu geladenes Programm? Kein alter Programmcode vorhanden Start von vorne......also in main()? nein! Vor Aufruf von main sind Initialisierungen durchzuführen z.b. Nullsetzen von Inhalten der.bss-sektion MARE 04 Startup 17

Überblick Programmstart Loader ruft _start auf Start nutzt libc- Funktion _libc_start_main Diese ruft unsere main-funktion auf! MARE 04 Startup 18

Das einfachste C-Programm Adressen der Instruktionen...ein leeres main() Im Disassembler (Ausschnitte): $ objdump d prog1 080482e0 <_start>: 80482e0: 31 ed xor %ebp,%ebp 80482e2: 5e pop %esi 80482e3: 89 e1 mov %esp,%ecx 80482e5: 83 e4 f0 and $0xfffffff0,%esp 80482e8: 50 push %eax Opcodes 80482e9: 54 push %esp 80482ea: 52 push %edx 80482eb: 68 00 84 04 08 push $0x8048400 80482f0: 68 a0 83 04 08 push $0x80483a0 80482f5: 51 push %ecx 80482f6: 56 push %esi 80482f7: 68 94 83 04 08 push $0x8048394 80482fc: e8 c3 ff ff ff call 8048301: f4 hlt prog1.c: Disassemblierte Mnemonics und Parameter int main(void) Übersetzen mit: 80482c4 < libc_start_main@plt> gcc g o prog1 prog1.c Compiler-Option -g fügt zusätzliche Debug-Symbole in ELF-Daten ein MARE 04 Startup 19

x86-architektur Hier: 32-Bit-Architektur ( ia32 ) Register EAX, EBX, ECX, EDX sind 32 Bit breit (general purpose*) Auch als 16-Bit-Register AX, BX, CX, DX ansprechbar High-/lowbyte von AX,..., DX als AH/AL,..., DH/DL ansprechbar Zusätzliche Register Stackpointer ESP Basepointer EBP Source- und Destination-Index z.b. für Kopierbefehle *fast nicht alle Maschinenbefehle können mit allen 4 Registern arbeiten MARE 04 Startup 20

Die Funktion start() 1 2 3 080482e0 <_start>: 80482e0: xor %ebp,%ebp ; Register ebp auf 0 setzen 80482e2: pop %esi ; Register esi von Stack holen 80482e3: mov %esp,%ecx ; Stackpointer aus Register ecx kopieren 80482e5: and $0xfffffff0,%esp; Stack alignment auf Vielfaches von 16 Byte 80482e8: push %eax ; Register eax, esp, edx auf Stack sichern 80482e9: push %esp 80482ea: push %edx 80482eb: push $0x8048400 ; Adresse 0x8048400 auf Stack sichern 80482f0: push $0x80483a0 ; Adresse 0x80483a0 auf Stack sichern 80482f5: push %ecx ; Register ecx, esi auf Stack sichern 80482f6: push %esi 80482f7: push $0x8048394 ; Adresse 0x8048394 auf Stack sichern 80482fc: call 80482c4 < libc_start_main@plt> ; _libc_start_main aufrufen 8048301: hlt ; Prozessor anhalten Drei Schritte: 1. Stack-Initialisierung 2. Parameter für _libc_start_main auf Stack & Aufruf 3. Prozessor anhalten MARE 04 Startup 21

Parameterübergabe an _libc_start_main Prototyp von _libc_start_main: Funktionszeiger auf unser main int libc_start_main( int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (*stack_end) ); * Teil der GNU libc-source in glibc-datei csu/libc-start.c Argumentzähler argc und Array von Argumentstrings argv Stackpointer Funktionszeiger auf Konstruktur und Destruktur für dieses Programm* Funktionszeiger für Destruktor des dyn. Linkers (Entfernen von shared libraries) MARE 04 Startup 22

Die main-funktion eines C-Programms Prototyp für main: int main(int argc, char **argv, char **envp); argc: Anzahl der Argumente auf der Befehlszeile (>= 1) argv: Array mit Text der Argumente (nullterminierte Strings) argv[0] = Name des aufgerufenenprogramms envp: Array mit Text der Umgebungsvariablen der Shell (nullterminierte Strings, Form A=B) $ export VAR= fasel $./prog 1 foo bla argc = 4 argv =./prog, 1, foo, bla, 0 envp = VAR=fasel,, 0 Environment ausgeben: #include <stdio.h> int main(int argc, char **argv, char **envp) while(*envp) printf("%s\n",*envp++); MARE 04 Startup 23

Parameterübergabe an _libc_start_main: Stack Parameter werden auf Stack in umgekehrter Reihenfolge der Signatur übergeben: 080482e0 <_start>: 80482e0: xor %ebp,%ebp 80482e2: pop %esi 80482e3: mov %esp,%ecx 80482e5: and $0xfffffff0,%esp 80482e8: push %eax ; unbenutzt 80482e9: push %esp ; Stack pointer 80482ea: push %edx ; Adr. Destr. ld.so 80482eb: push $0x8048400 ; Adr. _libc_csu_fini 80482f0: push $0x80483a0 ; Adr. _libc_csu_init 80482f5: push %ecx ; argv 80482f6: push %esi ; argc 80482f7: push $0x8048394 ; Adresse von main 80482fc: call 80482c4 < libc_start_main@plt> 8048301: hlt MARE 04 Startup 24

Funktion von _libc_start_main Linken und Laden Takes care of some security problemswith setuid setgid programs Starts upthreading Registers the fini (our program), and rtld_fini (run-time loader) arguments to get run by at_exit to run the program's and the loader's cleanup routines Calls the init argument Calls the main with the argc and argv arguments passed to it and with the global environargument as detailedabove Calls exit with the return value of main MARE 04 Startup 25

C-Programmkonstruktor _libc_csu_init Das ist doch kein C++?!? Auch jedes C-Programm hat Funktionen zum Initialisieren und Entfernen von Datenelementen (aber keine Objekte) Konstruktor libc_csu_init, Destruktor libc_csu_fini void libc_csu_init (int argc, char **argv, char **envp) _init (); const size_t size = init_array_end - init_array_start; for (size_t i = 0; i < size; i++) (* init_array_start [i]) (argc, argv, envp); MARE 04 Startup 26

Was macht _init? * in glibc-source csu/elf-init.c Vorbereitung globaler Informationen Zeiger auf globale Tabellen Optionaler Start des Profilers Speichern von Informationen zur Unterstützung von Exception Handlers Aufruf globaler Konstruktoren (auch für C++): #include <stdio.h> void attribute ((constructor)) a_constructor() printf("%s\n", FUNCTION ); int main() printf("%s\n", FUNCTION ); gcc-erweiterung: Name der aktuellen Funktion Ausgabe: $./prog2 a_constructor main MARE 04 Startup 27

...endlich! Aufruf von unserem main ist ganz unspektakulär Verwendet übergebenen Zeiger auf Main-Funktion Übergibt auf Stack erhaltene argc, argv und envp an main * Teil der GNU libc-source in glibc-datei csu/libc-start.c MARE 04 Startup 28

Funktionsaufrufe und der Stack Der Stack verwaltet Informationen über Funktionsaufrufe Aufrufhierarchie: Rücksprungadressen Parameter von Funktionen lokale Variable (Gültigkeitsbereich = Funktion) Wächst bei x86 von oben nach unten, also zu niedrigeren Adressen hin Langfristig benötigte Informationen sind in globalen Datensektionen (.data,.rodata,.bss) und im Heap enthalten! MARE 04 Startup 29

Stack-Aufbau (1) http://duartes.org/gustavo/blog/post/journey-to-the-stack/ Jeder Funktionsaufruf erzeugt dynamisch neuen stack frame: Enthält Parameter, lokale Variablen, Kontextinformationen MARE 04 Startup 30

Stack-Aufbau (2) Verwendete CPU-Register Stackpointer esp: Zeigt auf letztes belegtes Element im Stack Base- oder Framepointer ebp: Zeigt auf stack frame der aktuellen Funktion Referenzadresse für Funktionsparameter (oberhalb von ebp: ab ebp+8) Lokale Variable (unterhalb von ebp) Rückgabewert der Funktion in eax MARE 04 Startup 31

Details des stack frame Von links (niedrigere Adresse) nach rechts (höhere Adressen) Lokale Variablen: local_buffer: 7 Byte langer String ( foobar\0 ) + Padding local1: 4 Byte große Integer-Variable (Wert 8) Verwaltungsinformationen: Gesicherter Framepointer (ebp) der aufrufenden Funktion Rücksprungadresse zu aufrufender Funktion Funktionsparameter: param1: 4 Byte-Integer, Wert 512 param2: 4 Byte-Integer, Wert 65536 int foo(int param1, int param2) int local1; char local_buffer[7]; MARE 04 Startup 32

Erzeugen von stack frames (1) Compiler fügt Code zur Verwaltung von Stackframes ein: Prolog/Epilog: Verwalten von ebp und Raum für lokale Variablen int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 33

Erzeugen von stack frames (2) Framepointer ebp muss vor Aufruf gesichert werden Wird von aufgerufener Funktion überschrieben Hier: ebp=0 (main ist oberste Funktion) int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 34

Erzeugen von stack frames (3) Setzen des neuen Framepointers Auf aktuelles unteres Ende des Stacks int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 35

Erzeugen von stack frames (4) Schritte 2 4 sind der Stackpointer anpassen Funktionsprolog! Platz auf Stack für lokale Variablen und Parameter schaffen int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 36

Erzeugen von stack frames (5) Parameter 40 und 2 für Funktionsaufruf von add auf Stack Umgekehrte Reihenfolge, Adressierung relativ zu esp int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 37

Erzeugen von stack frames (6) Parameter 40 und 2 für Funktionsaufruf von add auf Stack Umgekehrte Reihenfolge, Adressierung relativ zu esp int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 38

Erzeugen von stack frames (7) Neuer Prolog für add geschaffen Stack = verkettete Liste von stack frames Platz für Sichern des vorherigen ebp int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 39

Erzeugen von stack frames (8) Alten Framepointer sichern Neuen Framepointer ebp auf Wert des aktuellen Stackpointers setzen int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 40

Erzeugen von stack frames (9) Platz für lokale Variable result schaffen Stackpointer esp um 4 erniedrigen Framepointer ebp bleibt gleich! int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 41

Erzeugen von stack frames (10) Parameter lesen und addieren Parameter in ebp+12 (b) und ebp+8 (a) int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 42

Erzeugen von stack frames (11) Ergebnis der Addition in lokale Variable result schreiben Result liegt an Adresse ebp-4 int add(int a, int b) int result = a + b; return result; int main(int argc) int answer; answer = add(40, 2); MARE 04 Startup 43

Fazit Startup von Programmen ist aufwendiger Prozess Initialisierung, Konstruktoren, glibc... Stack ist zentrales Konzept für hierarchische Funktionsaufrufe Funktionsparameter Rücksprungadressen Lokale Variable Aufrufhierarchie MARE 04 Startup 44

Literatur Unix-Prozessmodell, Prozess-Startup Eric S. Raymond, The Art of UNIX Programming, Addison-Wesley 2003, ISBN-13: 978-0131429017 x86-assembler (32/64 Bit) http://www.cs.umd.edu/~meesh/cmsc311/links/handouts/ia32.pdf https://www.cs.cmu.edu/~fp/courses/15213-s07/misc/asm64-handout.pdf Stack Giuseppe Di Cataldo, Stack Frames A Look From Inside, Apress 2016, ISBN-13: 978-1-4842-2181-5 ABI-Konventionen https://sites.google.com/site/x32abi/ MARE 04 Startup 45

Anhang: Wo ist envp? Bei Aufruf von _libc_start_main wird envp nicht übergeben! Prototyp: int main(int argc, char** argv, char** envp); envp = Zeiger auf Array von Strings mit Environmentvariablen Dieses Array fängt direkt hinter den Strings von argv an: _libc_init_firstwird von _libc_start_main aufgerufen void libc_init_first(int argc, char *arg0,...) char **argv = &arg0, **envp = &argv[argc + 1]; environ = envp; libc_init (argc, argv, envp); MARE 04 Startup 46

Anhang: Was kommt nach envp? Weitere Informationen aus ELF-Header ebenfalls übergeben: Array fängt direkt hinter den Strings von envp an: $ LD_SHOW_AUXV=1./prog1 AT_SYSINFO: 0xe62414 AT_SYSINFO_EHDR: 0xe62000 AT_HWCAP: fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe AT_PAGESZ: 4096 AT_CLKTCK: 100 AT_PHDR: 0x8048034 AT_PHENT: 32 AT_PHNUM: 8 AT_BASE: 0x686000 AT_FLAGS: 0x0 AT_ENTRY: 0x80482e0 AT_UID: 1002 AT_EUID: 1002 AT_GID: 1000 AT_EGID: 1000 AT_SECURE: 0 AT_RANDOM: 0xbff09acb AT_EXECFN:./prog1 AT_PLATFORM: i686 MARE 04 Startup 47