我正在尝试创建一个程序来将参数写入屏幕。 我创建了一些程序来获取 C 函数参数,或者我使用 C 将参数发送到我的 asm 程序。 有没有办法只使用汇编程序获取程序参数
例如:
./Program "text"
我正在使用(Gnu 汇编程序)
通常我会使用这些参数
[esp+4]
因为esp是程序/函数调用指针,但是在纯asm中它并没有获取命令行参数。
有办法吗?
我用谷歌搜索过,但找不到太多信息
最佳答案
在 Linux 上,来自 C 的熟悉的 argc
和 argv
变量总是由内核在堆栈上传递,甚至可用于完全独立的汇编程序t 与 C 库中的启动代码链接。这记录在 i386 System V ABI 中,以及进程启动环境的其他细节(寄存器值、堆栈对齐)。
在 x86 Linux 可执行文件的 ELF 入口点(又名 _start
):
- ESP 指向
argc
- ESP + 4 指向
argv[0]
,数组的开始。即,您应该作为char **argv
传递给 main 的值是lea eax, [esp+4]
,而不是mov eax, [esp+4]
)
最小汇编程序如何获取argc和argv
我将展示如何在 GDB 中读取 argv
和 argc[0]
。
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
示例 session
$ 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
来打印argc
表达式*(int*)$esp
argv
与表达式((char**)($esp + 4))[0]
x86-64 版本
差异很小:
- 用RSP替换ESP
- 将地址大小从 4 更改为 8
- 当我们调用
exit_group(0)
以正确终止进程时,符合不同的Linux 系统调用调用约定
命令行.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
命令行.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
程序为例:
$ 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 的值。 (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.
关于linux - x86 Linux 汇编程序从_start 获取程序参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16721164/