本发明属于系统安全技术领域,具体涉及一种驱动层防注入方法、装置及客户端。
背景技术:
异步过程调用(APC:asynchronous procedure call)是指函数在特定线程中被异步执行。在Microsoft Windows操作系统中,APC是一种并发机制,用于异步IO或者定时器。
客户端程序的稳定性和安全性是必不可少的参考指标。某些第三方模块会有漏洞(Bug)的存在,这些漏洞会通过APC的方式注入到其它客户端程序,从而带来客户端程序的不稳定,由此带来负面的用户体验和反馈。因此,如何减少第三方模块注入给软件所造成的影响便成了客户端软件稳定性中的一个不可或缺的环节。
现有技术中,尚未发现在驱动层拦截第三方模块APC注入的技术。
技术实现要素:
因此,本发明提出一种驱动层防注入方法、装置及客户端。所述驱动层防注入方法包括如下步骤:
创建驱动层防注入动态链接库,所述驱动层防注入动态链接库包含第一钩子函数和驱动层注入模块名单;建立所述驱动层防注入动态链接库与应用程序之间的静态链接,以使得所述应用程序的主线程被建立时,所述驱动层防注入动态链接库被首先调用,所述第一钩子函数和所述驱动层注入模块名单被加载;响应于所述应用程序的主线程对第三方模块的加载,判断所述被加载的第一钩子函数返回的第三方模块是否属于所述驱动层注入模块名单;若是,通过第一钩子函数拦截所述返回的第三方模块。
所述驱动层防注入装置包括如下模块:
驱动层防注入动态链接库创建模块,用于创建驱动层防注入动态链接库,所述驱动层防注入动态链接库包含第一钩子函数和驱动层注入模块名单;静态链接建立模块,用于建立应用程序与所述驱动层防注入动态链接库之间的静态链接,以使得当所述应用程序的主线程被建立时,所述驱动层防注入动态链接库被首先调用,所述第一钩子函数和所述驱动层注入模块名单被加载;判断模块,用于判断所述被加载的第一钩子函数返回的模块是否属于所述驱动层注入模块名单;拦截模块,用于在被加载的第一钩子函数返回的模块属于所述驱动层注入模块名单时,拦截第一钩子函数返回的所述模块。
所述驱动层防注入客户端包括前述的装置。
本发明具有如下有益效果:本发明能够在进程创建主线程时即对可能存在的驱动层注入进行识别和拦截,有效拦截驱动层的第三方模块注入,从而提升系统的安全性和稳定性。
附图说明
下面结合附图对本发明的具体实施方式作进一步详细的说明;
图1是本发明实施例一提供的驱动层防异步过程调用注入方法流程图。
图2是本发明实施例一提供的驱动层防异步过程调用注入方法流程图。
图3是本发明实施例二提供的驱动层防异步过程调用注入方法流程图。
图4是本发明实施例三提供的防异步过程调用注入装置结构示意图。
图5是本发明实施例三提供的获取异步过程调用(APC)注入模块名单模块结构示意图。
图6是本发明实施例三提供的防异步过程调用动态链接库创建模块结构示意图。
图7是本发明实施例四提供的包含本发明装置的通用计算机系统结构示意图。
具体实施方式
为了使本技术领域的人员更好地理解本发明方案,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分的实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都应当属于本发明保护的范围。
本发明涉及的技术术语解释如下:
ntdll.dll:该动态链接库描述了windows本地NTAPI的接口。是重要的Windows NT内核级文件。当Windows启动时,ntdll.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。ntdll.dll是Windows系统从ring3到ring0的入口。位于Kernel32.dll和user32.dll中的所有win32 API最终都是调用ntdll.dll中的函数实现的。ntdll.dll中的函数使用SYSENTRY进入ring0,函数的实现实体在ring0中。
user32.dll(Windows User API Client DLL):该动态链接库是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。
kernel32.dll:该动态链接库是Windows 9x/Me中非常重要的32位动态链接库文件,属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。
上述三个动态链接库都属于系统动态链接库,其不会被第三方模块注入。
静态链接:静态链接的时候,载入代码就会把程序会用到的动态代码或动态代码的地址确定下来,静态库的链接可以使用静态链接,动态链接库也可以使用静态链接的方法链接导入库。
动态链接方法:使用动态链接方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序。
静态链接与动态链接在运行时的比较:静态库和应用程序编译在一起,在任何情况下都能运行,而动态库是动态链接,顾名思义就是在应用程序启动的时候才会链接,所以,当用户的系统上没有该动态库时,应用程序就会运行失败。
实施例一:
本实施例提供一种驱动层防异步过程调用(APC)注入方法,如图1所示,方法包括如下步骤:
S101,获取异步过程调用(APC)注入模块名单。
S102,创建防异步过程调用动态链接库(ApcRefuseInject.dll)。所述防异步过程调用注入动态链接库中包含LdrLoadDLL的钩子函数和APC注入模块名单。在本实施例中,LdrLoadDLL即所述动态链接库加载函数。
S103,建立与所述防异步过程调用注入动态链接库的静态链接。
S104,在创建主线程时,调用所述防异步过程调用动态链接库,加载LdrLoadDLL的钩子函数,获取经过编译的所述APC注入模块名单。
S105,根据所述LdrLoadDLL的钩子函数和APC注入模块名单判断是否存在APC注入模块;若存在,拦截所述APC注入模块。
在所述步骤S101中,获取异步过程调用(APC)注入模块名单,如图2所示,该步骤进一步包含如下子步骤:
S1011,注册驱动层映像加载回调函数。
在具体的实施过程中,驱动层映像加载回调函数可以通过PsSetLoadImageNonifyRoutine来注册和加载回调。
S1012,根据所述驱动层映像加载回调函数判断是否加载指定动态链接库;若是,则进行蓝屏调试。
S1013,分析蓝屏dump,若奔溃的栈为KiUserApcDispatcher,则判断所述动态链接库为是通过驱动层APC注入的。
S1014,将所述模块加入APC注入模块名单。
在所述步骤S102中,创建防异步过程调用注入动态链接库(ApcRefuseInject.dll),在创建ApcRefuseInject.dll的同时,还导出LdrLoadDLL的钩子函数,所述APC注入模块名单被编译于LdrLoadDLL的钩子函数中。该步骤还可能进一步包含如下子步骤:
S1021,仅基于ntdll.dll、user32.dll和kernel32.dll创建防异步过程调用注入动态链接库(ApcRefuseInject.dll)。
在步骤S1021中,ApcRefuseInject.dll的建立仅依靠ntdll.dll、user32.dll和kernel32.dll建立是因为这三个动态链接库为系统动态链接库,依靠这三个动态链接库建立的防异步过程调用注入动态链接库只会调用系统模块,而不会调用任何三方模块,这就保证了ApcRefuseInject.dll本身不存在被三方模块APC注入。
S1022,导出用于拦截APC注入的函数Hook_LdrLoadDll,该函数为LdrLoadDll的钩子函数,用于获取LdrLoadDll函数返回的加载模块。
在具体的实施方式中,步骤S101获取到的APC注入模块名单被以二进制形式编译到该模块中。
在所述步骤S103中,建立与防异步过程调用注入动态链接库(ApcRefuseInject.dll)之间的静态链接。
建立静态链接保证在主线程启动时,防异步过程调用注入动态链接库首先被调用,LdrLoadDll的钩子函数优先于其他模块被加载。
在所述步骤S104中,创建主线程,加载LdrLoadDLL的钩子函数编译所述黑名单。
由于与ApcRefuseInject.dll之间的静态链接关系,当创建主线程时,该动态链接库首先被调用,其中的LdrLoadDLL的钩子函数被加载,编译于钩子函数中的APC注入模块名单被编译,通常是二进制的形式。由于ApcRefuseInject.dll仅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的风险,通过其来对其他模块是否被注入进行判断也是安全的。
在所述步骤S105中,根据所述LdrLoadDLL的钩子函数判断是否存在APC注入模块;若存在,拦截所述APC注入模块。
判断是否存在APC注入可以是一个比较的过程,该过程比较LdrLoadDLL的钩子函数返回的模块是否属于APC注入模块名单。但是该比较过程不能使用字符串比较函数,因为字符串比较函数会调用除ntdll.dll、user32.dll和kernel32.dll之外的动态链接库,这会造成被第三方模块APC注入的风险。具体的实施过程中,可以采用手动比较的方式来实现。
在本发明中,APC注入名单与传统的病毒库并不相同,其会被编译于LdrLoadDLL函数的钩子函数中,以例如二进制的形式存在。并且其与钩子函数的返回值进行比较时,也不会使用系统的字符串比较函数,而使用手动设定的循环比较方式。
实施例二:
本实施例提供一种防异步过程调用(APC)注入装置,如图3所示,所述方法包括如下步骤:
S201,创建防异步过程调用动态链接库(ApcRefuseInject.dll)。
所述防异步过程调用动态链接库中包含LdrLoadDLL的钩子函数和APC注入模块名单。
APC注入模块名单可以通过诸如蓝屏调试的方式事先获得。
步骤S201还可以进一步包含如下两个子步骤:
S2021,仅基于ntdll.dll、user32.dll和kernel32.dll创建防异步过程调用注入动态链接库(ApcRefuseInject.dll)。
在步骤S2021中,ApcRefuseInject.dll的建立仅依靠ntdll.dll、user32.dll和kernel32.dll建立是因为这三个动态链接库为系统动态链接库,依靠这三个动态链接库建立的防异步过程调用注入动态链接库只会调用系统模块,而不会调用任何三方模块,这就保证了ApcRefuseInject.dll本身不存在被三方模块APC注入。
S2022,导出用于拦截APC注入的函数Hook_LdrLoadDll,该函数为LdrLoadDll的钩子函数,用于获取LdrLoadDll函数返回的加载模块。
在具体的实施方式中,APC注入模块名单被以二进制形式编译到该模块中。
S202,建立与所述防异步过程调用动态链接库之间的静态链接。
建立静态链接保证在主线程启动时,防异步过程调用注入动态链接库首先被调用,LdrLoadDll的钩子函数优先于其他模块被加载。因为APC注入多数是发生在进程创建主线程的时候,所以必须在进程创建主线程的时候,加载钩子函数,并对可能存在的APC注入进行判定和然后拦截。
S203,在创建主线程时,调用所述防异步过程调用动态链接库,加载LdrLoadDLL的钩子函数,获取经过编译的所述APC注入模块名单。
由于与ApcRefuseInject.dll之间的静态链接关系,当创建主线程时,该动态链接库首先被调用,其中的LdrLoadDLL的钩子函数被加载,编译于钩子函数中的APC注入模块名单被编译,通常是二进制的形式。由于ApcRefuseInject.dll仅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的风险,通过其来对其他模块是否被注入进行判断也是安全的。
S204,根据所述LdrLoadDLL的钩子函数和APC注入模块名单判断是否存在APC注入模块;若存在,拦截所述APC注入模块。
判断是否存在APC注入可以是一个比较的过程,该过程比较LdrLoadDLL的钩子函数返回的模块是否属于APC注入模块名单。但是该比较过程不能使用字符串比较函数,因为字符串比较函数会调用除ntdll.dll、user32.dll和kernel32.dll之外的动态链接库,这会造成被第三方模块APC注入的风险。具体的实施过程中,可以采用手动比较的方式来实现。
在具体的实施过程中,手动比较方式包括建立循环函数,在所述循环函数的循环中逐一比较APC注入模块名单与所述LdrLoadDLL的钩子函数返回的模块。
因为LdrLoadDLL的钩子函数会返回如下值:
动态链接库的路径设置;
动态链接库的属性设置;
动态链接库的名称;
动态链接库所引用的句柄。
建立一个循环函数,在单个循环中比较LdrLoadDLL的钩子函数返回的动态链接库与APC注入模块名单中的一个APC诸如名称,如果发现返回的动态链接库名称存在于名单中,则说明模块存在APC注入,需要对注入进行拦截。
在具体的实施过程中,所述拦截所述APC注入模块包括将所述LdrLoadDLL的钩子函数中的动态链接库的句柄设置为空,如此动态连接库将不会被调用,对应的APC注入也被拦截。
在本发明中,APC注入名单与传统的病毒库并不相同,其会被编译于LdrLoadDLL函数的钩子函数中,以例如二进制的形式存在。并且其与钩子函数的返回值进行比较时,也不会使用系统的字符串比较函数,而使用手动设定的循环比较方式。
实施例三:
本实施例提供一种防异步过程调用(APC)注入装置,如图4所示,所述装置包括如下模块:
APC注入模块名单获取模块,用于获取APC注入模块名单,如图5所示,其包括如下子模块:
注册子模块,用语注册驱动层映像加载回调函数。
蓝屏调试子模块,用于根据所述驱动层映像加载回调函数判断是否加载指定动态链接库;若是,则进行蓝屏调试。
分析子模块,用于分析蓝屏dump,判断奔溃的栈是否为KiUserApc-Dispatcher,若是,则判断所述动态链接库为是通过驱动层APC注入的。
将所述模块加入APC注入模块名单。
防异步过程调用动态链接库创建模块,用于创建防异步过程调用动态链接库(ApcRefuseInject.dll),所述防异步过程调用动态链接库包含LdrLoadDLL的钩子函数和APC注入模块名单。
该模块创建防异步过程调用注入动态链接库(ApcRefuseInject.dll),并且在创建ApcRefuseInject.dll的同时,还导出LdrLoadDLL的钩子函数,APC注入模块名单被编译于LdrLoadDLL的钩子函数中。如图6所示,该模块还可能进一步包含如下子模块:
系统动态链接库链接模块,仅基于ntdll.dll、user32.dll和kernel32.dll创建防异步过程调用注入动态链接库(ApcRefuseInject.dll)。
该子模块的作用是ApcRefuseInject.dll仅依靠ntdll.dll、user32.dll和kernel32.dll建立。因为这三个动态链接库为系统动态链接库,依靠这三个动态链接库建立的防异步过程调用注入动态链接库只会调用系统模块,而不会调用任何三方模块,这就保证了ApcRefuseInject.dll本身不存在被三方模块APC注入。
钩子函数导出模块,该子模块的作用是导出用于拦截APC注入的函数Hook_LdrLoadDll,该函数为LdrLoadDll的钩子函数,用于获取LdrLoadDll函数返回的加载模块。
在具体的实施方式中,APC注入模块名单被以二进制形式编译到该模块中。
静态链接建立模块,用于建立与所述防异步过程调用动态链接库之间的静态链接。
建立静态链接保证在主线程启动时,防异步过程调用注入动态链接库首先被调用,LdrLoadDll的钩子函数优先于其他模块被加载。
主线程创建模块,用于创建主线程,调用所述防异步过程调用动态链接库,加载LdrLoadDLL的钩子函数,获取经过编译的所述APC注入模块名单。
由于与ApcRefuseInject.dll之间的静态链接关系,当创建主线程时,该动态链接库首先被调用,其中的LdrLoadDLL的钩子函数被加载,编译于钩子函数中的APC注入模块名单被编译,通常是二进制的形式。由于ApcRefuseInject.dll仅依靠ntdll.dll、user32.dll和kernel32.dll建立,其不存在被APC注入的风险,通过其来对其他模块是否被注入进行判断也是安全的。
在加载钩子函数时,如果使用回调函数,则会有死锁产生。在该步骤中,在进程创建主线程的时候加载LdrLoadDLL的钩子函数,而不通过模块加载回调LOAD_IMAGE_NOTIFY_ROUTINE来加载钩子函数,能够有效避免在加载回调过程的死锁问题。
拦截模块,根据所述LdrLoadDLL的钩子函数和APC注入模块名单判断是否存在APC注入模块;若存在,拦截所述APC注入模块。
判断是否存在APC注入可以是一个比较的过程,该过程比较LdrLoadDLL的钩子函数返回的模块是否属于APC注入模块名单。但是该比较过程不能使用字符串比较函数,因为字符串比较函数会调用除ntdll.dll、user32.dll和kernel32.dll之外的动态链接库,这会造成被第三方模块APC注入的风险。具体的实施过程中,可以采用手动比较的方式来实现。
在具体的实施过程中,手动比较方式包括建立循环函数,在所述循环函数的循环中逐一比较APC注入模块名单与所述LdrLoadDLL的钩子函数返回的模块。
因为LdrLoadDLL的钩子函数会返回如下值:
动态链接库的路径设置;
动态链接库的属性设置;
动态链接库的名称;
动态链接库所引用的句柄。
建立一个循环函数,在单个循环中比较LdrLoadDLL的钩子函数返回的动态链接库与APC注入模块名单中的一个APC诸如名称,如果发现返回的动态链接库名称存在于名单中,则说明模块存在APC注入,需要对注入进行拦截。
在具体的实施过程中,所述拦截所述APC注入模块包括将所述LdrLoadDLL的钩子函数中的动态链接库的句柄设置为空,如此动态连接库将不会被调用,对应的APC注入也被拦截。
在本发明中,APC注入名单与传统的病毒库并不相同,其会被编译于LdrLoadDLL函数的钩子函数中,以例如二进制的形式存在。并且其与钩子函数的返回值进行比较时,也不会使用系统的字符串比较函数,而使用手动设定的循环比较方式。
实施例4:
本发明涉及的装置可应用于客户端中,所述客户端可以是诸如台式机、笔记本电脑、移动终端(例如智能手机)、ipad等。
当然,装置也可应用于平台中。或者,所述装置或系统也可以软件的形式运行于终端(客户端)上。
图7示出了上述装置或系统或服务器的一种通用计算机系统结构。
上述计算机系统包括总线,处理器1、存储器2、通信接口3、输入设备4和输出设备5通过总线相互连接。其中,总线在计算机系统各个部件之间传送信息。
处理器1可以是通用处理器,例如通用中央处理器(CPU)、网络处理器(Network Processor,简称NP)、微处理器等,也可以是特定应用集成电路(application-specific integrated circuit,ASIW),或一个或多个用于控制本发明方案程序执行的集成电路。还可以是数字信号处理器(DSP)、专用集成电路(ASIC)、现成可编程门阵列(FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。
处理器1可包括主处理器,还可包括基带芯片、调制解调器等。存储器2中保存有执行本发明技术方案的程序,还可以保存有操作系统和其他关键业务。具体地,程序可以包括程序代码,程序代码包括计算机操作指令。更具体的,存储器2可以包括只读存储器(read-onlymemory,ROM)、可存储静态信息和指令的其他类型的静态存储设备、随机存取存储器(random access memory,RAM)、可存储信息和指令的其他类型的动态存储设备、磁盘存储器、flash等等。
输入设备4可包括接收用户输入的数据和信息的装置,例如键盘、鼠标、摄像头、扫描仪、光笔、语音输入装置、触摸屏、计步器或重力感应器等。
输出设备5可包括允许输出信息给用户的装置,例如显示屏、打印机、扬声器等。
通信接口3可包括使用任何收发器一类的装置,以便与其他设备或通信网络通信,如以太网,无线接入网(RAN),无线局域网(WLAN)等。
处理器1执行存储器2中所存放的程序、指令或者代码,以及调用其他设备,并与操作系统交互或者调用操作系统中的部分指令,用于实现本发明实施例的如下各个步骤:
创建防异步过程调用动态链接库(ApcRefuseInject.dll),所述防异步过程调用动态链接库包含LdrLoadDLL的钩子函数和APC注入模块名单。
建立与所述防异步过程调用动态链接库之间的静态链接。
创建主线程,调用所述防异步过程调用动态链接库,加载LdrLoadDLL的钩子函数,获取经过编译的所述APC注入模块名单。
根据所述LdrLoadDLL的钩子函数和APC注入模块名单判断是否存在APC注入模块;若存在,拦截所述APC注入模块。
在一个具体实施过程中,方法还包括:获取APC注入模块名单。
在一个具体实施过程中,获取APC注入名单包括如下步骤:
注册驱动层映像加载回调函数;根据所述驱动层映像加载回调函数判断是否加载指定动态链接库;若是,则进行蓝屏调试;分析蓝屏dump,判断奔溃的栈是否为指定栈,若是,则判断所述动态链接库为是通过驱动层APC注入的;将所述模块加入APC注入模块名单。
在一个具体实施过程中,所述防异步过程调用动态链接库仅依靠ntdll.dll、user32.dll和kernel32.dll建立。
在一个具体实施过程中,在创建主线程时,LdrLoadDLL的钩子函数先于其他模它被加载。
在一个具体实施过程中,所述根据所述LdrLoadDLL的钩子函数和APC注入模块名单判断是否存在APC注入模块步骤中,采用采用手动比较的方式判断LdrLoadDLL的钩子函数返回的模块是否属于APC注入模块名单。
在一个具体实施过程中,所述的手动比较方法包括建立循环函数,在所述循环函数的循环中逐一比较APC注入模块名单与所述LdrLoadDLL的钩子函数返回的模块。
在一个具体实施过程中,所述拦截所述APC注入模块包括将所述LdrLoadDLL的钩子函数中的动态链接库的句柄设置为空。
专业人员还可以进一步意识到,结合本文中所公开的实施例描述的各示例的单元及算法步骤,能够以电子硬件、计算机软件或者二者的结合来实现,为了清楚地说明硬件和软件的可互换性,在上述说明中已经按照功能一般性地描述了各示例的组成及步骤。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本发明的范围。
结合本文中所公开的实施例描述的方法或算法的步骤可以直接用硬件、处理器执行的软件模块,或者二者的结合来实施。软件模块可以置于随机存储器(RAM)、内存、只读存储器(ROM)、电可编程ROM、电可擦除可编程ROM、寄存器、硬盘、可移动磁盘、WD-ROM、或技术领域内所公知的任意其它形式的存储介质中。
对所公开的实施例的上述说明,使本领域专业技术人员能够实现或使用本发明。对这些实施例的多种修改对本领域的专业技术人员来说将是显而易见的,本文中所定义的一般原理可以在不脱离本发明的精神或范围的情况下,在其它实施例中实现。因此,本发明将不会被限制于本文所示的这些实施例,而是要符合与本文所公开的原理和新颖特点相一致的最宽的范围。