现在的位置: 首页 > 综合 > 正文

ActiveX控件的保护技术之保护方案研究

2013年08月29日 ⁄ 综合 ⁄ 共 2995字 ⁄ 字号 评论关闭

1.2保护ActiveX控件遭受0day溢出攻击的方法

1.2.1 地址空间随机化简介

从上面的栈溢出实现的过程可知,攻击实现的关键是获得溢出指针(jmp esp指令的地址),从而利用溢出指针实现跳转到shellcode。因为在windows系统中诸如kernel32.dlluser32.dll之类的动态链接库几乎被所有的进程加载,且加载基地址始终相同。攻击可以在自己的系统上搜索这些DLL中的类似jmp esp指令的地址,然后把它作为在目标系统中的溢出指针,就可以准确地实现溢出跳转。根据上面的分析可知,如果能改变系统每次运行起来之后加载DLL的基地址的话,就能很好的抑制溢出攻击的实现。地址空间随机化技术可以很好地解决利用静态地址的溢出攻击,但是不能解决相对地址攻击、信息泄露攻击和本地攻击。
本文提出函数行为预测方法来杜绝0day攻击。

1.2.2 函数行为预测

1.2.2.1 函数溢出点分析

因为ActiveX控件的实现体是DLLDLL的导出函数作为接口提供给程序使用。如果某个导出函数存在0day漏洞的话,攻击者可以通过这个存在漏洞的接口实现溢出攻击。一个函数可能存在的可以被利用的漏洞地点无非是两个地方:一是函数体内部某个地方由于调用其它函数而发生溢出,从而导致在函数未执行完就遭受攻击;二是函数体内部漏洞利用,导致函数执行ret返回后发生溢出,程序执行流程发生改变。函数溢出点见图1-8

1.2.2.2 行为预测的整体设计

见下图1-9

ActiveX导出函数inline hook设计

 ActiveX的每个导出函数配备一块跳板,导出函数的开头和结尾都采用inline hook进行重定向,使该函数被调用时能最终跳入跳板。

跳板的设计

跳板的设计分成四部分,一是承接导出函数开头调到跳板的上下文,然后跳入分发器;二是指向session链表头指针;三是承接导出函数结尾跳板的上下文,然后跳入分发器;四是指向下块跳板指针。

Session链表

每个session结构体对应一次该函数的调用过程。当应用程序调用ActiveX控件的接口的时候,分发器就会根据进入跳板的上下文来决定是否创建sessionSession结构体中包含一个定时器,一个保存导出函数返回地址的变量(记为FirstCallRet),一个也是保存导出函数返回地址的变量(记为SecondCallRet),一个布尔型变量。其中,定时器作用是session创建时候,设定定时器,当定时器到期的时候,等待定时器的线程就会被唤醒。

分发器设计

分发器总体上完成四步工作,一是创建session;二是把导出函数的返回地址保存进session;三是跳回跳板(pop eax,jmp 跳板+y),四是使定时器到期。

线程和队列设计

 系统中创建两个线程,一个是用来等待定时器(假设为A线程),另外一个是等待信号量(假设为B线程)A线程等待定时器,定时器一旦到期则唤醒,然后把session相关信息放入队列,并把信号量置有信号。线程B等待信号量,一旦信号量有信号则线程B唤醒,线程B读取队列头的session信息,然后根据session中的相关信息来判断是否发生溢出

1.2.2.3 函数行为预测方法保护ActiveX控件免受0day漏洞攻击的过程

I 溢出发生在导出函数的内部ret之前

  见图1-9。函数被调用之后,会进入跳板,跳板使之跳入分发器。分发器为这次调用创建一个session,并保存这次调用的返回地址到sessionFirstCallRet中,同时创建定时器,启动定时器,把定时器放入session中,并置session中的布尔型变量为FALSE

之后有以下两种可能:

如果对该导出函数的调用是正常的情况的话,在导出函数快结束的时候,势必又要跳入跳板,跳板再次进入分发器,分发器根据这次调用的session ID搜索session链表,找到之后把函数返回地址放入该sessionSecondCallRet中,置布尔型变量为TRUE,并置定时器到期。

如果对该导出函数的调用是恶意的话,在导出函数结束之前,势必已经发生溢出并跳入恶意预定的shellcode去执行。在这种情况下,原导出函数的结尾跳转部分未得到执行,关于这次调用的session中的定时器只有自然的到期,并且SecondCallRet为空,布尔型变量为FALSE

对于上面的两种情况,线程B明显可以根据三个变量FiresCallRetSecondCallRet和布尔型变量的不同情况来判断是否中途程序被劫持了。

判读的伪代码如下:

If(布尔型变量 == FALSE)

{

   //

   //说明函数中途被劫持,发生溢出

   //

 

}

Else

  。。。

 

II 溢出发生在导出函数的内部ret之后

见图1-9。函数被调用之后,会进入跳板,跳板使之跳入分发器。分发器为这次调用创建一个session,并保存这次调用的返回地址到sessionFirstCallRet中,同时创建定时器,启动定时器,把定时器放入session中,并置session中的布尔型变量为FALSE

之后有以下两种可能:

如果对该导出函数的调用是正常的情况的话,在导出函数快结束的时候,势必又要跳入跳板,跳板再次进入分发器,分发器根据这次调用的session ID搜索session链表,找到之后把函数返回地址放入该sessionSecondCallRet中,置布尔型变量为TRUE,并置定时器到期。

如果对该导出函数的调用是恶意的话,在导出函数准备返回时,再次跳入跳板。此时,分发器用session ID搜索session链,找到之后, 将栈中的返回地址放入SecondCallRet中,置布尔型变量为TRUE,并置定时器过期。

对于上面的两种情况线程B,可以根据三个变量FiresCallRetSecondCallRet和布尔型变量的不同情况来判断是否中途程序被劫持了。

判读的伪代码如下:

If(布尔型变量 == FALSE)

{

   //

   //说明函数中途被劫持,发生溢出

   //

 

}

Else

  If(FirstCallRet = = SecondCallRet )

    //

    //正常执行ActiveX接口的调用

    //

 

  Else

    //

    //发生栈溢出攻击

    //

2、反逆向方法:
消除符号信息,字节码混淆器可以做到这点。
 DLL
导出表,以函数名导出易被逆向分析,以序号导出不易被逆向分析。
打乱程序,修改程序的规划,逻辑,数据及组织来实现,在保持原有程序的功能不变的基础上最大程度的降低程序的可读性。
嵌入反调试代码

3、反调试方法:
自己手工实现IsDebuggerPresent API
检测内核调试器windbg,调用ZwQuerySystemInformation/NtQuerySystemInformation,返回SYSTEM_KERNEL_DEBUGGER_INFORMATION中,检测DebuggerEnable
检测内核调试器softice,检测int 1中断的异常处理代码是否是STATUS_ACCESS_VIOLATION
设置trap标志,检测是否出现异常,如果没有异常,则表明存在调试器。缺点:pushfdpopad太显眼,检测代码易被绕过。
通过代码校验保护敏感代码。缺点:不能检验硬件断点。

抱歉!评论已关闭.