Ваш код понапрасну трудно следовать из-за использования пуш/поп-музыки в странно способ, но работает программу под strace -f ./a.out
отслеживать системные вызовы шоу:
... dynamic linker and libc init stuff before main() is called ...
execve("/bin/sh", ["/bin/sh", "\211\307\350\t\222\1", "\367", "\367", 0x100000000, "\350\10"], [/* 0 vars */]) = -1 EFAULT (Bad address)
exit_group(0) = ?
+++ exited with 0 +++
Так что на моей системе, execve
возвращается с ошибкой, но программа завершается успешно. IDK, как вы получаете /bin/sh: 0: Can't open ????
. Ваш вопрос не содержит достаточной информации для воспроизведения ваших результатов. Но, может быть, когда вы попытались, в стеке попали разные мусора. Я построил его с помощью gcc -g foo.S
.
После того, как main
не смог вернуться, выполнение проваливается в любую функцию CRT после main
, которая заканчивается инструкцией RET. Он также должен иметь нулевой eax, так как после SYSCALL будет -EFAULT
.
Во всяком случае, ваш асмовый эквивалент этого не-полезный код:
int main(void) {
const char *p = "/bin/sh";
execve(p, &p, NULL);
}
отмечает, что push %rsp; pop %rsi
эквивалентно mov %rsp, %rsi
. Таким образом, RSI содержит указатель на стек стек, где CALL пишет «обратный адрес».
Еще один POP после этого разыгрывает указатель стека и загружает указатель на строку в RDI.
Использование CALL для ввода адреса строки действительно противно. IDK, почему вы это сделаете. Просто используйте MOV, как обычный человек.
Как сделать это правильно
# build with gcc -g shell.S
#include <asm/unistd.h> // for __NR_execve
// #include <sys/syscall.h> // or include this glibc header for SYS_execve
main:
mov $shell, %edi # filename = shell
# argv = main's argv, already in rsi (not on the stack like in _start)
xor %edx, %edx # envp = NULL
mov $__NR_execve, %eax # execve(
syscall
ret # in case the syscall fails
.section .rodata
shell:
.string "/bin/sh"
Это работает, и ничего странного не делать.
Или, таким образом, работает как позиционно-независимая плоский бинарный и не использует основными() 's ARGV, так как вы добавили этот запрос:
#include <asm/unistd.h> // for __NR_execve
// #include <sys/syscall.h> // or include this glibc header for SYS_execve
.globl main
main:
lea shell(%rip), %rdi # filename = shell
xor %edx, %edx # envp = NULL
push %rdx # or push $0
push %rdi
mov %rsp, %rsi # argv = { $shell, NULL } that we just pushed
mov $__NR_execve, %eax # execve(
syscall
ret # in case the syscall fails
shell: # still part of the .text section, and we don't use the absolute address of the label, only for a RIP-relative LEA.
.string "/bin/sh"
Вашей Идея RSI = RSP неплохая, но вы забыли добавить завершающий указатель NULL в конец ARGV.
Альтернативой является использование функции 'system', вызывающей внешнюю программу. взгляните на [this] (https://godbolt.org/g/jN057x), чтобы просмотреть пример ассемблера – Garf365
Но я слышал, что функция 'system' также использует' execve' во внутреннем вызове функции. Поэтому я хочу использовать 'execve' – Damotorie
Точный,' system' вызовет 'execve', но это немного сложнее, чем вы думаете. вызов 'system' проще.Взгляните на эту статью [post] (http://stackoverflow.com/questions/9342410/sys-execve-system-call-from-assembly) для 'execve' – Garf365