zoukankan      html  css  js  c++  java
  • 对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进程链表。
        检测系统服务,分为普通检测和深度检测。普通检测就是驱动中枚举注册表CurrentControlSetServices。深度检测就是在系统启动时在注册表刚初始化好时枚举依次,然后做一次对比。
        检测网络连接,主要是显示网络连接状态。先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,PrintMonitors,PrintProviders注册表项传给应用层。
        一键体检。主要是在应用层调用前面的检测方式输出到文件中。
        下面是手动配置中的功能,在文件ProtectSetting中。
        强制删除文件。就是把文件对象FileObject的SECTION_OBJECT_POINTERS结构的DataSectionObject和ImageSectionObject两个域清空,常规代码。
        禁止加载驱动。就是hook SeSinglePrivilegeCheck,在权限检查的时候都返回失败。
        强制环保重启就是KeBugCheck(POWER_FAILURE_SIMULATE),其实是HalReturnToFirmware。
        一键卸载360主要是PspTerminateThread结束360进程里面的所有线程。然后删除目录和注册表。
        禁止创建进程,禁止创建文件,进程服务回写,禁止内核线程,禁止全局钩子,关闭dll劫持防护在开源代码中目前还没有实现。 
  • 相关阅读:
    POJ 2723 Get Luffy Out(2-SAT)
    ZOJ 3613 Wormhole Transport
    HDU 4085 Peach Blossom Spring
    NBUT 1221 Intermediary
    NBUT 1223 Friends number
    NBUT 1220 SPY
    NBUT 1218 You are my brother
    PAT 1131. Subway Map (30)
    ZSTU OJ 4273 玩具
    ZSTU OJ 4272 最佳淘汰算法
  • 原文地址:https://www.cnblogs.com/vcerror/p/4289088.html
Copyright © 2011-2022 走看看