Переписываем небольшой execve шеллкод

Проходя через http://hackoftheday.securitytube.net/2013/04/demystifying-execve-shellcode-stack.html

Я понял программу Nasm, которая вызывает execve и пытался переписать это.

Некоторая справочная информация:

int execve(const char *filename, char *const argv[], char *const envp[]);

Так, eax = 11 (номер вызова функции для execve), ebx следует указать на char* filename, ecx следует указать на argv[] (который будет таким же, как ebx так как первый аргумент является *filename сам, например «/ bin / sh» в этом случае) и edx будет указывать на envp[] (null в этом случае).

Оригинальный код носа:

global _start

section .text
_start:

xor eax, eax
push eax

; PUSH //bin/sh in reverse i.e. hs/nib//

push 0x68732f6e
push 0x69622f2f

mov ebx, esp

push eax
mov edx, esp

push ebx
mov ecx, esp

mov al, 11
int 0x80

Стек выглядит следующим образом:

введите описание изображения здесь

Теперь я попытался оптимизировать это, уменьшив несколько инструкций. Я согласен, что до mov ebx, esp код останется прежним. Тем не менее, так как ecx нужно будет указать на ebxЯ могу переписать код следующим образом:

global _start

section .text
_start:

xor eax, eax
push eax

; PUSH //bin/sh in reverse i.e. hs/nib//

push 0x68732f6e
push 0x69622f2f
mov ebx, esp

mov ecx,ebx

push eax
mov edx, esp

mov al, 11
int 0x80

Тем не менее, я получаю ошибку сегментации, когда я запускаю свой переписанный код.

Мой стек выглядит следующим образом: введите описание изображения здесь

Есть идеи, почему переписанный код не работает? Я также запустил GDB, и значения адресов соответствуют моим представлениям, но он просто не запускается.

4

Решение

В обоих случаях ebx указывает на строку «// bin / sh». Эквивалент кода C, подобный этому:

char *EBX = "//bin/sh";

Но в вашем первом примере ecx установлен на адрес указателя на эту строку. Эквивалент кода C, подобный этому:

char *temp = "//bin/sh"; // push ebx
char **ECX = &temp;      // mov ecx, esp

В то время как во втором примере для ecx установлено то же значение, что и для ebx.

char *ECX = "//bin/sh";

Таким образом, два примера принципиально различны, поскольку ecx имеет два совершенно разных типа и значения.

Обновить:

Я должен добавить, что технически ecx — это массив указателей на символы ( ARGV аргумент), а не просто указатель на указатель на символ. Вы фактически строите массив из двух элементов в стеке.

char *argv[2];
argv[1] = NULL;         // push eax, eax being zero
argv[0] = "//bin/sh";   // push ebx
ECX = argv;             // mov ecx,esp

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

EDX = envp = &argv[1];

Это достигается установкой edx в esp, в то время как массив argv создается только наполовину. Комбинируя код для двух назначений вместе, вы получаете это:

char *argv[2];
argv[1] = NULL;         // push eax, eax being zero
EDX = &argv[1];         // mov edx,esp
argv[0] = "//bin/sh";   // push ebx
ECX = argv;             // mov ecx,esp

Это немного запутанно, но я надеюсь, что это имеет смысл для вас.

Обновление 2

Все аргументы execve передаются как регистры, но эти регистры являются указателями на память, которую необходимо где-то разместить — в данном случае в стеке. Поскольку стек строится вниз в памяти, куски памяти должны быть построены в обратном порядке.

Память для трех аргументов выглядит следующим образом:

char *filename:  2f 2f 62 69 | 6e 2f 73 68 | 00 00 00 00
char *argv[]:    filename    | 00 00 00 00
char *envp[]:    00 00 00 00

имя файла построен так:

push eax        // '\0' terminator plus some extra
push 0x68732f6e // 'h','s','/','n'
push 0x69622f2f // 'i','b','/','/'

ARGV аргумент как это:

push eax // NULL pointer
push ebx // filename

И envp аргумент как это:

push eax // NULL pointer

Но, как я уже сказал, оригинальный пример решил разделить память между argv и evp, так что в этом нет необходимости push eax,

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

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]