我的堆栈程序的第一个变量是什么?

What is the first variables of my stack program?

我已经开始组装了。

我不明白为什么我在argc之前有两个变量。

0000 和 0008 是什么?

global _main

section .text
_main:
    ; write
    mov rax, 0x2000004
    mov rdi, 0x1
    mov rsi, [rsp+24]
    mov rdx, 3
    syscall

    ; return (0)
    mov rax, 0x2000001
    mov rdi, 0x0
    syscall

我在 macOSX Mojave 上编译:

nasm -f macho64 ex01.s && ld -macosx_version_min 10.14 -lSystem ex01.o

您的目标是现代 MacOS,因此 ld 将发出 dyld 辅助 LC_MAIN 加载命令以进行入口点处理。 [rsp] 是 libdyld _start 函数结尾的 return 地址:

mov        edi, eax ; pass your process return code as 1st argument under System V 64bit ABI
call       exit ;from libSystem
hlt

这意味着您不需要像在以下情况中那样通过系统调用退出进程:

; return (0)
mov rax, 0x2000001
mov rdi, 0x0
syscall

改为:

xor eax,eax
ret

就足够了(顺便说一句,这就是编译器会发出的)。

您的缓冲区也将在 ret / libdyld 方法中刷新。这与您正在执行的系统写入调用无关,但可能与 printf 相关。

这是一个很棒的article,描述了很多细节。

I don't understand why I have two variables before argc.

你写了一个 main,而不是 _start 你的 return 地址上面的堆栈 space 是 "not yours";对于 CRT 启动代码在调用 main 之前使用多少堆栈 space,或者它在 argc/argv/env 和调用 main.

之间留在堆栈上的内容,没有标准

main(int argc, char **argv, char **envp) 中,您会发现 EDI 中有 argc,RSI 中有指向 argv[] 的指针,RDX 中有指向 envp[] 的指针。

但我们可以看看有什么可以对 main 的调用者进行逆向工程:


0000开头的数字是相对于RSP的字节偏移量。无论生成什么图像,都会转储和分析 8 字节堆栈 "slots" 作为整数,如果它们指向有效内存,则作为指针。

堆栈上的所有这些东西都是通过调用 main_start 代码到达那里的,或者内核在进入 user-space 之前把它放在那里的。

  • [rsp + 0]main 的 return 地址,所以它指向代码。大概 _start 使用 call main / mov edi, eax / call exit 之类的代码调用您的 main 以将您的 return 值传递给 exit() 如果 main returns(你的没有)。因此,您的 return 地址指向 mov edi, eax.
  • 是有道理的
  • 0 可能是帧指针哨兵,因为使用 -fno-omit-frame-pointer 编译的代码能够回溯保存的 RBP 值链。在 _start 中推送 0 会终止该链表,如果调用者随后执行 mov rbp, rsp,则其被调用者中的 push rbp 会将指针推送到该终止符。 x86-64 System V ABI 文档建议这样做。

其余条目看起来与 _start

处的堆栈的 entry-to-user-space 状态完全一样
  • 1 = argc 意味着你 运行 没有参数的程序,所以 shell 传递了 1 个隐含的第一个参数(程序名称,argv[0]).
  • 然后是一个 NULL 终止的 argv[](不是指向 argv 的 指针 ,实际数组就在堆栈上)。第一个元素是指向包含可执行文件路径的字符串的指针,因为您的调用者选择按照惯例将其传递给 execve()
  • 然后是一个以 NULL 结尾的 envp[] 数组。同样不是 char **envp 而是按值排列的实际数组。每个条目都是 char* 到环境中的一个条目。

同样,x86-64 System V ABI 记录了这个堆栈布局。 MacOS 遵循 x86-64 System V ABI。 https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI


(虽然我对堆栈对齐感到惊讶。在 Linux 上,RSP 在用户 space 的条目上是 16 字节对齐的;它不是一个函数,也不是 called 所以堆栈上没有 return 值。所以 argc 是 16 字节对齐的。但是在这里,你的代码似乎表明 rsp in main 具有相同的对齐方式为 argc。这意味着 main 的调用者的堆栈距离 call 之前的 16 字节对齐有 8 个字节。也许这就是 OS X 一直做的事情? )