小编典典
在Linux上,熟悉的C语言argc和argv变量始终由内核传递到堆栈上,甚至可以用于完全独立的汇编程序,并且不与C库中的启动代码链接。这在i386
System V ABI中进行了记录,同时还介绍了流程启动环境的其他详细信息(寄存器值,堆栈对齐)。
在_startx86 Linux可执行文件的ELF入口点(aka ):
ESP 指向argc
ESP + 4 指向argv[0],数组的开始。即,数值应该传递给主为char **argv是lea eax, [esp+4],不是mov eax, [esp+4])
最小汇编程序如何获得argc和argv
我将展示如何阅读argv和argc[0]在GDB中。
cmdline-x86.S
#include
.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脚本中使用了打印 argc 与表达 *(int*)$esp
argv 与表达 ((char**)($esp + 4))[0]
x86-64版本
差异很小:
用 RSP*替换 ESP*
将地址大小从4更改为8
当我们调用exit_group(0)以正确终止进程时,请遵循不同的Linux syscall调用约定
命令行
#include
.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 : xor %ebp,%ebp
0x0000000000401582 : mov %rdx,%r9
0x0000000000401585 : pop %rsi
0x0000000000401586 : mov %rsp,%rdx
0x0000000000401589 : and $0xfffffffffffffff0,%rsp
0x000000000040158d : push %rax
0x000000000040158e : push %rsp
0x000000000040158f : mov $0x404040,%r8
0x0000000000401596 : mov $0x403fb0,%rcx
0x000000000040159d : mov $0x4014c0,%rdi
0x00000000004015a4 : callq 0x401310 <__libc_start_main>
0x00000000004015a9 : hlt
0x00000000004015aa : xchg %ax,%ax
0x00000000004015ac : nopl 0x0(%rax)
前三个参数__libc_start_main()是:
RDI :指向的指针main()
RSI :argc,您可以看到它是如何从堆栈中弹出的第一件事
RDX :argv,价值 RSP 权后,argc被弹出。(ubp_av在GLIBC来源中)
x86 _start 非常相似:
Dump of assembler code for function _start:
0x0804842c : xor %ebp,%ebp
0x0804842e : pop %esi
0x0804842f : mov %esp,%ecx
0x08048431 : and $0xfffffff0,%esp
0x08048434 : push %eax
0x08048435 : push %esp
0x08048436 : push %edx
0x08048437 : push $0x80485e0
0x0804843c : push $0x8048570
0x08048441 : push %ecx
0x08048442 : push %esi
0x08048443 : push $0x80483d0
0x08048448 : call 0x80483b0 <__libc_start_main>
0x0804844d : hlt
0x0804844e : xchg %ax,%ax
End of assembler dump.
2020-06-02