Преобразование строки символов в функцию

Я пытаюсь научиться выполнять шеллкод из программы, но не могу запустить даже самый простой код. Следующий код должен просто выйти из терминала при его запуске:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>

char exitcode[] = "\xb0\x01\x31\xdb\xcd\x80";

int main() {
    int (*func)();
    func = (int (*)())exitcode;
    (int)(*func)();
    return 0;
}

Но все, что я получаю, это segfault. GDB говорит, что это происходит, когда программа обращается к ячейке памяти с кодом выхода [at (int)(*func)(); ], но я не уверен, почему это вызывает проблему. Я использую 64-битную ОС Linux Mint. Любая помощь приветствуется.


person vonhoenec    schedule 08.08.2015    source источник
comment
Если память для шеллкода находится в неисполняемом регионе, то это не сработает. Большинство современных операционных систем, вероятно, не позволяют этого. Вы также должны убедиться, что шелл-код подходит для вашей архитектуры.   -  person Mike Weller    schedule 08.08.2015
comment
Это для C или C++? Семантика и возможные ответы могут различаться.   -  person too honest for this site    schedule 08.08.2015
comment
Приведение указателя объекта к указателю функции является неопределенным поведением. Все может случиться   -  person too honest for this site    schedule 08.08.2015


Ответы (4)


Современные операционные системы используют защиту памяти. Страницы памяти имеют такие же права доступа, как и файлы: на чтение, на запись, на выполнение. Сегмент данных вашей программы обычно находится на неисполняемой странице, и попытка выполнить ее приводит к ошибке сегментации.

Если вы хотите выполнить динамически написанный двоичный код из своей программы в Linux, вам сначала нужно сопоставить страницу с помощью mmap(), на которую вы можете писать, затем поместить туда свой код, а затем изменить его на исполняемый только для чтения с помощью mprotect(). ТОГДА вы можете прыгнуть туда.

Например, вы можете прочитать эту статью для получения подробной информации.

EDIT: если речь идет о нарушениях безопасности, обратите внимание, что в настоящее время стек обычно также не является исполняемым ... поэтому все эти старые «учебники по взлому» больше не будут работать. Если вас интересуют новые методы, прочитайте программирование, ориентированное на возврат.

person Community    schedule 08.08.2015

Код должен быть помечен как исполняемый код. Один из способов сделать это — скопировать этот двоичный машинный код в исполняемый буфер.

#include <unistd.h>
#include <sys/mman.h>
#include <string.h>

char exitcode[] = "\xb0\x01\x31\xdb\xcd\x80";

int main(int argc, char **argv)
{   
    void *buf;

  /* copy code to executable buffer */    
  buf = mmap (0,sizeof(exitcode),PROT_READ|PROT_WRITE|PROT_EXEC,
              MAP_PRIVATE|MAP_ANON,-1,0);
  memcpy (buf, exitcode, sizeof(code));

  /* run code */
  int i = ((int (*) (void))buf)();
  printf("OK. returned: %d", i);
return 0;
}
person 4pie0    schedule 08.08.2015

Ваш шеллкод:

mov    $0x1,%al
xor    %ebx,%ebx
int    $0x80

Есть две проблемы:

  1. Системный вызов 0x1 — это sys_write в 64-разрядной версии (а в 32-разрядной — sys_exit)
  2. Вы должны назначить %rax, а не %al. %rax будет содержать остатки в старших битах.
person hate-engine    schedule 08.08.2015

У меня была эта проблема, и я много искал, чтобы решить ее.

Вы должны использовать этот код для компиляции кода C (чтобы отключить защиту стека и сделать его исполняемым):

gcc -fno-stack-protector -z execstack -o hello hello.c

Протестировано в Kali 32/64 бит. Сегфолта больше нет.

Удачи

person Mohammad Reza Ramezani    schedule 10.08.2015