CTF权威指南 笔记 -第二章二进制文件- 2.2 -ELF文件格式

目录

ELF的文件类型

ELF文件的结构

 ELF文件头

 节头表

代码节

数据节和只读数据节

 bss节

字符串表

 符号表

重定位

可执行文件的装载

常见的段


ELF就是可执行可连接格式 为linux运行文件格式

ELF的文件类型

我们使用复杂的例子进行演示

#include<stdio.h>

int global_init_var = 10;
int global_uninit_var;
定义全局变量

void func(int sum){
    printf("%d\n",sum);
}
定义func函数

void main(void){
    static int local_static_init_var=20;
    static int local_static_uninit_var;
局部变量
只能在main函数中访问
    int local_init_val=30;
    int local_uninit_var;

    func(global_init_var + local_init_val + local_static_init_var);
打印这个的值    10+20+30
}

发现确实是60 

gcc elfDemo.c -o elfDemo.exce

这里把他编译成windows 的pe文件 exe文件类型

gcc -static elfDemo.c -o elfDEmo_static.exec

这里也是windows的但是是静态链接的


gcc -c elfDemo.c -o elfDemo.rel

这里编译成 rel文件  为 可重定位文件 这里就是之前的汇编阶段


gcc -c -fPIC elfDemo.c -o elfDemo_pic.rel && gcc -shared elfDemo_pic.rel -o elfdemo.dyn

这里把文件编译 为pic类型 位置独立代码 就是 代码可以是在不固定的虚拟内存区域 我们无法预测

同时前面成功的话编译一个 共享库的这个文件 名为 .dyn


&&是前面成功 才执行后面的
 这样可以实现代码函数的共享和重用

 这里可以发现 ELF文件 分为3类

可执行文件 exec :经过链接 可执行的目标文件  叫做程序

可重定位文件 : 预编译文件编译但没有实现链接的文件 .o结尾 通常是PIC类型 

共享目标文件 :动态链接库文件 用于在链接过程中和其他共享库进行链接 构建目标文件
或者在可执行文件运行的时候 链接到进程中 成为运行代码 的一部分

ELF文件的结构

在看目标文件的两个视角

链接视角 通过节进行划分

运行视角 通过段进行划分 

节和段 

节是一种逻辑的划分 一个程序中 具有很多节 可以是代码 调试信息等
段是一种物理的划分 一个段中 具有一组节 段又可以分为代码段 数据段等

这里section header tables 为节头表 用来保存节的信息 内容等

而我们例子的链接视角为

 ELF文件头

后面的所有是在汇编链接过程中得到的

文件头是在目标文件最开始的位置 包含着基本信息

ELF文件类型 版本 目标机器 程序入口 段表和节表的位置和长度等

ELF的魔术字符 和jpg的文件头字符一样 遇到就说明是这个类型

7f 45 4c 46   \177ELF

我们可以使用readelf来查看文件头

readelf -h elfDemo.rel

 

 节头表

一个文件包含很多个节 这些节的信息存放在节头表中 这个表的每一个项都是 Elf64_Shdr结构体

记录着 节的名字 长度 偏移 读写权限等信息  

节头表的位置记录在e_shoff域中

但是节头表在程序中并不是必须的

所以一些会除去节头表来增加反编译的难度

我们通过readelf查看

readelf -S elfDemo.rel

我们进行深入查看节头表的.text , .data, .bss节

代码节

objdump -x -s -d elfDemo.rel


-x 列出完整的头部信息

-s 显示每一个节的大小

-d  把符号的地址和名字列出来

 我们只看text

 

 先看这个 这个内容为

Contents of section .text:

是text数据的十六进制形式 总共有 0x4e个字节 4个算一个字节

最左边为偏移量 中间为内容 最右边为ASCII表示

 这里是反汇编的结果

数据节和只读数据节

data节保存着初始化的全局变量和局部静态变量

global_init_var  (0a000000)
全局变量

local_static_init_var  (14000000)
局部静态变量

每一个变量4个字节 一共8个字节

.rodata为只读数据 包括只读变量和字符串常量

源代码中调用printf函数 用到了字符串常量 "%d\n" 这是一种只读数据

所以保存在rodata中

 bss节

 这个节用于保存 未初始化的全局变量和局部静态变量 这个节在文件中其实不存在

只是变量预留的空间

 所以下面没有contents属性

 这里继续给出其他常见的节

字符串表

包括了以 null结尾的字符序列 用来表示符号名和节名

所以引用字符串只需要给出在字符序列中的偏移量即可

字符串表达第一个字符和最后一个字符 都是 null

readelf -x .strtab elfDemo.rel


readelf -x .shstrtab elfDemo.rel

 能发现第一个和最后一个都是 00000000 null

 符号表

是记录了 目标文件中 所需要用到的所有符号信息 分为 .dynsym .dyntab

前者是后者的子集
 .dynsym 保存了引用外部文件的符合 只能在运行的时候被解析
.dyntab 不仅保存了外部 还保存了本地符合 用于调试和链接

索引值都是从 0 开始计数 但是0不具有实际意义

每一个符号都要符号值

readelf -s elfDemo.rel

这里能看见 printf 为 und 说明是外部 需要程序运行才能知道地址

重定位

重定位是连接符号定义和符号引用的过程  

可重定位文件在构建可执行文件和共享目标文件的过程中 需要把节中符号引用转换为这些符号在进程空间的虚拟地址

包含这些转换信息的数据 就是重定位项

readelf -r elfDemo.rel

可执行文件的装载

