当前位置: 首页 > 面试题库 >

x86 Linux汇编器从_start获取程序参数

公孙阳文
2023-03-14
问题内容

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

例如:

./Program "text"

我正在使用(Gnu汇编器)

通常我使用

[esp+4]

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

有没有办法做到这一点?

我用谷歌搜索,但是我找不到很多信息


问题答案:

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

_startx86 Linux可执行文件的ELF入口点(aka ):

  1. ESP 指向argc
  2. ESP + 4 指向argv[0],数组的开始。即,数值应该传递给主为char **argvlea eax, [esp+4],不是mov eax, [esp+4]

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

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

cmdline-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

cmdline-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)之后放置了一个软件断点(),以使程序重新陷入调试器。
  • 然后我printf在GDB脚本中使用了打印
    1. argc 与表达 *(int*)$esp
    2. argv 与表达 ((char**)($esp + 4))[0]

差异很小:

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

命令行

#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

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

$ 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,价值 RSP 权后,argc被弹出。(ubp_av在GLIBC来源中)

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.


 类似资料:
  • 我需要从英特尔处理器中的随机生成器(英特尔酷睿i3)获取随机数。我不想使用任何图书馆。我想在C中使用汇编程序粘贴,但我不知道应该使用哪些寄存器和指令。

  • 问题内容: 如何做到这一点? 如果我想分析某些东西是如何编译的,我将如何获取发出的汇编代码? 问题答案: 使用该选项来gcc(或g ++)。 这将在helloworld.c上运行预处理器(cpp),执行初始编译,然后在运行汇编器之前停止。 默认情况下,这将输出一个文件。仍可以使用该选项设置输出文件。 当然,这只有在您拥有原始来源的情况下才有效。如果仅具有结果对象文件,则可以通过设置选项(或-d缩写

  • 我正在linux 64bit中构建没有glibc的简单应用程序。但是我不知道如何获取参数。 我谷歌了一下,发现RDI是argc,RSI是argv。但它不起作用。 当_start函数开始使用gdb时,我看到了寄存器,但RDI和RSI都是0x0。我还用最简单的汇编应用程序进行了测试,但结果是一样的。RDI和RSI是0x0。我认为即使我没有向程序传递参数,argc也不应该是0x0。 这是我尝试过的C代码

  • 问题内容: 在大多数应用程序服务器上,J2EE Ejb规范禁止“手动”创建线程,因为这些资源应由服务器管理。 但是有什么方法可以从Tomcat,Glassfish,Jboss等获取线程;因此访问他们的ThreadPool? 问题答案: 您可以使用commonj WorkManager 。IBM和BEA提出了一项建议,以提供一种完成此任务的标准方法(访问容器管理的线程)。 尽管它没有包含在实际规范中

  • 问题内容: 我需要检查是否可以显式设置可以传递给JVM的某些选项,或者是否具有其默认值。 更具体地说:我需要创建一个本机堆栈大小比默认线程大的特定线程,但是如果用户想通过指定-Xss选项自己处理此类事情,我想创建所有具有默认堆栈大小的线程(将由用户在-Xss选项中指定)。 我已经检查了类和,但是这些类并没有给我有关VM参数的任何有用信息。 有什么方法可以获取我需要的信息吗? 问题答案: 通过此代码

  • 问题内容: 是否有任何Linux程序可以反汇编OSX通用x86 / x86_64胖Mach-O二进制文件,如objdump?GNU binutils的objdump支持ELF和Windows PE文件,但不支持Mach-O。 问题答案: AFAIK,本地的Darwin二进制工具是cctools软件包的一部分。它们没有与GNU binutils 相同的命令行语法或输出。但是后来的binutils(即