问题描述
我正在尝试创建一个程序以仅在屏幕上编写参数.我创建了一些程序来获取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
EX:
./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.
有办法吗?
我用谷歌搜索,但是我找不到很多信息
I googled it, but i wans't able to find much information
推荐答案
在Linux上,内核始终将C中熟悉的argc
和argv
变量传递给堆栈,甚至对于完全组装的汇编程序也可用.独立的,并且不与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:
- ESP 指向
argc
- ESP + 4 指向数组的开头
argv[0]
.即您应作为char **argv
传递给main的值是lea eax, [esp+4]
,而不是mov eax, [esp+4]
)
- ESP points to
argc
- ESP + 4 points to
argv[0]
, the start of the array. i.e. the value you should pass to main aschar **argv
islea eax, [esp+4]
, notmov eax, [esp+4]
)
最小汇编程序如何获得argc和argv
我将展示如何在GDB中读取argv
和argc[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\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
进行打印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-
argc
,其表达式为*(int*)$esp
-
argv
的表达式为((char**)($esp + 4))[0]
argc
with the expression*(int*)$esp
argv
with the expression((char**)($esp + 4))[0]
-
- 用 RSP 替换 ESP
- 将地址大小从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\n", *(int*)$rsp printf "argv[0]: %s\n", ((char**)($rsp + 8))[0] quit
常规C程序如何获取argc和argv
您可以从常规C程序中反汇编
_start
,以查看其如何从堆栈中获取argc
和argv
并在调用__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 obtainsargc
andargv
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()
的前三个参数是:- RDI :指向
main()
的指针 - RSI :
argc
,您可以看到它是如何从堆栈中弹出的第一件事 - RDX :
argv
,在弹出argc
之后的 RSP 值. (ubp_av)
- RDI: pointer to
main()
- RSI:
argc
, you can see how it was the first thing popped off the stack - RDX:
argv
, the value of RSP right afterargc
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获取程序参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- I placed a software breakpoint (