x86 Linux 汇编器从 _start 获取程序参数 [英] x86 Linux assembler get program parameters from _start

查看:16
本文介绍了x86 Linux 汇编器从 _start 获取程序参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a program to just write the param on the screen. I created some programs to get the C function parameter, or i used C to send the parameter to my asm program. Is there a way to get the program parameter using only assembler

例如:

./Program "text"

我正在使用 (Gnu 汇编程序)

I'm using as (Gnu Assembler)

通常我使用这些参数

[esp+4]

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

Because the esp is the program/function call pointer, but in pure asm it don't get the command line parameter.

有没有办法做到这一点?

Is there a way to do that?

我用谷歌搜索了它,但我无法找到太多信息

I googled it, but i wans't able to find much information

推荐答案

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

On Linux, the familiar argc and argv variables from C are always passed on the stack by the kernel, available even to assembly programs that are completely standalone and don't link with the startup code in the C library. This is documented in the i386 System V ABI, along with other details of the process startup environment (register values, stack alignment).

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

At the ELF entry point (a.k.a. _start) of an x86 Linux executable:

  1. ESP 指向 argc
  2. ESP + 4 指向 argv[0],数组的开始.即您应该作为 char **argv 传递给 main 的值是 lea eax, [esp+4],而不是 mov eax, [esp+4])
  1. ESP points to argc
  2. ESP + 4 points to argv[0], the start of the array. i.e. the value you should pass to main as char **argv is lea eax, [esp+4], not mov eax, [esp+4])

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

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

#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

cmdline-x86.gdb

set confirm off
file cmdline-x86
run
# We'll regain control here after the breakpoint trap
printf "argc: %d
", *(int*)$esp
printf "argv[0]: %s
",  ((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 来打印

    Explanation

    • I placed a software breakpoint (int $0x03) to cause the program to trap back into the debugger right after the ELF entry point (_start).
    • I then used printf in the GDB script to print

      1. argc 带有表达式 *(int*)$esp
      2. argv 带有表达式 ((char**)($esp + 4))[0]
      1. argc with the expression *(int*)$esp
      2. argv with the expression ((char**)($esp + 4))[0]

    • 差异很小:

      • ESP 替换为 RSP
      • 将地址大小从 4 更改为 8
      • 当我们调用exit_group(0)以正确终止进程时,符合不同的Linux syscall调用约定
      • Replace ESP with RSP
      • Change address size from 4 to 8
      • Conform to different Linux syscall calling conventions when we call exit_group(0) to properly terminate the process
      #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
      ", *(int*)$rsp
      printf "argv[0]: %s
      ",  ((char**)($rsp + 8))[0]
      quit
      

      <小时>

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

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


      How Regular C Programs Obtain argc and argv

      You can disassemble _start from a regular C program to see how it obtains argc and argv from the stack and passes them as it calls __libc_start_main. Using the /bin/true program on my x86-64 machine as an example:

      $ 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. 的指针
      3. RSI:argc,你可以看到它是如何从堆栈中弹出的第一件事
      4. RDX:argvargc弹出后的RSP的值.(ubp_av 在 GLIBC 源代码中)
      1. RDI: pointer to main()
      2. RSI: argc, you can see how it was the first thing popped off the stack
      3. RDX: argv, the value of RSP right after argc was popped. (ubp_av in the GLIBC source)

      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.
      

      这篇关于x86 Linux 汇编器从 _start 获取程序参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