Kali rolling x86-64 环境,默认动态链接
参考 32 位: http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html
流程图如下:

64 位草图

最简单的 main
|
gcc -ggdb -o prog1 prog1.c
execve
运行程序时,shell 或者 gui 调用 execve() 函数触发系统调用:
- 系统会分配栈区并将 argc, argv, envp 压栈
- 按照 shell 设定 FD
- 装载器负责重定位和调用
preinitializers(图中preinitarray1..n) - 从程序代码段中 _start 位置开始执行程序
_start
_start 是程序执行的初始位置,通过objdump -d prog1查看汇编
|
_start的作用就是配置__libc_start_main的参数并进行调用:
xor %ebp, %ebp用于将%ebp清零,同时作为最外层标记对
%rdi,%rsi,%rdx,%rcx,%r8,%r9的操作均为传参,因为共 7 个参数,还用到了栈来传递第一个参数main地址, 由__libc_start_main调用, 另外在程序终止后main的返回值会由__libc_start_main传递给exitargcargv__libc_csu_init__libc_csu_fini- Destructor of dynamic linker. Registered by libc_start_main with cxat_exit()
to call the FINI for dynamic libraries that got loaded before us. - 栈 - 函数调用前的
%rsp
为了提升访存效率,编译器通常采用 16B 对齐。为了保证函数调用时的新栈帧是 16B 对齐的,使用
and指令将 %esp 对齐。同时,为了将 %esp 保存在 16B 对齐的位置,使用
push %rax提前填充 8B
_start调用__libc_start_main前的状态:

__libc_start_main
__libc_start_main定义如下:
|
main的完整参数调用应该是int main(int argc, char** argv, char** envp), 但是__libc_start_main中却并不包含 envp, 因为envp可以由argc和argv计算得到
ELF auxiliary vector
使用 gdb 调试 prog1, 在_start处下断点, 运行初始状态如下:
可以看到从栈顶向栈底依次放置的是: argc, argv, 0x0, 环境变量等, 即ELF 辅助向量.
__libc_start_main 的主要功能
setuid, setgid
启动线程
寄存
fini和rtld_fini的参数, 等待at_exit调用调用
__libc_csu_init调用
main调用
exit
__libc_csu_init

|
|
|
__libc_csu_init返回__libc_start_main前:
