Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

进程堆栈初始化.md #18

Open
chenpengcong opened this issue Jul 17, 2018 · 2 comments
Open

进程堆栈初始化.md #18

chenpengcong opened this issue Jul 17, 2018 · 2 comments

Comments

@chenpengcong
Copy link
Owner

chenpengcong commented Jul 17, 2018

当加载器(ELF Loader)将ELF文件加载到内存后,会初始化进程堆栈,包括argc, argv, 环境变量辅助向量,初始化后的进程堆栈结构如下(x86_64)

position            content                         size(bytes) + comment
-------------------------------------------------------------------------------------------------

stack pointer ->    [argc = number of args]         8
                    [argv[0](pointer)]              8
                    [argv[1](pointer)]              8
                    [argv[...](pointer)]            8 * x
                    [argv[n-1](pointer)]            8
                    [argv[n](pointer)]              8 (=NULL)


                    [envp[0](pointer)]              8
                    [envp[1](pointer)]              8
                    [envp[..](pointer)]             8 * x
                    [envp[term](pointer)]           8 (=NULL)


                    [auxv[0](Elf64_auxv_t)]         16
                    [auxv[1](Elf64_auxv_t)]         16
                    [auxv[..](Elf64_auxv_t)]        16 * x
                    [auxv[term](Elf64_auxv_t)]      16 (=NULL)

                    [padding]                       >= 0

                    [rand bytes]                    16

                    [String identifying platform]   >= 0

                    [padding for align]             >= 0 (sp - (get_random_int() % 8192)) & (~0xf)

                    [argument ASCIIZ strings]       >= 0
                    [environment ASCIIZ str]        >= 0

该图主要参考这里, 但进行了修改,因为在本地环境编写代码验证发现[auxv[term]][argument ASCIIZ strings]这部分区域的结构并不像参考文章里图示所展示的那样

通过翻阅ELF Loader源码linux/fs/binfmt_elf.c,找到与初始化堆栈相关的函数create_elf_tables

我把create_elf_tables函数里面操作堆栈的代码圈出如下图所示

code1

code2

标号1处的arch_align_stack函数具体实现如下, 该函数定义在linux/arch/x86/kernel/process.c

unsigned long arch_align_stack(unsigned long sp)
{
	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
		sp -= get_random_int() % 8192;
	return sp & ~0xf;
}

该函数将堆栈指针向下移动了x(0 <= x <=8192), 分配出[padding for align]这部分空间

标号2的代码为[String identifying platform]在栈上分配空间并进行赋值操作

标号3的代码生成16bytes大小的随机数,然后为[rand bytes]在栈上分配空间并进行赋值操作

标号4的代码

sp = STACK_ADD(p, ei_index)

在栈上分配辅助向量(auxiliary vector)所需存储空间

items = (argc + 1) + (envc + 1) + 1;
bprm->p = STACK_ROUND(sp, items);

在栈上分配argc, argv, encironment vector所需存储空间, 值得注意的是这两步都只是移动堆栈指针分配空间,并没有进行赋值初始化数据操作

标号5, 6, 7, 8的代码做了如下操作
5. 初始化栈上argc的值
6. 初始化栈上argv的值
7. 初始化栈上envp的值
8. 初始化栈上auxv的值

通过阅读代码可以看出执行结果与上面的结构图是相匹配的, 可能会有疑惑的地方就是图示中[padding]这一区域, 这一块数据来源如下:

通过上面解释我们可以看到标号4的代码在栈上一次性分配了argc, argv, envp auxv所需要的空间,然后再通过堆栈指针按顺序向上初始化每一块数据, 重点在于分配的空间并不刚好等于所需空间, 因为标号4的分配空间时使用了宏STACK_ROUND, 该宏定义如下

#define STACK_ROUND(sp, items) \
	(((unsigned long) (sp - items)) &~ 15UL)

会向下16字节对齐,因此分配的空间可能会比所需空间多,而标号5, 6 ,7 ,8的初始化操作又是从栈顶初始化的,所以最后在[auxvterm]和[rand bytes]这两块区域之间会多出[padding]这块数据

最后编写的测试代码如下

本机环境

$ uname -a
Linux debian 4.16.0-2-amd64 #1 SMP Debian 4.16.16-2 (2018-06-22) x86_64 GNU/Linux

#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <string.h>

