1 附加向量
1.1 附加向量
Auxiliary vector是一种机制,内核的ELF binary loader使用附加向量在程序执行时传递某些信息到用户空间。
#include <sys/auxv.h>
unsigned long getauxval(unsigned long type);
sys/auxv.h
#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_HWCAP2 26 /* More machine-dependent hints about processor capabilities. */ #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 |
1.2 auxv的位置
Local variable |
|
Return Address |
|
argc |
|
argv[0] argv[1] |
没有参数的情况下 argv[1]=NULL |
envp[X] |
最后一个指针为NULL |
auxv[40] |
键值对,测试中共20条记录,最后一条记录为0,0 |
X字节 |
结构不清楚,这个是调试分析的,未必准确; 32位(38字节) 7个0x0 AT_RANDOM(16字节) AT_PLATFORM (“i686” 0x0) 10个0x0 64位(24字节/32个字节) 0x0/9个0x0 AT_RANDOM(16字节) AP_PLATFORM (“x86_64” 0x0) |
env string |
|
1.2.1 X86
millionsky@ubuntu-16:~/tmp/return-to-vdso$ gdb ./hello (gdb) b *0x8048061 (gdb) r (gdb) disass Dump of assembler code for function _start: => 0x08048061: mov $0x4,%eax 0x08048066: mov $0x1,%ebx 0x0804806b: mov $0x8048054,%ecx 0x08048070: mov $0xd,%edx 0x08048075: int $0x80 0x08048077: mov $0x1,%eax 0x0804807c: mov $0x0,%ebx 0x08048081: int $0x80 End of assembler dump. (gdb) x/100wx $esp 0xffffd570: 0x00000001 0xffffd6b0 0x00000000 0xffffd6da envp 0xffffd580: 0xffffd6ed 0xffffd6fd 0xffffd708 0xffffd736 0xffffd590: 0xffffd757 0xffffd76b 0xffffd77b 0xffffd7a5 0xffffd5a0: 0xffffdd2d 0xffffdd39 0xffffddf3 0xffffde0d 0xffffd5b0: 0xffffde1c 0xffffde3d 0xffffde65 0xffffde8c 0xffffd5c0: 0xffffde9d 0xffffdea6 0xffffdebc 0xffffdec4 0xffffd5d0: 0xffffded6 0xffffdee9 0xffffdf1b 0xffffdf6d 0xffffd5e0: 0xffffdf8d 0xffffdfac 0x00000000 0x00000020 auxv 0xffffd5f0: 0xf7ffcc80 0x00000021 0xf7ffc000 0x00000010 0xffffd600: 0x0fabfbff 0x00000006 0x00001000 0x00000011 0xffffd610: 0x00000064 0x00000003 0x08048034 0x00000004 0xffffd620: 0x00000020 0x00000005 0x00000001 0x00000007 0xffffd630: 0x00000000 0x00000008 0x00000000 0x00000009 0xffffd640: 0x08048061 0x0000000b 0x000003e8 0x0000000c 0xffffd650: 0x000003e8 0x0000000d 0x000003e8 0x0000000e 0xffffd660: 0x000003e8 0x00000017 0x00000000 0x00000019 0xffffd670: 0xffffd69b 0x0000001a 0x00000000 0x0000001f 0xffffd680: 0xffffdfce 0x0000000f 0xffffd6ab 0x00000000 0xffffd690: 0x00000000 0x00000000 0xa6000000 0xb5678ea1 0xffffd6a0: 0x77696372 0x2183ba58 0x697e970f 0x00363836 0xffffd6b0: 0x6d6f682f 0x696d2f65 0x6f696c6c 0x796b736e 0xffffd6c0: 0x706d742f 0x7465722f 0x2d6e7275 0x762d6f74 0xffffd6d0: 0x2f6f7364 0x6c6c6568 0x4458006f 0x45535f47 0xffffd6e0: 0x4f495353 0x44495f4e 0x3435313d 0x45485300 0xffffd6f0: 0x2f3d4c4c 0x2f6e6962 0x68736162 0x52455400 |
1.2.2 X64
millionsky@ubuntu-16:~/tmp/return-to-vdso$ gdb ./hello (gdb) b *0x400085 (gdb) r (gdb) disass Dump of assembler code for function _start: => 0x0000000000400085: mov $0x4,%eax 0x000000000040008a: mov $0x1,%ebx 0x000000000040008f: mov $0x400078,%ecx 0x0000000000400094: mov $0xd,%edx 0x0000000000400099: int $0x80 0x000000000040009b: mov $0x1,%eax 0x00000000004000a0: mov $0x0,%ebx 0x00000000004000a5: int $0x80 End of assembler dump. (gdb) x/72gx $rsp 0x7fffffffe460: 0x0000000000000001 0x00007fffffffe6b0 0x7fffffffe470: 0x0000000000000000 0x00007fffffffe6da envp 0x7fffffffe480: 0x00007fffffffe6ed 0x00007fffffffe6fd 0x7fffffffe490: 0x00007fffffffe708 0x00007fffffffe736 0x7fffffffe4a0: 0x00007fffffffe757 0x00007fffffffe76b 0x7fffffffe4b0: 0x00007fffffffe77b 0x00007fffffffe7a5 0x7fffffffe4c0: 0x00007fffffffed2d 0x00007fffffffed39 0x7fffffffe4d0: 0x00007fffffffedf3 0x00007fffffffee0d 0x7fffffffe4e0: 0x00007fffffffee1c 0x00007fffffffee3d 0x7fffffffe4f0: 0x00007fffffffee65 0x00007fffffffee8c 0x7fffffffe500: 0x00007fffffffee9d 0x00007fffffffeea6 0x7fffffffe510: 0x00007fffffffeebc 0x00007fffffffeec4 0x7fffffffe520: 0x00007fffffffeed6 0x00007fffffffeee9 0x7fffffffe530: 0x00007fffffffef1b 0x00007fffffffef6d 0x7fffffffe540: 0x00007fffffffef8d 0x00007fffffffefac 0x7fffffffe550: 0x0000000000000000 0x0000000000000021 auxv 0x7fffffffe560: 0x00007ffff7ffd000 0x0000000000000010 0x7fffffffe570: 0x000000000fabfbff 0x0000000000000006 0x7fffffffe580: 0x0000000000001000 0x0000000000000011 0x7fffffffe590: 0x0000000000000064 0x0000000000000003 0x7fffffffe5a0: 0x0000000000400040 0x0000000000000004 0x7fffffffe5b0: 0x0000000000000038 0x0000000000000005 0x7fffffffe5c0: 0x0000000000000001 0x0000000000000007 0x7fffffffe5d0: 0x0000000000000000 0x0000000000000008 0x7fffffffe5e0: 0x0000000000000000 0x0000000000000009 0x7fffffffe5f0: 0x0000000000400085 0x000000000000000b 0x7fffffffe600: 0x00000000000003e8 0x000000000000000c 0x7fffffffe610: 0x00000000000003e8 0x000000000000000d 0x7fffffffe620: 0x00000000000003e8 0x000000000000000e 0x7fffffffe630: 0x00000000000003e8 0x0000000000000017 0x7fffffffe640: 0x0000000000000000 0x0000000000000019 0x7fffffffe650: 0x00007fffffffe699 0x000000000000001a 0x7fffffffe660: 0x0000000000000000 0x000000000000001f 0x7fffffffe670: 0x00007fffffffefce 0x000000000000000f 0x7fffffffe680: 0x00007fffffffe6a9 0x0000000000000000 0x7fffffffe690: 0x0000000000000000 0x164976e45ea81400 |
1.3 AT_SYSINFO_EHDR&AT_SYSINFO
kernel告诉C库VDSO/__kernel_vsyscall的位置,则是通过elf的interpreter的auxiliary vector。
AT_SYSINFO __kernel_vsyscall的地址
AT_SYSINFO_EHDR VDSO的地址
64位系统只有AT_SYSINFO_EHDR,没有AT_SYSINFO;
GDB调试(x86)
(gdb) info auxv 32 AT_SYSINFO Special system info/entry points 0xb7fdd414 33 AT_SYSINFO_EHDR System-supplied DSO's ELF header 0xb7fdd000 (gdb) info program Using the running image of child process 7749. Program stopped at 0x80483e8. It stopped at breakpoint 1. (gdb) shell cat /proc/7749/maps | grep vdso b7fdd000-b7fde000 r-xp 00000000 00:00 0 [vdso] |
LD_SHOW_AUXV环境变量
millionsky@ubuntu-12:~/tmp$ LD_SHOW_AUXV=1 /bin/ls AT_SYSINFO: 0xb77c0414 AT_SYSINFO_EHDR: 0xb77c0000 |
1.4 AT_RANDOM
16字节随机数的地址;
这个地址在附加向量的后面,环境字符串的前面;
对于确定的系统,可以通过这个地址计算栈中数据的地址
泄露栈数据
计算AT_RANDOM的值,记为address
计算AT_RANDOM距离栈开始数据,如argc的偏移,记为offset;
Address-offset即栈开始数据如argc的地址
1.5 AT_PLATFORM
平台字符串i386\0或x86_64\0
位于AT_RANDOM字符串后面
可以通过这个地址计算栈中数据的地址
2 结论
1. 附加向量位于环境指针数组的后面,环境字符串的前面;
2. 附加向量中的AT_SYSINFO_EHDR指示VDSO的地址;
3. 附加向量中的AT_SYSINFO指示__kernel_vsyscall的地址(32位系统);
4. 附加向量中的AT_RANDOM指示栈中16字节随机数的地址。在栈中位于附加向量的后面,环境字符串的前面。可以通过这个地址计算栈中数据的地址。
5. AT_PLATFORM指示平台字符串,可以通过这个地址计算栈中数据的地址。
3 参考文章
1. Return to VDSO using ELF Auxiliary Vectors。https://v0ids3curity.blogspot.jp/2014/12/return-to-vdso-using-elf-auxiliary.html。