非法代码执行的防止方法、非法代码执行的防止用程序以及非法代码执行的防止用程序...的制作方法

文档序号:6496079阅读:214来源:国知局
专利名称:非法代码执行的防止方法、非法代码执行的防止用程序以及非法代码执行的防止用程序 ...的制作方法
技术领域
本发明涉及保护在计算机上动作的程序不受到非法代码引起的动作不完备或者外部攻击的非法代码执行的防止方法、非法代码执行的防止用程序以及非法代码执行的防止用程序的记录媒体。
更详细地讲,涉及检测缓冲区溢出,改善程序的动作不完备的非法代码执行的防止方法,非法代码执行的防止用程序以及非法代码执行的防止用程序的记录媒体。
背景技术
电子计算机的操作系统被复杂地设计出来。从而,在操作系统中,存在称为安全漏洞的弱点。所谓安全漏洞,是由软件设计的缺陷或者错误产生的脆弱性的构造。存在恶意的使用者有时利用操作系统的该安全漏洞,非法地侵入操作系统,进行侵犯、攻击等恶意的行为。作为其方法,有利用存储器的缓冲区溢出的方法。
这里,说明缓冲区溢出。在电子计算机中动作的程序由程序代码和程序数据的两个部分构成。程序代码是用机器语言编写的只用于读出的代码。程序数据是根据操作系统的执行命令执行的程序代码在存储器上的位置等的信息部分。
程序通常保存在计算机的硬盘中。当由操作系统调出并执行程序时,程序整体或者其一部分保存在作为电子计算机的主存储器的RAM(随机访问存储器)中动作。主存储器是能够从计算机的CPU(中央处理装置)直接进行数据读写的存储器,针对每一个保存数据的单位容量建立地址号码进行管理。把主存储器的地址号码小的一方作为高位地址(高位存储器)区,如果地址号码增大,则作为低位地址(低位存储器)区。以下,仅把主存储器作为存储器进行说明。
如果由操作系统读出程序,则存储器的一部分分配给该程序,在该所分配的存储器的高位地址(高位存储器)区中保存程序数据,在低位地址(低位存储器)区中保存程序代码。程序数据分为栈数据(栈数据)、堆数据(堆数据)、状态数据(状态数据)的三个数据区。这三个数据区相互独立配置在存储器中。如果由操作系统从硬盘调用所执行的程序,则首先读出程序代码保存在存储器中。接着,读出程序数据保存在存储器中。
图5是表示电子计算机的存储器的构造的概念图。存储器的高位地址一侧成为栈存储区。在每次执行程序时,栈存储区在这里确保其程序和程序内的子程序用的栈存储器,顺序保存到存储器的低位地址。栈存储器由变元区、返回地址区、栈数据区等构成。
存储器的低位地址一侧由堆数据区、栈数据区、程序代码区等区域构成。栈数据区与程序代码区相比较位于高位地址区一侧,是预约全部变量和staticC++等级号码的存储区。堆数据区位于比栈数据区高位的地址一侧。堆数据区是分配给C语言的malloc( )、alloc( )函数、C++语言的new操作器的区域。
栈存储区用FIFO(后入先出)方式访问。栈存储器保存执行命令结束了以后执行下一个命令的返回地址等函数参数或者局部变量等。该返回地址是非常重要的值。
图6中例示出用C语言编写的程序。当执行程序后,首先执行main( )函数(行1~3),调用第4行的子程序的sub(Date1),使程序的处理移动到第10行。在sub( )子程序中,在第16行的return命令下,把处理移动到调用了sub( )的原来的位置。说明这时在存储器中怎样保存数据。
当调用子程序后,如图7所示,在栈存储区中写入数据。从栈存储区的高位地址一侧保存「向main( )的返回地址」,预约保存子程序内的局部变量的区域。在该例子中,有变量i(第11行)和buf(第12行)。在第14行的strcpy命令下把子程序的变元Data的值复制到buf中。这时,在变元Data的值大于buf的尺寸时,局部变量i根据情况,覆盖到向main( )程序的返回地址上。这样,所确保的存储器的区域中容不下进入的数据,而将其写入到用于其它变量的区域中。这就是缓冲区溢出。由于返回地址被改写为其它的值,因此程序不能够进行正常的动作。
通常结束执行这些程序、程序的子程序和函数后,返回到返回地址表示的位置,继续执行程序。但是,如果在程序的编写方法中有错误,则如在上面说明过的那样,当写入数据时,有可能超过局部变量的确保区域而覆盖返回地址。
由于返回地址的改写而引起的缓冲区溢出的程序通常为不稳定的执行状态。根据情况,程序几乎都是失控或者停止。如果返回地址返回到有意准备的存储器地址,则操作系统不知其为非法代码而继续执行保存在该存储器地址中的命令。利用了缓冲区溢出的脆弱性的攻击就在于如此执行有意准备的代码。
在进行程序的执行管理的操作系统中不能够完全把握这种由缓冲区溢出引起的非法代码的执行。为了防止该非法代码的执行,重要的是如何防止或者能够检测返回地址的篡改和改写。
作为解决该问题的方法,提出了在操作系统中加入修正的方法或者在编译程序中建立防止缓冲区溢出的结构的方法等。作为在操作系统中加入修正的方法,有非专利文献1(Openwall Linux kernel patchproject,UPLhttp//www.openwall.com/linux/)的设计。在该设计中,为了防止开放源的操作系统的缓冲区溢出,用把栈的返回地址区移动到没有执行函数的其它存储区中的方法应对。
作为在编译程序中建立防止存储缓冲区溢出的结构的方法,有非专利文献2(StackGuardSimple Stack Smash Protection go GCC,URLhttp//www.immunix.com/~wagle)。该方法在GCC编译程序中,在栈存储器的低位地址设置保护段,来检测数据的溢出写入。
另外,在专利文献1(美国公开专利号码US2001013094?Al?-?2001-08-09,“Memory device,stack protection system,computer system,compiler,stack protection method,storage mediumand program transmission apparatus”)的情况下,在存储装置中定义保护数值的区域,把栈存储器的数据保存在保护数值的区域中进行保护,执行处理命令。由于在保护数值的区域中保护返回地址等,因此即使执行子程序等处理指令也能够保护程序计数器。

发明内容
在上述任一种方法中,都需要程序代码的变更以及重建。由此,在执行这些方法时花费时间。另外,利用该非法代码执行的代表性的是计算机病毒。当前防止计算机病毒的方法是署名方式,在未知的攻击模型的情况下没有任何效果。从而,在每次发生错误时,都需要变更操作系统,提供批处理文件。
本发明是根据上述那样的技术背景而完成的,达到下述的目的。
本发明的目的在于提供防止保存在电子计算机的存储器的地址中的数据篡改,检测数据篡改的方法,及其程序和程序的记录媒体。
本发明的目的在于提供防止对于程序执行时的栈存储器内的返回地址的篡改和进行检测的方法。
本发明的其它目的在于提供能够不变更硬件、操作系统、核心模式软件、应用软件而是加以利用的非法代码执行的防止功能。
本发明的又一个目的在于提供即使在应用软件以及核心模式软件有缓冲区溢出的脆弱性时也能够有效地防止非法代码执行的功能。
本发明的又一个目的在于在执行非法代码之前进行检测,抑制非法代码的执行。
本发明为了达到上述目的,采用以下的方法。
本发明方案1的非法代码执行的防止方法当由中央运算处理装置执行保存在电子计算机的存储媒体中的程序时,检测保存在存储器的栈存储区的返回地址由于非法代码的执行而被改写的上述存储器的缓冲区溢出,防止发生上述缓冲区溢出。
该非法代码执行的防止方法的特征是备份上述返回地址,当由于上述非法代码的执行而篡改上述返回地址时,根据上述中央运算处理装置的故障排除功能检测上述篡改。
另外,也可以在上述故障排除功能中利用的故障排除寄存器内,记录保存上述返回地址的存储器地址,当篡改了记录在上述故障排除寄存器内的上述存储器地址的值时,上述中央运算处理装置输出出错的信号,进行上述检测。
进而,也可以把上述返回地址保存在没有保存执行程序的数据的存储区中,进行上述备份。
另外,还可以具有把保存在上述栈存储区中的上述返回地址与上述备份了的地址进行比较,检测上述缓冲区溢出的单元。
进而,还可以具有当篡改了上述返回地址时,用所保存的上述返回地址改写上述存储器地址的控制单元。
进而,还可以把保存上述返回地址的上述栈存储区设为只读的属性,保护上述返回地址,当在设定为只读属性的上述栈存储区中进行写入时,上述中央运算处理装置输出出错的信号进行上述检测,具有当接收到上述出错的信号后,用于使上述程序停止或者控制上述程序的流程的控制单元。
上述返回地址也可以是当执行上述程序时调用的过程以及从上述过程调用的线程内的大于等于一个的返回地址。
本发明方案2的非法代码执行的防止用程序用于使计算机动作,使得当由中央运算处理装置执行保存在电子计算机的存储媒体中的程序时,检测保存在存储器的栈存储区中的返回地址由于非法代码的执行而被改写的存储器的缓冲区溢出,防止发生上述缓冲区溢出。
该非法代码执行的防止用程序的特征是由以下步骤构成,这些步骤是当从上述存储媒体调用上述程序时,取得上述程序中的转移命令进行分析的分析步骤、用于抽取上述程序的过程或者线程的上述返回地址的抽取步骤、用于把在上述栈存储区中保存上述返回地址的地址登录到上述中央运算处理装置的故障排除功能的故障排除地址中的登录步骤、当上述程序动作时,用于控制上述程序的流程的控制步骤、登录上述返回地址和上述地址进行备份的备份步骤,在执行上述程序时,当篡改上述返回地址时,通过上述故障排除功能,上述中央运算处理装置输出出错信号,在上述程序的执行中进行中断,把上述程序的流程移动到上述控制步骤。
另外,当改写了上述返回地址时,上述控制步骤还可以具有使上述程序停止的步骤。
进而,当改写了上述返回地址时,上述控制步骤还可以具有用备份的上述返回地址改写上述返回地址的步骤。
进而,当改写了上述返回地址时,上述控制步骤还可以具有保存上述改写了的值的步骤。
还可以具有把保存上述返回地址的上述栈存储区设置成只读的属性,用于保护上述返回地址的保护步骤、当在设定为只读属性的上述栈存储器中进行写入时,上述中央运算处理装置输出出错信号,用于进行上述检测的检测步骤、当接收到上述出错的信号后,用于使上述程序停止或者控制上述程序的流程的上述控制步骤。
进而,上述程序可以是从在应用软件、操作系统的软件模块、核心模式软件中使用的函数、子程序中选择出的大于等于一个的程序。
本发明方案3的非法代码执行的防止用程序的记录媒体是记录了上述非法代码执行的防止用程序的记录媒体。
发明的效果如果依据本发明,则起到以下的效果。
本发明的非法代码防止方法能够不变更硬件、操作系统、核心模式软件、应用软件而防止非法代码的执行。
本发明的非法代码防止方法当应用软件以及核心模式软件具有缓冲区溢出的脆弱性时也能够有效地应对。
本发明的非法代码防止方法能够在执行非法代码之前进行检测,抑制非法代码的执行。


图1是图示出本发明的概要的概念图。
图2是表示本发明的缓冲区溢出的出错检测的概念图。
图3是表示执行文件的装载时的顺序的流程图。
图4是表示执行文件的执行时的顺序的流程图。
图5是表示存储器的构造的图。
图6是例示了程序的主程序和子程序的图。
图7是表示栈存储器的构造的图。
图8是表示驱动器软件起动时的初始化处理的顺序的流程图。
图9是表示过程生成回叫的登录的顺序的流程图。
图10是表示线程生成事件的连接设定的顺序的流程图。
图11是表示正在跟踪CALL、RET等转移命令时的处理过程的流程图。
图12是表示图11的CALL或者JMP处理的处理顺序的流程图。
图13是表示执行CALL命令时的处理的流程图。
图14是表示执行RET命令时的处理的流程图。
图15是表示执行RET命令时的处理的流程图。
图16是表示JPM ESP处理的顺序的流程图。
符号的说明1......软件2......驱动器软件3......文件系统驱动器4......硬盘5......可执行文件6......存储器10......网卡具体实施方式
以下,根据附图具体地说明本发明的最佳实施形态。

以下,说明本发明的实施形态1。
本发明提供检测改写、篡改保存在电子计算机的主存储器中的数据的行为的方法。另外,提供用于根据该方法,检测改写、篡改保存在电子计算机的主存储器中的数据的行为,恢复被改写或者被篡改了的数据的程序。进而,本发明提供记录了该程序的记录媒体。说明本发明的实施形态的概要。
CPU的故障排除功能是用于检测在执行应用程序时发生的错误的功能。为此,在CPU中准备多个称为故障排除寄存器的存储器,利用为监视主存储器的特定地址的动作。在该故障排除寄存器中登录所监视的地址的地址以及CPU动作,当变更该地址的值时CPU检测出该动作,输出出错信号。而且,能够在应用程序的执行中进行中断,使其它的程序动作。
在本实施形态1中,说明检测基于缓冲区溢出的非法代码的执行,防止数据篡改等的程序的动作。当程序在电子计算机上动作时,如在现有技术中说明过的那样,针对每次调用程序、子程序和函数,其返回地址保存在栈存储区中。在电子计算机的CPU的故障排除寄存器中,指定并预先登录保存返回地址的主存储器的地址。
另外,同时把返回地址预先备份在主存储器的其它区域中。如果篡改该地址的数据,则由CPU检测错误,在所执行的程序中进行中断,使控制移动到其它的程序,能够防止数据篡改、非法代码的执行。把备份了的返回地址改写到原来的地址,使程序返回到正常的动作。另外,还能够备份被改写了的地址,在基于缓冲区溢出的计算机病毒攻击的模型分析中利用。
以下,本发明实施形态1的非法代码防止方法为了实现利用了该故障排除寄存器的检测数据的篡改,修复被篡改了的数据的方法,提供驱动器软件层和出错程序。该驱动器软件层具有把握上述的返回地址,登录到故障排除寄存器中进行备份的功能。出错程序提供如果篡改返回地址的数据,则修复该篡改的功能。以下,详细地说明本发明的实施形态1。
图1表示本发明的实施形态的概要。在图1中,图示出在电子计算机上动作的软件1、驱动器软件2、文件系统驱动器3、硬盘4。通常,可执行的程序作为可执行的文件5保存在硬盘4中,按照操作系统的调用命令读出,保存到存储器6中。软件1意味着在电子计算机上动作的应用程序。该应用程序可以是在操作系统的核心模式或者用户模式下动作的任一种程序。
驱动器软件2位于文件系统驱动器3与操作系统提供的服务之间,是进行从操作系统向或者从电子计算机的各设备读出/写入时的控制的程序。
文件系统驱动器3是用于读出在电子计算机内置的或者与电子计算机连接的存储装置中保存的数据,并在该存储装置中写入数据的驱动器。硬盘4通常是在电子计算机中内置的硬盘。但是如果是保存了软件1,能够从操作系统调用执行,则也可以是外装硬盘、闪存、CD-ROM等外存装置。
在本实施形态1中,采用从文件系统调用程序(图1的可执行文件5)的命令经过驱动器软件2向文件系统驱动器3发送的形式。
文件系统驱动器3从硬盘4调用程序,传送给驱动器软件2。驱动器软件2分析程序,把握主程序、子程序,取得各个返回地址,进行检测缓冲区溢出的控制。返回地址是用于按照CALL命令等转移命令输出并保存到栈存储器中,按照RET、RETxx命令返回的地址。
参照图3的流程图说明该一系列的动作。从操作系统或者应用程序起动程序(图1的可执行文件5)(步骤1)。驱动器软件2检测出程序的起动(步骤2)。驱动器软件2分析程序,把握主程序、子程序,取得各个返回地址。驱动器软件2检查通过程序的起动所生成的变元、局部变量、函数地址(步骤3),保存函数地址。具体地讲,检查在程序内执行的呼叫(CALL)、返回(RET、RETN)、跳转(JMP)等转移命令的执行事件,取得并保存返回地址(步骤4)。
而且,驱动器软件2在执行程序的期间,使呼叫命令(CALL命令)等转移命令挂钩,以便能够使控制移动到驱动器软件2(步骤5)。具体地讲,调用OS提供的PsSetLoadlmageNotifyRoutine( ),在过程起动时登录调用的回叫函数(LoadlmageNotifyRoutine)。在线程生成的情况下,取得beginthread( )的开始地址,在该开始地址中设置断点。驱动器软件2在程序的执行时,安装栈存储器上的返回地址的保护和检测篡改的功能(步骤6)。
在返回地址的保护中,利用上述的CPU的故障排除功能。这样,在CPU的故障排除功能内,具有如果改写特定的存储器地址则进行出错输出的功能,能够使控制移动到所指定的地址。这时,在CPU的故障排除寄存器中指定返回地址的存储器地址,当检测到出错时,操作系统输出中断命令,把控制移动到驱动器软件2。
在返回地址中适用该功能。由此,设定成如果改写返回地址,则通过故障排除功能检测到出错,把控制向驱动器软件2移动。驱动器软件2执行在步骤1中指定的程序(步骤7)。
图4是表示检测驱动并执行程序时的缓冲区溢出的顺序的流程图。
在执行程序时如果从操作系统或应用程序执行调用命令(Call命令),则发生CPU的中断,控制移动到驱动器软件2(步骤10~11)。驱动器软件2检查通过程序的执行生成的变元、局部变量、函数地址(步骤12),根据故障排除功能,保护或者存储执行时的栈存储器上的返回地址(步骤13)。
把保存返回地址的栈存储器设定为只读属性进行该保护。当在该栈存储器中进行写入时,CPU发生出错,由于发生CPU的中断,控制移动到驱动器软件2,因此不能够变更、篡改返回地址,能够进行保护。上述的存储把栈存储器上的返回地址备份到存储器的其它区域中保存。当篡改了返回地址时,与该备份返回地址进行比较,能够检验篡改。
而且,驱动器软件3输出命令(IRET)(步骤14),向在步骤11中中断了的执行地址返回控制(步骤15),执行命令(步骤16)。
在程序的执行过程中如果成为缓冲区溢出,则覆盖返回地址,CPU输出出错。另外,在即将从调用的函数返回之前,驱动器软件把在步骤13中保存的返回地址与栈上的返回地址进行比较(步骤17~19)。驱动器软件2检测出错(步骤20)。而且,中断程序的执行,控制向出错程序移动(步骤21)。出错程序(未图示)是在检测到出错时执行,具有停止执行程序,保存栈存储器的内容或者把返回地址用事前保存的数据改写等功能的程序。根据该出错程序,能够停止、继续程序的执行,而且能够保存非法代码(步骤22)。
在图2中图示出从外部攻击计算机的例子。经过网卡10,传送来具有病毒或者非法代码等的外部数据。外部数据经过网卡10、NDIS11、Winsock12保存在存储器6中。当外部数据保存到存储器6中时,如果改写程序的返回地址的一部分或者全部,则CPU输出出错,控制移动到驱动器软件2。驱动器软件2接收该出错检测,挂钩出错程序来应对。
这样,能够全部把握利用了缓冲区溢出的非法侵入和攻击进行对应处理。能够停止执行中的过程,保存栈存储器的内容,继续执行原来的过程等。通过停止过程,停止正在执行的过程,能够制止程序的失控。通过保存栈存储器的内容,能够保存非法代码,能够在以后的分析等作业中把握攻击、病毒的种类及其模型。
本实施形态不仅适应于只在用户模式下动作的应用程序,还能够适应于在核心模式下动作的程序。另外,如果是能够在同样的方法下利用缓冲区溢出的方法的程序,则就都能够适应。
(实施例)示出本发明的实施形态1的实施例。在本实施例中,是Intel公司(登录商标)的32比特结构的处理器,假定安装了命令跟踪功能。具体地讲,在PentiumPro(登录商标)以后开发的处理器或者与该处理器具有互换性的处理器。操作系统是微软公司的Windows2000(登录商标)。
驱动器软件2动作,进行作为用于检测缓冲区溢出的准备的初始化处理,如果执行程序则检测所发生的过程和线程,把握主程序、子程序。而且,驱动器软件2如果检测出存储器溢出,则作为出错程序使过程中断处理动作进行应对。对这些动作详细地进行说明。
如果驱动器软件起动,则进行初始化处理(参照图8,在后面进行说明。)。在该初始化处理中,进行在调用程序时所生成的过程和线程的检测。该初始化处理的详细过程用图8~10的流程图(后述)表示。
在进行了该初始化处理以后,程序开始动作。全部登录并跟踪在该程序的动作过程中执行的跳转(JMP)、呼叫(CALL)、返回(RET)等转移命令。如果执行CALL、RET、RETxx命令时,则检测缓冲区溢出。CALL、RET、RETxx命令的检测在图11、12所示的流程图中表示。
检测了CALL、RET、RETxx命令以后的处理在图13~图16的流程图和与该流程图相对应的说明中的程序代码中表示。
(初始化处理)图8的流程图表示初始化处理的概要。首先,驱动器软件起动,从登记处读入监视缓冲区溢出的过程名(步骤100)。然后,登录监视对象的过程的过程生成回叫(步骤101)。关于该过程生成回叫的登录的详细过程在图9的流程图中表示。然后,把栈记录器初始化,确保存储区(步骤102)。而且,进行监视对象线程的线程生成事件的挂钩设定(步骤103)。然后,开始执行命令的跟踪。
调用OS提供的PsSetLoadImageNotifyRoutine( ),登录在过程起动时调用的回叫函数( )进行过程生成回叫的登录。该回叫函数用以下的标准定义。
void LoadImageNotifyRoutine(PUNICODE_STRING FullImageName,HANDLE ProcessId,PIMAGE_INFO ImageInfo)其次,在图9的流程图中表示过程生成回叫的登录的顺序。如果生成过程,则调用LoadImageNotifyRoutine函数(步骤110)。以下,表示LoadImageNotifyRoutine内的动作。判定是否是所监视的对象的过程(步骤111)。在该判定时,检查在LoadImageNotifyRoutine的变元FullImageName中是否存在成为对象的过程模块名。存在时转移到随后的处理(是)。
取得过程模块的进入点地址(步骤112)。检查在Windows中使用的执行模块文件的起始部分(标题),取得首先执行的函数(进入点)的地址。然后,在进入点,设置断点(步骤113)。这时的程序代码的例子如下。
PVOID ImageBase=(PVOID)ImageInfo->ImageBase;
MZ_HEADER*mz_Header=(MZ_HEADER*)ImageBase;
MZ_NE*mz_ne=(MZ_NE*)((char*)ImageBase+sizeof(MZ_HEADER));I MAGE_NT_HEADERS*ImageNtHeaders=(IMAGE_NT_HEADERS*)((char*)ImageBase+mz_ne->ne_header);char*EntryPoint=(char*)((ULONG)ImageInfo->ImageBase+ImageNtHeaders->OptionalHeader.AddrassOfEntryPoint);
然后,使IA-32命令的跟踪功能有效,为了登录跟踪回叫函数(ASO_Hook_INT01H),改写IDT(中断描述符表)的01H(步骤114)。用于该登录的程序代码如下。
<pre listing-type="program-listing">   IDTR idtr;   PIDTENTRY OIdt;   PIDTENTRY NIdt;   _asm{   SIDT idtr;   }   OIdt=(PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);   gOIdINT01H_Handler=MAKELONG(OIdt[IGATE01].OffsetLow,OIdt[IGATE01].OffsetHigh);   NIdt=&amp;amp;(OIdt[IGATE01]);   _asm{   LEA EAX,ASO_Hook_INT01H//   MOV EBX,NIdt;   MOV [EBX],AX   SHR EAX,16   MOV [EBX+6],AX;   LIDT idtr   }</pre>在过程起动时最初执行的命令中设定硬件断点,以便在执行时调用跟踪回叫函数(ASO_Hook_INT01H)(步骤115)。进行该动作的程序代码如下。
MOV EAX,KickStartAddress//最初に実行される命のアドレスMOV DR0,EAXMOV EAX,DR7OR EAX,0x00000000;//Set LEN0=00(1Byte Length)OR EAX,0x00000000;//Set R/W0=00(On Execution Only)OR EAX,0x00000200;//Set GEOR EAX,0x00000002;//Enable G0MOV DR7,EAX; //Set DR7在每次生成所指定的监视对象的过程的线程时动态实施栈记录器的初始化(参照步骤102)。栈记录器的各栈定义如下。
typedef struct_ASO_STACK_LIST{LIST_ENTRY m_LIstEntry;
ULONG ThreadId;
ULONG*StackPointer;
LONG CurrentStackLocation;
}ASO_STACK_LIST,*PASO_STACK_LIST;
在图10的流程图中表示线程生成事件的挂钩设定(参照步骤103)的顺序。如果生成线程(步骤120),则判定是否是所监视的对象的过程(步骤121)。当所生成的线程是所监视的对象的过程时,取得_beginthread的开始地址(步骤122)。在该开始地址中设置断点(步骤123)。然后,开始跟踪(步骤124)。
在多个线程的系统中,通过把作为生成线程的核心API的NtCreateThread挂钩而适用。为此,改写在调用NtCreateThread时所经过的矢量2E的中断处理程序(ASO_Hook_INT2EH)。这时的程序代码如下。
<pre listing-type="program-listing">  IDTR idtr;  PIDTENTRY OIdt;PIDTENTRY NIdt;_asm SIDT idtr;OIdt=(PIDTENTRY)MAKELONG(idtr.LowIDTbase,Idtr.HllDTbase);gOIdINT2EH_Handler=MAKELONG(OIdt[IGATE2E].OffsetLow,  OIdt[IGATE2E].OffsetHigh);  NIdt=&amp;amp;(OIdt[IGATE2E]);  _asm{   CLI   LEA EAX,ASO_Hook_INT2EH   MOV EBX,NIdt;   MOV [EBX],AX   SHR EAX,16   MOV [EBX+6],AX;   LIDT idtr   STI  }</pre>在线程生成事件(CreateThread( ))的挂钩设定中使用的程序代码如下。
KIRQL OIdIrql;
KeRaiseIrql(HIGH_LEVEL,&amp;OldIrql);
_asm{PUSHAD//for CreateThread()MOV EAX,EBP //現在のEBPMOV EAX,[EAX] //前のEBP(ASO_Hook_INT2BH)MOV EAX,[EAX] //前のEBP(CreateThread)ADD EAX,0x10//Stack+10H(IpStartAddress)MOV EBX,[EAX] //EBX&lt;-Thread addressCMP EBX,0x7800BE4A //if EBX==_beginthread's start_address(2K+SP0)thenJNZ SET_MEMORYBREAK//for_beginthread()MOV EAX,EBP //現在のEBPMOV EAX,[EAX] //前のEBP(ASO_Hook_INT2BH)MOV EAX,[EAX] //前のEBP(CreateThread)MOV EAX,[EAX] //前のEBP(_begInthread)ADD EAX,0x0C//Stack+0CH(start_address)MOV EBX,[EAX] //EBX&lt;-Thread addressSET_MEMORYBREAK:
PUSH EBX //Param1CALL InstallNewInt01 HandlerPOPAD}
这样,当结束一系列的初始化处理后,执行程序,跟踪CALL、RET等转移命令。其次,图11、12的流程图中表示正在跟踪时的处理。在开始跟踪处理后(步骤150),清除DR6的跟踪标志(步骤151),判别CALL命令、RET命令。在图11、图12的转移判定时(步骤154~183),判别CALL、RET、RETN命令,分别成为「至CALL处理」、「至RET处理」、「至RENT处理」。「至CALL处理」、「至RET处理」、「至RENT处理」分别在图13、图14、图15的流程图中表示。
判别CALL、RET、RETN命令时的程序代码如下。
<pre listing-type="program-listing">  //DR6<-0x00000000  MOV EAX,DR6  AND EAX,0xFFFFBFFF  MOV DR6,EAX  //EDX:EAX<-LastBranchFromIp  MOV ECX,0x000001DB;//MSR=0x01DB(LastBranchFromIp)  RDMSR;  PUSH ES  MOV BX,0x001B  MOV ES,BX  MOV EDX,EAX  MOV EAX,ES:[EAX]  POP ES  //  //Branch on Instruction  //  CMP AL,0xE8 //Relative near call  JZ CALL_FOUND  CMP AL,0xFF //Direct near/far call  JZ CALLORJMP_FOUND  CMP AL,0x9A //Direct far call  JZ CALL_FOUND  CMP AL,0xC3 //near RET  JZ RET_FOUND  CMP AL,0xCB //far RET  JZ RET_FOUND  CMP AL,0xC2 //near RET with POP  JZ RETN_FOUND  CMP AL,0xCA //far RET with POP  JZ RETN_FOUND  JMP CALL_NOTFOUND  CALLORJMP_FOUND:  TEST AH,0x10 //CALL/2  JNZ CALL_FOUND  TEST AH,0x18 //CALL/3  JNZ CALL_FOUND  CMP AH,0xE4 //JMP ESP  JZ JMPESP_FOUND  JMP CALL_NOTFOUND</pre>这里,CALL、RET、RETN的判别分别作为CALL_FOUND、RET_FOUND、RETN_FOUND被编码。在程序代码的转移命令下跳转到CALL_FOUND时视为执行CALL命令,进行图13的流程图所示的处理。RET、RETN的情况也相同。
图13中表示执行CALL命令时的处理。当开始执行CALL命令后(步骤200),取得分配给CALL命令的栈存储器的栈段(CS)的地址(步骤201)。然后,取得用CALL命令保存的返回地址的栈点(步骤202)。然后,从栈存储器取得返回地址(步骤203)。这时的程序代码如下。
<pre listing-type="program-listing">  CALL_FOUND:  PUSH ES  //Get Stack segment(CS)  MOV ECX,EBP  ADD ECX,+4+4+4+4+4  MOV EAX,[ECX]  MOV ES,AX  //Get Stack pointer  MOV ECX,EBP  ADD ECX,+4+4+4+4  LES EDX,[ECX]//Now EDX point to Stack Address  //Get RetIP  MOV ECX,EDX  MOV AX,0x001B //Usermode Only  MOV ES,AX //  MOV EDX,ES:[ECX] //Retrieve RetIP on Stack  //  //Now EDX point to RetIP on Stack  //  POP ES</pre>把该取得的返回地址登录到栈记录器中(步骤204)。这时的程序代码如下。
<pre listing-type="program-listing">  KeRalseIrql(HIGH_LEVEL,&amp;amp;OIdIrql);  PASO_STACK_LIST StackList=(PASO_STACK_LIST)gStackList[ThreadId];  if(StackList==0){   //Error  }else if(StackList->CurrentStackLocation>STACK_LIMIT){   StackList=NULL;  }else if(StackList->CurrentStackLocation&gt;=0){   StackList->StackPointer[StackList->CurrentStackLocation]=ExpectedRetIp;   StackList->CurrentStackLocation++;  }  KeLowerIrql(OldIrql);</pre>然后,设定MSR和EFLAG,再次开始命令跟踪(步骤205、206)。用IRETD结束处理。
在图14中表示执行RET命令时的处理。当开始执行RET命令后(步骤250),取得分配给RET命令的栈存储器的栈段(CS)的地址(步骤251)。然后,取得用RET命令指定的返回地址的栈点(步骤252)。然后,从栈存储器取得返回地址(步骤253)。这时的程序代码如下。
<pre listing-type="program-listing">  RET_FOUND:  PUSH ES  //Get Stack segment(CS)  MOV ECX,EBP  ADD ECX,+4+4+4+4+4  MOV EAX,[ECX]  MOV ES,AX  //Get Stack pointer  MOV ECX,EBP  ADD ECX,+4+4+4+4  MOV EAX,[ECX]  LES EDX,[ECX] //Now EDX point to Stack Address  SUB EDX,+4//Back 4Bytes from Current Stack Address  MOV ECX,EDX  MOV AX,0x001B  MOV ES,AX  MOV EDX,ES:[ECX]</pre>然后,从栈记录器检索是否存在与返回地址相同的值(步骤254)。返回地址是在与该RET命令相对应的CALL命令时登录到栈记录器中的地址。但是,在篡改了返回地址的情况下,不能够从栈记录器中找到相同的地址。这时,移动到过程中断处理(下一个代码的Terminate_VirusCode( ))(步骤260)。如果找到相同的地址,则从栈记录器清除一个代码(步骤255)。这时的程序代码如下。
<pre listing-type="program-listing">  KeRaiseIrql(HIGH_LEVEL,&amp;amp;OldIrql);  PASO_STACK_LIST StackList=(PASO_STACK_LIST)gStackList[ThreadId];  If(StackList==0){   //Stack not found  }else if(StackList-&gt;CurrentStackLocation>0){   StackList-&gt;CurrentStackLocation-;   ULONG ExpectedRetIp   =StackList->StackPointer[StackList-&gt;CurrentStackLocation];   StackList-&gt;StackPointer[StackList->CurrentStackLocation]=0;   if(ExpectedRetIp I=ToIp){   LONG i;   BOOLEAN StackFound=FALSE;   for(I=StackList->CurrentStackLocation;i>=0;i-){   if(StackList->StackPointer[i]==ToIp){   LONG j;   for(j=i;j<=StackList->CurrentStackLocation;j++){   StackList->StackPointer[j]=0;   }   StackList->CurrentStackLocation=i;   StackFound=TRUE;   break;   }   }   if(IStackFound){   //Not found   Terminate_VirusCode(FromIp,ToIp,ExpectedRetIp);   }   }  }else{   DbgPrint("Illegal Stack Locationn");  }  KeLowerIrql(OldIrql);</pre>然后,设定MSR和EFLAG,再次开始命令跟踪(步骤256、257)。用IRETD结束处理。
在图15中表示执行RETN命令时的处理。当开始执行RETN命令后(步骤300),取得分配给RETN命令的栈存储器的栈段(CS)的地址(步骤301)。然后,取得用RETN命令指定的返回地址的栈点(步骤302)。然后,从栈存储器取得返回地址(步骤303)。这时的程序代码如下。
<pre listing-type="program-listing">  RETN_FOUND:  //Get Stack Byte Length  ADD EDX,+1  MOV EAX,[EDX]  PUSH ES  PUSH EAX  //Get Stack segment(CS)  MOV ECX,EBP  ADD ECX,+4+4+4+4+4  MOV EAX, [ECX]  MOV ES,AX  //Get Stack pointer  MOV ECX,EBP  ADD ECX,+4+4+4+4  MOV EAX,[ECX]  LES EDX,[ECX]//Now EDX point to Stack Address  POP EAX  MOVZX EAX,EAX  SUB EDX,EAX  SUB EDX,+4  MOV ECX,EDX  MOV AX,0x001B  MOV ES,AX  MOV EDX,ES:[ECX]</pre>然后,从栈记录器检索是否存在与返回地址相同的值(步骤304)。返回地址是在与该RETN命令相对应的CALL命令时登录到栈记录器中的地址。但是,在篡改了返回地址的情况下,不能够从栈记录器中找到相同的地址。这时,移动到过程中断处理(下一个代码的Terminate_VirusCode( ))(步骤310)。如果找到相同的地址,则从栈记录器清除一个代码(步骤305)。这时的程序代码如下。
<pre listing-type="program-listing">  KeRaiseIrql(HIGH_LEVEL,&amp;amp;OldIrql);  PASO_STACK_LIST StackList=(PASO_STACK_LIST)gStackList[Threadid];  if(StackList==0){   //Stack not found  }else if(StackList->CurrentStackLocation>0){   StackList->CurrentStackLocation-;   ULONG ExpectedRetIp   =StackList->StackPointer[StackList->CurrentStackLocation];   StackList->StackPointer[StackList->CurrentStackLocation]=0;   if(ExpectedRetIp I=ToIP){   LONG i;   BOOLEAN StackFound=FALSE;   for(I=StackList->CurrentStackLocation;i>=0;i-){   if(StackList->StackPointer[i]==ToIp){   LONG j;   for (j=i;j<=StackList->CurrentStackLocation;j++){  StackList->StackPointer[j]=0;   }   StackList->CurrentStackLocation=i;   StackFound=TRUE;   break;   }   }   if(IStackFound){  //Not found  Terminate_VirusCode(FromIp,ToIp,ExpectedRetIp);   }  }  }else{  DbgPrint("Illegal Stack Locationn");  }  KeLowerIrql(OldIrql);</pre>然后,设定MSR和EFLAG,再次开始命令跟踪(步骤306、307)。用IRETD结束处理。
在图16中表示执行JMP ESP处理时的处理。JMP ESP是例如经过网络侵入的病毒等为了执行栈存器上的程序代码所必需的命令。因此,不依赖于栈的返回地址的检索结果,由于使用JMP ESP命令执行的模块稀少,因此使其为禁止对象。当判断为是JMP ESP后,进行过程中断处理(步骤351)。
步骤260、310、351的过程中断处理取得在RET、RETN命令以后执行的命令的地址,把其改写为非法命令(INT3等)。继续执行过程,以非法命令停止过程。这时的程序代码如下。
<pre listing-type="program-listing">  void_stdcall Terminate_VirusCode(ULONG FromIp,ULONG ToIp)  {   IsDetected=TRUE;   //Rewrite FromIp(Next instruction of JMP ESP)to INT3   _asm{  PUSH EAX  PUSH EDX  MOV AL,0xCC//INT3  MOV EDX,FromIp  MOV SS:[EDX],AL  POP EDX  POP EAX  }  }</pre>如上所述,能够全部把握并且应对利用了缓冲区溢出的非法入侵和攻击。能够停止所执行的过程,制止程序的失控。
这样的方法也能够适应于有可能实现缓冲区溢出的所有的操作系统。
(其它的实施形态)产业上的可利用性本发明能够在计算机病毒对策、防止来自外部的非法入侵、要求安全的所有领域中利用。特别是,可以在与网络连接的,利用了网络的个人计算机、超级计算机、服务器的系统中利用。可用于个人信息保护、要求电子文件的保密的电子政府、军事、防务相关的系统中。
另外,还可以在检测程序的缺陷、非法代码的使用时加以利用。
权利要求
1.一种非法代码执行的防止方法,该方法在由中央运算处理装置执行保存在电子计算机的存储媒体中的程序时,检测保存在存储器的栈存储区中的返回地址由于执行非法代码而被改写的上述存储器的缓冲区溢出,防止发生上述缓冲区溢出,其特征在于备份上述返回地址,在由于执行上述非法代码篡改了上述返回地址时,通过上述中央运算处理装置的故障排除功能检测上述篡改。
2.根据权利要求1所述的非法代码执行的防止方法,其特征在于在上述故障排除功能中所利用的故障排除寄存器内,记录保存上述返回地址的存储器的地址,当篡改了记录在上述故障排除寄存器中的上述存储器地址的值时,上述中央运算处理装置输出出错的信号进行上述检测。
3.根据权利要求1或2所述的非法代码执行的防止方法,其特征在于把上述返回地址保存在没有保存执行程序的数据的存储区中,进行上述备份。
4.根据权利要求3所述的非法代码执行的防止方法,其特征在于具有把保存在上述栈存储区中的上述返回地址与上述备份的地址进行比较,检测上述缓冲区溢出的单元。
5.根据权利要求3或4所述的非法代码执行的防止方法,其特征在于具有当篡改了上述返回地址时,把上述存储器地址用所保存的上述返回地址改写的控制单元。
6.根据权利要求1或2所述的非法代码执行的防止方法,其特征在于使保存上述返回地址的上述栈存储区成为只读的属性,保护上述返回地址,当在设定为只读属性的上述栈存储区中进行写入时,上述中央运算处理装置输出出错信号进行上述检测,具有当接收到上述出错的信号后,用于停止上述程序或者控制上述程序的流程的控制单元。
7.根据权利要求1~6中选择出的任一项所述的非法代码执行的防止方法,其特征在于上述返回地址是当执行上述程序时调用的过程以及从上述过程调用的线程内的大于等于一个的返回地址。
8.一种非法代码执行的防止用程序,该非法代码执行的防止用程序当由中央运算处理装置执行保存在电子计算机的存储媒体内的程序时,使上述计算机动作,以便检测保存在存储器的栈存储区中的返回地址由于执行非法代码而被改写的存储器的缓冲区溢出,防止发生上述缓冲区溢出,其特征在于包括当从上述存储媒体调用上述程序时,用于取得并分析上述程序中的转移命令的分析步骤;用于抽取上述程序的过程或者线程的上述返回地址的抽取步骤;用于把在上述栈存储区中保存上述返回地址的地址登录到上述中央运算处理装置的故障排除功能的故障排除地址中的登录步骤;当上述程序动作时,用于控制上述程序的流程的控制步骤;登录上述返回地址和上述地址,用于进行备份的备份步骤,当在执行上述程序时篡改了上述返回地址时,通过上述故障排除功能,上述中央运算处理装置输出出错信号,在上述程序的执行中进行中断,使上述程序的流程移动到上述控制步骤。
9.根据权利要求8所述的非法代码执行的防止用的程序,其特征在于当改写了上述返回地址时,上述控制步骤具有使上述程序停止的步骤。
10.根据权利要求8或9所述的非法代码执行的防止用程序,其特征在于当改写了上述返回地址时,上述控制步骤具有用备份了的上述返回地址改写上述返回地址的步骤。
11.根据权利要求8或9所述的非法代码执行的防止用程序,其特征在于当改写了上述返回地址时,上述控制步骤具有保存上述改写了的值的步骤。
12.根据权利要求8所述的非法代码执行的防止用程序,其特征在于包括用于使保存上述返回地址的上述栈存储区成为只读的属性,保护上述返回地址的保护步骤;当在设定为只读属性的上述帧存储区中进行写入时,上述中央运算处理装置输出出错信号,用于进行上述检测的检测步骤;当接收到上述出错的信号后,用于使上述程序停止或者控制上述程序的流程的上述控制步骤。
13.根据从权利要求8~12中选择出的任一项所述的非法代码执行的防止用程序,其特征在于上述程序是从在应用软件、操作系统的软件模块、核心模式软件中使用的函数、子程序中所选择出的大于等于一个的程序。
14.一种非法代码执行的防止用程序的记录媒体,其特征在于记录了从权利要求8~13中选择出的任一项所述的非法代码执行的防止用程序。
全文摘要
本发明提供防止程序执行时的由缓冲区溢出产生的返回地址的篡改和事前检测缓冲区溢出的方法,当改写程序执行时的返回地址时,利用中央运算处理装置的故障清除功能,进行出错输出,根据出错输出,检测返回地址篡改,重新用保存的值改写被篡改了的返回地址进行恢复,另外,当检测出返回地址篡改时,强制结束正在执行的程序。
文档编号G06F21/00GK1886728SQ200480028989
公开日2006年12月27日 申请日期2004年9月3日 优先权日2003年9月4日
发明者小路幸市郎, 武藤佳恭, 野崎隆 申请人:科学园株式会社
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1