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神的更多相关文章

  1. YYLabel计算富文本高度-膜拜大神

    http://www.jianshu.com/p/07cd655fee7e YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:C ...

  2. ListView实现原理

    转载:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListView了 ...

  3. Android ListView工作原理完全解析,带你从源码的角度彻底理解

    版权声明:本文出自郭霖的博客,转载必须注明出处.   目录(?)[+] Adapter的作用 RecycleBin机制 第一次Layout 第二次Layout 滑动加载更多数据   转载请注明出处:h ...

  4. Android ListView工作原理完全解析(转自 郭霖老师博客)

    原文地址:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListVie ...

  5. Android ListView工作原理全然解析,带你从源代码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...

  6. 深入理解RunLoop

    网上看的一篇文章,写的真好,我得多看几次好好理解理解 膜拜大神,转载至此便于学习查看. 此处标明原文链接:http://blog.ibireme.com/2015/05/18/runloop/    ...

  7. 【CImg】霍夫变换——直线检测

    霍夫变换——直线检测 考古debug,其实很久之前就解决的bug......一直忘记过来改文章....欸 =============================原文================ ...

  8. JAVA学习博客---2015.5

    上一次的学习博客写的和流水账差不多,有点生硬的和背目录一样,所以既然学习的目的是程序,那么这个月的学习博客就用程序来说点东西吧.这个月看了一些C和JAVA的视频,开始看别人写的程序,能看的懂但是自己去 ...

  9. 《Xenogears》(异度装甲)隐含的原型与密码

    <Xenogears>(异度装甲)隐含的原型与密码 X 彩虹按:一种高次元的“生命体”,因“事故”被抓来当成“超能源”,其实那不只是“无限的能源”而已,“它”是有意志的!在我们眼里看来,这 ...

随机推荐

  1. h5判断设备是ios还是android

    var u = navigator.userAgent, app = navigator.appVersion;var isAndroid = u.indexOf('Android') > -1 ...

  2. vue 绑定 class 和 内联样式(style)

    <div id="app31"> <!--多个属性 ,号隔开--> <!-- v-bind:style="{fontSize: fontSi ...

  3. Android中的surfaceHolder.lockCanvas(null)返回为null详解

    对于新手学习SurfaceView的时候获取lockCanvas的时候总是返回null的问题很是纠结 canvas = surfaceHolder.lockCanvas(new Rect(0, 0, ...

  4. 概率——17icpc西安

    不知道为什么是这样子的.. #include<bits/stdc++.h> using namespace std; int m,n; int main(){ while(scanf(&q ...

  5. 表格排序tablesort小案列

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  6. hive中分隔符‘\001’到底是什么鬼

    答:hive中的默认的是'\001'是一种特由的分隔符 使用的是ascii编码的值,键盘是打不出来的.

  7. [7.18NOIP模拟测试5]星际旅行 题解

    题面(加密) 考场上靠打表yy出的规律进而想到的正解233333 可以把一条双向边拆成两条单向边,这样的话每个点度数都为偶数,符合欧拉图的定义. 那么题目可以转化为:去掉两条边,使图中存在一条欧拉路. ...

  8. NYOJ 737 (石子合并)

    该题是一道DP题,核心思想如下: 某个区间一定是这个区间内的某两个子区间合成的(这两个子区间互补,即这两个区间加起来等于大区间), 所以我们枚举所有的情况,取个最大值即可.因为最初是从2堆石子开始无法 ...

  9. 记一次Tomcat运行失败记录

    记一次Tomcat运行失败记录 如图tomcat运行之后会出现这样的情况,在网上百度之后大部分都说的是web.xml或者其他配置文件的问题,但是根据网上修改了之后却还是老样子. 这里有比较好的网址可以 ...

  10. Editor REST Client

    Editor REST Client 制作一个http请求 请求行 GET https://example.com/comments/1 HTTP/1.1 POST https://example.c ...