天天看點

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

上文講解了sysmon的ring3部分實作原理,本文則開始講解ring0部分。Sysmon的ring0是一個minifilter類型的驅動,内部實作了程序資訊、檔案通路資訊以及系統資料庫通路資訊的記錄,下面開始具體講解它的實作流程。

  • 驅動DriverEntry的初始化

從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;           
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

然後從pRegistry系統資料庫中去擷取sysmon的政策規則

微軟輕量級系統監控工具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”

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

然後再次擷取L”Parameters”項下面的對應的L”Rules”的KeyValues資訊,這裡是驅動設定的規則。

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

下面展示出部分規則的數組

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

上面的過程結束後就開始判斷作業系統是否支援flt

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

如果支援隻實作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。

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

然後根據作業系統是否支援FltRegisterFilter(Driver, &g_Registration, &g_pFilter);

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

具體建立了哪些minifilter,接着看結構體

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
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原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

為了記錄系統資料庫sysmon還系統資料庫系統資料庫CmRegisterCallback(RegisterCallback, 0, &Cookie);回調,

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

為了記錄程序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);           
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

為了擷取管道的事件,它挂接了裝置L

\\Device\\NamedPipe

,建立了L

\\Device\\SysmonPipeFilter

的過濾裝置

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

至此sysmon的DriverEntry的初始化動作基本結束了。

  • IRP_MJ_DEVICE_CONTROL例程

Case 0x83400000:

打開驅動開啟标志,并且擷取且儲存目前UI程序的句柄

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

Case  0x83400004:

Ring3請求事件資訊,并傳回到ring3的緩沖區

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

Case 0x83400008:

加載政策規則

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

Case 0x8340000C:

擷取傳入程序的相關資訊(包括TokenUser、pTokenStatics、TokenGroup、TokenSeesion)

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

還會擷取程序pImagePathName、pCommandLine、CurrentDirectory

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

擷取程序的CreateTime

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

該事件類型為4或者1

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
  • 檔案資訊的記錄

Minifilter的PreOperation(PFLT_CALLBACK_DATA pData, PFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext)例程為主要的判斷邏輯例程,先判斷目前FileObject的路徑是否為管道路徑,管道事件直接記錄上報事件

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

特别判斷下IRP_MJ_SET_INFORMATION、IRP_MJ_CLEANUP,并且分别上報_,注意在判斷IRP_MJ_SET_INFORMATION的時候隻記錄了RequestorMode是1即USER_MODE,并且是設定FileBasicInformation的請求。

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

PreOperation處理完畢,則PostOperation(PFLT_CALLBACK_DATA pData, PFLT_RELATED_OBJECTS pFltFileObj, PVOID CompletionContext, int Flags)對前者處理的上下文CompletionContext進行記錄日志或者釋放的處理,以IRP_MJ_SET_INFORMATION為例,PostOPerate則對PreOperate的CompletionContext的資料進行上報。

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
  • 系統資料庫資訊的記錄

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原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
  • 程序操作過濾

Sysmon注冊了程序操作過濾,g_ObRegisterCallbacks(&g_CallbackRegistration, &RegistrationHandle);,

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

他隻記錄操作類型為OB_OPERATION_HANDLE_CREATE,并且隻記錄A程序操作B程序,A和B不是同一個程序,注意RtlWalkFrameChain這個函數是擷取目前操作線程的線程棧,KeQuerySystemTime(&pOpenInfo.CreateTime);是擷取目前系統時間,并且會把這些資訊上報。

  • 其他重點技術細節
  1. 程序子產品的枚舉
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

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;

};           
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
  1. 程序參數的擷取

大緻可以看到如下,首先要KeStackAttachProcess程序的空間,然後擷取PEB位址,從PEB中的到ProcessParameters的結構

微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

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;

};           

可以看到該結構中程序參數相關的各種資訊。

  1. 程序Token相關資訊的擷取
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)
微軟輕量級系統監控工具sysmon原理與實作完全分析(下篇)

都是通過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;           

需要擷取那個就可以選擇那一個。

本文大緻講解完畢,内部還有很多很有意思的技術細節由于篇幅原因,讀者可以自己深入挖掘,在做一個産品的時候,我們可以分析他人的産品,不僅可以了解他人的産品的長處和不足,同時也可以補充自己産品的不足的之處,一個好的産品就是在不斷的琢磨研究與推翻,更重要的是細節的展現才能做好産品。