CN105022956B - 一种抵御代码重用攻击的方法 - Google Patents
一种抵御代码重用攻击的方法 Download PDFInfo
- Publication number
- CN105022956B CN105022956B CN201510501698.XA CN201510501698A CN105022956B CN 105022956 B CN105022956 B CN 105022956B CN 201510501698 A CN201510501698 A CN 201510501698A CN 105022956 B CN105022956 B CN 105022956B
- Authority
- CN
- China
- Prior art keywords
- code
- progress
- work
- shuffling
- new version
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Active
Links
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F21/00—Security arrangements for protecting computers, components thereof, programs or data against unauthorised activity
- G06F21/50—Monitoring users, programs or devices to maintain the integrity of platforms, e.g. of processors, firmware or operating systems
- G06F21/52—Monitoring users, programs or devices to maintain the integrity of platforms, e.g. of processors, firmware or operating systems during program execution, e.g. stack integrity ; Preventing unwanted data erasure; Buffer overflow
- G06F21/54—Monitoring users, programs or devices to maintain the integrity of platforms, e.g. of processors, firmware or operating systems during program execution, e.g. stack integrity ; Preventing unwanted data erasure; Buffer overflow by adding security routines or objects to programs
Landscapes
- Engineering & Computer Science (AREA)
- Computer Security & Cryptography (AREA)
- Software Systems (AREA)
- Theoretical Computer Science (AREA)
- Computer Hardware Design (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Storage Device Security (AREA)
Abstract
本发明提供一种抵御代码重用攻击的方法,其特征在于,包括下列步骤:1)在工作进程运行过程中,洗牌进程生成工作进程的新版本代码并将其存入代码缓存区,所述代码缓存区被工作进程和洗牌进程所共享;2)所述工作进程完成新旧版本代码的切换。本发明具有下列技术效果:本发明实现了应用级的持续随机化,能够有效地防御代码重用攻击。本发明的防御代码重用攻击方法不需要修改操作系统内核,不需要修改现有的CPU硬件,并且不需要源代码的支持,兼容性高。本发明的防御代码重用攻击方法不会破坏DEP机制,能够避免额外的安全隐患。本发明的防御代码重用攻击方法的开销非常低。
Description
技术领域
本发明涉及应用软件的安全和防护(Security and Protection)技术领域以及代码生成(Code generation)技术领域,具体地说,本发明涉及一种抵御代码重用攻击的方法。
背景技术
为了抵御代码注入攻击(code injection),计算机系统中引入了数据执行保护机制(data execution prevention,DEP),限定任何一块内存区的属性为W⊕X,该机制使得攻击者上载的恶意代码(shell code)无法执行。DEP机制可参考:Pax.homepage of the paxteam,2001.http://pax.grsecurity.net。作为回应,攻击者则提出代码重用攻击(codereuse),该攻击手段能够有效绕过DEP机制。代码重用攻击方案中,攻击者会首先获得目标机器的代码布局,然后通过精心构造载体(payload)利用目标机器的间接跳转(indirectjmp)、间接调用(indirect call)和函数返回指令(ret),将目标机器的代码片段编织起来,进而实现攻击者所需的功能。返回libc库函数(Return-to-libc)和面向return的编程(Return-Oriented Programming,ROP)是两种最为典型的代码重用攻击手段。Return-to-libc通过缓冲区溢出(buffer overflow)覆盖栈上的返回地址来改变程序的执行流,将控制转移到一个特定的库函数中。ROP则利用代码中的gadget(以ret、indirect jmp和indirect call指令为结尾的指令序列)组成载体并通过缓冲区溢出执行载体来完成攻击者的意图。
代码重用攻击的前提条件是要掌握目标机器上代码的布局。因此人们又提出了地址随机化(Address Space Layout Randomization,ASLR)的方案来抵御代码重用攻击的。目前,地址随机化方法已经部署到大多数主流操作系统中,其具体做法是在装载应用时,系统为各个模块随机加载地址,这样攻击者就无法推断出应用运行时的代码布局情况。为了进一步增加攻击者破解代码布局的难度,人们还探讨了更加细粒度(fine-grained)的随机化方法,如函数级别(Function-level)、基本块级别(BasicBlock-level)、指令级别(Instruction-level)的随机化方法。
然而,商业软件常常存在内存泄露(memory disclosure)漏洞,攻击者利用这种漏洞可以动态读取被攻击程序的内存,进而突破DEP+ASLR机制的防御能力。也就是说,即使一个系统同时部署了ASLR和DEP机制,攻击者依然可以利用内存泄露漏洞,对随机化后的代码布局进行破解,然后对系统发动代码重用攻击,从而获得目标机器的控制权。利用内存泄露发动代码重用攻击的方法有JIT-ROP方案等(可参考K.Snow,F.Monrose,L.Davi,A.Dmitrienko,C.Liebchen,and A.Sadeghi.Just-in-time code reuse:On theeffectiveness of fine-grained address space layout randomization.In Securityand Privacy(SP),2013IEEE Symposium on,pages 574-588,May 2013.)。JIT-ROP可以对付任意粒度的ASLR,其方法是从程序某一处开始,读取该代码所在的内存页,然后反汇编分析该页可能跳转/调用的其它代码页,依据这些信息,读取对应代码页的内容。反复上述过程,就可以获得所有的代码页,从而实现对代码布局的破解。完成代码布局破解后,再通过JIT编译技术,构造ROP载体再配合缓冲区溢出漏洞实现代码重用攻击。
基于内存泄露漏洞的代码重用攻击给应用系统带来了严重威胁,为了抵御这种攻击,人们在多个方向展开了相应的研究,包括:阻止攻击者利用内存泄露读取代码;执行路径多样化;持续地进行随机化。
阻止攻击者利用内存泄露漏洞读取代码的防御方法有:XnR方法、HideM方法和Readactor方法等。上述三种防御方法主要解决的是如何在维护代码页可执行权限的情况下,阻止处理器对代码页进行有害的读操作。下面以XnR方法为例进行说明。XnR方法的主要思想是通过修改内核内存管理(MMU)相关代码取消掉进程中所有代码页的映射,因此当进程访问代码页时会产生页面异常(Page Fault)。XnR方案中,基于Page Fault捕捉到进程对代码页的访问,然后做如下处理:如果是执行请求就正常执行操作系统的缺页异常处理;如果是读请求就报错杀掉当前进程。代码页在页表中的映射关系建立起来以后,该页就长时间具有可读可执行权限。为了能够再次捕捉到这些代码页的读操作,XnR方案中设置了一个滑动窗口,在某些时刻取消掉已经建立好的映射关系,从而避免代码页长时间具有可读可执行权限。然而在滑动窗口内,还是有很多内存页是即可执行又可读的,如果攻击者在滑动窗口内进行攻击,XnR方案仍然是无法防御的。
执行路径多样化的防御方法以Isomeron多样化方法为代表。该方法的主要思想都是执行流多样化,使攻击者生成的载体不能够按照原有攻击语意执行。该方法在内存中加载两份不同版本的代码,其中一个保存有原有代码的布局,另一个是随机化后的版本。它对所有的indirect call、ret和indirect jmp指令进行动态插桩,然后在运行时决定跳转的目标是原有版本代码还是随机后的代码版本。由于攻击者并不知道这三类指令会跳转到哪个版本,因此攻击者上传的载体在执行时可能会出错。理论上载体有能够正确执行的可能性,但是概率非常低,仅为0.5的n次方(n为载体使用的gadget数量)。然而,Isomeron执行流多样化方法需要在跳转指令处进行掷骰子选择跳转目标,因此该方法存在开销非常大的问题。又由于Isomeron方案需要进行动态插桩,因此它还会破坏DEP防护机制,带来另外的安全隐患。
Cristiano Giuffrida提出了一种基于重新设计内核的持续随机化方法。该方法重新设计了自己的操作系统内核Minix microkernel,由专门的内核随机线程对其它内核线程进行持续随机化。其做法是基于LLVM框架,由编译器通过对操作系统源码进行编译生成比特码(Bitcode)。在操作系统运行过程中,周期性地由JIT编译器生成新代码。该方法会在形成的每个版本的代码中插入同步点,随机线程会发送信息(message)通知旧版本停下来(停在同步点),然后利用内核线程将原有线程的状态迁移到新线程上执行,最后销毁原有线程。该方法不仅有效地改变了进程内存代码布局而且还可以低开销地防御代码重用攻击。然而,由于Cristiano Giuffrida方案需要修改整个操作系统的内核来支持其部署LLVM的JIT编译器等,因此无法在已有操作系统上进行部署。又由于该方法需要源代码的支持,因此也不能有效部署到应用层下(主要原因有:版权保护,商业机密和遗产代码等)。
发明内容
因此,本发明的任务是克服现有技术的缺陷,提供一种抵御代码重用攻击的解决方案。
本发明提供了一种抵御代码重用攻击的方法,包括下列步骤:
1)在工作进程运行过程中,洗牌进程生成工作进程的新版本代码并将其存入代码缓存区,所述代码缓存区被工作进程和洗牌进程所共享,对于工作进程,所述代码缓存区的权限被设置为可读可执行但不可写,对于洗牌进程,所述代码缓存区的权限被设置为可读可写不可执行;所述洗牌进程不对外提供服务;这样就可以利用共享内存机制动态生成或修改代码来维护工作进程的DEP防护机制,进而阻止代码注入攻击;
2)所述工作进程完成新旧版本代码的切换。
其中,所述步骤1)中,所述新版本代码做随机化处理确保新代码的布局与之前的旧代码不同。
其中,所述步骤1)之前,所述洗牌进程在启动时进行初始化,包括:洗牌进程对工作进程的所有代码段进行反汇编并记录下中间表示,识别代码段中的函数信息,分析函数内的执行流并划分basic block(基本块)。
其中,所述步骤1)中,所述新版本代码的生成方法包括下列子步骤:
11)对旧版本代码的函数内的基本块进行乱序处理;
12)在基本块内部随机插入一些无关指令,得到新版本代码。
其中,所述步骤2)包括下列子步骤:
21)洗牌进程触发工作进程中断;
22)洗牌进程将工作进程由旧版本代码迁移至新版本代码;
23)洗牌进程唤醒工作进程。
其中,所述步骤22)包括下列子步骤:
221)洗牌进程对工作进程的栈上的所有返回地址进行同步;
222)洗牌进程对工作进程的PC寄存器状态进行同步;
223)使代码指针指向新版本代码的位置。
其中,所述步骤223)还包括:洗牌进程在进行新旧代码迁移时,在工作进程原有函数的入口处插入跳转指令使其指向新版本函数位置。
其中,所述步骤223)还包括:先跳转到地址表(Address Table),查找所述新版本代码的相应函数的存储地址,然后再将代码指针指向所述新版本代码的相应函数;所述地址表用于存储所有新版本代码的函数的存储地址。
其中,用gs段寄存器指向所述地址表的首地址,所述步骤223)还包括:利用gs段寄存器跳转指令实现对所述地址表的查找。
其中,在每次生成新版本代码时,所述地址表的存储位置随之发生变化。
其中,在每次生成新版本代码时,所述地址表内部表项之间进行乱序处理。
其中,对于多线程应用程序,工作进程中所有线程共用同一份代码,所述步骤2)中,所有线程都同步完成新旧版本代码的切换。
其中,对于多线程应用程序,所有线程的栈都共享给洗牌进程。
与现有技术相比,本发明具有下列技术效果:
1、本发明实现了应用级的持续随机化,能够有效地防御代码重用攻击。
2、本发明的防御代码重用攻击方法不需要修改操作系统内核,不需要修改现有的CPU硬件,并且不需要源代码的支持,兼容性高。
3、本发明的防御代码重用攻击方法不会破坏DEP机制,能够避免额外的安全隐患。
4、本发明的防御代码重用攻击方法的开销非常低。
附图说明
以下,结合附图来详细说明本发明的实施例,其中:
图1示出了本发明一个实施例的抵御代码重用攻击的方法的流程示意图;
图2示出了本实施例中共享内存区域在工作进程(Working process)和洗牌进程(Shuffle process)中的权限设置示意图;
图3示出了图1的实施例中的step 3、4、5、6运行过程中工作进程的内存区域的变化情况;
图4示出了本发明一个实施例中的中断进程运行处理的伪代码;
图5示出了本发明一个实施例中采用地址表来隐藏新版本代码的示意图;
图6示出了本发明一个实施例的洗牌进程处理Parsec benchmarks和SPEC2006benchmarks一遍的时间;
图7示出本发明一个实施例的洗牌进程在不同随机化处理时间间隔下的运行开销。
具体实施方式
为了能够既维护应用程序的DEP机制,又能够对应用程序进行持续的随机化,发明人设计了如下方案:将随机化任务交给一个专门的进程来完成,为了便于描述,将该进程被称为洗牌进程(Shuffle process),另外称执行应用程序的进程为工作进程(Workingprocess)。在程序启动之前,将工作进程的代码页共享给洗牌进程。工作进程自身对于任何一个内存页,不同时具有可写和可执行权限。洗牌进程对工作进程的代码页具有读写权限但不具有可执行权限。由于洗牌进程不对外提供任何服务,因此不会接收来自攻击者提供的数据。另外,虽然洗牌进程对工作进程的代码区域具有写权限,但由于共享内存机制的支持,它不会破坏工作进程的DEP防护机制。洗牌进程通过共享内存方法获得工作进程的所有代码页,然后对工作进程的代码进行随机化处理,从而达到防御代码重用攻击的技术效果。由于工作进程一直在运行,因此洗牌进程无法精确判断工作进程正在执行哪块代码区域。此时如果直接修改工作进程正在运行的代码,可能会造成工作进程运行崩溃。为了解决这个问题,洗牌进程在工作进程内部的代码缓存动态生成一份与工作进程当前代码等价的新版本代码,然后适时进行新旧版本切换。工作进程内部的代码缓存通过我们的代码隐藏方法使得攻击者通过内存泄露漏洞不能够找到该代码区域。这样就能在持续随机化的同时保障工作进程的正常运行。
下面结合附图和具体实施例对本发明做进一步地描述。
图1示出了本发明一个实施例的抵御代码重用攻击的方法的流程示意图,参考图1,该抵御代码重用攻击的方法包括下列步骤:
Step1:将工作进程的内存空间共享给洗牌进程。为了完成这一功能,本实施例中开发了一个共享库文件(SharedSO),将应用程序的入口函数进行了重载。利用操作系统提供的预装载功能(如linux中的LD_PRELOAD),预装载该库文件。这样就能够在应用程序执行前,接管工作进程的执行权。在获得执行权后,该库文件完成如下功能:1>将工作进程中的所有代码段共享给洗牌进程;2>将工作进程的栈共享给洗牌进程;3>申请一块区域作为代码缓存(Code cache),用于存储洗牌进程生成的新版本代码,代码缓存被工作进程和洗牌进程所共享,但它们各自设置不同的权限。对于工作进程,将代码缓存的权限设置为可读可执行但不可写,这样攻击者无法向代码缓存中注入恶意代码,而对于洗牌进程,将代码缓存的权限设置为可读可写但不可执行,这样,洗牌进程既可在代码缓存中写入新版本代码,又能降低洗牌进程本身被攻击而导致的安全隐患。4>共享一块内存空间用于洗牌进程和工作进程的数据交换。5>通过IPC(Inter-Process Communication,进程间通信)区域与洗牌进程建立通信关系。5>选择一个系统预留给用户的信号并注册信号处理函数,用来接收洗牌进程发来的信号。6>将控制移到应用程序原先的入口。
图2示出了本实施例中共享内存区域在工作进程和洗牌进程中的权限设置示意图,其中RW代表可读可写不可执行,R可读不可执行不可写,RX代表可读可执行不可写。其中IPC区域的任务是工作进程与洗牌进程进行通信,Address Table区域里存放随机化处理后的代码的位置信息,Address Table区域的具体作用还会在后面进行详细介绍。
Step2:完成共享内存操作后,洗牌进程进行初始化。在一个实施例中,初始化包括:1>洗牌进程对所有的代码段进行反汇编并记录下中间表示。存储的这些中间表示被用于生成新版本的代码。2>识别代码段中的函数信息。3>分析函数内的执行流并划分基本块(basic block)。
Step3:在工作进程运行过程中,洗牌进程在工作进程的代码缓存中生成新版本代码。对于新版本代码,洗牌进程做随机化处理确保新代码的布局与之前的不同。本实施例中采用是细粒度随机方法,具体做法包括:1>乱序函数内的基本块;2>在基本块内部随机插入一些无关指令(例如nop指令),其目的是尽可能地减少非对齐的gadget数量。生成新版本代码时,洗牌进程创建一个map用来记录原有指令位置与随机化处理后位置的映射关系。
图3示出了图1的实施例中的工作进程在运行和新旧版本代码切换过程中的内存变化情况的示例。图3中,(a)部分示例性地给出了step 3,即新版本代码生成时工作进程的内存布局。可观察到工作进程将要执行函数funcB的第一条指令instrB,此时栈上的返回地址为Addr3,说明当前正在执行的函数funcB的调用者函数是函数funcA。同时,可以观察到在工作进程的代码缓存中洗牌进程已经为其生成了一个新版本代码,并且该版本的代码进行了随机化处理。
Step4:中断工作进程。图4示出了一个实施例中的中断进程运行处理的伪代码,其中signal_handler表示信号处理函数、send_signal_to_stop表示发送信号函数和wake_up表示唤醒函数。其中结构体CommunicationInfo里存放的是工作进程与洗牌进程通信的数据,该结构体存放在IPC内存区域。结构体变量uc存储的是结构体ucontext在栈上的位置信息(操作系统接收到信号后会将中断指令处所有寄存器的值存储到用户栈,也就是结构体ucontext)。由于工作进程的栈是共享的,因此洗牌进程可以读取到被中断指令处的所有寄存器状态。结构体变量curr_rsp存储当前信号处理函数内RSP寄存器的值,洗牌进程通过读取当前RSP的值来确定工作进程目前栈顶的位置方便扫描栈内容。结构体的address_table_base变量是一个安全的优化操作。变量flag用做洗牌进程与工作进程的同步操作。
在一个例子中,洗牌进程中断工作进程运行的步骤如下:1>洗牌进程通过调用发送信号函数send_signal_to_stop向工作进程发送信号后(line2)循环等待工作进程被中断(line3);2>工作进程在接收到信号后会立即进入信号处理函数:首先保存需要通信的信息内容(line1-line4),然后循环等待(line5);3>洗牌进程在确认工作进程已经中断执行并且保存相应信息后,开始进行状态迁移(line4)。图3的(b)部分示例性地给出了step 4,即工作进程被中断时内存布局。通过图3的工作进程(b)部分,可以观察到ucontext结构体已经存放在栈上,其中(RIP寄存器,也就是PC寄存器的值,本文中有时也简称为PC)记录了被中断指令的地址是Addr4。
Step5:完成工作进程新旧版本代码的迁移。众所周知,内存中存在大量的代码指针(code pointer),对所有的代码指针都进行同步是非常困难的。发明人将内存中的代码指针存储的数据分为两类:函数入口地址(GOT表和虚函数表等)和函数内地址(栈上返回地址等)。对于第一种代码指针,可以在函数的起始位置插入跳转指令指向随机后的代码位置,这样新旧版本切换时就不需要同步此类代码指针。对于栈上返回地址,其同步方法是:将工作进程的栈共享给洗牌进程,然后由洗牌进程完成返回地址的同步。由于工作进程始终在运行,它的栈会随时发生变化,也就意味着会时刻向栈上压返回地址。为了解决这个问题,利用Linux的信号机制让洗牌进程给工作进程发信号,中断工作进程的运行。为了不终止工作进程的运行,在工作进程中注册信号处理函数,工作进程在接收到信号后会进入信号处理函数,然后在信号处理函数中循环等待。通过这种方法可以保证栈不再发生变化,洗牌进程有机会同步栈上的返回地址。信号机制解决了栈返回地址同步的同时,还能够解决了PC寄存器的同步问题(将旧版本的PC切换到新版本代码处)。当进程接收到信号后,操作系统会向该进程的栈上存储被中断指令处的所有寄存器状态。如果在信号处理函数中修改这些寄存器状态,那么在信号处理函数返回后OS会将最新寄存器状态存回寄存器中。利用这一机制,可以通过修改PC寄存器在栈上的值达到同步PC的目的。由于工作进程的栈是共享给洗牌进程的,因此洗牌进程可以通过修改栈上的PC寄存器的值完成新旧版本PC的切换。
一个实施例中,工作进程新旧版本代码的迁移包括三步操作:1>同步栈上所有的返回地址:洗牌进程通过IPC得到工作进程栈顶位置,然后对栈上的所有返回地址进行同步(通过查找之前记录的map信息,将当前返回地址修正为随机后的地址);2>同步工作进程的PC:通过IPC读取ucontext获得RIP寄存器(PC寄存器)的值。然后查找map信息得到随机后指令的地址,然后将新地址写回;3>在函数入口处插入跳转指令,使其指向随机后函数的位置。由于信号处理函数也会被随机并且工作进程此时的PC在该函数第5行循环执行。为了确保工作进程不会崩溃,在信号处理函数入口处插入跳转指令时会确保被修改的字节数小于第5行循环代码与函数入口的距离(保证不会破坏line5以后的代码)。图3的(c)部分示例性地给出了step 5,即工作进程完成新旧版本代码的迁移后的内存布局。参考图3的(c)部分显示栈上的返回地址此时已经从地址Addr3同步到地址Addr8,PC也从地址Addr4同步到地址Addr6,原始函数的起始位置也已经插入跳转指令指向随机化处理后的新版本代码位置。
Step6:唤醒工作进程。在一个实施例中,洗牌进程通过调用图4中的wake_up函数唤醒工作进程。具体方法是将flag置0(line1),然后循环等待工作进程切换到新版本代码(line2)。当flag变为0后,工作进程会跳出信号处理函数中的循环,最后返回去执行sigreturn系统调用(返回中断指令处重新执行)。由于洗牌进程在Step5进行了状态迁移处理(信号处理函数的返回地址已经同步到新地址),因此信号处理函数signal_handler会返回到新版本的sigreturn相关指令中。在生成新版本代码的sigreturn相关指令时在其开头处插入两条指令将flag置位1用来通知洗牌进程,工作进程已经运行到新版本代码中(如图4所示)。洗牌进程在确认工作进程已经开始执行新版本代码后,开始抹掉之前旧版本的代码。抹掉的方式是通过插入非法指令进行抹除。图3的(d)部分示例性地给出了step 6,即工作进程被唤醒后的内存布局。从图3的(d)部分中可以观察到在信号处理函数结束运行后,工作进程开始执行新版本代码。此时工作进程的旧代码也已经同步进行抹除。
Step7:洗牌进程隔一段时间后,开始再次重复step3、step4,step5和step6。新版本代码还是存储在代码缓存中。与第一次随机不同的是对于返回地址和PC的同步:由于每次生成随机代码都是通过之前反汇编记录的中间表示生成的,所以map信息里只记录了最初版本(随机之前代码)指令地址与随机后地址的映射关系。再次随机时洗牌进程里就会有新旧版本的map信息。同步返回地址和PC时,需要将新旧版本map信息进行对比,然后得到旧版本指令对应新版本的地址。需要注意的是在洗牌进程发送信号中断工作进程运行时,工作进程会进入代码缓存中旧版本的信号处理函数代码,而不再是原始代码。
进一步地,在一个优选实施例中,提出了一种共享工作进程的所有代码段和栈的方法,该方法可用于所述step1中。
应用程序在加载阶段,加载器会把主程序和其依赖的库加载到内存空间中并分配栈和堆空间,加载和分配的方法是使用“mmap”系统调用并以MAP_PRIVATE作为其中一个参数。Linux操作系统提供给用户的“mmap”系统调用同时还支持共享内存的实现,但是需要使用“MAP_SHARED”参数。本实施例提出了一个非常简单的解决方法,即修改加载器,将其中的“mmap”都改为使用MAP_SHARED。
为了获得更好的移植性,本实施例不修改操作系统中的任何库。但是这同样会带来一个实现上的问题:在执行被预装载进工作进程的共享库文件时,所有的代码和栈已经被加载分配到内存中但是不能进行共享内存。如果要将代码和栈共享给洗牌进程,就需要无效当前内存中需要共享的区域然后重新调用mmap系统调用并使用MAP_SHARED作为参数。但是这样会影响到正在进行共享工作代码的正常执行。为了解决这个问题,本实施例中使用一个临时共享库文件(记为ShareTmpSO)来辅助共享共享库文件(即SharedSO)的代码。临时共享库文件由共享库文件通过dlopen加载进来,临时共享库文件会通过读取“/proc/self/maps”文件获取当前进程的内存布局,然后保存内存中除了临时共享库文件以外的所有代码段和栈的数据,在无效这些代码段和栈空间后,再次调用“mmap”系统调用进行共享,最后将数据复原。临时共享库文件中的代码不需要调用外部库函数并且会通过内嵌汇编切换到自己全局数据区的栈进行执行(因此不会因为无效栈区域导致临时共享库文件的代码不能正常运行)。当共享代码执行完后,共享库文件会自动卸载临时共享库文件,此时共享工作进程的所有代码段和栈的过程结束。
进一步地,在另一个优选实施例中,还提供了一种隐藏新生成的代码的方法,它可以用于前文中的step5中。在step5中,需要在函数的入口处插入跳转指令指向随机化处理后的新版本代码位置,并且新代码在运行时会向栈上压最新代码的返回地址。这些信息都可能会泄露新版本代码的位置,使攻击者能够根据代码指针(GOT表,虚函数表和栈上返回地址等)读取新版本代码。
本优选实施例在不改变原有功能的前提下,利用x86的gs段寄存器的支持来隐藏新生成的代码。由于目前主程序和库里都没有使用gs段寄存器,因此我们对该寄存器的使用不影响原有程序的运行。gs段寄存器里存储的是GDT表(全局描述符表)的一个索引,具体指向的地址保存在GDT表中,攻击者是无法读取到GDT表中的内容。由于目前主程序和库代码都没有使用gs段寄存器,因此内存中不存在使用gs段寄存器进行访存的对齐指令。对于非对齐的指令,可以在做代码随机时通过插入一些填充(即padding)来有效消除掉。有了gs段寄存器的支持,就可以把所有需要隐藏的地址存入地址表(Address Table)中,然后用gs段寄存器指向地址表的基址。地址表存放的位置为图2中所示的地址表区域。
图5示出了本实施例中采用地址表来隐藏新版本代码的示意图。在函数funcA的入口处,插入的不再是相对跳转的指令,而是jmpq%gs:index指令。gs段寄存器指向的是地址表的首地址,然后通过索引index进行检索。为了隐藏栈上的返回地址,本实施例的方案中,在新生成的代码中还将call和ret指令进行了修改,使栈上存放的是地址表的索引index(如图5代码缓存中的代码所示)。由于修改了call和ret指令,因此在新旧版本代码迁移时,重定位的不再是指令地址而是地址表的索引。为了确保安全,内存中没有任何的指针(pointer)指向该地址表。为了更进一步加大攻击者攻击的难度,地址表在每次随机后不仅位置发生变化,而且地址表内部表项之间也进行乱序处理。如图5所示,相对于原先的地址表,新生成的第二地址表(即Address Table’)中地址Addr2和地址Addr3(即第0项与第2项)的顺序进行了调换。本实施例的方案中,还会在表中随机插入一些非法的地址,使攻击者在读取地址表里面的值后,进一步查找对应代码页时系统发生崩溃。如图5中新地址表所示的第1项填入的是非法地址。对地址表位置进行随机处理时,动态修改gs段寄存器使其指向新生成的第二地址表。随机处理完成后,第二地址表便被视为新的地址表。图4中信号处理函数的第6行是设置gs段寄存器的时机。为了阻止记录地址表的基址被泄露,图4中的唤醒函数wake_up会在之后清除掉该基址的值。
在程序有内存泄露漏洞的情况下,理论上攻击者有能力读取内存中任意位置的数据。但如果攻击者要在不使程序发生崩溃的前提下读取内存,就要通过读取代码指针找到对应的代码页,而上述方法能够阻止攻击者读取代码指针,从而有效地隐藏新生成的代码。
进一步地,在一个实施例中,对于多线程应用程序,所有线程共用同一份代码,不需要为每个线程都创建一个洗牌进程进行代码随机化。但是每个工作进程线程之间又相互独立,各有自己的运行栈和PC寄存器,因此在新旧版本切换时,需要对每个线程的栈和PC都进行同步:将所有线程的栈都共享给洗牌进程。当洗牌进程需要中断工作进程时,洗牌进程对所有工作进程发送信号(子线程继承主线程注册的信号)并且确保所有工作进程都停下来后才进行状态迁移(同步每个线程栈上的返回地址和PC寄存器)。最后唤醒所有工作进程继续运行。
本实施例中,对于多线程应用程序,由于子线程在应用程序运行时动态创建的,因此需要运行时进行线程栈的共享操作,其过程如下:主线程通过调用pthread库的pthread_create函数创建子线程,pthread_create库函数会调用libc库的mmap函数进行线程栈的分配。共享线程栈的方法是:在共享库文件中对pthread_create和mmap库函数进行重载。当主线程调用pthread_create创建新线程时,共享库文件会截获到该行为并开始监控mmap库函数的调用。在真正调用mmap库函数分配栈时,共享库文件会截获mmap库函数然后将线程栈与洗牌进程进行共享。
另外,在一个实施例中,应用所依赖的所有库在进程间是共享的,操作系统只会为库代码申请一块物理内存区域,目的是减少应用程序对物理内存的消耗。由于全生命周期随机化方法会对工作进程内的所有代码做随机化处理,因此库里的代码会被改变,但操作系统的copy-on-write机制能够保障一个进程对库代码的修改不会影响到其他进程的库代码。操作系统为库代码分配的是写时拷贝的内存区域,即当一个进程修改库代码时,操作系统(OS)会为该进程的库代码所对应的物理内存做一份拷贝,然后让该进程使用拷贝后的物理内存区域。因此,该进程对库代码的修改不会影响到其他进程的库代码。
本发明提出了一种新的适用于应用程序的持续随机化的防御方法,以抵御通过内存泄露漏洞进行的代码重用攻击。本发明中,通过持续随机化的防御方法在应用程序的执行过程中周期性地对程序的代码进行随机化,这样攻击者通过内存泄露漏洞所读取的代码会很快被随机化机制抹掉,无法被用于代码重用攻击。并且,该防御方法始终维护了DEP机制,不存在遭受代码注入攻击的隐患。本发明的方案还能够隐藏随机后的代码进而阻止攻击者搜集代码指针快速找到随机后的代码,从而提升防御效果。另外,本发明的机制还能够确保应用代码在动态随机时运行不发生崩溃。最后,本发明的方案对应用程序引入的性能开销较小。当具有多核机器的硬件资源时,可将随机化任务转移到单独的处理器核上,从而使随机化的周期和所引入的开销都非常小。
图6示出了本发明一个实施例的洗牌进程处理Parsec benchmarks和SPEC2006benchmarks一遍的时间,其中(a)部分示出了处理Parsec benchmarks的时间,(b)部分示出了处理SPEC2006benchmarks的时间。可以看出,平均完成一遍随机化的周期在150ms(随机周期为代码生成周期的2倍,因为第一个版本只有在第二个版本生成后才能抹掉)以内,随机周期远小于现有文献中所公开的攻击者读取代码组织载体进行攻击的周期。
图7示出本发明一个实施例的洗牌进程在不同随机化处理时间间隔下的运行开销。参考图7,当以1s作为随机间隔时,本发明的防御方法所引入的开销小于7%。
最后应说明的是,以上实施例仅用以描述本发明的技术方案而不是对本技术方法进行限制,本发明在应用上可以延伸为其它的修改、变化、应用和实施例,并且认为所有这样的修改、变化、应用、实施例都在本发明的精神和教导范围内。
Claims (11)
1.一种抵御代码重用攻击的方法,其特征在于,包括下列步骤:
1)在工作进程运行过程中,洗牌进程生成工作进程的新版本代码并将其存入代码缓存区,所述代码缓存区被工作进程和洗牌进程所共享;
2)所述工作进程完成新旧版本代码的切换;
在所述步骤1)中,对于所述新版本代码,洗牌进程做随机化处理确保新代码的布局与之前的旧代码不同。
2.根据权利要求1所述的抵御代码重用攻击的方法,其特征在于,所述步骤1)之前,所述洗牌进程在启动时进行初始化,包括:洗牌进程对工作进程的所有代码段进行反汇编并记录下中间表示,识别代码段中的函数信息,分析函数内的执行流并划分基本块。
3.根据权利要求2所述的抵御代码重用攻击的方法,其特征在于,所述步骤1)中,所述新版本代码的生成方法包括下列子步骤:
11)对旧版本代码的函数内的基本块进行乱序处理;
12)在基本块内部随机插入一些无关指令,得到新版本代码。
4.根据权利要求1所述的抵御代码重用攻击的方法,其特征在于,所述步骤2)包括下列子步骤:
21)洗牌进程触发工作进程中断;
22)洗牌进程将工作进程由旧版本代码迁移至新版本代码;
23)洗牌进程唤醒工作进程。
5.根据权利要求4所述的抵御代码重用攻击的方法,其特征在于,所述步骤22)包括下列子步骤:
221)洗牌进程对工作进程的栈上的所有返回地址进行同步;
222)洗牌进程对工作进程的PC寄存器状态进行同步;
223)使代码指针指向新版本代码的位置。
6.根据权利要求5所述的抵御代码重用攻击的方法,其特征在于,所述步骤223)还包括:洗牌进程在进行新旧代码迁移时,在工作进程原有函数的入口处插入跳转指令使其指向新版本函数位置。
7.根据权利要求6所述的抵御代码重用攻击的方法,其特征在于,所述步骤223)还包括:先跳转到地址表,查找所述新版本代码的相应函数的存储地址,然后再将代码指针指向所述新版本代码的相应函数;所述地址表用于存储所有新版本代码的函数的存储地址。
8.根据权利要求7所述的抵御代码重用攻击的方法,其特征在于,用gs段寄存器指向所述地址表的首地址,所述步骤223)还包括:利用gs段寄存器跳转指令实现对所述地址表的查找。
9.根据权利要求7所述的抵御代码重用攻击的方法,其特征在于,在每次生成新版本代码时,所述地址表的存储位置随之发生变化。
10.根据权利要求9所述的抵御代码重用攻击的方法,其特征在于,在每次生成新版本代码时,所述地址表内部表项之间进行乱序处理。
11.根据权利要求1所述的抵御代码重用攻击的方法,其特征在于,对于多线程应用程序,工作进程中所有线程共用同一份代码,所有线程的栈都共享给洗牌进程,所述步骤2)中,所有线程都同步完成新旧版本代码的切换。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510501698.XA CN105022956B (zh) | 2015-08-14 | 2015-08-14 | 一种抵御代码重用攻击的方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201510501698.XA CN105022956B (zh) | 2015-08-14 | 2015-08-14 | 一种抵御代码重用攻击的方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN105022956A CN105022956A (zh) | 2015-11-04 |
CN105022956B true CN105022956B (zh) | 2018-11-09 |
Family
ID=54412919
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201510501698.XA Active CN105022956B (zh) | 2015-08-14 | 2015-08-14 | 一种抵御代码重用攻击的方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN105022956B (zh) |
Families Citing this family (15)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN106096407B (zh) * | 2016-05-31 | 2020-02-18 | 华中科技大学 | 一种代码复用攻击的防御方法 |
CN106372501B (zh) * | 2016-08-22 | 2019-03-26 | 南京大学 | 一种针对rop攻击的防御方法 |
CN106529224A (zh) * | 2016-10-27 | 2017-03-22 | 南京大学 | 基于rop攻击特点的二进制混淆方法 |
CN107220537B (zh) * | 2017-05-25 | 2021-02-23 | 南京大学 | 一种程序内存布局信息泄露行为的检测方法 |
CN108491694A (zh) * | 2018-03-26 | 2018-09-04 | 湖南大学 | 一种动态随机化防御Cache攻击的方法 |
CN109298880B (zh) * | 2018-08-09 | 2022-02-18 | 恒生电子股份有限公司 | 多版本代码生成方法、设备及电子设备 |
CN109446802A (zh) * | 2018-11-13 | 2019-03-08 | 国网江苏省电力有限公司电力科学研究院 | 一种抵抗实时代码复用攻击的防御方法 |
CN109543401B (zh) * | 2018-11-23 | 2021-05-04 | 中国人民解放军战略支援部队信息工程大学 | 基于控制流锁的sgx侧信道攻击防御方法 |
US11036852B2 (en) * | 2019-03-14 | 2021-06-15 | LGS Innovations LLC | System and method for software diversification |
CN110502933B (zh) * | 2019-07-05 | 2021-07-13 | 中国科学院信息工程研究所 | 一种可抵抗基于flush操作的cache攻击的软硬协同计时器实现方法和系统 |
US11947663B2 (en) | 2019-09-24 | 2024-04-02 | The Trustees Of Columbia University In The City Of New York | Control flow protection based on phantom addressing |
US11341241B2 (en) * | 2019-11-08 | 2022-05-24 | International Business Machines Corporation | Enhancing memory safe programming using a page frame tag mechanism |
CN111797388A (zh) * | 2020-06-12 | 2020-10-20 | 武汉大学 | 基于运行时随机化的JavaScript引擎内存信息泄露防御方法及系统 |
CN114448660A (zh) * | 2021-12-16 | 2022-05-06 | 国网江苏省电力有限公司电力科学研究院 | 一种物联网数据接入方法 |
CN114756856B (zh) * | 2022-06-15 | 2022-08-23 | 中国海洋大学 | 一种基于函数动态载入的代码重用攻击防御方法 |
Citations (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1564098A (zh) * | 2004-04-09 | 2005-01-12 | 南京大学 | 一种防止缓冲区溢出攻击的动态堆栈内存管理方法 |
Family Cites Families (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20110191848A1 (en) * | 2010-02-03 | 2011-08-04 | Microsoft Corporation | Preventing malicious just-in-time spraying attacks |
CN102799493A (zh) * | 2012-06-21 | 2012-11-28 | 北京伸得纬科技有限公司 | 一种对具有自我保护的目标进程实现拦截的方法 |
CN102982283B (zh) * | 2012-11-27 | 2015-07-22 | 蓝盾信息安全技术股份有限公司 | 一种杀死受保护的恶意计算机进程的系统及方法 |
CN103399927B (zh) * | 2013-08-05 | 2016-11-02 | 百度在线网络技术(北京)有限公司 | 分布式计算方法和装置 |
-
2015
- 2015-08-14 CN CN201510501698.XA patent/CN105022956B/zh active Active
Patent Citations (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1564098A (zh) * | 2004-04-09 | 2005-01-12 | 南京大学 | 一种防止缓冲区溢出攻击的动态堆栈内存管理方法 |
Also Published As
Publication number | Publication date |
---|---|
CN105022956A (zh) | 2015-11-04 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN105022956B (zh) | 一种抵御代码重用攻击的方法 | |
CN105224864B (zh) | 一种抵御代码重用攻击的工作进程随机化方法及系统 | |
Volckaert et al. | Cloning your gadgets: Complete ROP attack immunity with multi-variant execution | |
Frigo et al. | Grand pwning unit: Accelerating microarchitectural attacks with the GPU | |
Biondo et al. | The Guard's Dilemma: Efficient {Code-Reuse} Attacks Against Intel {SGX} | |
Williams-King et al. | Shuffler: fast and deployable continuous code {re-randomization} | |
Bigelow et al. | Timely rerandomization for mitigating memory disclosures | |
CN104881596B (zh) | 在安全处理环境中修改存储器权限 | |
CN103955438B (zh) | 基于硬件辅助虚拟化技术的进程内存保护方法 | |
CN109923546B (zh) | 虚拟机安全性应用程序的事件过滤 | |
CN102339371B (zh) | 一种检测恶意程序的方法、装置及虚拟机 | |
Volckaert et al. | GHUMVEE: efficient, effective, and flexible replication | |
Österlund et al. | kMVX: Detecting kernel information leaks with multi-variant execution | |
Kirth et al. | PKRU-Safe: Automatically locking down the heap between safe and unsafe languages | |
Voulimeneas et al. | You shall not (by) pass! practical, secure, and fast PKU-based sandboxing | |
CN106897121B (zh) | 一种基于虚拟化技术的无代理客户机进程防护方法 | |
Park et al. | Nojitsu: Locking down javascript engines | |
CN108351935A (zh) | 用于控制有界指针的使用的设备及方法 | |
Gawlik et al. | Detile: Fine-grained information leak detection in script engines | |
Zhang et al. | {SHELTER}: Extending Arm {CCA} with Isolation in User Space | |
Wang et al. | Making information hiding effective again | |
Park et al. | Libmpk: software abstraction for Intel memory protection keys | |
CN108052415B (zh) | 一种恶意软件检测平台快速恢复方法及系统 | |
Guan et al. | Protecting mobile devices from physical memory attacks with targeted encryption | |
CN108563491B (zh) | 一种基于虚拟机的自省自动化管理、配置与自省方法 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |