CompOrg Fall 2004 Lab

Lab #8 - C Structs and Buffer Overflow

10/27/2004

The files p1.s, p2.s, etc. are also available on monte.cs.rpi.edu in ~hollingd/public/lab8


> mkdir lab8
> cp ~hollingd/public/lab8/* lab8
> cd lab8

p1: C Structs and Assembly Language

The progam shown below defines a C struct named "list". A list structure includes an array of 10 integers and a count. The count (the field n) represents the number of items in the array, 10 is just the maximum.

You jobs is to write a function named listsum that computes the sum of a list (the sum of the first n n integers in the array vals) in assembly language. The C code below can be converted to assembly with "gcc -S", then edit the function named listsum (with the C prototype shown).

Want something harder (not really harder, but a little different)? Try writing the function lsum that does the same thing as listsum, but has a parameter that is a structure, not a pointer to a structure (the entire structure is passed on the stack).

p1.c
/* C Structure Lab */
#include <stdio.h>

/* A list structure holds an array of up to 10 integers,
   n is the number of integers in the list.
*/

typedef struct list {
  int vals[10];
  int n;
} list;


/* listsum returns the sum of a list
   you need to write this! (in assembly).
*/

int listsum(list *l) {
  /* your code goes here */
  return(0);
}

/* Harder version  (optional) - the parameter is an actual
   struct (not a pointer to a struct). Use gcc to 
   see what is passed and how!

int lsum(list l) {
  return(0);
}

*/

int main(){
  int i;
  list x;
  for (i=0;i<5;i++)
	x.vals[i]=i;

  x.n=5;

  printf("Sum of list is %d\n",
		 listsum(&x));

/* call to optional function 
  printf("Sum of list is %d\n",
		 lsum(x));
*/
}


p2: The Stack and the Return Address

The idea here is manually replace the return address of a function with some other address. You need to use GDB to replace the return address used by the function blah, so that when blah returns it jumps to the function named wizard().

p2.c
/* Use GDB to get this program to print "You are a wizard" 

   Notes:
    1. set a breakpoint in blah
    2. run (until the above breakpoint)
    3. determine the address of the function wizard()
    4. find out where the return address is located in memory.
       The return address will be the address of the 
       "return(1)" statement in main.
    5. replace the return address with the address of wizard().
    6. continue the program in gdb ("continue"), and verify that
       it prints out "You are a wizard".
*/

#include <stdio.h>

void wizard() {
  printf("You are a wizard\n");
}

void blah() {
  int x,y;
  x = y + 3;
}

int main(){
  blah();
  return(1);
}



p3: Simple buffer overflow

Below is a program similar to the one above, the main difference is that blah() has a potential buffer overflow, and main() reads a string from standard input that is passed to blah(). Your job is (once again) to make this program print "You are a wizard", but here you run the program and feed it a string that causes this behavior (overflows the buffer in blah and replaces the return address with a new one).

p3.c
/* Similar to p2.c, but now blah has a potential
   overflow you must exploit. You need to create 
   a string which when read (via stdin by main),
   will cause this progam to print "You are a wizard".
 
   Notes:
     The string that overflows the buffer must have the
     new return address in the right place (so it overwrites
     the real return address). The actual values placed in the
     buffer are irrelevant (only the new return address is important).

     Use gdb to find the number of bytes of padding you need to
     put in your string.
*/

#include <stdio.h>

void wizard() {
  printf("You are a wizard\n");
}

void blah(char *s) {
  char buff[12];
  strcpy(buff,s);
}

/* main calls read to get a string from stdin,
   then passes the address of this string to blah.

   You want to create a string that will cause blah
   to "return to wizard()".
*/

int main(void) {
  char x[10000];
 
  read(0,x,2000);
  blah(x);
  printf("Done\n");
}

Important Note: You need some way to construct a string that can be fed as input to this program. Write a program that generates the string ! If your program is named genstring, you can test it with: ./genstring | ./p3 Here is some code to get you started, it prints all the byte values 1-255 to stdout:

/* writes the byte values 1-255 to stdout */
int main() {
  int i;
 
  unsigned char s[300];
  for (i=1;i<=255;i++) {
        s[i-1]=i;
  }
  /* write all 255 bytes to stdout */
  write(1,s,255);
}

You may find the Unix program od (octal dump) useful, it can display binary files in hex, decimal or octal. "man od" for more info (or ask Dave).