这里是从运行视角进行审视

运行一个可执行文件

 将该文件和动态链接库 装载到进程空间中 形成进程镜像
每一个进程都有自己的独立虚拟地址空间  这个空间如何布局是段头表中的程序头决定
readelf -l elfDemo.exce
root@lxz-virtual-machine:~/下载# readelf -l elfDemo.exce

Elf 文件类型为 DYN (Position-Independent Executable file)
Entry point 0x1060
There are 13 program headers, starting at offset 64

程序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000628 0x0000000000000628  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x00000000000001b1 0x00000000000001b1  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x0000000000000114 0x0000000000000114  R      0x1000
  LOAD           0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000260 0x0000000000000270  RW     0x1000
  DYNAMIC        0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000030 0x0000000000000030  R      0x8
  NOTE           0x0000000000000368 0x0000000000000368 0x0000000000000368
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000030 0x0000000000000030  R      0x8
  GNU_EH_FRAME   0x0000000000002008 0x0000000000002008 0x0000000000002008
                 0x000000000000003c 0x000000000000003c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
                 0x0000000000000248 0x0000000000000248  R      0x1

 Section to Segment mapping:
  段节...
   00     
   01     .interp 
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.got .plt.sec .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .data .bss 
   06     .dynamic 
   07     .note.gnu.property 
   08     .note.gnu.build-id .note.ABI-tag 
   09     .note.gnu.property 
   10     .eh_frame_hdr 
   11     
   12     .init_array .fini_array .dynamic .got 

 这里我们可以从段节发现 一个段中出现了很多的节

段的出现就是对这些节进行分类

实际上 系统并不关心这些节的内容 而是关心这些的读写执行权限

那么就将不同权限的节分组 这样就可以同时装载多个节

.data .bss 具有读写权限

.text .plt.got 具有读和执行权限

常见的段

可执行文件至少有一个 PT_LOAD类型的段 用于描述可装载的节
而动态链接的可执行文件包含两个  .data 和 .plt 分开存放
动态段 PT_DYNAMIC包含动态链接器所必须的信息 
例如 动态共享库 GOT表 和 重定位表等
PT_NOTE 类型的段 保存了系统相关的附加信息 
但是程序运行不需要这个内容
PT_INTERP段 将位置和大小信息存放在一个字符串中 
是对程序解释器的位置描述
PT_PHDR段保存了 程序头本身的位置和大小

在进程中 使用段是不够的  还需要使用到栈堆vDSO等空间

动态链接的可执行文件装载后  还需要进行动态链接才可以顺利执行

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ctfhub 文件上传 - 00截断是一种常见的安全漏洞,攻击者可以通过截断文件名或者文件内容来绕过文件上传的限制,从而上传恶意文件或者执行任意代码。这种漏洞需要开发人员在编写文件上传功能时注意对文件名和内容进行严格的校验和过滤,以防止攻击者利用截断漏洞进行攻击。同时,用户也应该注意不要上传可疑的文件或者访问不可信的网站,以保护自己的计算机安全。 ### 回答2: 文件上传漏洞是目前很多Web应用存在的一种常见漏洞,该漏洞的攻击者可以利用该漏洞从Web应用程序中上传恶意文件,绕过访问控制机制,并在受害者服务器上执行任意命令。 在CTFHub文件上传-00截断中,漏洞原理是:在上传文件时,上传文件的后缀名是通过从客户端请求中获取的,如果在获取后缀名的过程中,我们可以通过攻击来修改请求,就可以上传任意类型的文件,甚至是可执行文件,从而达到绕过文件类型的限制。 具体细节如下: 1. 开始上传文件,上传的文件后缀名为.php 2. 修改上传请求中的文件后缀名为.gif,并截断请求,使之只保留文件的前8个字节。 3. 上传的文件类型变为gif,并成功上传。 4. 由于文件类型被篡改,服务器未检测到有可执行文件被上传,因此上传成功。 5. 资产管理窗口中能够看到已上传的文件,并能够通过访问路径访问到上传的文件,例如,可以直接访问上传的可执行文件,从而达到绕过文件类型限制,执行任意命令的目的。 由此可见,文件上传漏洞是一种危害性较高的漏洞,因此开发人员在开发Web应用程序时,一定要认真检查,确保不会出现类似的漏洞现象。同时,在测试人员测试网站时,也应该重点检查文件上传功能,以确保网站的安全性和可靠性。 ### 回答3: ctfhub 文件上传 - 00截断是一种常见的文件上传漏洞攻击,攻击者利用该漏洞可以上传恶意文件并将其存储到服务器中,从而导致服务器被攻击。 文件上传 - 00截断漏洞主要是利用了一些文件上传的不足之处,攻击者可以通过伪造请求包来修改原始文件名,从而实现文件截断的目的,也就是只保留了原始文件名的部分内容而去掉了后面的内容。 当攻击者上传文件时,如果原始文件名过长,则服务器会自动截断文件名,一旦攻击者将文件名截断并发送一个伪造的请求包到服务器上,则服务器会根据该请求包上传一个被截断的文件,从而导致服务器受到攻击。 例如,攻击者可以将文件名设置为“hack.php\x00.jpg”,当该文件上传到服务器上时,服务器会将文件名截断为“hack.php”,从而隐藏了文件的真实后缀名,诱骗用户下载并执行该文件。 为了避免被此类文件上传漏洞攻击,开发人员应该加强字符串截断的限制,防止非法输入,并进行文件类型检测,只允许上传指定的文件类型,同时加密重要文件和数据,保护系统安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值