gpt4 book ai didi

linux - shell 的 Ubuntu 16.04 汇编代码

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:06:25 24 4
gpt4 key购买 nike

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

我像上面那样为 execute/bin/sh 编写了程序集 lagunage我编译了它,但是当我尝试执行程序时,/bin/sh: 0: Can't open ???? 发生了这个错误。它不执行/bin/sh。我想知道为什么我不能执行/bin/sh

I'm using Ubuntu 16.04 and x64 Architectures

最佳答案

由于以一种奇怪的方式使用 push/pop,您的代码不必要地难以理解,但是在 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 返回失败后,执行落入 main 之后的任何 CRT 函数,它以 RET 指令结束。它还必须将 eax 归零,因为它将在 SYSCALL 之后为 -EFAULT


无论如何,你的 asm 相当于这个无用的代码:

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 -no-pie -g shell.S

#include <asm/unistd.h> // for __NR_execve
// #include <sys/syscall.h> // or include this glibc header for SYS_execve

main: # main(argc, argv, envp)
mov $shell, %edi # filename = shell
# argv = main's argv, already in rsi (not on the stack like in _start)

# leave RDX = envp
# xor %edx, %edx # envp = NULL

mov $__NR_execve, %eax # execve
syscall # execve(shell, argv, envp)
ret # in case the syscall fails

.section .rodata
shell:
.string "/bin/sh"

这有效,并且不会做任何奇怪的事情。


或者,以一种与位置无关的平面二进制文件的方式工作,并且不使用 main() 的 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 想法不错,但是你忘了在 argv[] 数组的末尾添加一个终止 NULL 指针。

在获取 envp[] 作为 arg 的 main 之外,我们没有可在任何地方访问的已构建的 envp[]方便,所以只需传递 NULL。在 Linux 上,这相当于将一个有效指针传递给一个以 NULL 结尾的空数组,即指向内存中 8 字节 0 的指针。

关于linux - shell 的 Ubuntu 16.04 汇编代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39848264/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com