前情提要
前两次我们分别讲了sysmon的ring3与ring0的实现原理,但是当初使用的版本的是8.X的版本,最新的版本10.X的sysmon功能有所增加,经过分析代码上也有变化。比如增加DNS得功能,这个功能实现也很简单,就是ETW里获取Microsoft-Windows-DNS-Client得数据,但是本篇不讲这个,本续篇主要讲内核里的事件结构。
所有的内核里上报的事件开头基本都是。
ReportSize ReportType struct _Report_Common_Header { ULONG ReportType; ULONG ReportSize; };
下面具体讲解每个事件的结构。
正文开始
1.FileCreate
下图是文件上报事件,除了上报上诉三个字段外,还有ProcessPid、EventCreateTime,FileCreateTime、hashVlaue算法id,hashvalue、三组进程相关的数据用户UserSid、进程ImageFileName、文件名FileName
可以看到内核里上报出来的事件类型是根据是否计算hash来判断,分别是10 、11
struct _Report_File { Common_Header Header; CHAR data[16]; ULONG ProcessPid; ULONG ParentPid; LARGE_INTEGER CreateTime; LARGE_INTEGER FileCreateTime; ULONG HashingalgorithmRulev; CHAR FileHash[84]; ULONG DataLength[4]; CHAR Data2[1]; };
2. 设置文件属性时间改变事件
内核出来的事件Type 值是2
结构体与FileCreate稍微有些不同,少了文件hash的计算的步骤,但是多了一个设置文件改变的时间。
struct _Report_File_SetAttrubute { Common_Header Header; CHAR data[16]; ULONG ProcessPid; ULONG ParentPid; LARGE_INTEGER CreateTime; LARGE_INTEGER FileTime; LARGE_INTEGER FileCreateTime; ULONG DataLength[4]; CHAR Data2[1]; };
3.进程创建事件
进程创建上报事件内核的事件Type值是4或者1
他的结构体如下(具体不在讲解,名字字面意思都能看懂)
struct _Report_Process { Report_Common_Header Header; CHAR data[16]; ULONG ProcessPid; ULONG ParentPid; ULONG SessionId; ULONG UserSid; LARGE_INTEGER CreateTime; LUID AuthenticationId; ULONG TokenIsAppContainer; LUID TokenId; ULONG HashingalgorithmRule; DWORD DataChunkLength[6]; CHAR Data[1]; };
4. 进程退出事件
进程退出事件内核的Type值是3
struct _Report_Process_Create { Report_Common_Header Header; CHAR data[16]; ULONG ProcessPid; ULONG ParentPid; LARGE_INTEGER CreateTime; ULONG SidLength; ULONG XXXXXXX; SID UserSid; CHAR Data[1]; };
可以看到数据有进程id、 父进程id、事件创建时间、UserSid
5. 线程创建事件
内核里的事件类型是7
结构体如下
struct _ Report_Process_Thread { Report_Common_Header Header; CHAR data[16]; LARGE_INTEGER CreateTime; ULONG ThreadOwnerPidv; ULONG ThreadId; ULONG ThreadAddress; ULONG OpenProcessPid; WCHAR DllInfo[261]; WCHAR DllExportInfo[261]; };
DllInfo是指线程所在的模块名,DllExportInfo是该模块的导出表信息
6. OpenProcess事件
内核事件类型是: 9
结构体定义如下:
struct _ Report_OpenProcess { Report_Common_Header Header; CHAR data[16]; ULONG ProcessId; ULONG MyThreadId; ULONG OpenPrcesid; ULONG AccessMask; LARGE_INTEGER CreateTime; ULONG StatckTrackInfoSize; ULONG DataLength[3]; CHAR Data[1]; };
7. 注册表事件
进程注册表操作事件的Type值是12
结构体如下:
struct _Report_Process_Registry { Report_Common_Header Header; CHAR data[16]; ULONG OperateEventType; ULONG ParentPid; LARGE_INTEGER CreateTime; ULONG ProcessPid; ULOG DataLenth[5]; CHAR Data[1]; };
这里要说明的是附加数据段有5个数据
UserSid
RegistryOperateName
进程名带参数
KeyName
ValueName
其中RegistryOperateName的值是根据OperateEventType的值从下面的数组中选取
g_RegistryTypeName dd offset aUnknownEventTy .rdata:100134D8 ; DATA XREF: SysmonCreateRegistryReportInfo+15E↑r .rdata:100134D8 ; "Unknown Event type" .rdata:100134DC dd offset aCreatekey ; "CreateKey" .rdata:100134E0 dd offset aDeletekey ; "DeleteKey" .rdata:100134E4 dd offset aRenamekey ; "RenameKey" .rdata:100134E8 dd offset aCreatevalue ; "CreateValue" .rdata:100134EC dd offset aDeletevalue ; "DeleteValue" .rdata:100134F0 dd offset aRenamevalue ; "RenameValue" .rdata:100134F4 dd offset aSetvalue ; "SetValue" .rdata:100134F8 dword_100134F8 dd 100010h ; DATA XREF: Regist
8. 命名管道事件
内核的事件的Type的值是:13
结构体如下:
struct _Report_Process_NameedPipe { Report_Common_Header Header; CHAR data[16]; ULONG NamedPipeType; ULONG ParentPid; LARGE_INTEGER CreateTime; ULONG ProcessPid; DWORD DataChunkLength[3]; CHAR Data[1]; };
在data块里会输出: NamePipeFileName 和ImageFileName 两个数据
9. 上报错误信息事件
内核的事件Type值是:6
结构体定义:
struct _ _Report_Event_Error { Report_Common_Header Header; CHAR data[16]; ULONG ErrorDataLength[2]; CHAR Data[1]; };
Data信息里会输出两个错误信息的字符串,如:
下面我做一个小实验,以进程信息为例子,向sysomn的驱动发送IO控制码0xXXX0000X(我打码屏蔽了,希望读者自己去发现,不要做伸手党)
LARGE_INTEGER Request; Request.LowPart = GetCurrentProcessId(); Request.HighPart = FALSE; BYTE OutBuffer[4002] = { 0 }; ULONG BytesReturned = 0; if ( SUCCEEDED( DeviceIoControl( hObjectDrv, SYSMON_REQUEST_PROCESS_INFO, &Request, 8. OutBuffer, sizeof(OutBuffer), &BytesReturned, 0 ) ) ) { if ( BytesReturned ) { Report_Process* pSysmon_Report_Process = (_Report_Process *) &OutBuffer[0]; if ( pSysmon_Report_Process->Header.ReportSize ) { CheckServiceOk = TRUE; } } } CloseHandle( hObjectDrv );
看结果:
可以看到结构体上的值都是对的,然后6个DataChunkLenggth都有值,我们在去看下面的Data内存
今天的续篇就此结束,sysmon还是可以挖掘很多很实用得东西,比如每个事件里得ProcessGuid 并不是随机生成得,而是有一定算法得,具体读者可以自行研究发现。
来源:freebuf.com 2020-09-25 16:46:34 by: 浪子_三少
请登录后发表评论
注册