程序集中的Linux 64命令行参数

Ale*_*x F 7 linux 64-bit assembly command-line

此描述适用于Linux 32位:当Linux程序开始时,所有指向命令行参数的指针都存储在堆栈中.参数的数量存储在0(%ebp),程序的名称存储在4(%ebp),参数存储在8(%ebp).

64位需要相同的信息.

编辑:我有工作代码示例,演示如何使用argc,argv [0]和argv [1]:http://cubbi.com/fibonacci/asm.html

.globl _start
_start:
    popq    %rcx        # this is argc, must be 2 for one argument
    cmpq    $2,%rcx
    jne     usage_exit
    addq    $8,%rsp     # skip argv[0]
    popq    %rsi        # get argv[1]
    call ...
...
}

看起来参数在堆栈上.由于此代码不清楚,我问这个问题.我猜我可以将rp保留在rbp中,然后使用0(%rbp),8(%rbp),16(%rbp)等来访问这些参数.这是正确的吗?

ead*_*ead 11

尽管接受的答案绰绰有余,但我想给出一个明确的答案,因为还有一些其他答案可能会引起混淆.

最重要的(有关更多信息,请参见下面的示例):在x86-64中,命令行参数通过堆栈传递:

(%rsp) -> number of arguments
8(%rsp) -> address of the name of the executable
16(%rsp) -> address of the first command line argument (if exists)
... so on ...
Run Code Online (Sandbox Code Playgroud)

它与x86-64中传递的函数参数不同,后者使用%rdi,%rsi依此类推.

还有一件事:人们不应该推断出C main函数逆向工程的行为.C运行时提供入口点_start,将命令行参数和调用包装main为通用函数.为了看到它,让我们考虑以下示例.

没有C运行时/ GCC与-nostdlib

让我们检查一下这个简单的x86-64汇编程序,它只返回42:

.section .text
.globl _start
_start:   
    movq $60, %rax #60 -> exit
    movq $42, %rdi #return 42
    syscall #run kernel 
Run Code Online (Sandbox Code Playgroud)

我们建立它:

as --64 exit64.s -o exit64.o
ld -m elf_x86_64 exit64.o -o exit64
Run Code Online (Sandbox Code Playgroud)

或者

gcc -nostdlib exit64.s -o exit64
Run Code Online (Sandbox Code Playgroud)

用gdb运行

./exit64 first second third
Run Code Online (Sandbox Code Playgroud)

然后停在断点处_start.我们来看看寄存器:

(gdb) info registers
...
rsi            0x0  0
rdi            0x0  0
...
Run Code Online (Sandbox Code Playgroud)

空空如也.堆栈怎么样?

(gdb) x/5g $sp
0x7fffffffde40: 4   140737488347650
0x7fffffffde50: 140737488347711 140737488347717
0x7fffffffde60: 140737488347724
Run Code Online (Sandbox Code Playgroud)

所以堆栈中的第一个元素是4- 期望的argc.接下来的4个值看起来很像指针.让我们看看第二个指针:

(gdb) print (char[5])*(140737488347711)
$1 = "first"
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,它是第一个命令行参数.

因此有实验证据表明命令行参数是通过x86-64中的堆栈传递的.但是,只有通过阅读ABI(作为接受的答案建议),我们可以肯定,情况确实如此.

使用C运行时

我们必须稍微更改程序,重命名_startmain,因为入口点_start由C运行时提供.

.section .text
.globl main
main:   
    movq $60, %rax #60 -> exit
    movq $42, %rdi #return 42
    syscall #run kernel 
Run Code Online (Sandbox Code Playgroud)

我们用它构建它(默认情况下使用C运行时):

gcc exit64gcc.s -o exit64gcc
Run Code Online (Sandbox Code Playgroud)

用gdb运行

./exit64gcc first second third
Run Code Online (Sandbox Code Playgroud)

然后停在断点处main.什么在堆栈?

(gdb) x/5g $sp
0x7fffffffdd58: 0x00007ffff7a36f45  0x0000000000000000
0x7fffffffdd68: 0x00007fffffffde38  0x0000000400000000
0x7fffffffdd78: 0x00000000004004ed
Run Code Online (Sandbox Code Playgroud)

它看起来并不熟悉.和寄存器?

(gdb) info registers
...
rsi            0x7fffffffde38   140737488346680
rdi            0x4  4
...
Run Code Online (Sandbox Code Playgroud)

我们可以看到rdi包含该argc值.但是如果我们现在检查指针中rsi发生了奇怪的事情:

(gdb) print (char[5])*($rsi)
$1 =  "\211\307???"
Run Code Online (Sandbox Code Playgroud)

但等等,mainC中函数的第二个参数不是char *,而且char **:

(gdb) print (unsigned long long [4])*($rsi)
$8 = {140737488347644, 140737488347708, 140737488347714, 140737488347721}
(gdb) print (char[5])*(140737488347708)
$9 = "first"
Run Code Online (Sandbox Code Playgroud)

现在我们找到了我们的参数,这些参数通过寄存器传递,就像x86-64中的普通函数一样.

结论: 正如我们所看到的,关于在使用C运行时的代码和不执行C代码的代码之间传递命令行参数是有区别的.


rkh*_*rov 8

看起来像3.4 流程初始化,特别是图3.9,在已经提到过的System V中,AMD64 ABI正好描述了你想知道的内容.

  • 链接只有答案是脆弱的.该页面对我不起作用.*www.x86-64.org没有发送任何数据.ERR_EMPTY_RESPONSE* (5认同)