您的位置  > 互联网

缓冲区溢出攻击与防御技术中科院计算所培训

• Stack,堆栈从高地址向低地址增长,用于存储函数参数、局部变量和堆栈状态,如函数返回地址、栈帧地址等。 • Heap,堆,从.bss 向高地址增长地址并用于存储动态变量。 使用(3)申请空间。 • .bss:用于存储静态未初始化数据,该数据在进程开始时被系统清除。 • .data:数据段,用于存储静态初始化数据。 • .text,代码段,存储从地址0开始的程序代码,只读。 014 Win32 进程内存空间 • 系统内存区域 – ~0(4G~2G) – 为操作系统保留 • 用户内存区域 – 00(2G~0G) – 堆:动态分配的变量 (),向高地址增长 – 堆栈:向低地址增长地址增长 – 静态存储区:全局和静态变量 – 代码区:从0到15开始 堆栈和函数调用 • 堆栈高地址 – 维持程序执行的动态环境,为进程提供嵌套执行函数并自动返回的能力调用者的数据栈帧 – LIFO、PUSH、POP 函数参数恢复 – ESP 栈顶指针返回地址 EIP 前一帧 – EBP (FP) 栈底指针,当前栈帧的前一个 %ebp 栈帧 (%ebp) –被调用函数栈的 EIP 指令指针 • 函数调用三步中保存的寄存器增长 – :保存当前栈帧指针(ebp) 局部变量 1 方向 Stack – Call...(%esp) 局部变量 n • 保存函数参数及返回地址 • 跳转到函数入口地址低位 – 后序:恢复旧的堆栈帧 16 函数调用流程详解 • 函数调用流程及堆栈状态场景保护 (1) 调用者保存 EAX、ECX、和 EDX 寄存器 值栈 (2) 调用者以相反的顺序压入函数的参数 (3) 调用者执行 CALL 指令 (4) 被调用者保存调用者的堆栈帧指针 (EBP) 帧堆栈器被调用call (5) 被调用者保存 EBX、EXI、EDI 寄存器的值 (6) 被调用者压入局部变量执行函数 (7) 执行函数 (8) 释放局部变量内存 (9)被调用者恢复EBX、EXI和EDI寄存器 (10) 将函数的返回值放入寄存器%eax中。 帧堆栈器使用调用者立即恢复 (11) 执行ret指令并从被调用函数返回 (12) 调用者释放函数参数内存 (13) 调用或恢复EAX、ECX和EDX寄存器的值17 W32 函数调用示例 • 函数:Stack func(int a, int b){…int = a + b; ;2}1Ret- main(int argc, char* argv[] )ebp{ = func(1, 2);("Hello World!\n");… 0;}18 *NIX 函数调用示例 • Main 函数反汇编分析保存之前的栈帧,并将栈顶指针向下移动24个字节的地址与x、y对齐,并逆序压入func参数y。 '%'前缀不需要加pushl前缀 % eax 立即数加'$'前缀不需要加pushl $1push 1个操作数 目的操作数在源操作数的左边目标操作数位于源操作数的右侧 addl $1, % eax, 1 字长由运算符的最后一个字母决定 (b, w, l) "byte ptr" 和 "word ptr" 前缀 movb val, %almov al, byte ptr val 内存寻址: disp (base,index,scale):[base + index*scale + disp]movw array(%ebx, %eax, 4), %cx mov cx, [ebx + 4*eax + array]20 寄存器 寄存器名称 说明 功能 eax 累加器 加法乘法指令 默认寄存器,函数返回值 ecx REP & LOOP 指令默认计数器 edx 除法寄存器存储整数除法产生的余数 ebx 基地址寄存器存储内存寻址时的基地址 esp栈顶指针寄存器 ESS:ESP 当前栈顶指针 ebp 栈底指针寄存器 ESS:EBP 当前栈底指针 字符串操作指令中的 esi、dei 源和目标索引寄存器,EDS:ESI 指向源字符串,EES:EDI 指向指向目标字符串 eip 指令寄存器 ECS:EIP 指向下一条指令的地址 标志寄存器 标志寄存器 ecs 代码段寄存器 当前执行的代码段 ess 椎栈段寄存器 stack,当前栈段 eds 数据段寄存器 data,当前数据段 ees 、efs、eqs 辅助段寄存器指定附加数据 第 21 节 与函数调用相关的汇编命令 • 函数调用时常用汇编命令说明 PUSH%esp -= 4; movl %REG, (%esp) (%esp), %REG; %esp += 地址, % %eip; %eip = %ebp, % esp; pop % %eip22 不严重的溢出# int main(int argc, char **argv){char jayce[4]="Oum";char herc[8]=""; (herc, "");("%s\n", 杰斯); 0; }23 堆栈溢出攻击 • 已知条件 – Call 指令将返回地址(EIP 中的内容)压入栈帧顶部 – Ret 指令将其传回 EIP – 当堆栈上的缓冲区溢出时,将覆盖数据• 我们需要 – 找到包含漏洞的程序( ) – 编写一个简短的攻击代码( ),执行它以获得对系统的控制 – 编写一个导致溢出的程序(称为),并将其发送给漏洞程序中,覆盖栈上的返回地址,函数返回时,执行EIP指向的攻击代码 24 栈溢出示例 # 高地址 Para1 # Para2... char [] = " \xeb\x1f\x…… ”; 添加 char [128];... int main(int argc, char **argv){ [96]; 添加()int i; * =(长*); (i = 0 ; i < 32; i++)i*( + i) = (int) ;for (i = 0; i < (int) (); i++)[i] = [i];(, );低地址0; 结果:获得外壳! }25 堆 • 堆是指进程空间中.data 段和栈顶之间的内存区域。 堆向高地址增长 • 当程序需要使用内存空间,但无法预先确定所需空间的大小时 或者 空间太大而无法在堆栈上分配时,会在堆中动态申请。

• 进程使用//free动态申请、增加和释放堆上的缓冲区 • .bss:用于存储全局或局部静态未初始化的数据,在进程开始时被系统清除 • .data:数据段,用于存储全局或局部静态初始化的数据 • 堆溢出是指以上三部分的缓冲区溢出 26 堆和栈的区别 • 结构 堆结构——栈是一个向下发展的连续空间,栈顶是一个连续的空间,向上延伸。地址是线性结构高端未分配块——堆是向上发展的不连续空间。 它是一个链表结构,已经按照不断增长的堆的方向进行了分配。 • 管理空闲块——堆栈上的缓冲区由系统自动分配和释放。 已分配——堆上的缓冲区需要程序员动态申请和释放。 回收空闲块 • 已分配的功能 – 堆栈用于维护系统的动态运行环境 – 堆主要用于存储用户数据。 低地址已分配 27. 堆溢出攻击 • 堆中主要是用户数据,并没有系统关键数据,如“激活记录”” • 堆缓冲区溢出虽然可以重写其后续内存的内容,但不能直接改变程序执行流程 • 堆溢出需要迂回手段改变程序执行流程 – 改变堆上函数指针的内容,指向恶意函数 – 重写表,指向恶意函数 • 由于结构进程空间,需要一些先决条件——缓冲区在指针 char buf[];char buf[]; 之前声明。