【问题标题】:x86 Linux assembler get program parameters from _startx86 Linux 汇编器从 _start 获取程序参数
【发布时间】:2013-05-19 05:45:44
【问题描述】:

我正在尝试创建一个程序来在屏幕上写入参数。 我创建了一些程序来获取 C 函数参数,或者我使用 C 将参数发送到我的 asm 程序。 有没有办法只使用汇编程序来获取程序参数

前:

./Program "text"

我正在使用 as (Gnu Assembler)

通常我使用这些参数获取这些参数

[esp+4]

因为esp是程序/函数调用指针,但是在纯asm中它没有得到命令行参数。

有没有办法做到这一点?

我用谷歌搜索过,但我找不到太多信息

【问题讨论】:

    标签: linux assembly x86 gnu-assembler


    【解决方案1】:

    在 Linux 上,C 中熟悉的 argcargv 变量总是由内核在堆栈上传递,甚至可用于完全独立且不与 C 库中的启动代码链接的汇编程序.这在i386 System V ABI 中进行了记录,以及进程启动环境的其他详细信息(寄存器值、堆栈对齐)。

    在 x86 Linux 可执行文件的 ELF 入口点(又名_start):

    1. ESP 指向argc
    2. ESP + 4 指向数组的开头argv[0]。即你应该作为char **argv传递给main的值是lea eax, [esp+4],而不是mov eax, [esp+4])

    最小汇编程序如何获取argc和argv

    我将展示如何在 GDB 中读取 argvargc[0]

    命令行-x86.S

    #include <sys/syscall.h>
    
        .global _start
    _start:
        /* Cause a breakpoint trap */
        int $0x03
    
        /* exit_group(0) */
        mov $SYS_exit_group, %eax
        mov $0, %ebx
        int $0x80
    

    命令行-x86.gdb

    set confirm off
    file cmdline-x86
    run
    # We'll regain control here after the breakpoint trap
    printf "argc: %d\n", *(int*)$esp
    printf "argv[0]: %s\n",  ((char**)($esp + 4))[0]
    quit
    

    示例会话

    $ cc -nostdlib -g3 -m32 cmdline-x86.S -o cmdline-x86
    $ gdb -q -x cmdline-x86.gdb cmdline-x86
    <...>  
    Program received signal SIGTRAP, Trace/breakpoint trap.
    _start () at cmdline-x86.S:8
    8   mov $SYS_exit_group, %eax
    argc: 1
    argv[0]: /home/scottt/Dropbox/stackoverflow/cmdline-x86
    

    说明

    • 我放置了一个软件断点 (int $0x03) 以使程序在 ELF 入口点 (_start) 之后立即陷入调试器。
    • 然后我在 GDB 脚本中使用printf 进行打印
      1. argc 与表达式 *(int*)$esp
      2. argv 与表达式 ((char**)($esp + 4))[0]

    x86-64 版本

    差异很小:

    • ESP 替换为 RSP
    • 将地址大小从 4 更改为 8
    • 当我们调用exit_group(0) 以正确终止进程时,符合不同的 Linux syscall 调用约定

    命令行.S

    #include <sys/syscall.h>
    
        .global _start
    _start:
        /* Cause a breakpoint trap */
        int $0x03
    
        /* exit_group(0) */
        mov $SYS_exit_group, %rax
        mov $0, %rdi
        syscall
    

    cmdline.gdb

    set confirm off
    file cmdline
    run
    printf "argc: %d\n", *(int*)$rsp
    printf "argv[0]: %s\n",  ((char**)($rsp + 8))[0]
    quit
    

    正则C程序如何获取argc和argv

    您可以从常规 C 程序中反汇编 _start,以查看它如何从堆栈中获取 argcargv,并在调用 __libc_start_main 时传递它们。以我的 x86-64 机器上的/bin/true 程序为例:

    $ gdb -q /bin/true
    Reading symbols from /usr/bin/true...Reading symbols from /usr/lib/debug/usr/bin/true.debug...done.
    done.
    (gdb) disassemble _start
    Dump of assembler code for function _start:
       0x0000000000401580 <+0>: xor    %ebp,%ebp
       0x0000000000401582 <+2>: mov    %rdx,%r9
       0x0000000000401585 <+5>: pop    %rsi
       0x0000000000401586 <+6>: mov    %rsp,%rdx
       0x0000000000401589 <+9>: and    $0xfffffffffffffff0,%rsp
       0x000000000040158d <+13>:    push   %rax
       0x000000000040158e <+14>:    push   %rsp
       0x000000000040158f <+15>:    mov    $0x404040,%r8
       0x0000000000401596 <+22>:    mov    $0x403fb0,%rcx
       0x000000000040159d <+29>:    mov    $0x4014c0,%rdi
       0x00000000004015a4 <+36>:    callq  0x401310 <__libc_start_main@plt>
       0x00000000004015a9 <+41>:    hlt    
       0x00000000004015aa <+42>:    xchg   %ax,%ax
       0x00000000004015ac <+44>:    nopl   0x0(%rax)
    

    __libc_start_main() 的前三个参数是:

    1. RDI:指向main()的指针
    2. RSIargc,你可以看到它是如何从堆栈中弹出的第一件事
    3. RDXargv,弹出argc之后的RSP值。 (GLIBC 源中的ubp_av

    x86 _start 非常相似:

    Dump of assembler code for function _start:
       0x0804842c <+0>: xor    %ebp,%ebp
       0x0804842e <+2>: pop    %esi
       0x0804842f <+3>: mov    %esp,%ecx
       0x08048431 <+5>: and    $0xfffffff0,%esp
       0x08048434 <+8>: push   %eax
       0x08048435 <+9>: push   %esp
       0x08048436 <+10>:    push   %edx
       0x08048437 <+11>:    push   $0x80485e0
       0x0804843c <+16>:    push   $0x8048570
       0x08048441 <+21>:    push   %ecx
       0x08048442 <+22>:    push   %esi
       0x08048443 <+23>:    push   $0x80483d0
       0x08048448 <+28>:    call   0x80483b0 <__libc_start_main@plt>
       0x0804844d <+33>:    hlt    
       0x0804844e <+34>:    xchg   %ax,%ax
    End of assembler dump.
    

    【讨论】:

    • 一个问题:如何在gas中做dword [ebp + 4 * ebx]?
    • (%ebp, %ebx, 4) 实际上。但是你总是可以用nasm -felf32 组装并用objdump -d 反汇编,看看AT&T 语法是如何写的。
    • 也是一个好主意:链接到指定初始进程环境的 ABI 标准(即在 _start 的第一条指令运行之前寄存器和内存中的内容)。 github.com/hjl-tools/x86-psABI/wiki/X86-psABI 当前链接到 revision 252 of the x86-64 SystemV ABI
    猜你喜欢
    • 1970-01-01
    • 2016-10-04
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多