что вызывает эту ошибку сегментации?пример из книги - PullRequest
1 голос
/ 20 сентября 2010

Я просматриваю книгу и попробовал запустить этот пример, но я получаю ошибку сегментации - GDB говорит, что это когда он устанавливает argv [0] = имя файла;

этот код копируется / вставляется прямо иззагружаемые примеры кода.

#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);
}

Редактировать: Книга Джона Эриксона "Взлом: искусство эксплуатации", которая имеет ОЧЕНЬ хорошие отзывы.Этот конкретный пример используется в качестве первого руководства по преобразованию C в машинный код в разделе шелл-кода, в частности, это exec_shell.c и может быть загружен из http://nostarch.com/hacking2/htm.Я предполагаю, что некоторый контекст вокруг использования этого кода был необходим для того, чтобы избежать некоторых отрицательных комментариев ниже, извините за то, что опущены детали, и спасибо за помощь.

Ответы [ 7 ]

11 голосов
/ 20 сентября 2010

Очевидно, что это не очень хорошая книга. Проблема в том, что ни argv, ни envp не инициализируются, поэтому, когда вы пишете в argv[0], вы пытаетесь перезаписать какое-то случайное место в памяти.

Попробуйте что-то вроде этого:

#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);
}

Эта альтернатива инициализирует argv и envp в стеке с достаточным пространством для размещения двух указателей и одного указателя соответственно.

В приведенном выше коде я внес одно дополнительное изменение, чтобы устранить дополнительное общее (но в данном случае безвредное) недоразумение. \x00, который был в конце "/bin/sh\x00", является избыточным, поскольку в C статические строки неявно заканчиваются нулем. "/bin/sh\x00" - строка, оканчивающаяся на два нуля.

В качестве альтернативы, как указано caf , вот более компактный пример с точно эквивалентным значением:

#include <unistd.h>

int main() {
  char *filename = "/bin/sh";
  char *argv[2] = { filename, 0 };
  char *envp[1] = { 0 };

  execve(filename, argv, envp);
}
3 голосов
/ 20 сентября 2010

Вы никогда не выделяете «массивы указателей», которые должны входить в argv и envp! Что это за книга, которая пропускает такие важные шаги?!

Либо добавьте argv = malloc(2 * sizeof(char*)) (и аналогично для envp) перед началом присвоения argv[0] и друзьям, либо измените объявления argv и envp на массивы указателей, а не указателей на указатели (последний - вполне выполнимый подход, в данном конкретном случае, поскольку вы точно знаете, сколько указателей вам нужно в каждом на момент написания кода - динамическое выделение, таким образом, несколько суперрегрогативно; -).

0 голосов
/ 20 сентября 2010

Многие люди здесь находятся на правильном пути, но упускают некоторые из многочисленных проблем здесь.

#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);
}

Проблемы здесь:
1. Указательмассив строк символов никогда не инициализируется.Указатели также занимают место, и поэтому массив указателей должен использовать malloc в c.
2. Каждый символьный указатель в вашем массиве указателей должен использовать свой собственный оператор malloc.

Вот рабочий код с распечатками, чтобы показать вам, что происходит:

#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]);
}
0 голосов
/ 20 сентября 2010

Прежде чем использовать такие многоуровневые указатели, я рекомендую прочитать о динамическом распределении памяти в C.

Всякий раз, когда вы используете указатели, вы должны также подумать, нужно ли вам выделять место для данных, которые указателисобирается указывать (как и сами указатели, для многоуровневых указателей).

Например,

char **bar; 

здесь, bar выделяет пространство для 1 указателя на указатель, т.е.,достаточно места для хранения одного адреса.Это не очень полезно без какого-либо дополнительного распределения данных.

На самом деле, вы должны сделать следующее:

char **bar = calloc( 2 , sizeof(char *) );

здесь bar выделяет место для 1 указателя на указатель, т.е.Опять же, место для хранения одного адреса в виде строки И 2 последовательных расположения для хранения еще двух указателей, а именно: bar [0] и bar 1 .

char bar[0]= calloc( 10 , sizeof(char) );

здесь, bar [0]выделяет место для хранения строки размером 10 - 1 (для \ 0 в конце).

Теперь, если вы выполняете копирование строки:

strcpy(bar[0],"Hello!");

, окончательная карта памяти будет иметь вид: (адреса в кружках, содержимое в блоках) alt text

0 голосов
/ 20 сентября 2010

Понятия не имею, где вы взяли эту книгу, но она явно отстой. argv - указатель неинициализированный , он содержит случайный адрес. Следовательно, доступ к нему, скорее всего, приведет к нарушению доступа.

0 голосов
/ 20 сентября 2010

Похоже, вам нужно получить лучшую книгу!В этом коде argv является указателем без выделенного ему хранилища и указывает на случайную память (или, вероятно, NULL).Когда вы разыменовываете его с помощью argv[0] = ..., ваш код в конечном итоге пытается записать в произвольную память.Объявление вашей переменной должно выглядеть примерно так:

char *argv[3], *envp[1];
0 голосов
/ 20 сентября 2010

char **argv

argv указывает на область памяти, к которой у вас нет доступа или записи.Это то, что более известно как дикий указатель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...