对A盾原理的小小总结,膜拜A神
A盾的原理是在驱动加载时重载os内核,获取原始ssdt表的地址。
应用层点击查询的代码在文件A-ProtectView.cpp中,每种点击操作调用相应的
query查询函数,在query函数里 ReadFile。读操作的Handle是A盾自定义的操作码,
类似DeviceIoControl的控制码,比如handle 为LIST_SSDT,LIST_INLINEHOOK等。
驱动加载时hook 了NtReadFile,在hook函数里做应用层要求的操作,返回对应的结构buffer
给应用层。
下面分两部分做分析。驱动加载的操作和加载和应用层交互完成具体功能部分。
驱动加载的DriverEntry在SafeSystem.c中,驱动加载时主要完成 1.判断是否是系统刚刚启动。通过当前进程数大于三。2.创建注册表标识驱动运行起来,应用层启动成功删除,主要是判断是否启动成功。3.
判断是否是hook 了 KiFastCallEntry。主要是读取msr寄存器指向该函数的指针,inline 前五个字节到新内核。3.重载内核。重载内核的目的是获取原始ssdt表的地址,方便查询ssdt hook 和 自己调用函数时不经过其他软件的过滤。4.对服务做深度扫描。主要是在驱动里面枚举Services的注册表键值。
加载驱动的核心操作在第3步重载内核ReLoadNtos函数中。函数中操作主要是1.获取已经加载的内核的信息,2.调用InitSafeOperationModule来peload一个ntos避免其它软件hook的过滤,peload的操作需要先获取内核文件大小,通过IRP_MJ_QUERY_INFORMATION自己构造IRP来获取。然后自己通过IRP_MJ_READ自己构造IRP把文件全部读入内存。然后读取dos,nt头和节表,获取模块基地址。然后修复导入表,重定位表。这么麻烦的操作主要是内存中的pe文件和硬盘中的文件会有字节对齐的差别,导致计算ssdt偏移时出错。重载os后,在导出表中搜寻KeServiceDescriptorTable,然后计算它和加载基址的偏移差。通过旧的ssdt偏移,新的os内核基址,旧的os内核基址,_KiServiceTable,计算出重载后的os的ssdt表的基址。得到基址后,修复对ssdt表的地址重定位。将重定位后的ssdt表保存到自己的全局变量中了。3.将导出表里面的函数地址信息保存到自己的结构中。
4.调用ReLoadNtosCALL通过刚才保存的结构从新内核中获取PsGetCurrentProcess,MmIsAddressValid的原始地址,方便后面调用。5.hook KiFastCallEntry开头5个字节跳转到新内核的KiFastCallEntry,再 hook dwReloadKiFastCallEntry,目的不是很清楚。6.初始化和应用层的通信,hook ZwReadFile ,通过handle和应用层通信。hook ZwTerminateProcess保护自己不被结束进程。hook ZwSetValueKey监控start,ImagePath,ServiceDll启动服务,加载驱动。hook ZwCreateSection监控进程启动,object hook,子进程创建,dll加载,dll劫持。7. hook PsCreateSystemThread监控系统线程的创建。8.hook NtReadFile获取csrss.exe的
EPROCESS. Reload win32k根据对话框,判断是否是A盾发送的命令。
和应用层交互完成具体功能部分。按菜单提供的功能从上到下分析。
查询SSDT的hook,分为两种ssdt hook 和inline hook。通过reload os的操作,对比下系统的ssdt和reload os的ssdt就可以出来了。对于inline hook,依次遍历ssdt表的函数,在导出表中找到对应的函数名,然后二分法查找旧的函数和reload 的函数汇编代码,如果不同就是inline hook 了,然后根据call 指令还是jmp指令判断跳转类型。还有简单处理一下多级跳。
查询Shadow SDT的hook,先附加CSRSS进程,查找方法同SSDT hook。
查询内核钩子,对于win32k和ntos处理一样。先检查模块的eat导出表hook,对于导出的函数依次调用反汇编引擎,二分法查找每个函数内是否有hook 指令。它的反汇编引擎是libdasm 开源库。如果是扫描指定模块,方法同上面。
查询Object Hook,对于FileObject,DeviceObject,DriverObject,CmpKeyObject分别进行检测。对于FileObject,检测FileCloseProcedure,IopProcedure,IopQueryName是否被inline hook,这个是文件对象的关闭函数,打开函数,查询函数。对于DeviceObject,检测IopDeleteDevice,IopParseDevice设备对象的删除,打开函数。对于DriverObject,检测IopDeleteDriver函数。对于CmpKeyObject,检测CmpCloseKeyObject,CmpDeleteKeyObject,CmpParseKey,CmpKeyObjectType函数。注册表的是openkey注册表,然后ObReferenceObjectByHandle,ObGetObjectType。
检测驱动模块,检测分为链表检测和A盾运行后的驱动监控,暴力枚举驱动对象。链表检测主要是遍历DriverObject->DriverSection->InLoadOrderLinks。暴力枚举参考了sysnap的代码貌似,搜索MmNonPagedPoolStart开始的内存区,搜索0xf000000个字节,通过判断MajorFunction[28]来确定是不是驱动。
检测内核中线程的创建,主要是hook PsCreateSystemThread监视线程的创建。
检测内核中系统线程或者进程的线程,主要是检测硬编码偏移,eprocess的ThreadListHead 线程链表和ethread的ThreadListEntry。
检测DPC定时器,系统有DPC和IO两种定时器。获取每个cpu的kpcr+0x34->KdVersionBlock->KiProcessorBlock结构,每个cpu有个KPRCB控制结构,里面有KTIMER_TABLE_ENTRY,即DPC定时器的地址。
检测IO定时器,在IoInitializeTimer定时器初始化函数中,搜寻到nt!IopTimerQueueHead定时器链表
指针的偏移指令,然后枚举这个链表。
检测系统回调,分别检测文件系统,创建进程,创建线程,loadImage,BugCheck,关机回调,LeaveSession注销回调。对于文件系统回调链表,在IoRegisterFsRegistrationChange函数搜索IopFsNotifyChangeQueueHead回调链表的地址。对于进程,是在PsSetCreateProcessNotifyRoutine搜索回调数组的指令偏移。对于线程,是在PsSetCreateThreadNotifyRoutine搜索回调数组的指令固定偏移。对于LoadImage是在PsSetLoadImageNotifyRoutine中搜索回调数组指令偏移。对于BugCheck,是搜索KeRegisterBugCheckCallback函数中的回调例程指令地址。关机回调是搜索IoRegisterShutdownNotification的固定偏移。对于注销回调,是搜索SeRegisterLogonSessionTerminatedRoutine中的固定偏移。
检测工作队列线程。硬编码WorkSuspendThread检查。可以枚举ExWorkerQueue。
检测过滤驱动,分别枚举\\FileSystem,\\Driver目录下的驱动。依次调用ZwOpenDirectoryObject,
ZwQueryDirectoryObject打开目录对象,查询目录对象,然后遍历设备栈看AttachedDevice附加设备。
检测Ntfs驱动例程,Peload 驱动文件ntfs.sys,找到驱动入口点DriverEntry后,硬编码找到派遣例程,
重定位ntfs,然后找到各种irp_mj_xx的派遣例程地址。
检测TcpIp驱动例程,Nsiproxy网络netBios驱动例程,KbdClass,Mouclass,Atapi。即网络,键盘,鼠标的驱动派遣例程。方式同ntfs。Atapi是Windows IDE/ATAPI 硬盘的小端口驱动程序。Nsiproxy是以前的
netio.sys驱动。
检测系统进程,主要是遍历Eprocess中的ActiveProcessLinks进程链表。
检测系统服务,分为普通检测和深度检测。普通检测就是驱动中枚举注册表CurrentControlSet\Services。深度检测就是在系统启动时在注册表刚初始化好时枚举依次,然后做一次对比。
检测网络连接,主要是显示网络连接状态。先reload tcpip.sys和nsiproxy.sys,然后自己构建一个
IRP向Tcpip驱动发送IOCTL_TCP_QUERY_INFORMATION_EX查询,然后打印出来。
检测被动防御,主要是向驱动查询日志信息,驱动启动后会记录日志信息,比如进程,线程创建等。
本机所有数据的监控。这个是自己注册了一个Ndis协议驱动,监控所有发送出去的包。当开启监控时,
加载A-ProtectTcpSniffer.sys协议驱动,向该驱动发送控制码IOCTL_NDIS5PKT_BIND_ADAPTER绑定网卡,
发送IOCTL_NDIS5PKT_SET_OID_VALUE控制码设置网卡信息,然后创建A-Protect-TcpSniffer.txt记录文件
最后开启一个线程注册事件死循环等待ndis激活事件,事件激活后输出到记录文件中。向协议驱动发送读请求,然后驱动中把请求队列包中的一个包复制到输出缓冲区。驱动在ReceiveHandler中把包保存到接收队列里。
检测启动项,主要是在驱动中读Winlogon,CurrentVersion,Installed Components,Print\Monitors,Print\Providers注册表项传给应用层。
一键体检。主要是在应用层调用前面的检测方式输出到文件中。
下面是手动配置中的功能,在文件ProtectSetting中。
强制删除文件。就是把文件对象FileObject的SECTION_OBJECT_POINTERS结构的DataSectionObject和ImageSectionObject两个域清空,常规代码。
禁止加载驱动。就是hook SeSinglePrivilegeCheck,在权限检查的时候都返回失败。
强制环保重启就是KeBugCheck(POWER_FAILURE_SIMULATE),其实是HalReturnToFirmware。
一键卸载360主要是PspTerminateThread结束360进程里面的所有线程。然后删除目录和注册表。
禁止创建进程,禁止创建文件,进程服务回写,禁止内核线程,禁止全局钩子,关闭dll劫持防护在开源代码中目前还没有实现。
对A盾原理的小小总结,膜拜A神的更多相关文章
- YYLabel计算富文本高度-膜拜大神
http://www.jianshu.com/p/07cd655fee7e YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:C ...
- ListView实现原理
转载:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListView了 ...
- Android ListView工作原理完全解析,带你从源码的角度彻底理解
版权声明:本文出自郭霖的博客,转载必须注明出处. 目录(?)[+] Adapter的作用 RecycleBin机制 第一次Layout 第二次Layout 滑动加载更多数据 转载请注明出处:h ...
- Android ListView工作原理完全解析(转自 郭霖老师博客)
原文地址:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListVie ...
- Android ListView工作原理全然解析,带你从源代码的角度彻底理解
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...
- 深入理解RunLoop
网上看的一篇文章,写的真好,我得多看几次好好理解理解 膜拜大神,转载至此便于学习查看. 此处标明原文链接:http://blog.ibireme.com/2015/05/18/runloop/ ...
- 【CImg】霍夫变换——直线检测
霍夫变换——直线检测 考古debug,其实很久之前就解决的bug......一直忘记过来改文章....欸 =============================原文================ ...
- JAVA学习博客---2015.5
上一次的学习博客写的和流水账差不多,有点生硬的和背目录一样,所以既然学习的目的是程序,那么这个月的学习博客就用程序来说点东西吧.这个月看了一些C和JAVA的视频,开始看别人写的程序,能看的懂但是自己去 ...
- 《Xenogears》(异度装甲)隐含的原型与密码
<Xenogears>(异度装甲)隐含的原型与密码 X 彩虹按:一种高次元的“生命体”,因“事故”被抓来当成“超能源”,其实那不只是“无限的能源”而已,“它”是有意志的!在我们眼里看来,这 ...
随机推荐
- 关于if else 和 三目运算符的效率问题-java
1.从类型转换上看,因为三目运算符在做判断的时候需要考虑到类型转换的问题,而if else 不需要考虑类型转换. 所以 if else 效率高一点. 2.从总体上看 A:需要考虑到循环自身所占用的时间 ...
- 吉首大学校赛 I 滑稽树上滑稽果 (Lucas + 莫队)
链接:https://ac.nowcoder.com/acm/contest/925/I来源:牛客网 题目描述 n个不同的滑稽果中,每个滑稽果可取可不取,从所有方案数中选取一种,求选取的方案中滑稽果个 ...
- django_websocket实现简单聊天室
一.安装模块 pip install channels pip install channels-redis 二.代码 #websocket_v1/settings.py INSTALLED_APPS ...
- (转)即时通讯IM OpenFire源码学习之三:在Eclipse中构建源码
转:http://blog.csdn.net/huwenfeng_2011/article/details/43412617 源码搭建 下载地址: 地址:http://www.igniterealti ...
- STM32嵌入式开发学习笔记(一)
本文中,笔者将介绍使用嵌入式开发工具Keil uVision5,使用C语言,对微处理器STM32F103C8进行嵌入式开发. 开发使用C语言,首先需要新建一个C语言文件,将其设为主函数的入口,因此,将 ...
- angularjs 中使用 service 在controller 之间 share 对象和数据
在做angularjs 的UI 时,我们经常会遇到一个页面之间有几个controller,在controller 之间share 公共的一些数据和方法就变得比较困难,目前推荐的做法是创建一个servi ...
- HVM(Hardware-Assisted Virtualization)
A set of extra instructions is added that can be used by a process in VMX rootmode. These instructio ...
- POJ3630-Phone List-Trie字典树模板题
Given a list of phone numbers, determine if it is consistent in the sense that no number is the pref ...
- socket API CSocket CAsyncSocket 用法及区别
要进行网络编程就要和Socket打交道,Socket有同步阻塞方式和异步非阻塞方式两种使用,事实上同步和异步在我们编程的生涯中可能遇到了很多,而Socket也没什么特别.虽然同步好用,不费劲,但不能满 ...
- JS Window对象 计时器setInterval() 在执行时,从载入页面后每隔指定的时间执行代码。
计时器setInterval() 在执行时,从载入页面后每隔指定的时间执行代码. 语法: setInterval(代码,交互时间); 参数说明: 1. 代码:要调用的函数或要执行的代码串. 2. 交互 ...