当前位置: 首页 > news >正文

汉鼎中国 网站建设重庆网上房地产官网查询备案价

汉鼎中国 网站建设,重庆网上房地产官网查询备案价,企业建站公司实力对比,[wordpress环境搭建 虚拟机安装 镜像下载网站为了避免环境问题建议 22.04 #xff0c;20.04#xff0c;18.04#xff0c;16.04 等常见版本 ubuntu 虚拟机环境各准备一份。注意定期更新快照以防意外。虚拟机建议硬盘 256 G 以上#xff0c;内存也尽量大一些。硬盘大小只是上界#…环境搭建 虚拟机安装 镜像下载网站为了避免环境问题建议 22.04 20.0418.0416.04 等常见版本 ubuntu 虚拟机环境各准备一份。注意定期更新快照以防意外。虚拟机建议硬盘 256 G 以上内存也尽量大一些。硬盘大小只是上界256 G 不是真就占了 256 G而后期如果硬盘空间不足会很麻烦。 基础工具 vim sudo apt install vimgedit 不习惯 vim 的可以使用 gedit 文本编辑器。 sudo apt install geditgit sudo apt install gitgcc sudo apt install gccpython ipython 提供了很好的 python 交互命令行建议安装。 sudo apt install python2 ipython2 sudo apt install python3 ipython3另外有的版本 ubuntu 的不好安装 pip2 可以使用 get-pip.py 脚本安装。 curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py sudo python2 get-pip.pypwn 相关工具 gdb sudo apt-get install gdb gdb-multiarchpwntools 注意我这里的 pwntools 是 python2 版本的。 pip install pwntools这样安装的 pwntools 的 plt 功可能无法正常使用需要手动安装 Unicorn 库。 pip install unicorn1.0.3gdb 插件 主要有 pwndbgpedagef 这里我常用的是 pwndbg 。对于一些版本过于古老导致环境装不上的可以尝试一下 peda 。 先将三个项目的代码都拉取下来。 git clone https://github.com/longld/peda.git git clone https://github.com/pwndbg/pwndbg.git git clone https://github.com/hugsy/gef.gitpwndbg 需要运行初始化脚本。 cd pwndbg sudo ./setup.sh另外还有一个 pwngdb 插件在调试多线程堆heapinfoall 命令的时候很有用建议安装。 git clone https://github.com/scwuaptx/Pwngdb.git gdb 在启动的时候会读取当前用户的主目录的 .gdbinit 文件进行 gdb 插件的初始化这里提供一个配置方案。 source /home/sky123/tools/pwndbg/gdbinit.py #source /home/sky123/tools/peda/peda.py #source /home/sky123/tools/gef/gef.py#source /home/sky123/tools/muslheap/muslheap.pysource /home/sky123/tools/Pwngdb/pwngdb.py source /home/sky123/tools/Pwngdb/angelheap/gdbinit.pydefine hook-run python import angelheap angelheap.init_angelheap() end end注意以普通用权限和管理员权限启动 gdb 时读取的 .gdbinit 文件的路径是不同的普通权限读取的是 /home/username/.gdbinit 而管理员权限读取的是 /root/.gdbinit 。 gadget 搜索工具 ROPgdbget 安装 git clone https://github.com/JonathanSalwan/ROPgadget.git cd ROPgadget sudo python3 setup.py install使用 ROPgadget --binary ntdll.dll ropropper 安装 在 pypi 的 ropper 官网上下载 ropper运行安装脚本完成 ropper 安装python setup.py install使用ropper --file ./pwn --nocolor ropone_gadget 用于搜索 libc 中能够实现 execve(/bin/sh, (char *[2]) {/bin/sh, NULL}, NULL); 的效果的跳转地址由于是采用特征匹配的方法因此只能是在 libc 中查找。 安装sudo apt install -y ruby ruby-dev sudo gem install one_gadget使用可以查找到 gadget 地址以及条件限制。➜ ~ one_gadget /lib/x86_64-linux-gnu/libc.so.6 0x50a37 posix_spawn(rsp0x1c, /bin/sh, 0, rbp, rsp0x60, environ) constraints:rsp 0xf 0rcx NULLrbp NULL || (u16)[rbp] NULL0xebcf1 execve(/bin/sh, r10, [rbp-0x70]) constraints:address rbp-0x78 is writable[r10] NULL || r10 NULL[[rbp-0x70]] NULL || [rbp-0x70] NULL0xebcf5 execve(/bin/sh, r10, rdx) constraints:address rbp-0x78 is writable[r10] NULL || r10 NULL[rdx] NULL || rdx NULL0xebcf8 execve(/bin/sh, rsi, rdx) constraints:address rbp-0x78 is writable[rsi] NULL || rsi NULL[rdx] NULL || rdx NULLseccomp-tools 用于查看和生成程序沙箱规则。 安装sudo gem install seccomp-tools使用seccomp-tools dump ./pwnLibcSearcher 通过泄露的 libc 中函数的地址来确定 libc 版本。 git clone https://github.com/lieanu/LibcSearcher.git cd LibcSearcher sudo python3 setup.py installpatchelf 用于对于依赖不是很复杂的程序更换 libc 有一下几点需要注意 如果在漏洞利用时用到了动态链接相关结构最好不要 patchelf因为 patchelf 会改变动态链接相关结构的位置。一个程序在一个版本的虚拟机里面 patchelf 后换到另一个版本虚拟机中可能会运行失败。在 patch 完 libc 后最好把 ld 也 patch 成大版本相同的 ld 否则会运行失败。 安装 sudo apt install patchelf修改 libc patchelf --replace-needed libc.so.6 ./libc.so.6 ./pwn修改 ld patchelf --set-interpreter ./ld-2.31.so ./pwnqemu sudo apt install qemu-user qemu-system 工具使用 docker shell ssh ELF 文件格式 ELFExecutable and Linkable Format是一种常见的可执行文件和可链接文件格式主要用于Linux和类Unix系统。ELF 文件可以包含不同的类型常见的 ELF 文件类型包括 可执行文件ET_EXEC这种类型的 ELF 文件是可直接执行的程序可以在操作系统上运行。共享目标文件ET_DYN这种类型的 ELF 文件是可被动态链接的共享库可以在运行时与其他程序动态链接。该类型文件后缀名为 .so 。可重定位文件ET_REL这种类型的 ELF 文件是编译器生成的目标文件通常用于将多个目标文件链接到一个可执行文件或共享库中。该类型文件后缀名为 .o 静态链接库.a也可以归为这一类。核心转储文件ET_CORE这种类型的 ELF 文件是操作系统在程序崩溃或发生错误时生成的核心转储文件用于调试和分析程序崩溃的原因。 ELF 文件结构及相关常数被定义在 /usr/include/elf.h 里因为 ELF 文件在各种平台下都通用ELF文件有 32 位版本和 64 位版本。32 位版本与 64 位版本的 ELF 文件的格式基本是一样的部分结构体为了优化对齐后大小调整了成员的顺序只不过有些成员的大小不一样。 elf.h 使用 typedef 定义了一套自己的变量体系 自定义类型描述原始类型长度字节Elf32_Addr32 位版本程序地址uint32_t4Elf32_Half32 位版本的无符号短整型uint16_t2Elf32_Off32 位版本的偏移地址uint32_t4Elf32_Sword32 位版本有符号整型uint32_t4Elf32_Word32 位版本无符号整型int32_t4Elf64_Addr64 位版本程序地址uint64_t8Elf64_Half64 位版本的无符号短整型uint16_t2Elf64_Off64 位版本的偏移地址uint64_t8Elf64_Sword64 位版本有符号整型uint32_t4Elf64_Word64 位版本无符号整型int32_t4 ELF 主要管理结构为文件头程序头表可重定位文件没有和节表其他部分有一个个节组成多个属性相同的节构成一个段。对于节的介绍这里按照静态链接相关和动态链接相关分别介绍。 文件头 我们这里以 32 位版本的文件头结构 Elf32_Ehdr 作为例子来描述它的定义如下 /* The ELF file header. This appears at the start of every ELF file. */#define EI_NIDENT (16)typedef struct {unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */Elf32_Half e_type; /* Object file type */Elf32_Half e_machine; /* Architecture */Elf32_Word e_version; /* Object file version */Elf32_Addr e_entry; /* Entry point virtual address */Elf32_Off e_phoff; /* Program header table file offset */Elf32_Off e_shoff; /* Section header table file offset */Elf32_Word e_flags; /* Processor-specific flags */Elf32_Half e_ehsize; /* ELF header size in bytes */Elf32_Half e_phentsize; /* Program header table entry size */Elf32_Half e_phnum; /* Program header table entry count */Elf32_Half e_shentsize; /* Section header table entry size */Elf32_Half e_shnum; /* Section header table entry count */Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr;e_identELF 文件的魔数和其他信息。 前 4 字节为 ELFMAG 即 \x7fELF 。第 5 字节为 ELF 文件类型值为 ELFCLASS32(1) 代表 32 位值为 ELFCLASS64(2) 代表 64 位。第 6 字节为 ELF 的字节序0 为无效格式1 为小端格式2 为大端格式。第 7 字节为 ELF 版本一般为 1 即 1.2 版本。后面 9 字节没有定义一般填 0 有些平台会使用这 9 个字节作为扩展标志。 e_type表示ELF文件类型如可执行文件、共享对象文件.so、可重定位文件.o等。e_machine表示目标体系结构即程序的目标平台如 x86、ARM 等。相关常量以 EM_ 开头。e_versionELF 文件版本号一般为常数 1 。e_entry表示程序入口点虚拟地址。操作系统加载完程序后从这个地址开始执行进程的命令。可重定位文件一般没有入口地址则这个值为 0 。e_phoff表示程序头表的文件偏移量。e_shoff表示节表的文件偏移量。e_flags表示处理器特定标志。e_ehsize表示 ELF 文件头的大小。e_phentsize表示程序头表中每个表项的大小。e_phnum表示程序头表中表项的数量。e_shentsize表示节表中每个表项的大小。e_shnum表示节表中表项的数量。e_shstrndx表示节表中字符串表的索引。 程序头表 ELF 可执行文件中有一个专门的数据结构叫做程序头表Program Header Table用来保存段注意不是节的信息。因为 ELF 目标文件不需要被装载所以它没有程序头表而 ELF 的可执行文件和共享库文件都有程序头表。 程序头表是由 Elf*_Phdr 组成的数组用于描述 ELF 文件中每个节的属性和信息。 /* Program segment header. */typedef struct {Elf32_Word p_type; /* Segment type */Elf32_Off p_offset; /* Segment file offset */Elf32_Addr p_vaddr; /* Segment virtual address */Elf32_Addr p_paddr; /* Segment physical address */Elf32_Word p_filesz; /* Segment size in file */Elf32_Word p_memsz; /* Segment size in memory */Elf32_Word p_flags; /* Segment flags */Elf32_Word p_align; /* Segment alignment */ } Elf32_Phdr;p_type段的类型例如可执行段、数据段等。p_offset段在文件中的偏移量。p_vaddr段在虚拟内存中的起始地址。p_paddr段在物理内存中的起始地址。因为 ELF 还没装载不知道物理地址所以作为保留字段。通常和 p_vaddr 的值是一样的。p_filesz段在文件中的大小。p_memsz段在内存中的大小。p_flags段的标志例如可读、可写、可执行等。p_align段在文件和内存中的对齐方式。段的的加载地址要能被 2 p_align 2^{\text{p\_align}} 2p_align 整除。 节表 ELF文件里面定义一个固定长度的 Elf*_Shdr 结构体数组用来存放节相关信息与 PE 文件的节表相似。 在 ELF 文件中段Segment和节Section是两个不同的概念它们在文件结构中具有不同的作用和目的。 段Segment是一种逻辑上的组织单位它定义了可执行文件或共享库在内存中的一个连续区域。每个段都有自己的虚拟地址空间可以包含多个节。常见的段类型包括代码段.text数据段.data、.bss只读数据段.rodata等。段在加载和执行时被操作系统用来管理内存设置内存保护属性以及指定虚拟地址空间的起始地址和大小。 节Section是一种更细粒度的组织单位它包含了文件中的特定类型的数据或代码。每个节都有自己的名字、类型和内容。常见的节类型包括代码节.text数据节.data、.bss只读数据节.rodata符号表节.symtab字符串表节.strtab等。节不直接参与内存的加载和执行而是用于链接器Linker和调试器Debugger等工具对文件进行处理和分析。 通俗的讲在装载程序的时候为了节省内存会将 ELF 文件中属性相同的节Section合并成在一个段Segment加载到内存中。 段和节之间存在对应关系和映射关系 一个段可以包含多个节这些节的内容和属性都属于该段。段提供了对应于虚拟内存的逻辑映射而节则提供了对应于文件的逻辑映射。段的加载和执行涉及内存管理和地址映射而节则用于链接和调试过程中的符号解析、重定位等操作。 其中 Elf32_Shdr 定义如下 /* Section header. */typedef struct {Elf32_Word sh_name; /* Section name (string tbl index) */Elf32_Word sh_type; /* Section type */Elf32_Word sh_flags; /* Section flags */Elf32_Addr sh_addr; /* Section virtual addr at execution */Elf32_Off sh_offset; /* Section file offset */Elf32_Word sh_size; /* Section size in bytes */Elf32_Word sh_link; /* Link to another section */Elf32_Word sh_info; /* Additional section information */Elf32_Word sh_addralign; /* Section alignment */Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr;sh_name表示节的名称在字符串表中的索引。字符串表节存储了所有节的名称sh_name 指定了节的名称在字符串表中的位置。sh_type表示节的类型指定了节的用途和属性。常见的类型包括代码段SHT_PROGBITS(1)、数据段SHT_PROGBITS(1)、符号表SHT_SYMTAB(2)、字符串表SHT_STRTAB(3)等。sh_flags表示节的标志用于描述节的特性和属性。标志的具体含义取决于节的类型和上下文。sh_addr表示节的虚拟地址只在可执行文件中有意义。对于可执行文件sh_addr 指定了节在内存中的加载地址如果该节不可被加载则该值为 0 。sh_offset表示节在文件中的偏移量指定了节在文件中的位置。对于 bss 段来说该值没有意义。sh_size表示节的大小指定了节所占据的字节数。sh_link表示链接到的其他节的索引用于建立节之间的关联关系具体含义依赖于节的类型。sh_info附加信息具体含义依赖于节的类型。sh_addralign表示节的地址对齐要求指定了节在内存中的对齐方式。即 sh_addr 需要满足 sh_addr m o d 2 sh_addralign 0 \text{sh\_addr} \mod 2^{\text{sh\_addralign}} 0 sh_addrmod2sh_addralign0 。如果 sh_addralign 为 0 或 1 表示该段没有对齐要求。sh_entsize表示节中每个项的大小如果该字段为 0 说明节中不包含固定大小的项。 ELF 中常见的节如下 .text代码段Code Section用于存储程序的可执行指令。.rodata只读数据段Read-Only Data Section用于存储只读的常量数据例如字符串常量。.data数据段Data Section用于存储已初始化的全局变量和静态变量。.bss未初始化的数据段Block Started by Symbol用于存储未初始化的全局变量和静态变量。它不占用实际的文件空间而是在运行时由系统自动初始化为零。.symtab符号表节Symbol Table Section用于存储程序的符号表信息包括函数、变量和其他符号的名称、类型和地址等。.strtab字符串表节String Table Section用于存储字符串数据如节名称、符号名称等。字符串表节被多个其他节引用通过偏移量和索引来访问具体的字符串。.rel.text 或 .rela.text代码重定位节Relocation Section用于存储代码段中的重定位信息以便在链接时修正代码中的符号引用。.rel.data 或 .rela.data数据重定位节Relocation Section用于存储数据段中的重定位信息以便在链接时修正数据段中的符号引用。.dynamic动态节Dynamic Section用于存储程序的动态链接信息包括动态链接器需要的重定位表、共享对象的名称、版本信息等。.note注释节Note Section用于存储与程序或库相关的注释或调试信息。 静态链接相关 注意静态链接相关只在可重定位文件中存在。比如可执行文件如果不开启 PIE 加载地址固定不需要对自身进行重定位而开启 PIE 后为地址无关代码也不需要对自身进行重定位。因此不需要静态链接也就丢弃了静态链接相关的节。 符号表.symtab 注意符号表除了静态链接外没有用但是程序为了方便调试会保留符号表我们可以通过 strip 程序名 的方式将符号表去除这就是为什么有的 pwn 题的附件没有函数和变量名而有的却有。 ELF 文件中的符号表往往是文件中的一个段段名一般叫 .symtab 。符号表是一个 Elf*_Sym 结构32 位 ELF 文件的数组每个 Elf*_Sym 结构对应一个符号。 /* Symbol table entry. */typedef struct {Elf32_Word st_name; /* Symbol name (string tbl index) */Elf32_Addr st_value; /* Symbol value */Elf32_Word st_size; /* Symbol size */unsigned char st_info; /* Symbol type and binding */unsigned char st_other; /* Symbol visibility */Elf32_Section st_shndx; /* Section index */ } Elf32_Sym;st_name符号名称在字符串表中的偏移量。st_value符号的值即符号的地址或偏移量。 如果该符号在目标文件中如果是符号的定义并且该符号不是 COMMON 块类型的则 st_value 表示该符号在段中的偏移。在目标文件中如果符号是 COMMON 块类型的则 st_value 表示该符号的对齐属性。在可执行文件中st_value 表示符号的虚拟地址。 st_size符号的大小如果符号是一个函数则表示函数的大小。如果该值为 0 表示符号的大小为 0 或未知。st_info该字段是一个字节包含符号的类型和绑定信息。符号类型包括函数、数据、对象等符号绑定包括局部符号、全局符号、弱符号等。该字段的高 4 位表示符号的类型低 4 位表示符号的绑定信息。st_other保留字段通常为 0 。st_shndx通常为符号所在节的索引。 如果符号是一个常量该字段为 SHN_ABS初始值不为 0 的全局变量 或 SHN_COMMON初始值为 0 的全局变量。如果该符号未定义但是在该文件中被引用到说明该符号可能定义在其他目标文件中则该字段为 SHN_UNDEF 。 重定位表.rel.text/.rel.data 重定位表是一个 Elf*_Rel 结构的数组每个数组元素对应一个重定位入口。重定位表主要有.rel.text 或 .rela.text即代码重定位节Relocation Section和 .rel.data 或 .rela.data数据重定位节Relocation Section。 /* Relocation table entry without addend (in section of type SHT_REL). */typedef struct {Elf32_Addr r_offset; /* Address */Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel;r_offset需要进行重定位的位置的偏移量或地址。这个位置通常是指令中的某个操作数或数据的地址需要在链接时进行修正以便正确地引用目标符号。 对于可执行文件或共享库r_offset 表示需要修改的位置在内存中的位置用于动态链接。对于可重定位文件r_offset 表示需要修改的位置相对于段起始位置的偏移用于静态链接。 r_info低 8 位表示符号的重定位类型重定位类型指定了进行何种类型的修正例如绝对重定位、PC 相对重定位等。高 24 位表示该符号在符号表中的索引用于解析重定位所引用的符号。 字符串表.strtab ELF 文件中用到了很多字符串比如段名、变量名等。因为字符串的长度往往是不定的所以用固定的结构来表示它比较困难。一种很常见的做法是把字符串集中起来存放到一个表然后使用字符串在表中的偏移来引用字符串。 通过这种方法在ELF文件中引用字符串只须给出一个数字下标即可不用考虑字符串长度的问题。一般字符串表在ELF文件中也以段的形式保存常见的段名为“.strtab”或“.shstrtab”。这两个字符串表分别为字符串表String Table和段表字符串表Section Header String Table。顾名思义字符串表用来保存普通的字符串比如符号的名字段表字符串表用来保存段表中用到的字符串最常见的就是段名sh_name 。 注意在字符串表中的每个字符串的开头和结尾都有一个 \x00 填充。 动态链接相关 .interp 段 在动态链接的 ELF 可执行文件中有一个专门的段叫做 .interp 段“interp”是“interpreter”解释器的缩写。 .interp 的内容很简单里面保存的就是一个字符串 /lib64/ld-linux-x86-64.so.2 这个字符串就是可执行文件所需要的动态链接器的路径。 通常系统通过判断一个 ELF 程序是否有 .interp 来判断该 ELF 文件是否为动态链接程序。 .dynamic 段 动态链接 ELF 中最重要的结构是 .dynamic 段这个段里面保存了动态链接器所需要的基本信息比如依赖于哪些共享对象、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。.dynamic 段是由Elf*_Dyn 构成的结构体数组。 /* Dynamic section entry. */typedef struct {Elf32_Sword d_tag; /* Dynamic entry type */union{Elf32_Word d_val; /* Integer value */Elf32_Addr d_ptr; /* Address value */} d_un; } Elf32_Dyn;Elf32_Dyn 结构由一个类型值加上一个附加的数值或指针对于不同的类型后面附加的数值或者指针有着不同的含义。我们这里列举几个比较常见的类型值这些值都是定义在 elf.h 里面的宏 DT_SYMTAB指定了符号表的地址d_ptr 表示 .dynsym 的地址。DT_STRTAB指定了字符串表的地址d_ptr 表示 .synstr 的地址。DT_STRSZ指定了字符串表的大小d_val 表示大小。DT_HASH指定了符号哈希表的地址用于加快符号查找的速度d_ptr 表示 .hash 的地址。DT_SONAME指定了共享库的名称。DT_RPATH指定了库搜索路径已废弃不推荐使用。DT_INIT指定了初始化函数的地址动态链接器在加载可执行文件或共享库时会调用该函数。DT_FINI指定了终止函数的地址动态链接器在程序结束时会调用该函数。DT_NEEDED指定了需要的共享库的名称。DT_REL/DT_RELA指定了重定位表的地址。 动态符号表.dynsym 为了完成动态链接最关键的还是所依赖的符号和相关文件的信息。我们知道在静态链接中有一个专门的段叫做符号表 .symtabSymbol Table里面保存了所有关于该目标文件的符号的定义和引用。为了表示动态链接这些模块之间的符号导入导出关系ELF 专门有一个叫做动态符号表Dynamic Symbol Table的段用来保存这些信息这个段的段名通常叫做 .dynsymDynamic Symbol同样也是由 Elf*_Sym 构成的结构体数组。 与 .symtab 不同的是.dynsym 只保存了与动态链接相关的符号对于那些模块内部的符号比如模块私有变量则不保存。很多时候动态链接的模块同时拥有 .dynsym 和 .symtab 两个表.symtab 中往往保存了所有符号包括 .dynsym 中的符号。 与 .symtab 类似动态符号表也需要一些辅助的表比如用于保存符号名的字符串表。静态链接时叫做符号字符串表 .strtabString Table在这里就是动态符号字符串表 .dynstrDynamic String Table由于动态链接下我们需要在程序运行时查找符号为了加快符号的查找过程往往还有辅助的符号哈希表.hash。 动态链接重定位表.rel.dyn/.rel.data 共享对象需要重定位的主要原因是导入符号的存在。动态链接下无论是可执行文件或共享对象一旦它依赖于其他共享对象也就是说有导入的符号时那么它的代码或数据中就会有对于导入符号的引用。在编译时这些导入符号的地址未知在静态链接中这些未知的地址引用在最终链接时被修正。但是在动态链接中导入符号的地址在运行时才确定所以需要在运行时将这些导入符号的引用修正即需要重定位。 共享对象的重定位与我们在前面“静态链接”中分析过的目标文件的重定位十分类似唯一有区别的是目标文件的重定位是在静态链接时完成的而共享对象的重定位是在装载时完成的。在静态链接中目标文件里面包含有专门用于表示重定位信息的重定位表比如 .rel.text 表示是代码段的重定位表.rel.data 是数据段的重定位表。 动态链接的文件中也有类似的重定位表分别叫做 .rel.dyn 和 .rel.plt 它们分别相当于 .rel.data 和 .rel.text 。.rel.dyn 实际上是对数据引用的修正它所修正的位置位于 .got 以及数据段而 .rel.plt 是对函数引用的修正它所修正的位置位于 .got.plt 。 PLT 表.plt 在未开启 FULL RELRO 的情况下 PLT 表的结构如下图所示 PLT 表在 .plt 中。 PLT 表的形式如下所示 PLT0: push *(GOT8) jmp *(GOT16) ⋮ barPLT: jmp *(barGOT) push n jmp PLT0 \begin{align*} \text{PLT0:} \\ \qquad \text{push *(GOT8)} \\ \qquad \text{jmp *(GOT16)} \\ \qquad \vdots \\ \text{barPLT:} \\ \qquad \text{jmp *(barGOT)} \\ \qquad \text{push n} \\ \qquad \text{jmp PLT0} \\ \end{align*} ​PLT0:push *(GOT8)jmp *(GOT16)⋮barPLT:jmp *(barGOT)push njmp PLT0​ 其中 n n n 为函数 bar 在 GOT 表中的值的索引barGOT 中初始值为 jmp *(barGOT) 指令的下一条指令也就是说第一次调用 bar 函数的时候会继续执行跳转至 PLT0 进行 barGOT 的重定位并调用 bar 函数第二次调用 bar 函数的时候由于 barGOT 已完成重定位因此会直接跳转至 bar 函数。 在开启 FULL RELRO 的情况下 PLT 表的结构如下图所示此时的 PLT 表在 .plt.sec 而不是 .plt 中。 由于 GOT 表在装载时已经完成重定位且不可写因此不存在延迟绑定PLT 直接根据 GOT 表存储的函数地址进行跳转。 GOT 表.got/.got.plt ELF 将 GOT 拆分成了两个表叫做 .got 和 .got.plt 。其中 .got 用来保存全局变量引用的地址.got.plt 用来保存函数引用的地址也就是说所有对于外部函数的引用全部被分离出来放到了 .got.plt 中。另外 .got.plt 还有一个特殊的地方是它的前三项是有特殊意义的分别含义如下 第一项保存的是 .dynamic 段的偏移。第二项是一个 link_map 的结构体指针里面保存着动态链接的一些相关信息是重定位函数 _dl_runtime_resolve 的第一个参数。第三项保存的是 _dl_runtime_resolve 的地址。 .got.plt 在内存中的状态如下图所示 辅助信息数组 站在动态链接器的角度看当操作系统把控制权交给它的时候它将开始做链接工作那么至少它需要知道关于可执行文件和本进程的一些信息比如可执行文件有几个段“Segment”、每个段的属性、程序的入口地址因为动态链接器到时候需要把控制权交给可执行文件等。 这些信息往往由操作系统传递给动态链接器保存在进程的堆栈里面。我们在前面提到过进程初始化的时候事实上堆栈里面还保存了动态链接器所需要的一些辅助信息数组Auxiliary Vector。辅助信息的格式也是一个结构数组它的结构被定义在 elf.h typedef struct {uint32_t a_type; /* Entry type */union{uint32_t a_val; /* Integer value *//* We use to have pointer elements added here. We cannot do that,though, since it does not work when using 32-bit definitionson 64-bit platforms and vice versa. */} a_un; } Elf32_auxv_t;a_type 字段表示辅助信息数组的类型。下面是一些常见的 a_type 值及其对应的含义 AT_NULL (0)辅助向量列表的结束标志。在列表的最后一个条目中使用。AT_IGNORE (1)忽略的辅助向量类型。在某些情况下可以将该类型的辅助向量忽略。AT_EXECFD (2)可执行文件的文件描述符。表示打开可执行文件的文件描述符。AT_PHDR (3)程序头表的地址。指向程序头表在内存中的起始地址。AT_PHENT (4)程序头表中每个条目的大小字节。指示每个程序头表条目的字节数。AT_PHNUM (5)程序头表的条目数量。指示程序头表中的条目数量。AT_PAGESZ (6)页面大小。表示操作系统使用的页面大小。AT_BASE (7)共享对象的基地址。指向主共享对象的基地址。AT_FLAGS (8)标志位。包含一些特定于操作系统的标志。AT_ENTRY (9)程序入口点的地址。指向程序的入口点地址。AT_NOTELF (10)不是ELF文件。指示加载程序的文件不是有效的ELF文件。 a_un该成员是一个联合体union用于存储辅助向量条目的值。在这段代码中由于指针类型的元素会在 32 位和 64 位平台上产生兼容性问题所以注释中提到不再添加指针元素。 a_val如果辅助向量条目的类型是一个整数值那么该成员将存储该整数值。它也是一个 32 位的无符号整数。 程序编译过程 从源文件编译链接形成 ELF 文件的过程如下图所示 预编译 首先是源代码文件和相关的头文件如 stdio.h 等被预编译器 cpp 预编译成一个 .i 文件。对于 C 程序来说它的源代码文件的扩展名可能是 .cpp 或 .cxx 头文件的扩展名可能是 .hpp 而预编译后的文件扩展名是 .ii 。 第一步预编译的过程相当于如下命令-E 表示只进行预编译 gcc –E hello.c –o hello.i或者 cpp hello.c hello.i预编译过程主要处理那些源代码文件中的以 # 开始的预编译指令。比如 #include 、#define 等主要处理规则如下 将所有的 #define 删除并且展开所有的宏定义。处理所有条件预编译指令比如 #if 、#ifdef 、#elif 、#else 、#endif 。处理 #include 预编译指令将被包含的文件插入到该预编译指令的位置。注意这个过程是递归进行的也就是说被包含的文件可能还包含其他文件。删除所有的注释 // 和 /* */ 。添加行号和文件名标识比如 #2hello.c2 以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。保留所有的 #pragma 编译器指令因为编译器须要使用它们。 经过预编译后的 .i 文件不包含任何宏定义因为所有的宏已经被展开并且包含的文件也已经被插入到 .i 文件中。所以当我们无法判断宏定义是否正确或头文件包含是否正确时可以查看预编译后的文件来确定问题。 编译 编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件这个过程往往是我们所说的整个程序构建的核心部分也是最复杂的部分之一。 上面的编译过程相当于如下命令 gcc –S hello.i –o hello.s汇编 汇编器是将汇编代码转变成机器可以执行的指令每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单它没有复杂的语法也没有语义也不需要做指令优化只是根据汇编指令和机器指令的对照表一一翻译就可以了“汇编”这个名字也来源于此。 上面的汇编过程我们可以调用汇编器 as 来完成 as hello.s –o hello.o或者使用 gcc 命令从 C 源代码文件开始经过预编译、编译和汇编直接输出目标文件Object File gcc –c hello.c –o hello.o链接 静态链接 静态链接是在编译过程的最后阶段将多个目标文件如 .o 文件以及所需的库文件合并在一起生成最终的可执行文件或共享库的过程。 可以使用如下命令将 a.o 和 b.o 链接为目标文件 ab 。 ld a.o b.o -o ab合并代码和数据段Code and Data Segment Merging 链接器将多个目标文件中的代码段和数据段合并成一个更大的代码段和数据段。这样所有的目标文件中的代码和数据都会被整合到最终的可执行文件或静态库中。 符号解析Symbol Resolution 链接器负通过重定位表解析目标文件中的符号引用。每个目标文件都包含对其他目标文件或库中定义的符号的引用例如函数、变量等。链接器会检查这些引用并确定对应的定义位置。 对于可重定位的 ELF 文件来说它必须包含有重定位表用来描述如何修改相应的段里的内容。对于每个要被重定位的 ELF 段都有一个对应的重定位表而一个重定位表往往就是 ELF 文件中的一个段所以其实重定位表也可以叫重定位段。 比如代码段 .text 如有要被重定位的地方那么会有一个相对应叫 .rel.text 的段保存了代码段的重定位表如果代码段 .data 有要被重定位的地方就会有一个相对应叫 .rel.data 的段保存了数据段的重定位表。 链接器通过 Elf32_Rel 的 r_offset 加上所在段的起始位置得到重定位入口的位置通过 r_info 的低 8 为得知重定位类型通过 r_info 的高 24 位得到重定位符号在符号表.symtab中的下标。 符号重定位Symbol Relocation 链接器通过符号表对应的 Elf32_Rel 的 st_value 表示该符号在段中的偏移进而可以根据重定位类型计算出重定位入口所要修正的值。最后将对应的重定位入口 patch 成正确的值。32 位静态链接常用到的重定位类型如下 R_386_32绝对地址。R_386_PC32相对于当前指令地址的下一条指令相对地址。 解析库依赖关系Library Dependency Resolution 如果目标文件依赖于外部库文件如标准库或其他第三方库链接器会解析这些库的依赖关系并将所需的库文件链接到最终的可执行文件或静态库中。这样在运行时可执行文件或静态库就能够访问和使用这些库中提供的功能。 生成重定位表Relocation Table 链接器生成重定位表记录了需要进行符号重定位的位置和相关信息。这些重定位表将在最终的可执行文件或静态库中被使用以便在加载和执行时进行正确的符号重定位。 动态链接 动态链接Dynamic Linking本质是指把链接这个过程推迟到了运行时再进行准确的说这个过程应该放在装载部分。不过动态链接的出现很大一部分原因是为了解决内存浪费问题因此直接照搬静态链接的方式不合理需要做一些改变。 另外我们称一个程序为动态链接程序或静态链接程序指的是该程序是否有动态链接过程。 注意动态链接不包括合并代码和数据段的过程各个模块在内存中独立存在。 装载时重定位 由于需要将多个模块装载到内存中因此动态链接难免会有地址冲突问题这就需要我们在加载的时候将模块中的相关地址修改为正确的值这就是装载时重定位。 Linux和GCC支持这种装载时重定位的方法在产生共享对象时使用了两个GCC参数 -shared 和 -fPIC 如果只使用 -shared 那么输出的共享对象就是使用装载时重定位的方法。 地址无关代码 如果采用装载时重定位的方法虽然能够做到任意地址装载但存在弊端。比如模块装载到不同位置会导致模块的代码段内容发生改变无法实现共享库的复用造成内存浪费每次装载重定位会影响性能等。 地址无关代码的出现很好的解决了装载时重定位的缺点。地址无关代码的基本想法就是把指令中那些需要被修改的部分分离出来跟数据部分放在一起这样指令部分就可以保持不变而数据部分可以在每个进程中拥有一个副本。这种方案就是目前被称为地址无关代码PIC,Position-independent Code的技术。这也就是 GCC 的 -fPIC 编译参数。 模块中各种类型的地址引用方式有以下 4 种 模块内部的函数调用、跳转等。模块内部的数据访问比如模块中定义的全局变量、静态变量。模块外部的函数调用、跳转等。模块外部的数据访问比如其他模块中定义的全局变量。 对于前两种引用方式由于是在模块内部相对地址偏移固定因此可以通过 [rip xxx] 注意这里的 rip 是当前指令的下一条指令的地址下一条指令指的是地址相邻的下一条指令的方式进行引用从而做到地址无关。因此关键在于后两种怎么解决。 模块间的访问比模块内部稍微麻烦一点因为模块间的数据访问目标地址要等到装载时才决定我们前面提到要使得代码地址无关基本的思想就是把跟地址相关的部分放到数据段里面很明显这些其他模块的全局变量的地址是跟模块装载地址有关的。ELF 的做法是在数据段里面建立一个指向这些变量的指针数组也被称为全局偏移表Global Offset TableGOT当代码需要引用该全局变量时可以通过 GOT 中相对应的项间接引用。 前面模块内部的解决方法实际上并不严谨比如一些全局变量以及函数声明没有初始化会被认为是若弱符号这些弱符号编译器并不知道是否只在本模块定义因此不能仅使用 [rip xxx] 的方式访问。 针对这种情况的解决办法是所有的使用这个变量的指令都指向位于可执行文件中的那个副本。ELF 共享库在编译时默认都把定义在模块内部的全局变量当作定义在其他模块的全局变量也就是说当作前面的类型四通过 GOT 来实现变量的访问。当共享模块被装载时如果某个全局变量在可执行文件中拥有副本那么动态链接器就会把 GOT 中的相应地址指向该副本这样该变量在运行时实际上最终就只有一个实例。如果变量在共享模块中被初始化那么动态链接器还需要将该初始化值复制到程序主模块中的变量副本如果该全局变量在程序主模块中没有副本那么 GOT 中的相应地址就指向共享模块内部的该变量副本。这就是为什么 libc 的 GOT 表中会有自身函数。 地址无关代码虽然解决了模块复用的问题但是本质还是装载时重定位因此没有解决性能问题实际上 ELF 采用了延迟绑定的方法来解决这一问题。 地址无关代码技术除了可以用在共享对象上面它也可以用于可执行文件一个以地址无关方式编译的可执行文件被称作地址无关可执行文件PIE, Position-Independent Executable。与 GCC 的 -fPIC 和 -fpic 参数类似产生 PIE 的参数为 -fPIE 或 -fpie 。 延迟绑定 在动态链接下程序模块之间包含了大量的函数引用全局变量往往比较少因为大量的全局变量会导致模块之间耦合度变大所以在程序开始执行前动态链接会耗费不少时间用于解决模块之间的函数引用的符号查找以及重定位这不过可以想象在一个程序运行过程中可能很多函数在程序执行完时都不会被用到比如一些错误处理函数或者是一些用户很少用到的功能模块等如果一开始就把所有函数都链接好实际上是一种浪费。所以 ELF 采用了一种叫做延迟绑定Lazy Binding的做法基本的思想就是当函数第一次被用到时才进行绑定符号查找、重定位等如果没有用到则不进行绑定。所以程序开始执行时模块间的函数调用都没有进行绑定而是需要用到时才由动态链接器来负责绑定。这样的做法可以大大加快程序的启动速度特别有利于一些有大量函数引用和大量模块的程序。 注意延迟绑定一般只出先在未开启 FULL RELRO 的时候如果开启 FULL RELRO 则 got 表不可写程序在装载时完成 got 表的重定位。当然特殊情况也有在开启 FULL RELRO 的时候进行重定位比如 ret2dlresolve 。 我们以调用 puts 函数为例讲解一下延迟绑定的过程。 首先第一次调用 puts 时由于 putsgot 没有进行重定位因此会调用 _dl_runtime_resolve 函数进行重定位_dl_runtime_resolve 函数将查找到的 puts 函数地址填写到 putsgot 后会调用 puts 函数。 再次调用 puts 函数时由于 putsgot 已经完成重定位因此会直接调用 puts 函数。 其中在第一次调用 puts 函数时调用的 _dl_runtime_resolve 函数的具体实现为 用第一个参数 link_map 访问 .dynamic 取出 .dynstr .dynsym .rel.plt 的指针。.rel.plt 第二个参数 求出当前函数的重定位表项 Elf32_Rel 的指针记作 rel 。rel-r_info 8 作为 .dynsym 的下标求出当前函数的符号表项 Elf32_Sym 的指针记作 sym 。.dynstr sym-st_name 得出符号名字符串指针。在动态链接库查找这个函数的地址并且把地址赋值给 *rel-r_offset 即 GOT 表。调用这个函数。 动态链接的步骤和实现 动态链接器自举 由于动态链接器本身的作用是重定位因此自身的重定位也需要自身来完成完成自身重定位的过程成为自举Bootstrap。 动态链接器入口地址即是自举代码的入口当操作系统将进程控制权交给动态链接器时动态链接器的自举代码即开始执行。自举代码首先会找到它自己的 GOT 。而 GOT 的第一个入口保存的即是 .dynamic 段的偏移地址由此找到了动态连接器本身的“.dynamic”段。通过 .dynamic 中的信息自举代码便可以获得动态链接器本身的重定位表和符号表等从而得到动态链接器本身的重定位入口先将它们全部重定位。 从这一步开始动态链接器代码中才可以开始使用自己的全局变量和静态变量。 装载共享对象 完成基本自举以后动态链接器将可执行文件和链接器本身的符号表都合并到一个符号表当中我们可以称它为全局符号表Global Symbol Table。然后链接器开始寻找可执行文件所依赖的共享对象我们前面提到过 .dynamic 段中有一种类型的入口是 DT_NEEDED 它所指出的是该可执行文件或共享对象所依赖的共享对象。由此链接器可以列出可执行文件所需要的所有共享对象并将这些共享对象的名字放入到一个装载集合中。然后链接器开始从集合里取一个所需要的共享对象的名字找到相应的文件后打开该文件读取相应的 ELF 文件头和 .dynamic 段然后将它相应的代码段和数据段映射到进程空间中。 如果这个 ELF 共享对象还依赖于其他共享对象那么将所依赖的共享对象的名字放到装载集合中。如此循环直到所有依赖的共享对象都被装载进来为止当然链接器可以有不同的装载顺序如果我们把依赖关系看作一个图的话那么这个装载过程就是一个图的遍历过程链接器可能会使用深度优先或者广度优先或者其他的顺序来遍历整个图这取决于链接器比较常见的算法一般都是广度优先的。 当一个新的共享对象被装载进来的时候它的符号表会被合并到全局符号表中所以当所有的共享对象都被装载进来的时候全局符号表里面将包含进程中所有的动态链接所需要的符号。 重定位和初始化 当上面的步骤完成之后链接器开始重新遍历可执行文件和每个共享对象的重定位表将它们的 GOT/PLT 中的每个需要重定位的位置进行修正。因为此时动态链接器已经拥有了进程的全局符号表所以这个修正过程也显得比较容易跟我们前面提到的地址重定位的原理基本相同。 动态链接重定位除了前面静态链接重定位类型外还有如下重定位类型 R_386_RELATIVE针对下面这种代码的重定位由于加载地址不确定需要加载后的才能确定。static int a; static int* p a;R_386_GLOB_DAT位于 got.plt 的重定位入口只需要填入正确变量地址即可。R_386_JUMP_SLOT位于 got.plt 的重定位入口只需要填入正确的函数地址即可。 重定位完成之后如果某个共享对象有 .init 段那么动态链接器会执行 .init 段中的代码用以实现共享对象特有的初始化过程比如最常见的共享对象中的 C 的全局/静态对象的构造就需要通过 .init 来初始化。相应地共享对象中还可能有 .finit 段当进程退出时会执行 .finit 段中的代码可以用来实现类似 C 全局对象析构之类的操作。 如果进程的可执行文件也有 .init 段那么动态链接器不会执行它因为可执行文件中的 .init 段和 .finit 段由程序初始化部分代码负责执行。当完成了重定位和初始化之后所有的准备工作就宣告完成了所需要的共享对象也都已经装载并且链接完成了这时候动态链接器就如释重负将进程的控制权转交给程序的入口并且开始执行。 装载 Linux 内核装载 ELF 过程 首先在用户层面bash 进程会调用 fork() 系统调用创建一个新的进程然后新的进程调用 execve() 系统调用执行指定的 ELF 文件原先的 bash 进程继续返回等待刚才启动的新进程结束然后继续等待用户输入命令。 execve() 系统调用被定义在 unistd.h 它的原型如下 /* Replace the current process, executing PATH with arguments ARGV andenvironment ENVP. ARGV and ENVP are terminated by NULL pointers. */ int execve (const char *__path, char *const __argv[], char *const __envp[]);它的三个参数分别是被执行的程序文件名、执行参数和环境变量。 Glibc 对 execvp() 系统调用进行了包装提供了 execl() 、execlp() 、execle() 、execv() 和 execvp() 等5个不同形式的 exec 系列 API 它们只是在调用的参数形式上有所区别但最终都会调用到 execve() 这个系统调用。下面是一个简单的使用 fork() 和 execlp() 实现的 minibash #include stdio.h #include stdlib.h #include string.h #include unistd.h #include sys/wait.h #include stdbool.h#define MAX_COMMAND_LENGTH 1024int main() {char command[MAX_COMMAND_LENGTH];while (true) {printf(minibash$ );fgets(command, sizeof(command), stdin);// 删除换行符command[strcspn(command, \n)] \0;// 检查是否输入了退出命令if (strcmp(command, exit) 0) {break;}if (strlen(command) 0) {continue;}pid_t pid fork();if (pid 0) {// 子进程执行命令if (execlp(command, command, NULL) 0) {perror(minibash);exit(1);}} else if (pid 0) {// 父进程等待子进程结束int status;waitpid(pid, status, 0);} else {// fork失败printf(fork error\n);exit(1);}}return 0; }在进入 execve() 系统调用之后Linux 内核就开始进行真正的装载工作。在内核中 execve() 系统调用相应的入口是 sys_execve() 它被定义在 arch\i386\kernel\Process.c 。sys_execve() 进行一些参数的检查复制之后调用 do_execve() 。do_execve() 会首先查找被执行的文件如果找到文件则 do_execve() 读取文件的前128个字节判断文件的格式每种可执行文件的格式的开头几个字节都是很特殊的特别是开头4个字节常常被称做魔数Magic Number通过对魔数的判断可以确定文件的格式和类型。比如 ELF 的可执行文件格式的头 4 个字节为 \x7felf 而 Java 的可执行文件格式的头4个字节为 cafe 如果被执行的是 Shell 脚本或 perl 、python 等这种解释型语言的脚本那么它的第一行往往是 #!/bin/sh 或 #!/usr/bin/perl 或 #!/usr/bin/python 这时候前两个字节 # 和 ! 就构成了魔数系统一旦判断到这两个字节就对后面的字符串进行解析以确定具体的解释程序的路径。 当 do_execve() 读取了这 128 个字节的文件头部之后然后调用 search_binary_handle() 去搜索和匹配合适的可执行文件装载处理过程。Linux中所有被支持的可执行文件格式都有相应的装载处理过程 search_binary_handle() 会通过判断文件头部的魔数确定文件的格式并且调用相应的装载处理过程。比如 ELF 可执行文件的装载处理过程叫做 load_elf_binary() a.out 可执行文件的装载处理过程叫做 load_aout_binary()而装载可执行脚本程序的处理过程叫做 load_script() 。 这里我们只关心 ELF 可执行文件的装载 load_elf_binary() 被定义在 fs/Binfmt_elf.c 这个函数的代码比较长它的主要步骤是 检查ELF可执行文件格式的有效性比如魔数、程序头表中段Segment的数量。寻找动态链接的 .interp 段设置动态链接器路径。根据 ELF 可执行文件的程序头表的描述对 ELF 文件进行映射比如代码、数据、只读数据。初始化 ELF 进程环境比如进程启动时 EDX 寄存器的地址应该是 DT_FINI 的地址参照动态链接。将系统调用的返回地址修改成 ELF 可执行文件的入口点这个入口点取决于程序的链接方式对于静态链接的 ELF 可执行文件这个程序入口就是 ELF 文件的文件头中 e_entry 所指的地址对于动态链接的 ELF 可执行文件程序入口点是动态链接器。 当 load_elf_binary() 执行完毕返回至 do_execve() 再返回至 sys_execve() 时上面的第 5 步中已经把系统调用的返回地址改成了被装载的 ELF 程序的入口地址了。所以当 sys_execve() 系统调用从内核态返回到用户态时EIP 寄存器直接跳转到了 ELF 程序的入口地址于是新的程序开始执行ELF 可执行文件装载完成。 进程虚拟地址空间 在现代操作系统中每个进程都有自己的虚拟地址空间这是一个抽象的地址空间由连续的虚拟地址组成。每个进程在其虚拟地址空间中运行不会直接访问物理内存地址。 操作系统将每个进程的虚拟地址空间划分为多个区域例如代码段、数据段、堆和栈等。每个区域具有特定的用途和权限。 代码段包含可执行程序的机器指令。数据段包含静态和全局变量的初始值。BSS 段包含需要初始化为零的静态和全局变量。动态链接段包含动态链接所需的信息。 加载器将这些段从 ELF 文件中复制到相应的虚拟内存地址并建立虚拟地址与物理内存地址的映射关系。 运行 进程栈的初始化 我们知道进程刚开始启动的时候须知道一些进程运行的环境最基本的就是系统环境变量和进程的运行参数。很常见的一种做法是操作系统在进程启动前将这些信息提前保存到进程的虚拟空间的栈中。 假设我们运行如下命令即运行 ls 程序传入的参数为 /home 。 ls /home在程序初始状态的栈如下图所示。 栈顶寄存器 rsp 指向的位置是初始化以后堆栈的顶部最前面的 8 个字节表示命令行参数的数量我们的例子里面是两个即 /usr/bin/ls 和 /home 紧接的就是分布指向这两个参数字符串的指针后面跟了一个0接着是一个以 0 结尾的指向环境变量字符串的指针数组。 进程在启动以后程序的库部分会把堆栈里的初始化信息中的参数信息传递给 main() 函数也就是我们熟知的 main() 函数的两个 argc 和 argv 两个参数这两个参数分别对应这里的命令行参数数量和命令行参数字符串指针数组。 main 函数之外的代码 共享库 共享库版本 符号版本 共享库版本命名 Linux有一套规则来命名系统中的每一个共享库它规定共享库的文件名规则必须如下 libname.so.x.y.z最前面使用前缀 lib 、中间是库的名字和后缀 .so 最后面跟着的是三个数字组成的版本号。x 表示主版本号Major Version Numbery 表示次版本号Minor Version Numberz 表示发布版本号Release Version Number。三个版本号的含义不一样。 主版本号表示库的重大升级不同主版本号的库之间是不兼容的依赖于旧的主版本号的程序需要改动相应的部分并且重新编译才可以在新版的共享库中运行或者系统必须保留旧版的共享库使得那些依赖于旧版共享库的程序能够正常运行。次版本号表示库的增量升级即增加一些新的接口符号且保持原来的符号不变。在主版本号相同的情况下高的次版本号的库向后兼容低的次版本号的库。发布版本号表示库的一些错误的修正、性能的改进等并不添加任何新的接口也不对接口进行更改。相同主版本号、次版本号的共享库不同的发布版本号之间完全兼容依赖于某个发布版本号的程序可以在任何一个其他发布版本号中正常运行而无须做任何修改。 SO-NAME 系统普遍采用一种叫做 SO-NAME 的命名机制来记录共享库的依赖关系。每个共享库都有一个对应的 SO-NAME 这个 SO-NAME 即共享库的文件名去掉次版本号和发布版本号保留主版本号。比如一个共享库叫做 libfoo.so.2.6.1 那么它的 SO-NAME 即 libfoo.so.2 。很明显SO-NAME 规定了共享库的接口SO-NAME 的两个相同共享库次版本号大的兼容次版本号小的。在 Linux 系统中系统会为每个共享库在它所在的目录创建一个跟 SO-NAME 相同的并且指向它的软链接Symbol Link。比如系统中有存在一个共享库 /lib/libfoo.so.2.6.1 那么 Linux 中的共享库管理程序就会为它产生一个软链接 /lib/libfoo.so.2 指向它。比如 Linux 系统的 Glibc 共享库注意稍高版本的 libc 的 libc.so.6 本身就是动态库不是符号链接 $ ls -l /lib/x86_64-linux-gnu/libc.so.6 lrwxrwxrwx 1 root root 12 Apr 7 2022 /lib/x86_64-linux-gnu/libc.so.6 - libc-2.31.so $ ls -l /lib/x86_64-linux-gnu/libc-2.31.so -rwxr-xr-x 1 root root 2029592 Apr 7 2022 /lib/x86_64-linux-gnu/libc-2.31.so由于历史原因动态链接器和 C 语言库的共享对象文件名规则不按 Linux 标准的共享库命名方法但是 C 语言的 SO-NAME 还是按照正常的规则。 另外动态连接器的 SO-NAME 命名不按照普通的规则。 $ ls -al /lib64/ld-linux-x86-64.so.2 lrwxrwxrwx 1 root root 32 Apr 7 2022 /lib64/ld-linux-x86-64.so.2 - /lib/x86_64-linux-gnu/ld-2.31.so建立以 SO-NAME 为名字的软链接目的是使得所有依赖某个共享库的模块在编译、链接和运行时都使用共享库的 SO-NAME 而不使用详细的版本号。 共享库系统路径 共享库查找过程 常见保护 checksec 可以查看程序开启了哪些保护。 ➜ ~ checksec /bin/ls [*] /bin/lsArch: amd64-64-littleRELRO: Full RELROStack: Canary foundNX: NX enabledPIE: PIE enabledFORTIFY: EnabledCanary canary 是一种防止缓冲区溢出攻击的保护机制。它的基本思想是在程序的堆栈中插入一个随机生成的数值作为哨兵用于检测缓冲区溢出攻击。 .text:0000000000001189 endbr64 .text:000000000000118D push rbp .text:000000000000118E mov rbp, rsp .text:0000000000001191 sub rsp, 30h .text:0000000000001195 mov rax, fs:28h .text:000000000000119E mov [rbp-8], rax ... .text:00000000000011CE mov rdx, [rbp-8] .text:00000000000011D2 xor rdx, fs:28h .text:00000000000011DB jz short locret_11E2 .text:00000000000011DB .text:00000000000011DD call ___stack_chk_fail .text:00000000000011DD .text:00000000000011E2 ; --------------------------------------------------------------------------- .text:00000000000011E2 .text:00000000000011E2 locret_11E2: ; CODE XREF: f52↑j .text:00000000000011E2 leave .text:00000000000011E3 retncanary 的初始值值存储在 tls 中。 在编译 c 程序时使用 -fno-stack-protector 参数可以关闭 canary 保护注意高版本的 gcc 的 canary 保护关不掉。 NX NX 即 No-eXecute不可执行NX 的基本原理是将数据所在内存页标识为不可执行也就是同一内存可写与可执行不共存。 gcc 编译器默认开启了 NX 选项如果需要关闭 NX 选项可以给 gcc 编译器添加 -zexecstack 参数。 PIE PIE 主要随机了代码段.text初始化数据段.data和未初始化数据段.bss的地址。另外 PIE 是否开启还会影响堆的基址。 开启 PIE 关闭 PIE 在编译 c 程序时使用 -no-pie 参数可以关闭 PIE 保护。 ASLR ASLR 是系统级别的地址随机。通过修改 /proc/sys/kernel/randomize_va_space 的值可以控制 ASLR 的级别 0关闭 ASLR1栈基址共享库mmap 基址随机2在 1 的基础上增加堆基址的随机 RELRO 当 RELRO 保护为 NO RELRO 的时候init.array 、fini.array 、got.plt 均可读可写。为 PARTIAL RELRO 的时候init.array 、fini.array 可读不可写got.plt 可读可写。为 FULL RELRO 时init.array 、fini.array 、got.plt 均可读不可写。 调用约定 栈结构 注意 canary 不一定与 ebp 相邻因为有些函数会先将一些寄存器保存到栈中。canary 实际位置以调试为准。 函数调用过程 32位为例 push args call func { push next_eip jmp func push ebp mov ebp,esp ⋮ leave { mov esp,ebp pop ebp ret (pop eip) \begin{align*} \text{push args}\\ \text{call func}\left\{\begin{matrix} \text{push next\_eip}\\ \text{jmp func} \end{matrix}\right.\\ \text{push ebp}\\ \text{mov ebp,esp}\\ \vdots \\ \text{leave}\left\{\begin{matrix} \text{mov esp,ebp}\\ \text{pop ebp} \end{matrix}\right.\\ \text{ret}\ \text{(pop eip)} \end{align*} ​push argscall func{push next_eipjmp func​push ebpmov ebp,esp⋮leave{mov esp,ebppop ebp​ret (pop eip)​ 函数参数传递 32位程序 普通函数传参参数基本都压在栈上有寄存器传参的情况可查阅相关资料。syscall传参eax对应系统调用号ebx、ecx、edx、esi、edi、ebp 分别对应前六个参数多余的参数压在栈上。 64位程序 普通函数传参先使用 rdi、rsi、rdx、rcx、r8、r9 寄存器作为函数参数的前六个参数多余的参数会依次压在栈上。syscall传参rax 对应系统调用号传参规则与普通函数传参一致。 系统调用号 32 位 #ifndef _ASM_X86_UNISTD_32_H #define _ASM_X86_UNISTD_32_H 1#define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 #define __NR_open 5 #define __NR_close 6 #define __NR_waitpid 7 #define __NR_creat 8 #define __NR_link 9 #define __NR_unlink 10 #define __NR_execve 11 #define __NR_chdir 12 #define __NR_time 13 #define __NR_mknod 14 #define __NR_chmod 15 #define __NR_lchown 16 #define __NR_break 17 #define __NR_oldstat 18 #define __NR_lseek 19 #define __NR_getpid 20 #define __NR_mount 21 #define __NR_umount 22 #define __NR_setuid 23 #define __NR_getuid 24 #define __NR_stime 25 #define __NR_ptrace 26 #define __NR_alarm 27 #define __NR_oldfstat 28 #define __NR_pause 29 #define __NR_utime 30 #define __NR_stty 31 #define __NR_gtty 32 #define __NR_access 33 #define __NR_nice 34 #define __NR_ftime 35 #define __NR_sync 36 #define __NR_kill 37 #define __NR_rename 38 #define __NR_mkdir 39 #define __NR_rmdir 40 #define __NR_dup 41 #define __NR_pipe 42 #define __NR_times 43 #define __NR_prof 44 #define __NR_brk 45 #define __NR_setgid 46 #define __NR_getgid 47 #define __NR_signal 48 #define __NR_geteuid 49 #define __NR_getegid 50 #define __NR_acct 51 #define __NR_umount2 52 #define __NR_lock 53 #define __NR_ioctl 54 #define __NR_fcntl 55 #define __NR_mpx 56 #define __NR_setpgid 57 #define __NR_ulimit 58 #define __NR_oldolduname 59 #define __NR_umask 60 #define __NR_chroot 61 #define __NR_ustat 62 #define __NR_dup2 63 #define __NR_getppid 64 #define __NR_getpgrp 65 #define __NR_setsid 66 #define __NR_sigaction 67 #define __NR_sgetmask 68 #define __NR_ssetmask 69 #define __NR_setreuid 70 #define __NR_setregid 71 #define __NR_sigsuspend 72 #define __NR_sigpending 73 #define __NR_sethostname 74 #define __NR_setrlimit 75 #define __NR_getrlimit 76 #define __NR_getrusage 77 #define __NR_gettimeofday 78 #define __NR_settimeofday 79 #define __NR_getgroups 80 #define __NR_setgroups 81 #define __NR_select 82 #define __NR_symlink 83 #define __NR_oldlstat 84 #define __NR_readlink 85 #define __NR_uselib 86 #define __NR_swapon 87 #define __NR_reboot 88 #define __NR_readdir 89 #define __NR_mmap 90 #define __NR_munmap 91 #define __NR_truncate 92 #define __NR_ftruncate 93 #define __NR_fchmod 94 #define __NR_fchown 95 #define __NR_getpriority 96 #define __NR_setpriority 97 #define __NR_profil 98 #define __NR_statfs 99 #define __NR_fstatfs 100 #define __NR_ioperm 101 #define __NR_socketcall 102 #define __NR_syslog 103 #define __NR_setitimer 104 #define __NR_getitimer 105 #define __NR_stat 106 #define __NR_lstat 107 #define __NR_fstat 108 #define __NR_olduname 109 #define __NR_iopl 110 #define __NR_vhangup 111 #define __NR_idle 112 #define __NR_vm86old 113 #define __NR_wait4 114 #define __NR_swapoff 115 #define __NR_sysinfo 116 #define __NR_ipc 117 #define __NR_fsync 118 #define __NR_sigreturn 119 #define __NR_clone 120 #define __NR_setdomainname 121 #define __NR_uname 122 #define __NR_modify_ldt 123 #define __NR_adjtimex 124 #define __NR_mprotect 125 #define __NR_sigprocmask 126 #define __NR_create_module 127 #define __NR_init_module 128 #define __NR_delete_module 129 #define __NR_get_kernel_syms 130 #define __NR_quotactl 131 #define __NR_getpgid 132 #define __NR_fchdir 133 #define __NR_bdflush 134 #define __NR_sysfs 135 #define __NR_personality 136 #define __NR_afs_syscall 137 #define __NR_setfsuid 138 #define __NR_setfsgid 139 #define __NR__llseek 140 #define __NR_getdents 141 #define __NR__newselect 142 #define __NR_flock 143 #define __NR_msync 144 #define __NR_readv 145 #define __NR_writev 146 #define __NR_getsid 147 #define __NR_fdatasync 148 #define __NR__sysctl 149 #define __NR_mlock 150 #define __NR_munlock 151 #define __NR_mlockall 152 #define __NR_munlockall 153 #define __NR_sched_setparam 154 #define __NR_sched_getparam 155 #define __NR_sched_setscheduler 156 #define __NR_sched_getscheduler 157 #define __NR_sched_yield 158 #define __NR_sched_get_priority_max 159 #define __NR_sched_get_priority_min 160 #define __NR_sched_rr_get_interval 161 #define __NR_nanosleep 162 #define __NR_mremap 163 #define __NR_setresuid 164 #define __NR_getresuid 165 #define __NR_vm86 166 #define __NR_query_module 167 #define __NR_poll 168 #define __NR_nfsservctl 169 #define __NR_setresgid 170 #define __NR_getresgid 171 #define __NR_prctl 172 #define __NR_rt_sigreturn 173 #define __NR_rt_sigaction 174 #define __NR_rt_sigprocmask 175 #define __NR_rt_sigpending 176 #define __NR_rt_sigtimedwait 177 #define __NR_rt_sigqueueinfo 178 #define __NR_rt_sigsuspend 179 #define __NR_pread64 180 #define __NR_pwrite64 181 #define __NR_chown 182 #define __NR_getcwd 183 #define __NR_capget 184 #define __NR_capset 185 #define __NR_sigaltstack 186 #define __NR_sendfile 187 #define __NR_getpmsg 188 #define __NR_putpmsg 189 #define __NR_vfork 190 #define __NR_ugetrlimit 191 #define __NR_mmap2 192 #define __NR_truncate64 193 #define __NR_ftruncate64 194 #define __NR_stat64 195 #define __NR_lstat64 196 #define __NR_fstat64 197 #define __NR_lchown32 198 #define __NR_getuid32 199 #define __NR_getgid32 200 #define __NR_geteuid32 201 #define __NR_getegid32 202 #define __NR_setreuid32 203 #define __NR_setregid32 204 #define __NR_getgroups32 205 #define __NR_setgroups32 206 #define __NR_fchown32 207 #define __NR_setresuid32 208 #define __NR_getresuid32 209 #define __NR_setresgid32 210 #define __NR_getresgid32 211 #define __NR_chown32 212 #define __NR_setuid32 213 #define __NR_setgid32 214 #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #define __NR_pivot_root 217 #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_getdents64 220 #define __NR_fcntl64 221 #define __NR_gettid 224 #define __NR_readahead 225 #define __NR_setxattr 226 #define __NR_lsetxattr 227 #define __NR_fsetxattr 228 #define __NR_getxattr 229 #define __NR_lgetxattr 230 #define __NR_fgetxattr 231 #define __NR_listxattr 232 #define __NR_llistxattr 233 #define __NR_flistxattr 234 #define __NR_removexattr 235 #define __NR_lremovexattr 236 #define __NR_fremovexattr 237 #define __NR_tkill 238 #define __NR_sendfile64 239 #define __NR_futex 240 #define __NR_sched_setaffinity 241 #define __NR_sched_getaffinity 242 #define __NR_set_thread_area 243 #define __NR_get_thread_area 244 #define __NR_io_setup 245 #define __NR_io_destroy 246 #define __NR_io_getevents 247 #define __NR_io_submit 248 #define __NR_io_cancel 249 #define __NR_fadvise64 250 #define __NR_exit_group 252 #define __NR_lookup_dcookie 253 #define __NR_epoll_create 254 #define __NR_epoll_ctl 255 #define __NR_epoll_wait 256 #define __NR_remap_file_pages 257 #define __NR_set_tid_address 258 #define __NR_timer_create 259 #define __NR_timer_settime 260 #define __NR_timer_gettime 261 #define __NR_timer_getoverrun 262 #define __NR_timer_delete 263 #define __NR_clock_settime 264 #define __NR_clock_gettime 265 #define __NR_clock_getres 266 #define __NR_clock_nanosleep 267 #define __NR_statfs64 268 #define __NR_fstatfs64 269 #define __NR_tgkill 270 #define __NR_utimes 271 #define __NR_fadvise64_64 272 #define __NR_vserver 273 #define __NR_mbind 274 #define __NR_get_mempolicy 275 #define __NR_set_mempolicy 276 #define __NR_mq_open 277 #define __NR_mq_unlink 278 #define __NR_mq_timedsend 279 #define __NR_mq_timedreceive 280 #define __NR_mq_notify 281 #define __NR_mq_getsetattr 282 #define __NR_kexec_load 283 #define __NR_waitid 284 #define __NR_add_key 286 #define __NR_request_key 287 #define __NR_keyctl 288 #define __NR_ioprio_set 289 #define __NR_ioprio_get 290 #define __NR_inotify_init 291 #define __NR_inotify_add_watch 292 #define __NR_inotify_rm_watch 293 #define __NR_migrate_pages 294 #define __NR_openat 295 #define __NR_mkdirat 296 #define __NR_mknodat 297 #define __NR_fchownat 298 #define __NR_futimesat 299 #define __NR_fstatat64 300 #define __NR_unlinkat 301 #define __NR_renameat 302 #define __NR_linkat 303 #define __NR_symlinkat 304 #define __NR_readlinkat 305 #define __NR_fchmodat 306 #define __NR_faccessat 307 #define __NR_pselect6 308 #define __NR_ppoll 309 #define __NR_unshare 310 #define __NR_set_robust_list 311 #define __NR_get_robust_list 312 #define __NR_splice 313 #define __NR_sync_file_range 314 #define __NR_tee 315 #define __NR_vmsplice 316 #define __NR_move_pages 317 #define __NR_getcpu 318 #define __NR_epoll_pwait 319 #define __NR_utimensat 320 #define __NR_signalfd 321 #define __NR_timerfd_create 322 #define __NR_eventfd 323 #define __NR_fallocate 324 #define __NR_timerfd_settime 325 #define __NR_timerfd_gettime 326 #define __NR_signalfd4 327 #define __NR_eventfd2 328 #define __NR_epoll_create1 329 #define __NR_dup3 330 #define __NR_pipe2 331 #define __NR_inotify_init1 332 #define __NR_preadv 333 #define __NR_pwritev 334 #define __NR_rt_tgsigqueueinfo 335 #define __NR_perf_event_open 336 #define __NR_recvmmsg 337 #define __NR_fanotify_init 338 #define __NR_fanotify_mark 339 #define __NR_prlimit64 340 #define __NR_name_to_handle_at 341 #define __NR_open_by_handle_at 342 #define __NR_clock_adjtime 343 #define __NR_syncfs 344 #define __NR_sendmmsg 345 #define __NR_setns 346 #define __NR_process_vm_readv 347 #define __NR_process_vm_writev 348 #define __NR_kcmp 349 #define __NR_finit_module 350 #define __NR_sched_setattr 351 #define __NR_sched_getattr 352 #define __NR_renameat2 353 #define __NR_seccomp 354 #define __NR_getrandom 355 #define __NR_memfd_create 356 #define __NR_bpf 357 #define __NR_execveat 358 #define __NR_socket 359 #define __NR_socketpair 360 #define __NR_bind 361 #define __NR_connect 362 #define __NR_listen 363 #define __NR_accept4 364 #define __NR_getsockopt 365 #define __NR_setsockopt 366 #define __NR_getsockname 367 #define __NR_getpeername 368 #define __NR_sendto 369 #define __NR_sendmsg 370 #define __NR_recvfrom 371 #define __NR_recvmsg 372 #define __NR_shutdown 373 #define __NR_userfaultfd 374 #define __NR_membarrier 375 #define __NR_mlock2 376 #define __NR_copy_file_range 377 #define __NR_preadv2 378 #define __NR_pwritev2 379#endif /* _ASM_X86_UNISTD_32_H */64 位 #ifndef _ASM_X86_UNISTD_64_H #define _ASM_X86_UNISTD_64_H 1#define __NR_read 0 #define __NR_write 1 #define __NR_open 2 #define __NR_close 3 #define __NR_stat 4 #define __NR_fstat 5 #define __NR_lstat 6 #define __NR_poll 7 #define __NR_lseek 8 #define __NR_mmap 9 #define __NR_mprotect 10 #define __NR_munmap 11 #define __NR_brk 12 #define __NR_rt_sigaction 13 #define __NR_rt_sigprocmask 14 #define __NR_rt_sigreturn 15 #define __NR_ioctl 16 #define __NR_pread64 17 #define __NR_pwrite64 18 #define __NR_readv 19 #define __NR_writev 20 #define __NR_access 21 #define __NR_pipe 22 #define __NR_select 23 #define __NR_sched_yield 24 #define __NR_mremap 25 #define __NR_msync 26 #define __NR_mincore 27 #define __NR_madvise 28 #define __NR_shmget 29 #define __NR_shmat 30 #define __NR_shmctl 31 #define __NR_dup 32 #define __NR_dup2 33 #define __NR_pause 34 #define __NR_nanosleep 35 #define __NR_getitimer 36 #define __NR_alarm 37 #define __NR_setitimer 38 #define __NR_getpid 39 #define __NR_sendfile 40 #define __NR_socket 41 #define __NR_connect 42 #define __NR_accept 43 #define __NR_sendto 44 #define __NR_recvfrom 45 #define __NR_sendmsg 46 #define __NR_recvmsg 47 #define __NR_shutdown 48 #define __NR_bind 49 #define __NR_listen 50 #define __NR_getsockname 51 #define __NR_getpeername 52 #define __NR_socketpair 53 #define __NR_setsockopt 54 #define __NR_getsockopt 55 #define __NR_clone 56 #define __NR_fork 57 #define __NR_vfork 58 #define __NR_execve 59 #define __NR_exit 60 #define __NR_wait4 61 #define __NR_kill 62 #define __NR_uname 63 #define __NR_semget 64 #define __NR_semop 65 #define __NR_semctl 66 #define __NR_shmdt 67 #define __NR_msgget 68 #define __NR_msgsnd 69 #define __NR_msgrcv 70 #define __NR_msgctl 71 #define __NR_fcntl 72 #define __NR_flock 73 #define __NR_fsync 74 #define __NR_fdatasync 75 #define __NR_truncate 76 #define __NR_ftruncate 77 #define __NR_getdents 78 #define __NR_getcwd 79 #define __NR_chdir 80 #define __NR_fchdir 81 #define __NR_rename 82 #define __NR_mkdir 83 #define __NR_rmdir 84 #define __NR_creat 85 #define __NR_link 86 #define __NR_unlink 87 #define __NR_symlink 88 #define __NR_readlink 89 #define __NR_chmod 90 #define __NR_fchmod 91 #define __NR_chown 92 #define __NR_fchown 93 #define __NR_lchown 94 #define __NR_umask 95 #define __NR_gettimeofday 96 #define __NR_getrlimit 97 #define __NR_getrusage 98 #define __NR_sysinfo 99 #define __NR_times 100 #define __NR_ptrace 101 #define __NR_getuid 102 #define __NR_syslog 103 #define __NR_getgid 104 #define __NR_setuid 105 #define __NR_setgid 106 #define __NR_geteuid 107 #define __NR_getegid 108 #define __NR_setpgid 109 #define __NR_getppid 110 #define __NR_getpgrp 111 #define __NR_setsid 112 #define __NR_setreuid 113 #define __NR_setregid 114 #define __NR_getgroups 115 #define __NR_setgroups 116 #define __NR_setresuid 117 #define __NR_getresuid 118 #define __NR_setresgid 119 #define __NR_getresgid 120 #define __NR_getpgid 121 #define __NR_setfsuid 122 #define __NR_setfsgid 123 #define __NR_getsid 124 #define __NR_capget 125 #define __NR_capset 126 #define __NR_rt_sigpending 127 #define __NR_rt_sigtimedwait 128 #define __NR_rt_sigqueueinfo 129 #define __NR_rt_sigsuspend 130 #define __NR_sigaltstack 131 #define __NR_utime 132 #define __NR_mknod 133 #define __NR_uselib 134 #define __NR_personality 135 #define __NR_ustat 136 #define __NR_statfs 137 #define __NR_fstatfs 138 #define __NR_sysfs 139 #define __NR_getpriority 140 #define __NR_setpriority 141 #define __NR_sched_setparam 142 #define __NR_sched_getparam 143 #define __NR_sched_setscheduler 144 #define __NR_sched_getscheduler 145 #define __NR_sched_get_priority_max 146 #define __NR_sched_get_priority_min 147 #define __NR_sched_rr_get_interval 148 #define __NR_mlock 149 #define __NR_munlock 150 #define __NR_mlockall 151 #define __NR_munlockall 152 #define __NR_vhangup 153 #define __NR_modify_ldt 154 #define __NR_pivot_root 155 #define __NR__sysctl 156 #define __NR_prctl 157 #define __NR_arch_prctl 158 #define __NR_adjtimex 159 #define __NR_setrlimit 160 #define __NR_chroot 161 #define __NR_sync 162 #define __NR_acct 163 #define __NR_settimeofday 164 #define __NR_mount 165 #define __NR_umount2 166 #define __NR_swapon 167 #define __NR_swapoff 168 #define __NR_reboot 169 #define __NR_sethostname 170 #define __NR_setdomainname 171 #define __NR_iopl 172 #define __NR_ioperm 173 #define __NR_create_module 174 #define __NR_init_module 175 #define __NR_delete_module 176 #define __NR_get_kernel_syms 177 #define __NR_query_module 178 #define __NR_quotactl 179 #define __NR_nfsservctl 180 #define __NR_getpmsg 181 #define __NR_putpmsg 182 #define __NR_afs_syscall 183 #define __NR_tuxcall 184 #define __NR_security 185 #define __NR_gettid 186 #define __NR_readahead 187 #define __NR_setxattr 188 #define __NR_lsetxattr 189 #define __NR_fsetxattr 190 #define __NR_getxattr 191 #define __NR_lgetxattr 192 #define __NR_fgetxattr 193 #define __NR_listxattr 194 #define __NR_llistxattr 195 #define __NR_flistxattr 196 #define __NR_removexattr 197 #define __NR_lremovexattr 198 #define __NR_fremovexattr 199 #define __NR_tkill 200 #define __NR_time 201 #define __NR_futex 202 #define __NR_sched_setaffinity 203 #define __NR_sched_getaffinity 204 #define __NR_set_thread_area 205 #define __NR_io_setup 206 #define __NR_io_destroy 207 #define __NR_io_getevents 208 #define __NR_io_submit 209 #define __NR_io_cancel 210 #define __NR_get_thread_area 211 #define __NR_lookup_dcookie 212 #define __NR_epoll_create 213 #define __NR_epoll_ctl_old 214 #define __NR_epoll_wait_old 215 #define __NR_remap_file_pages 216 #define __NR_getdents64 217 #define __NR_set_tid_address 218 #define __NR_restart_syscall 219 #define __NR_semtimedop 220 #define __NR_fadvise64 221 #define __NR_timer_create 222 #define __NR_timer_settime 223 #define __NR_timer_gettime 224 #define __NR_timer_getoverrun 225 #define __NR_timer_delete 226 #define __NR_clock_settime 227 #define __NR_clock_gettime 228 #define __NR_clock_getres 229 #define __NR_clock_nanosleep 230 #define __NR_exit_group 231 #define __NR_epoll_wait 232 #define __NR_epoll_ctl 233 #define __NR_tgkill 234 #define __NR_utimes 235 #define __NR_vserver 236 #define __NR_mbind 237 #define __NR_set_mempolicy 238 #define __NR_get_mempolicy 239 #define __NR_mq_open 240 #define __NR_mq_unlink 241 #define __NR_mq_timedsend 242 #define __NR_mq_timedreceive 243 #define __NR_mq_notify 244 #define __NR_mq_getsetattr 245 #define __NR_kexec_load 246 #define __NR_waitid 247 #define __NR_add_key 248 #define __NR_request_key 249 #define __NR_keyctl 250 #define __NR_ioprio_set 251 #define __NR_ioprio_get 252 #define __NR_inotify_init 253 #define __NR_inotify_add_watch 254 #define __NR_inotify_rm_watch 255 #define __NR_migrate_pages 256 #define __NR_openat 257 #define __NR_mkdirat 258 #define __NR_mknodat 259 #define __NR_fchownat 260 #define __NR_futimesat 261 #define __NR_newfstatat 262 #define __NR_unlinkat 263 #define __NR_renameat 264 #define __NR_linkat 265 #define __NR_symlinkat 266 #define __NR_readlinkat 267 #define __NR_fchmodat 268 #define __NR_faccessat 269 #define __NR_pselect6 270 #define __NR_ppoll 271 #define __NR_unshare 272 #define __NR_set_robust_list 273 #define __NR_get_robust_list 274 #define __NR_splice 275 #define __NR_tee 276 #define __NR_sync_file_range 277 #define __NR_vmsplice 278 #define __NR_move_pages 279 #define __NR_utimensat 280 #define __NR_epoll_pwait 281 #define __NR_signalfd 282 #define __NR_timerfd_create 283 #define __NR_eventfd 284 #define __NR_fallocate 285 #define __NR_timerfd_settime 286 #define __NR_timerfd_gettime 287 #define __NR_accept4 288 #define __NR_signalfd4 289 #define __NR_eventfd2 290 #define __NR_epoll_create1 291 #define __NR_dup3 292 #define __NR_pipe2 293 #define __NR_inotify_init1 294 #define __NR_preadv 295 #define __NR_pwritev 296 #define __NR_rt_tgsigqueueinfo 297 #define __NR_perf_event_open 298 #define __NR_recvmmsg 299 #define __NR_fanotify_init 300 #define __NR_fanotify_mark 301 #define __NR_prlimit64 302 #define __NR_name_to_handle_at 303 #define __NR_open_by_handle_at 304 #define __NR_clock_adjtime 305 #define __NR_syncfs 306 #define __NR_sendmmsg 307 #define __NR_setns 308 #define __NR_getcpu 309 #define __NR_process_vm_readv 310 #define __NR_process_vm_writev 311 #define __NR_kcmp 312 #define __NR_finit_module 313 #define __NR_sched_setattr 314 #define __NR_sched_getattr 315 #define __NR_renameat2 316 #define __NR_seccomp 317 #define __NR_getrandom 318 #define __NR_memfd_create 319 #define __NR_kexec_file_load 320 #define __NR_bpf 321 #define __NR_execveat 322 #define __NR_userfaultfd 323 #define __NR_membarrier 324 #define __NR_mlock2 325 #define __NR_copy_file_range 326 #define __NR_preadv2 327 #define __NR_pwritev2 328#endif /* _ASM_X86_UNISTD_64_H */
http://www.w-s-a.com/news/595642/

相关文章:

  • 自适应网站做mip改造浏览器广告投放
  • 网站meta网页描述网站的推广费用
  • 偃师市住房和城乡建设局网站网站个人主页怎么做
  • 做网站要实名认证吗wordpress去掉仪表盘
  • 在哪做网站好Python建网站的步骤
  • 卢松松的网站办公室设计布局
  • 住房城乡建设干部学院网站织梦网站0day漏洞
  • 企业网站seo优帮云手机桌面布局设计软件
  • 无证做音频网站违法吗智能建站加盟电话
  • 鹿泉专业网站建设做网站为什么要建站点
  • 加强网站建设和维护工作新闻大全
  • 红鱼洞水库建设管理局网站左右左布局网站建设
  • 手机网站建设地址做网站公
  • 贵州建设厅网站首页网络公司除了做网站
  • 运动鞋建设网站前的市场分析wordpress 搜索框代码
  • app开发网站开发教程平台网站开发的税率
  • 百度网站优化排名加强服务保障满足群众急需i
  • 宁夏建设职业技术学院网站安徽网站优化建设
  • 四川关于工程建设网站硬盘做网站空间
  • 桂林网站制作培训学校外包seo公司
  • 莱州网站建设方案北京装修公司口碑
  • 大型网站建设济南兴田德润团队怎么样韩国女足出线了吗
  • 南通做网站找谁重庆网络推广网站推广
  • ps网站主页按钮怎么做怎样做网站的用户分析
  • 哪个网站做黑色星期五订酒店活动公司网络营销推广软件
  • 岳阳新网网站建设有限公司网页设计基础考试题目
  • 辽宁响应式网站费用海外平台有哪些
  • 杨凌规划建设局网站网站后台建设怎么进入
  • 有赞商城网站建设企业管理咨询是做什么的
  • 提供衡水网站建设中国石化工程建设有限公司邮政编码