首页 >> 大全

基础知识——程序保护

2024-01-11 大全 36 作者:考证青年

我们先来看一个实例,使用的对一个程序进行检测

RELRO( Read-Only):

设置符号重定位表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对 GOT 攻击。

(1)No RELRO:

在这种模式下关于重定位并不进行任何保护。

(2) RELRO:

1.这种模式是gcc编译的默认模式。

2.一些段 (包括. . .jcr . .got) 在初始化后将会被标识为只读。

3.ELF 部分被重新排序,以便 ELF 内部数据部分(.got、.dtors 等)在程序的数据部分(.data 和 .bss)之前。

4.对于攻击者来说,由于linux的lazy bind机制,(.plt.got)段依然可写,只是(.got)段不在可写。

(3)FULL RELRO:

1.Full RELRO 不是默认编译器设置,因为它可以大大增加程序启动时间,因为必须在程序启动之前解析所有符号。在需要链接数千个符号的大型程序中,这可能会导致启动时间明显延迟。

2.将会继承 RELRO的所有功能。

3.lazy bind 将被禁用,所有导入的符号都在 time被解析。

4.Full RELRO 使整个 GOT 成为只读的,其中一个函数的 GOT 地址不会被另一个函数或者通过ROP 覆盖。

关于重定位与Lazy Bind机制会再以后讲到

:

不管是实现还是设计思想都比较简单高效,就是插入一个值在 stack 发生的高危区域的尾部。当函数返回之时检测 的值是否经过了改变,以此来判断 stack/ 是否发生。

通常有三种类型

1.

由于大多数缓冲区溢出攻击都是基于以某些字符结束符终结的字符串操作。 是由零终止子,CR,LF和FF构成的。因此,攻击者必须在写入返回地址之前写入空字符,以避免更改金丝雀。这将有效的限制了( )和其他空字符结束的攻击方法,但缺点也很明显,因为对攻击者来说是已知的,攻击者仍然可以采取手段覆盖,从而控制程序。

2.

通常,随机金丝雀在程序初始化时生成,并存储在全局变量中。此变量通常由未映射的页面填充,因此尝试使用任何利用错误读取RAM的技巧来读取它都会导致分段错误,从而终止程序。如果攻击者知道金丝雀的位置,或者可以让程序从堆栈中读取,则仍然可以读取金丝雀。

Linux C 编译器 gcc,一般在ebp之前插入一段以/x00结尾的字节序,由于Intel处理器大多采用小端序,/x00其实位于字节序开头,对于字节序的其他部分将会由系统随机生成。当程序启用 编译后,在函数序言部分会取 fs 寄存器 0x28 处的值,存放在ebp之前。在函数返回之前,会将该值取出,并与 fs:0x28 的值进行异或。如果异或的结果为 0,说明 未被修改,函数会正常返回,这个操作即为检测是否发生栈溢出,否则将会执行 错误回调函数,停止程序运行。

的值会在进程开始时生成,并在程序运行期间保持不变。进程的任何分支都将包含相同的值。这给我们提供了一些绕过的机会,我们看下面的示例。

该程序包含两个漏洞,一个,和一个任意写

可以看到这两个函数都存在,且由于相同,可以考虑将泄露出来,再使用read写入和返回地址。具体过程不再累述。

Linux C 编译器 gcc 目前包含 Stack 保护程序,如果 /dev/ 可用,它将引入一个 。在没有随机数据源的情况下,它将恢复为 。gcc 仅在特定情况下引入。缓冲区超过 8 个字节并调用 ()的函数(允许在堆栈上分配内存空间的函数)将受到金丝雀的保护。程序员可以使用 –--all 编译器标志为所有函数引入 ,但这可能会妨碍程序的性能。

3. XOR

XOR 是使用全部或部分控制数据进行异或加扰的 。这样一来,一旦或控制数据被破坏,的值就是错误的。

XOR 具有与 相同的漏洞,只是获取的“从堆栈读取”方法稍微复杂一些。攻击者必须获得、算法和控制数据,才能重新生成欺骗保护所需的原。

很多时候它将根据程序中的非静态值(通常是基本指针EBP)进行异或化。由于操作系统现在在激活地址空间布局随机化(ASLR)的情况下运行,因此EBP在程序运行期间不会是静态的。这为 增加了一层额外的随机化,使得很难预测此值。

此外, XOR 可以防止某种类型的攻击,包括将结构中的缓冲区溢出到指针中,以将指针更改为指向一段控制数据。由于异或编码,如果控制数据或返回值发生变化,就会出错。由于指针,可以更改控制数据或返回值而不会溢出。

NX(No-):

NX即No-(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

一个最简单的例子,我们通过向栈中写入,然后将返回地址设置为所在的栈地址,如果程序没有NX保护的话,就会执行我们写入的恶意代码。

接下来简要说明一下该保护的具体原理。

在Linux系统中,物理内存被划为三个层次来管理。

层次

描述

存储节点(Node)

CPU被划分为多个节点(node), 内存则被分簇, 每个CPU对应一个本地物理内存, 即一个CPU-node对应一个内存簇bank,即每个内存簇被认为是一个节点

管理区(Zone)

每个物理内存节点node被划分为多个内存管理区域, 用于表示不同范围的内存, 内核可以使用不同的映射方式映射物理内存

页面(Page)

内存被细分为多个页面帧, 页面是最基本的页面分配的单位

页面作为最基本的页面分配单位,适时的从虚拟内存转移的物理内存,在每个页面中都具有一定的结构,存储着状态信息和页面内容。而页面的保护信息是由页表管理的,操作系统为每一个进程创建了一个独立的页表,因而进程可以方便的对自己的数据进行保护,为每个页进行权限管理,如果一条指令违背了这些许可条件,CPU就会抛出一个异常。

而页表的权限设置,是在程序的装载过程中发生的。我们可以回想在ELF可执行文件中,有一个专门的数据结构叫做程序头表( Table)

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;

其中的记录了的权限属性,例如R,W,X。

在IDA中我们可以看到程序各个段设置的权限。

由于NX保护只是栈数据没有执行权限,使用依然可以使用,rop之类的攻击手段。

PIE(- )

该技术是一个针对代码段(.text)、数据段(.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址,从而不能通过等一些工具来帮助解题。

未完待续。。。

参考:

Read-Only (RELRO) - CTF 101

程序保护的的机制 - 简书

二进制漏洞挖掘之栈溢出-开启的博客-CSDN博客 relro

stack--at-/

(Using the GNU (GCC))

Stack – the Cage | SANS

Linux内存描述之内存页面page--Linux内存管理(四) - - 博客园

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了