gpt4 book ai didi

assembly - execve syscall 在 64 位 AMD 上使用 32 位调用约定返回 EFAULT

转载 作者:行者123 更新时间:2023-12-04 14:49:00 24 4
gpt4 key购买 nike

我在汇编中使用手动系统调用。我之前能够使其正常启动,但在删除空值后,我无法让系统调用执行 /bin/date .这是我用 AT&T 语法编写的代码。

.global main
main:
jmp two

one:
# zero rax and rdx
xor %rax,%rax
mov %rax,%rdx

# save string location
mov (%rsp),%rbx

# push argv array onto the stack
add $16, %rsp
push %rax
push %rbx
# assign argv pointer
mov %rsp,%rcx

# execve call
mov $0xb, %al
int $0x80

# exit on failure
xor %rax,%rax
xor %rbx,%rbx
movb $0x1,%al
int $0x80

two:
# get address of the string
call one
.string "/bin/date"

如果我是对的, %rbx应该直接指向命名要启动的程序的字符串。 %rcx应该指向一个以空结尾的指针数组,表示程序的 argv , 和 %rdx会指向环境,所以我把它留空了。当然, %rax保存系统调用号(在本例中为 0x0b)。
(gdb) info registers 
rax 0xb 11
rbx 0x4000a0 4194464
rcx 0x7fffffffe968 140737488349544
rdx 0x0 0

(gdb) x/s $rbx
0x4000a0: "/bin/date"

(gdb) x/s *$rcx
0x4000a0: "/bin/date"

尽管如此,系统调用并没有执行程序,而是返回-14,转换为 EFAULT。 (段错误)。我不确定我忽略了什么,任何帮助将不胜感激。

因此,敏锐的读者可能已经注意到,上面的代码在 64 位系统上使用了 32 位系统调用约定(使用 %ebxint $0x80 和 friend )。这是一个错误,因为仅支持 32 位约定以启用执行 32 位代码。在为 64 位系统编写的代码中,系统调用使用 %rdi , %rsi , %rdx , %r10 , %r8%r9以及 syscall操作说明。这是 64 位系统的更正代码(nullfree):
.global main
main:
jmp two

one:
# zero rax and rdx
xor %rax,%rax
mov %rax,%rdx

# save string location, note that %rdi is used instead of %rbx
pop %rdi

# push argv array onto the stack
add $16, %rsp
push %rax
push %rdi
# assign argv pointer, using %rsi instead of %rcx
mov %rsp,%rsi

# execve call, note that the syscall number is different than in 32bit
mov $0x3b, %al
syscall

two:
# get address of the string
call one
.string "/bin/date"

但是,64 位系统支持 32 位系统调用约定(因此可以运行 32 位可执行文件),我也成功了 execve d 在此系统上使用 32 位调用约定的其他命令。事实上,我为 x86_64 系统检查的大部分“shellcode”都使用 32 位约定。所以,我的问题仍然存在: 为什么 32 位调用约定在上述代码中不起作用?

最佳答案

execve() 调用有原型(prototype)

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

请注意 NULL通常不传递指针,但如果 envp[]数组是空的,你应该传递一个指向 NULL 的指针,它作为环境变量的结尾。同样, argv[]不能是 NULL 指针。它必须至少包含 argv[0]这是程序名称。通常放置 filename 就足够了作为第一个元素。为了完全符合 shell 的功能,剥离路径并仅将最后一个组件作为 argv[0] (在您的示例中为 date )传递。

您的示例的等效 C 代码是:
char *filename = "/bin/date";
char *argv [2] = {filename, NULL};
char *envp [1] = {NULL};

execve (filename, argv, envp);

也许我错过了它,但看起来你正在做相当于(32 位和 64 位)
char *filename = "/bin/date";

execve (filename, NULL); // note missing third parameter, and malformed argv[]

我不明白你的堆栈操作。推送、推送、推送、系统调用应该足够了。我很困惑为什么你直接操作堆栈指针。

关于assembly - execve syscall 在 64 位 AMD 上使用 32 位调用约定返回 EFAULT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10965793/

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