我的堆栈程序的第一个变量是什么?
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 字节对齐的;它不是一个函数,也不是 call
ed 所以堆栈上没有 return 值。所以 argc
是 16 字节对齐的。但是在这里,你的代码似乎表明 rsp
in main
具有相同的对齐方式为 argc
。这意味着 main
的调用者的堆栈距离 call
之前的 16 字节对齐有 8 个字节。也许这就是 OS X 一直做的事情? )
我已经开始组装了。
我不明白为什么我在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
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 字节对齐的;它不是一个函数,也不是 call
ed 所以堆栈上没有 return 值。所以 argc
是 16 字节对齐的。但是在这里,你的代码似乎表明 rsp
in main
具有相同的对齐方式为 argc
。这意味着 main
的调用者的堆栈距离 call
之前的 16 字节对齐有 8 个字节。也许这就是 OS X 一直做的事情? )