int main(int argc, char** argv) {
    int i = 0;
    Elf64_auxv_t *auxv = NULL;
    long *auxv_start_addr = NULL;
    long *auxv_end_addr = NULL;
    long *env_start_addr = NULL;
    long *env_end_addr = NULL;
    long *argv_end_addr = NULL;
    char *platform;
    long *p = (long *)argv;
    char *env_str = NULL;
    unsigned char *rand_bytes = NULL;
    int arg_num = *(p - 1);
    printf("arg_num:%d\n", arg_num);
    for (i = 0;i < arg_num;i++) {
        printf("arg %d:%s\n", i, *p); 
        p++;
    }
    argv_end_addr = p;
    p++;//skip null
    printf("\nenvironment vector:\n");
    env_str = (char *)*p;
    env_start_addr = p;
    while (*p) {
        printf("%s\n", *p); 
        p++;
    }
    env_end_addr = p;
    p++;//skip null
    printf("\nauxiliary vectors:\n");
    auxv = (Elf64_auxv_t *)p; 
    auxv_start_addr = (long *)auxv;
    while (auxv->a_type != AT_NULL) {
        printf("auxv type:%ld, val:0x%x\n", auxv->a_type, auxv->a_un.a_val); 
        if (auxv->a_type == AT_PLATFORM) {
            platform = (char *)(auxv->a_un.a_val);
        }
        auxv++;
    }
    auxv_end_addr = (long *)auxv;
    auxv++;//skip AT_NULL vector
    printf("\naddress:%lx, env0_ascii_string:%s\n", env_str, env_str);
    printf("address:%lx ~ %lx, argument0_ascii_string:%s\n", *argv, argv[0] + strlen(argv[0]),*argv);
    printf("address:%lx ~ %lx, here contain %ld bytes data\n", platform + strlen(platform) + 1, (char *)*argv - 1, (long)*argv - (long)platform - strlen(platform) - 1);
    printf("address:%lx ~ %lx, String identifying platform:%s\n", platform, platform + strlen(platform), platform);
    rand_bytes = platform - 16; 
    printf("address:%lx ~ %lx, rand_bytes[16]:", rand_bytes, rand_bytes + 15);
    for (i = 0;i < 16;i++) {
        printf(" %d", *(rand_bytes + i)); 
    }
    printf("\naddress:%lx ~ %lx, auxivilary vector\n", auxv_start_addr, auxv_end_addr);
    printf("address:%lx ~ %lx, environment vector\n", env_start_addr, env_end_addr);
    printf("address:%lx ~ %lx, argv\n", argv, argv_end_addr);
    printf("address:%lx, argc\n", argv - 1);
    return 0;
}

本机运行结果如下:

$ ./a.out 
arg_num:1
arg 0:./a.out

environment vector:
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
XDG_MENU_PREFIX=gnome-
LANG=en_US.UTF-8
GDM_LANG=en_US.UTF-8
DISPLAY=:0
COLORTERM=truecolor
DESKTOP_AUTOSTART_ID=1067f02f661904b013153191243121980500000010550007
USERNAME=cike
XDG_VTNR=2
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
XDG_SESSION_ID=2
USER=cike
DESKTOP_SESSION=gnome
WAYLAND_DISPLAY=wayland-0
GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/1209a8c3_5cad_4323_b8e8_171909ba8809
PWD=/home/cike/workspace/linker_loader
HOME=/home/cike
XDG_SESSION_TYPE=wayland
XDG_SESSION_DESKTOP=gnome
TERM=xterm-256color
SHELL=/bin/bash
VTE_VERSION=5202
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
XDG_CURRENT_DESKTOP=GNOME
GNOME_TERMINAL_SERVICE=:1.107
XDG_SEAT=seat0
SHLVL=2
GDMSESSION=gnome
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=cike
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
SESSION_MANAGER=local/debian:@/tmp/.ICE-unix/1055,unix/debian:/tmp/.ICE-unix/1055
GTK_IM_MODULE=fcitx
OLDPWD=/home/cike/workspace/test
_=./a.out

auxiliary vectors:
auxv type:33, val:0x121d1000
auxv type:16, val:0xbfebfbff
auxv type:6, val:0x1000
auxv type:17, val:0x64
auxv type:3, val:0xdb1e4040
auxv type:4, val:0x38
auxv type:5, val:0x9
auxv type:7, val:0x30912000
auxv type:8, val:0x0
auxv type:9, val:0xdb1e45d0
auxv type:11, val:0x3e8
auxv type:12, val:0x3e8
auxv type:13, val:0x3e8
auxv type:14, val:0x3e8
auxv type:23, val:0x0
auxv type:25, val:0x1200c7c9
auxv type:26, val:0x0
auxv type:31, val:0x1200eff0
auxv type:15, val:0x1200c7d9

address:7ffd1200e5fb, env0_ascii_string:LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
address:7ffd1200e5f3 ~ 7ffd1200e5fa, argument0_ascii_string:./a.out
address:7ffd1200c7e0 ~ 7ffd1200e5f2, here contain 7699 bytes data
address:7ffd1200c7d9 ~ 7ffd1200c7df, String identifying platform:x86_64
address:7ffd1200c7c9 ~ 7ffd1200c7d8, rand_bytes[16]: 193 130 184 246 204 82 221 150 58 249 82 90 18 26 172 195
address:7ffd1200c680 ~ 7ffd1200c7b0, auxivilary vector
address:7ffd1200c548 ~ 7ffd1200c678, environment vector
address:7ffd1200c538 ~ 7ffd1200c540, argv
address:7ffd1200c530, argc

参考:
About ELF Auxiliary Vectors
《程序员自我修养》7.5章节

@liu-xuewen
Copy link

---- 该图主要参考这里, 但进行了修改
请教一下, 这个图是根据后面的程序自己修改画出来的吗? 还是有工具或者命令直接查出来

@chenpengcong
Copy link
Owner Author

---- 该图主要参考这里, 但进行了修改
请教一下, 这个图是根据后面的程序自己修改画出来的吗? 还是有工具或者命令直接查出来

根据后面实际分析自己修改画出来的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants