what is causing this segmentation fault? example from book
I am going through a book and I tried running this example but I receive a segmentation fault - gdb says it's when it sets argv[0] = filename;
this code is copied/pasted straight from book's downloadable code samples.
#include <unistd.h>
int main() {
char filename[] = "/bin/sh\x00";
char **argv, **envp; // arrays that contain char pointers
argv[0] = filename; // only argument is filename - segmentation fault here
argv[1] = 0; // null terminate the argument array
envp[0] = 0; // null terminate the environment array
execve(filename, argv, envp);
}
Edit: The book is Hacking: The Art of Exploitation by Jon Erickson, which has VERY good reviews. This specific example is used as the first tutorial on converting C into machine code in the shellcode section, specifically it is exec_shell.c and can be downloaded from http://nostarch.com/hacking2/htm . I imagine some context ar开发者_JAVA百科ound the use of this code was necessary in order to avoid some of the negative comments below, sorry for leaving details out, and thanks for the help.
It obviously isn’t a very good book. The problem is that neither argv
nor envp
are initialized, so when you write to argv[0]
, you’re trying to overwrite some random location in memory.
Try something like this:
#include <unistd.h>
int main() {
char *filename = "/bin/sh";
char *argv[2], *envp[1];
argv[0] = filename;
argv[1] = 0;
envp[0] = 0;
execve(filename, argv, envp);
}
This alternative initializes argv
and envp
on the stack, with enough space to contain two pointers and one pointer respectively.
In the code above, I’ve made one additional change to repair an additional common (but, in this case, harmless) misunderstanding. The \x00
that was at the end of "/bin/sh\x00"
is redundant, since in C static strings are implicitly null-terminated. "/bin/sh\x00"
is a string terminated by two nulls.
Alternatively, as pointed out by caf, here is a more compact example with exactly equivalent meaning:
#include <unistd.h>
int main() {
char *filename = "/bin/sh";
char *argv[2] = { filename, 0 };
char *envp[1] = { 0 };
execve(filename, argv, envp);
}
You never allocate the "arrays of pointers" meant to go in argv
and envp
! What book is it, that omits such crucial steps?!
Either add argv = malloc(2 * sizeof(char*))
(and similarly for envp
) before you start assigning to argv[0]
and friends, or change argv
's and envp
's declarations to be arrays of pointers rather than pointers to pointers (the latter's quite a feasible approach, in this specific case, since you do know exactly how many pointers you need in each at the time you're writing the code -- dynamic allocation is therefore somewhat supererogatory;-).
char **argv
argv
is pointing to a memory location which you are not allowed to access/write to. It is something that is better known as a wild pointer.
Looks like you need to get a better book! In this code argv
is a pointer with no storage allocated to it and pointing at random memory (or probably NULL
). When you dereference it with argv[0] = ...
, your code ends up trying to write to random memory. Your variable declaration should be something more like:
char *argv[3], *envp[1];
I have no idea where did you get this book, but it obviously sucks. argv
is an uninitialized pointer, it holds a random address. Hence accessing it will most probably lead to the access violation.
Before using such multi-level pointers, I recommend reading up on dynamic memmory allocation in C.
Whenever you use pointers, you must also think whether you need to allocate space for the data that the pointers are going to point to (as also the pointers themselves, for multi-level pointers).
For example,
char **bar;
here, bar allocates space for 1 pointer-to-pointer, ie. enough space to store one address. This is not very useful without any additional data allocation.
In reality, you should be doing:
char **bar = calloc( 2 , sizeof(char *) );
here, bar allocates space for 1 pointer-to-pointer, ie. again, space to store one address as bar, AND 2 consecutive locations for storing 2 more pointers, namely bar[0] & bar1.
char bar[0]= calloc( 10 , sizeof(char) );
here, bar[0] allocates space for storing a string of size 10 - 1 (for \0 at end).
Now, if you do a string copy:
strcpy(bar[0],"Hello!");
the final memory map comes to: (addresses in circles, contents in blocks)
Many of the people here are on the right track, but missing some of the numerous problems here.
#include <unistd.h>
int main() {
char filename[] = "/bin/sh\x00";
char **argv, **envp; // arrays that contain char pointers
argv[0] = filename; // only argument is filename - segmentation fault here
argv[1] = 0; // null terminate the argument array
envp[0] = 0; // null terminate the environment array
execve(filename, argv, envp);
}
The problems here are:
1. The pointer array of character strings is never initialized. Pointers take up space too, and thus an array of pointers needs to use malloc in c.
2. Each character pointer in your pointer array needs its own malloc statement before use.
Here is the working code, with printouts to show you what is going on:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned int i=0;
char filename[] = "/bin/sh\x00";
char **argv; // arrays that contain char pointers
argv=(char **)malloc(sizeof(char*));
argv[0]=(char *)malloc(strlen(filename)*sizeof(char));
strcpy(argv[0],filename);
printf("Arg 0 is %u chars long...\n",strlen(argv[0]));
printf("Arg 0 is ");
while (argv[0][i] != '\0') {
printf("%c",argv[0][i]);
i++;
}
printf("!\n");
free(argv[0]);
}
精彩评论