上文讲解了sysmon的ring3部分实现原理,本文则开始讲解ring0部分。Sysmon的ring0是一个minifilter类型的驱动,内部实现了进程信息、文件访问信息以及注册表访问信息的记录,下面开始具体讲解它的实现流程。
从DriverEntry(PDRIVER_OBJECT DriverObject, UNICODE_STRING *pRegistry)的pRegistry中截取末尾名称去获取并计算出设备名和DosDevices的名字。
pDriverName = pRegistry->Buffer;
Len = pRegistry->Length >> 1;
pFirstName = &pDriverName[Len];
if ( pFirstName == pDriverName )
{
LABEL_8:
if ( *pFirstName != '\\' )
goto LABEL_10;
}
else
{
while ( *pFirstName != '\\' )
{
--pFirstName;
if ( pFirstName == pDriverName )
goto LABEL_8;
}
}
++pFirstName;
然后从pRegistry注册表中去获取sysmon的策略规则
使用RtlQueryRegistryValues函数,填入5个RTL_QUERY_REGISTRY_TABLE结构体
RTL_QUERY_REGISTRY_TABLE QueryRegTable[5];
RtlInitUnicodeString(&g_ProcessAccessNamesRule, 0);
memset(QueryRegTable, 0, 560u);
QueryRegTable[0].Flags = 1;
QueryRegTable[0].Name = L"Parameters";
QueryRegTable[3].EntryContext = &OptionRulesv18;
QueryRegTable[4].EntryContext = &hash_alogrithms;
QueryRegTable[1].Flags = 304;
QueryRegTable[1].Name = g_Name_ProcessAccessNames;
QueryRegTable[1].EntryContext = &g_ProcessAccessNamesRule;
QueryRegTable[1].DefaultType = 0x7000007;
QueryRegTable[1].DefaultData = &unk_10015C34;
QueryRegTable[1].DefaultLength = 4;
QueryRegTable[2].Flags = 304;
QueryRegTable[2].Name = L"ProcessAccessMasks";
QueryRegTable[2].EntryContext = &g_ProcessAccessMasksRule;
QueryRegTable[2].DefaultType = 0x3000000;
QueryRegTable[3].Flags = 304;
QueryRegTable[3].Name = (PWSTR)&g_wOption;
QueryRegTable[3].DefaultType = 0x4000000;
QueryRegTable[4].Flags = 304;
QueryRegTable[4].Name = (PWSTR)&g_wHashingalgorithm;
QueryRegTable[4].DefaultType = 0x4000000;
RtlQueryRegistryValues(0, g_SysmonRegisterPath.Buffer, QueryRegTable, 0, 0);
if ( !g_ProcessAccessNamesRule.Buffer
|| g_ProcessAccessNamesRule.Length <= 2u
|| g_ProcessAccessNamesRule.MaximumLength <= 4u )
{
RtlFreeUnicodeString(&g_ProcessAccessNamesRule);
RtlInitUnicodeString(&g_ProcessAccessNamesRule, 0);
}
g_OptionRules = (OptionRulesv18 >> 1) & 1;
对应的注册表键分别是L”Parameters”、L”ProcessAccessNames”、 L”ProcessAccessMasks” 、L” Option”、L” Hashingalgorithm”
然后再次获取L”Parameters”项下面的对应的L”Rules”的KeyValues信息,这里是驱动设置的规则。
下面展示出部分规则的数组
上面的过程结束后就开始判断操作系统是否支持flt
如果支持只实现IRP_MJ_CREATE、IRP_MJ_CLOSE 、IRP_MJ_DEVICE_CONTROL三个例程,后续会注册miniFlt过滤,如果不支持Flt就使用老的模式Sfilter的模式
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
if ( IsOpenPipeConnect && !IsSupportFlt )
{
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[1] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CHANGE] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_QUERY_QUOTA] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
DriverObject->MajorFunction[IRP_MJ_SET_QUOTA] = (PDRIVER_DISPATCH)SysmonDispatchIrp;
}
然后就是常规过程,IoCreateDevice、IoCreateSymbolicLink。
然后根据操作系统是否支持FltRegisterFilter(Driver, &g_Registration, &g_pFilter);
具体创建了哪些minifilter,接着看结构体
OperationRegistration dd IRP_MJ_CREATE ; DATA XREF: .data:10015014↓o
.rdata:10013454 dd 0
.rdata:10013458 dd offset PreOperation
.rdata:1001345C dd offset PostOperation
.rdata:10013460 dd 0
.rdata:10013464 dd IRP_MJ_CLEANUP
.rdata:10013468 dd 0
.rdata:1001346C dd offset PreOperation
.rdata:10013470 dd offset PostOperation
.rdata:10013474 dd 0
.rdata:10013478 dd IRP_MJ_SET_INFORMATION
.rdata:1001347C dd 0
.rdata:10013480 dd offset PreOperation
.rdata:10013484 dd offset PostOperation
.rdata:10013488 dd 0
.rdata:1001348C dd IRP_MJ_CLOSE
.rdata:10013490 dd 0
.rdata:10013494 dd offset PreOperation
.rdata:10013498 dd offset PostOperation
.rdata:1001349C dd 0
.rdata:100134A0 dd IRP_MJ_CREATE_NAMED_PIPE
.rdata:100134A4 dd 0
.rdata:100134A8 dd offset PreOperation
.rdata:100134AC dd offset PostOperation
.rdata:100134B0 dd 0
.rdata:100134B4 dd IRP_MJ_OPERATION_END
.rdata:100134B8 dd 0
.rdata:100134BC dd 0
.rdata:100134C0 dd 0
.rdata:100134C4 dd 0
从上可以看到minifilter过滤了IRP_MJ_CREATE、IRP_MJ_CLEANUP、IRP_MJ_SET_INFORMATION、IRP_MJ_CLOSE、IRP_MJ_CREATE_NAMED_PIPE
文件系统相关的注册完毕,然后就是设置一些进程、线程相关的回调函数例程
PsSetLoadImageNotifyRoutine(SysmonLoadImageNotifyRoutine);
PsSetCreateThreadNotifyRoutine(PsCreateThreadNotifyRoutine);
PsSetCreateProcessNotifyRoutine(PsCreateProcessNotifyRoutine, 0);
为了记录注册表sysmon还注册表注册表CmRegisterCallback(RegisterCallback, 0, &Cookie);回调,
为了记录进程open对象的事件注册了ob事件
g_bIsRegisterCallback = 1;
g_OperationRegistration.ObjectType = (POBJECT_TYPE *)PsProcessType;
g_OperationRegistration.Operations = 1;
g_OperationRegistration.PreOperation = PreProcessOperation;
g_OperationRegistration.PostOperation = PostProcessOperation;
g_CallbackRegistration.OperationRegistration = &g_OperationRegistration;
*(_DWORD *)&g_CallbackRegistration.Version = 0x10100;
g_CallbackRegistration.RegistrationContext = 0;
RtlInitUnicodeString(&g_CallbackRegistration.Altitude, L"1000");
Status = g_ObRegisterCallbacks(&g_CallbackRegistration, &RegistrationHandle);
为了获取管道的事件,它挂接了设备L\\Device\\NamedPipe,创建了L\\Device\\SysmonPipeFilter的过滤设备
至此sysmon的DriverEntry的初始化动作基本结束了。
Case 0x83400000:
打开驱动开启标志,并且获取且保存当前UI进程的句柄
Case 0x83400004:
Ring3请求事件信息,并返回到ring3的缓冲区
Case 0x83400008:
加载策略规则
Case 0x8340000C:
获取传入进程的相关信息(包括TokenUser、pTokenStatics、TokenGroup、TokenSeesion)
还会获取进程pImagePathName、pCommandLine、CurrentDirectory
获取进程的CreateTime
该事件类型为4或者1
Minifilter的PreOperation(PFLT_CALLBACK_DATA pData, PFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext)例程为主要的判断逻辑例程,先判断当前FileObject的路径是否为管道路径,管道事件直接记录上报事件
特别判断下IRP_MJ_SET_INFORMATION、IRP_MJ_CLEANUP,并且分别上报_,注意在判断IRP_MJ_SET_INFORMATION的时候只记录了RequestorMode是1即USER_MODE,并且是设置FileBasicInformation的请求。
PreOperation处理完毕,则PostOperation(PFLT_CALLBACK_DATA pData, PFLT_RELATED_OBJECTS pFltFileObj, PVOID CompletionContext, int Flags)对前者处理的上下文CompletionContext进行记录日志或者释放的处理,以IRP_MJ_SET_INFORMATION为例,PostOPerate则对PreOperate的CompletionContext的数据进行上报。
Sysmon初始化的时候注册了一个注册表过滤,CmRegisterCallback(RegisterCallback, 0, &Cookie);回调函数是NTSTATUS __stdcall RegisterCallback(PVOID CallbackContext, PVOID Argument1, PVOID Argument2),参数Argument1是过滤的注册表操作类型,sysmon过滤了0(RegNtDeleteKey / RegNtPreDeleteKey) 、4( RegNtRenameKey\RegNtPreRenameKey)、11(RegNtPostCreateKey)、15(RegNtPostDeleteKey)、16(RegNtPostSetValueKey)、17(RegNtPostDeleteValueKey)、19(RegNtPostRenameKey)27(RegNtPostCreateKeyEx)的注册表操作
Sysmon注册了进程操作过滤,g_ObRegisterCallbacks(&g_CallbackRegistration, &RegistrationHandle);,
他只记录操作类型为OB_OPERATION_HANDLE_CREATE,并且只记录A进程操作B进程,A和B不是同一个进程,注意RtlWalkFrameChain这个函数是获取当前操作线程的线程栈,KeQuerySystemTime(&pOpenInfo.CreateTime);是获取当前系统时间,并且会把这些信息上报。
ZwQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessInformation, 0x18u, 0)获取ProcessInformation的信息,从PebBaseAddress = ProcessInformation.PebBaseAddress;取得进程PEB的地址,在PEB结构中得到LDR的地址,LDR是进程加载模块的结构体,
struct _PEB
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
ULONG CrossProcessFlags;
unsigned __int32 ProcessInJob : 1;
unsigned __int32 ProcessInitializing : 1;
unsigned __int32 ReservedBits0 : 30;
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved[1];
。。。。。。
}
PPEB_LDR_DATA Ldr;这个就是加载模块的结构,有三种加载表内存加载表,加载顺序表,初始化加载表从中可以枚举出模块信息。
struct _PEB_LDR_DATA
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
};
大致可以看到如下,首先要KeStackAttachProcess进程的空间,然后获取PEB地址,从PEB中的到ProcessParameters的结构
ProcessParameters结构如下:
struct _RTL_USER_PROCESS_PARAMETERS
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
PVOID StandardInput;
PVOID StandardOutput;
PVOID StandardError;
CURDIR CurrentDirectory;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32];
ULONG EnvironmentSize;
};
可以看到该结构中进程参数相关的各种信息。
都是通过ZwQueryInformationToken函数去获取,只是是使用不同的ClassInformation类去获取,定义如下
typedef enum _TOKEN_INFORMATION_CLASS {
TokenUser ,
TokenGroups ,
TokenPrivileges ,
TokenOwner ,
TokenPrimaryGroup ,
TokenDefaultDacl ,
TokenSource ,
TokenType ,
TokenImpersonationLevel ,
TokenStatistics ,
TokenRestrictedSids ,
TokenSessionId ,
TokenGroupsAndPrivileges ,
TokenSessionReference ,
TokenSandBoxInert ,
TokenAuditPolicy ,
TokenOrigin ,
TokenElevationType ,
TokenLinkedToken ,
TokenElevation ,
TokenHasRestrictions ,
TokenAccessInformation ,
TokenVirtualizationAllowed ,
TokenVirtualizationEnabled ,
TokenIntegrityLevel ,
TokenUIAccess ,
TokenMandatoryPolicy ,
TokenLogonSid ,
TokenIsAppContainer ,
TokenCapabilities ,
TokenAppContainerSid ,
TokenAppContainerNumber ,
TokenUserClaimAttributes ,
TokenDeviceClaimAttributes ,
TokenRestrictedUserClaimAttributes ,
TokenRestrictedDeviceClaimAttributes ,
TokenDeviceGroups ,
TokenRestrictedDeviceGroups ,
TokenSecurityAttributes ,
TokenIsRestricted ,
TokenProcessTrustLevel ,
TokenPrivateNameSpace ,
TokenSingletonAttributes ,
TokenBnoIsolation ,
TokenChildProcessFlags ,
MaxTokenInfoClass
} TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS;
需要获取那个就可以选择那一个。
本文大致讲解完毕,内部还有很多很有意思的技术细节由于篇幅原因,读者可以自己深入挖掘,在做一个产品的时候,我们可以分析他人的产品,不仅可以了解他人的产品的长处和不足,同时也可以补充自己产品的不足的之处,一个好的产品就是在不断的琢磨研究与推翻,更重要的是细节的体现才能做好产品。
文章浏览阅读7.4k次。1. 问题用json schema校验json数据的时候,遇到报错:java.lang.NoSuchMethodError: org.json.JSONObject.toMap()Ljava/util/Map; at org.everit.json.schema.loader.SchemaLoader$SchemaLoaderBuilder.schemaJson(SchemaLoade..._java.lang.nosuchmethoderror: org.json.jsonobject.tomap()
文章浏览阅读134次。String的不变性String在Java中特别常用,相信很多人都看过他的源码,在JDK中,关于String的类声明是这样的:public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {}可以看到,String类是final类型的,那么也就是说,String是一个不可变对象。不可变对象是在完全创建后其内部状态保持不变的对象。这意味着,一旦对象..._他白天学习晚上工作
文章浏览阅读5.1k次。对于oracle数据库只有物理备份 和逻辑备份 物理备份:是将实际组成数据库的操作系统文件从一处拷贝到另一处的备份过程,通常是从磁盘到磁带。 逻辑备份:是利用SQL语言从数据库中抽取数据并存于二进制文件的过程。 第一类为物理备份,该方法实现数据库的完整恢复,但数据库必须运行在归挡模式下(业务数据库在非归挡模式下运行),且需要极大的外部存储设备,例如磁带 库,具体包
文章浏览阅读4.9k次,点赞2次,收藏6次。一、创建虚拟环境并安装3.7的python1.打开Windows环境下的anaconda:conda create -n name python=3.7 你创建的虚拟环境文件可以在,Anaconda->envs文件下找到2.进入新建的虚拟环境:activate name二、添加清华镜像>conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/>conda c.
文章浏览阅读1.1k次。如下所示: # -*- coding=utf-8 -*-import urllib2import socketimport timeurls = raw_input("Please enter a web address: \n> ")print "\nAccess web page start..."brushNum = 3600for i in range(brushNum):url =..._urlopen 刷新网页
文章浏览阅读253次。2021年安徽省中小学教师招聘考试大纲已公布,安徽中小学教师招聘统一笔试时间是3月28日,现中公教师网整理了2021安徽省中小学教师招聘中学信息技术笔试大纲内容如下所示:一、考试目标与要求(一)考试目标考查考生中学信息技术课程与教学论的基本理论和基本方法,能运用这些基本理论和基本方法解决有关中学信息技术学科教学中的实际问题,具备从事中学信息技术学科教育教学工作所必需的基本教学技能。(二)考试要求1..._如何用逻辑的工具创造性解决语言交流中的问题
文章浏览阅读6.4k次,点赞2次,收藏3次。安装cdh 5.15.2的时候,因为下在的包MD5值,不对了,重新安装Parcel这一步。但是却报异常。现象通过Cloudera WEB界面安装Hadoop过程中,在安装Parcel步骤时,一个节点分配激活失败,报错信息显示”主机运行状况不良”,如下图所示。分析CM的集群是Server-Agent模式的,那么必须有一个唯一的id来标识Server和Agent属于同一个集群,在Agent端..._选定的 parcel 正在下载并安装在群集的所有主机上。
文章浏览阅读3.1k次。斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。斐波那契数列指的是这样一个数列:1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1,..._奇数数列求和python代码
文章浏览阅读4k次。一、单例模式a、单例模式:单例是最简单的很常用的一种设计模式,保证了一个类在内存中只能有一个对象。思路: 1) 如果其他程序能够随意用new创建该类对象,那么就无法控制个数。因此,不让其他程序用new创建该类的对象。 2) 既然不让其他程序new该类对象,那么该类在自己内部就要创建一个对象,否则该类就永远无法创建对象了。 3) 该类将创建的对象对外(整个系统)提供_impl和business属于什么设计模式
文章浏览阅读202次。声明:该文章系转载-转载地址有两个:1:http://epub.itpub.net/3/4.htm2:http://blog.csdn.net/wh62592855/article/details/4759755 如果发生侵权行为,本人将立即停止侵权行为:隔离级别(isolation level) 隔离级别定义了事务与事务之间的隔离程度。 ..._isolation_level
文章浏览阅读3.2k次。如果要为事件处理函数送参数的话,需要在匿名函数(事件函数)外包裹一个匿名函数, 并立即执行。
文章浏览阅读4.2k次。因更换护服务器需要,需要从源端SQLSERVER的数据全部迁移到目标端SQLSERVER服务器上。这里使用完整、事务日志进行备份和还原,及使用SSMS工具进行迁移。_sqlserver增量备份