Skip to content

Latest commit

 

History

History
229 lines (193 loc) · 7.27 KB

201205092043.txt.md

File metadata and controls

229 lines (193 loc) · 7.27 KB

2.23 ELF Auxiliary Vectors

http://scz.617.cn/unix/201205092043.txt

D: Manu Garg 2006

参看Linux内核源码:

fs/binfmt_elf.c

这里实现了ELF文件的加载。ELF文件加载时,栈被初始化成如下样子:

position content size(bytes) + comment

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

             [ envp[0] (pointer)         ] 4
             [ envp[1] (pointer)         ] 4
             [ envp[...] (pointer)       ] 4
             [ envp[term] (pointer)      ] 4    (=NULL)

             [ auxv[0] (Elf32_auxv_t)    ] 8
             [ auxv[1] (Elf32_auxv_t)    ] 8
             [ auxv[...] (Elf32_auxv_t)  ] 8
             [ auxv[term] (Elf32_auxv_t) ] 8    (=AT_NULL vector)

             [ padding                   ] 0~16

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

(0xbffffffc) [ end marker ] 4 (=NULL)

(0xc0000000) < bottom of stack > 0 (virtual)

大多数时候C程序员这样写main():

int main ( int argc, char * argv[] );

如果需要访问环境变量,就会这样写:

int main ( int argc, char * argv[], char * envp[] );

但在x86上没法直接访问auxv[],据说PowerPC上第4形参是auxv[]。


/*

  • /usr/include/elf.h / typedef struct { /
    • Entry type */ uint32_t a_type; union { uint32_t a_val; } a_un; } Elf32_auxv_t;

/*

  • Legal values for a_type (entry type). / #define AT_NULL 0 // End of vector #define AT_IGNORE 1 // Entry should be ignored #define AT_EXECFD 2 // File descriptor of program #define AT_PHDR 3 // Program headers for program #define AT_PHENT 4 // Size of program header entry #define AT_PHNUM 5 // Number of program headers #define AT_PAGESZ 6 // System page size #define AT_BASE 7 // Base address of interpreter #define AT_FLAGS 8 // Flags #define AT_ENTRY 9 // Entry point of program #define AT_NOTELF 10 // Program is not ELF #define AT_UID 11 // Real uid #define AT_EUID 12 // Effective uid #define AT_GID 13 // Real gid #define AT_EGID 14 // Effective gid #define AT_CLKTCK 17 // Frequency of times() /
  • Some more special a_type values describing the hardware. / #define AT_PLATFORM 15 // String identifying platform. #define AT_HWCAP 16 // Machine dependent hints about processor capabilities. /
  • This entry gives some information about the FPU initialization performed by the kernel. / #define AT_FPUCW 18 // Used FPU control word. /
  • Cache block sizes. / #define AT_DCACHEBSIZE 19 // Data cache block size. #define AT_ICACHEBSIZE 20 // Instruction cache block size. #define AT_UCACHEBSIZE 21 // Unified cache block size. /
  • A special ignored value for PPC, used by the kernel to control the
  • interpretation of the AUXV. Must be > 16. / #define AT_IGNOREPPC 22 // Entry should be ignored. #define AT_SECURE 23 // Boolean, was exec setuid-like? #define AT_BASE_PLATFORM 24 // String identifying real platforms. #define AT_RANDOM 25 // Address of 16 random bytes. #define AT_EXECFN 31 // Filename of executable. /
  • Pointer to the global system page used for system calls and other nice things. / #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 /
  • Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
  • log2 of line size; mask those to get cache size. */ #define AT_L1I_CACHESHAPE 34 #define AT_L1D_CACHESHAPE 35 #define AT_L2_CACHESHAPE 36 #define AT_L3_CACHESHAPE 37

绝大多数时候,只有ELF加载器需要关心ELF Auxiliary Vectors,程序员并不怎么关 心。但如果你非常好奇,有一个简便方法让你查看ELF Auxiliary Vectors:

$ LD_SHOW_AUXV=1 /bin/true AT_SYSINFO: 0xb7fc8400 AT_SYSINFO_EHDR: 0xffffe000 AT_HWCAP: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss AT_PAGESZ: 4096 AT_CLKTCK: 100 AT_PHDR: 0x8048034 AT_PHENT: 32 AT_PHNUM: 7 AT_BASE: 0xb7fc9000 AT_FLAGS: 0x0 AT_ENTRY: 0x80489e0 AT_UID: 0 AT_EUID: 0 AT_GID: 0 AT_EGID: 0 AT_SECURE: 0 AT_PLATFORM: i686

下面演示如何编程寻找AT_SYSINFO、AT_SYSINFO_EHDR:


/*

  • gcc-3.3 -Wall -pipe -O3 -s -o elf_auxv_demo elf_auxv_demo.c */ #include <stdio.h> #include <elf.h>

unsigned int get_auxv ( Elf32_auxv_t *auxv, unsigned int type ) { unsigned int value = 0xffffffff;

for ( ; AT_NULL != auxv->a_type; auxv++ )
{
    if ( type == auxv->a_type )
    {
        value   = auxv->a_un.a_val;
        break;
    }
}
return( value );

} /* end of get_auxv */

int main ( int argc, char * argv[], char * envp[] ) { Elf32_auxv_t *auxv; unsigned int value;

while ( NULL != *envp++ );
auxv    = ( Elf32_auxv_t * )envp;
if ( 0xffffffff != ( value = get_auxv( auxv, AT_SYSINFO ) ) )
{
    printf( "AT_SYSINFO      = 0x%x\n", value );
}
if ( 0xffffffff != ( value = get_auxv( auxv, AT_SYSINFO_EHDR ) ) )
{
    printf( "AT_SYSINFO_EHDR = 0x%x\n", value );
}
return( 0 );

} /* end of main */

$ for i in seq 0 1 2;do ./elf_auxv_demo;done AT_SYSINFO = 0xb7fcc400 AT_SYSINFO_EHDR = 0xffffe000 AT_SYSINFO = 0xb7f0d400 AT_SYSINFO_EHDR = 0xffffe000 AT_SYSINFO = 0xb7ee8400 AT_SYSINFO_EHDR = 0xffffe000

可以看出,AT_SYSINFO被随机化了,AT_SYSINFO_EHDR好像是无效的。禁用ASLR之后 的效果:

$ for i in seq 0 1 2;do setarch uname -m -R ./elf_auxv_demo | grep "AT_SYSINFO ";done AT_SYSINFO = 0xb7fe4400 AT_SYSINFO = 0xb7fe4400 AT_SYSINFO = 0xb7fe4400

利用LD_SHOW_AUXV环境变量时的效果:

$ for((i=0;i<3;i++));do LD_SHOW_AUXV=1 ./elf_auxv_demo | grep "AT_SYSINFO[ :]";done AT_SYSINFO: 0xb7f04400 AT_SYSINFO = 0xb7f04400 AT_SYSINFO: 0xb7f48400 AT_SYSINFO = 0xb7f48400 AT_SYSINFO: 0xb7f71400 AT_SYSINFO = 0xb7f71400

D: scz@nsfocus

elf_auxv_demo.c演示了一种比较繁琐的寻找auxv[]的办法,其实有更省事的办法:

$ setarch uname -m -R cat /proc/self/auxv | xxd -g 1 | grep "20 00 00 00" 0000000: 20 00 00 00 00 44 fe b7 21 00 00 00 00 e0 ff ff ....D..!....... 0000030: 04 00 00 00 20 00 00 00 05 00 00 00 07 00 00 00 .... ...........

可以看出AT_SYSINFO等于0xb7fe4400。