360 likes | 482 Views
Functions, Varargs, and Stack Smashing. Using the Stack for Good And Evil. Before You Sit Down Please Get The Handout at the Entrance This file is called mike-stacks-io-smash.ppt. In the Magical Land and of C, we never have to know about memory ever again!.
E N D
Functions, Varargs, and Stack Smashing Using the Stack for Good And Evil Before You Sit Down Please Get The Handout at the Entrance This file is called mike-stacks-io-smash.ppt
In the Magical Land and of C, we never have to know about memory ever again! All an illusion. And somebody has to pay for all of those people in mouse suits.
Where we are going • We recall the many things that need to go onto the stack every time you call one of those teensy little functions (and 1 new thing) • We use our l33t haxzor skills to break through the stack and run malicious code • You write a function that takes any number of arguments, and learn how that even makes sense. We we also talk a little bit about I/O in general but you might want to take a close look at Chapter 18. • We’ll also be going pretty fast!
What Goes On To The Stack During A Function Call? short exampleFunction(short firstParam, short secondParam) { short firstLocal; short secondLocal; static short thirdNotReallyLocal = 77; return 99; } /* EXECUTION STARTS HERE */ short result = exampleFunction(1,2); I can think of 6 different kinds of data.
What Goes On The Stack • Parameters to the function • Return value of the function • Address to allow functions to return • The frame pointer • Any automatic variables you define in the function • Values of any registers you happen to clobber in your function NOT any static variables you define in the function.
Using the stack pointer is annoying SP SP Local Variable X is at SP + 2 After some allocations, Local Variable X is at SP + 5
The Frame Pointer points to the first local variable SP SP FP FP Local Variable X is at FP - 1 After some allocations, Local Variable X is still at FP - 1
Things to Remember About the Frame Pointer • Its purpose is to give each variable a constant offset from a “known good” point of reference • On the LC-3, it’s often stored in R5 • It always points to the first local variable of a function • When you start your function, you save off the old function’s frame pointer to the stack, then set F5 to your new frame pointer
Who does what? • Caller • Puts arguments onto stack (RL) • Does a JSR (or JSRR) to function • Callee • Makes space for Return Value and Return Address (and saves Return address) • makes space for and saves old FP • Makes FP point to next space • Moves SP enough for all local variables • Starts execution of "work" of function
How about return? • Callee (continued) • As registers are needed their current contents can be spilled onto stack • When computation done... • Bring SP back to base • Restore FP (adjust SP) • Restore RA (adjust SP) • Leave SP pointing at return value • RET
short exampleFunction(short firstParam, short secondParam) { short firstLocal; short secondLocal; static short thirdNotReallyLocal = 77; return 99; } /* EXECUTION STARTS HERE */ short result = exampleFunction(1,2); • Remember the order from the last slide. • Caller Puts arguments onto stack (RL) • Callee • Makes space for Return Value and Return Address (and saves Return address) • makes space for and saves old FP • Makes FP point to next space • Moves SP enough for all local variables
Where We Are • You should be able to infer from source code what is going to be on the stack and where • Next we will use this knowledge for evil: how to exploit the structure of the stack to execute malicious code • Eventually we’ll also use it for useful things like varargs functions, but you really care more about the evil don’t you?
gets verses fgets C provides a input function called gets which you should never use. char *gets(char *s) gets reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with '\0'.
fgets – bounded input char *fgets(char *s, int size, FILE *stream); • fgets() • reads in at most one less than size characters from stream • stores characters read into the buffer pointed to by s. • Stops reading after an EOF or a newline. • Stores a newline into the buffer if one is read • Stores a '\0' after the last character in the buffer. • Returns s on success and NULL on error or when end of file occurs while no characters have been read.
How can I prevent these security holes? • NEVER use input/output functions that can overflow a buffer • Do not assume your input is well formed, even if it comes from someplace like a save file you’ve written • Keep it simple
Where we are • You should be able to infer from source code what is going to be on the stack and where • You know how to exploit the structure of the stack to execute malicious code, and you feel fully prepared to do it in interesting ways on your homework and lab • Now we’re going to write some code using varargs. It’s crazy stack manipulation for good!
Chapter 18: I/O in C I am skipping over some aspects of this chapter. I made a fancy cheat sheet for you to help. But reading the chapter might also be good.
Not Talking About Opening a file #include <stdio.h> FILE *fopen(const char *FILE, const char *MODE); Modes r - read w - write a - append b - binary + - combinations
Or Closing a file #include <stdio.h> int fclose(FILE *FP);
Character I/O #include <stdio.h> int putchar(int CH); int putc(int CH, FILE *FP); int getchar(void); int getc(FILE *FP);
We talked about fgets char *fgets(char *s, int size, FILE *stream); • fgets() • reads in at most one less than size characters from stream • stores characters read into the buffer pointed to by s. • Stops reading after an EOF or a newline. • Stores a newline into the buffer if one is read • Stores a '\0' after the last character in the buffer. • Returns s on success and NULL on error or when end of file occurs while no characters have been read.
Pop Quiz /* Here is the code */ char buf[8]; while(fgets(buf, sizeof(buf), stdin)) printf("Got [%s]\n", buf); Here is the input (each line is followed by a newline): 123456 abcdefgh 123456789012 What is the output?
123456 Got [123456 ] abcdefgh Got [abcdefg] Got [h ] 123456789012 Got [1234567] Got [89012 ] > fgets < input.txt Got [123456 ] Got [abcdefg] Got [h ] Got [1234567] Got [89012 ] > Solution
Formatted I/O int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int sprintf(char *str, const char *format, ...); void ham_VBAText(const char *format, ...); int scanf(const char *format, ...); int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...);
What's up with the ... int printf(const char *format, ...);
Variable Arguments printf("%d %d %d\n", a, b, c); Locals... FP Old FP Return Addr Return Val char *fmt a b c
Variable Arguments another(a, b, c, 0); Locals... FP Old FP Return Addr Return Val a b c 0
int main() { char buffer[1024]; strcpy (buffer, "The "); strcatv(buffer, "quick ", "brown ", "fox ", NULL); strcatv(buffer, "jumped ", "over ", NULL); strcatv(buffer, "the ", "lazy ", "dogs.", "\n", NULL); printf("%s", buffer); return EXIT_SUCCESS; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }
#include <stdio.h> #include <stdarg.h> #include <string.h> char *strcatv(char *dst, ...) { char *p; va_list arglist; va_start(arglist, dst); while ((p = va_arg(arglist, char *)) != NULL) strcat(dst, p); va_end(arglist); return dst; }