2016-10-04 3 views
0
.global main 
main: 
    call func 
    .string "/bin/sh" 
func: 
    push %rsp 
    pop %rsi 
    pop %rdi 
    mov $0x00, %edx 
    mov $0x3b, %eax 
    syscall 

Я написал сборку lagunage, как и выше для выполнения/бен/ш я скомпилированный его, но когда я пытаюсь выполнить программу, /bin/sh: 0: Can't open ???? такая ошибка возникает. Не выполняется/bin/sh. Я хочу знать, почему я не могу выполнить/bin/шUbuntu код 16,04 сборки для оболочки

Я использую Ubuntu 16,04 и 64 Архитектуры

+0

Альтернативой является использование функции 'system', вызывающей внешнюю программу. взгляните на [this] (https://godbolt.org/g/jN057x), чтобы просмотреть пример ассемблера – Garf365

+0

Но я слышал, что функция 'system' также использует' execve' во внутреннем вызове функции. Поэтому я хочу использовать 'execve' – Damotorie

+0

Точный,' system' вызовет 'execve', но это немного сложнее, чем вы думаете. вызов 'system' проще.Взгляните на эту статью [post] (http://stackoverflow.com/questions/9342410/sys-execve-system-call-from-assembly) для 'execve' – Garf365

ответ

2

Ваш код понапрасну трудно следовать из-за использования пуш/поп-музыки в странно способ, но работает программу под 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.

+0

Я считаю, что он пишет код оболочки, поэтому он не захочет использовать фиксированные разделы и абсолютные адреса, например, ваш пример. Его строка была помещена в код, чтобы он мог получить адрес строки, выкинув обратный адрес в _RDI_. Его метод является вариацией метода JMP/CALL/POP. Идея состоит в том, чтобы запустить этот код из исполняемого стека. –

+0

@MichaelPetch: Я подумал об этом, но OP никогда не говорил об этом. Помещение строки сразу после или до main (в разделе .text) создало бы один блок кода PIC с RIP-относительным LEA: 'lea $ shell (% rip),% rdi' вместо' mov $ shell,% edi'. Оригинал, очевидно, не пытается избежать '\ 0' байт или чего-то еще, поэтому мой ответ был направлен на обучение базовой отладке с помощью strace. –

+0

Фактически, когда я впервые увидел заголовок вопроса, я предположил, что это, скорее всего, вопрос с кодом оболочки. Когда я увидел строку в коде и то, как он вынул адрес возврата в качестве аргумента, он в значительной степени кричит «код оболочки». Что касается RIP-адресации, конечно, но ваш исходный код этого не сделал. –