3

获取 Sysmon 事件信息

 2 years ago
source link: https://exp-blog.com/lang/getsysmon/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

get_sysmon_event.exe 下载

C++ 源码

/*************************************************************************************************************
 * get_sysmon_event.cpp
 *             
 * Sysmon 事件查询脚本,使用方法:
 *   ./get_sysmon_event.exe 
 *                          -limit 100                              : 一次查询的数量上限(可选,默认值100)
 *                          -id 1                                   : 事件类型(可选,默认值1)
 *                          -ts '2019-12-16T00:00:00.000000000Z'    : 查询开始时间(可选,默认无此条件)
 *                          -te '2019-12-16T08:00:00.000000000Z'    : 查询结束时间(可选,默认值为当前时间)
 *  
 *  ./get_sysmon_event.exe 
 *                          -limit 100   : 一次查询的数量上限(可选,默认值100)
 *                          -query str   : 查询字符串,语法形式形如:
 *    "Event/System[TimeCreated[@SystemTime<'2019-12-16T08:00:00.000000000Z'] and TimeCreated[@SystemTime>'2019-12-05T00:00:00.000000000Z'] and EventID=3]"
 * 
 *************************************************************************************************************/


#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <locale.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib") // winevt.h 库文件


#define EVENTID_PROCESS_CREATE 1    // Sysmon事件ID: 进程创建
#define EVENTID_NETWORK_CONNECT 3   // Sysmon事件ID: 网络连接
#define EVENT_CHANNEL L"Microsoft-Windows-Sysmon/Operational"   // Sysmon事件管道名称
#define EVENT_QUERY L"Event/System[EventID=1]"  // 系统事件查询条件语句
#define EVENT_ITERATOR 10           // 单次迭代事件的个数
#define EVENT_LIMIT 50              // 默认查询返回的事件数量上限
static DWORD _evtLimit = (DWORD) EVENT_LIMIT; // 当前查询返回的事件数量上限



bool isEmpty(const char* str);              // 检测字符串是否为空
bool equal(const char* a, const char* b);   // 比较两个字符串是否相同(忽略大小写)
LPWSTR toLPWSTR(const char* str);           // ASCII字符 -> 宽字符
void delUnASCII(LPWSTR wstr);               // 把非 ASCII 字符替换成 ?

LPWSTR toEvtQuery(int argc, char* argv[]);  // 根据脚本入参生成系统事件查询条件语句
LPWSTR toEvtQuery(int eventId, const char* startTime, const char* endTime);     // 生成系统事件查询条件语句

DWORD printEvents(EVT_HANDLE hEvents, DWORD limit);   // 打印查询得到的系统事件列表
DWORD printEvent(EVT_HANDLE hEvent);        // 打印单个系统事件



int main(int argc, char* argv[]) {
    LPWSTR channel = EVENT_CHANNEL;
    LPWSTR evtQuery = toEvtQuery(argc, argv);

    EVT_HANDLE hEvents = EvtQuery(NULL, channel, evtQuery, EvtQueryChannelPath | EvtQueryReverseDirection);
    if(NULL == hEvents) {
        DWORD errId = GetLastError();
        if (ERROR_EVT_CHANNEL_NOT_FOUND == errId) {
            wprintf(L"[Error %lu] The channel was not found: %s\n", errId, channel);

        } else if (ERROR_EVT_INVALID_QUERY == errId) {
            wprintf(L"[Error %lu] The query is invalid: %s\n", errId, evtQuery);

        } else {
            wprintf(L"[Error %lu] EvtQuery failed.\n", errId);
        }

    } else {
        printEvents(hEvents, _evtLimit);
        EvtClose(hEvents);
    }

    // system("pause");
    return 0;
}



// 根据脚本入参生成系统事件查询条件语句
LPWSTR toEvtQuery(int argc, char* argv[]) {
    int eventId = EVENTID_PROCESS_CREATE;
    char* startTime = "";
    char* endTime = "";
    char* query = "";

    for(int i = 1; i < argc; i += 2) {
        if(equal(argv[i], "-limit")) {
            _evtLimit = (DWORD) atoi(argv[i + 1]);
            _evtLimit = (_evtLimit <= 0 ? EVENT_LIMIT : _evtLimit);

        } else if(equal(argv[i], "-id")) {
            eventId = atoi(argv[i + 1]);
            eventId = (eventId < 0 ? EVENTID_PROCESS_CREATE : eventId);

        } else if(equal(argv[i], "-ts")) {
            startTime = argv[i + 1];

        } else if(equal(argv[i], "-te")) {
            endTime = argv[i + 1];

        } else if(equal(argv[i], "-query")) {
            query = argv[i + 1];
        }
    }
    return (strlen(query) > 0 ? toLPWSTR(query) :
        toEvtQuery(eventId, startTime, endTime));
}



// 生成系统事件查询条件语句
LPWSTR toEvtQuery(int eventId, const char* startTime, const char* endTime) {
    char* evtQuery = NULL;
    if(isEmpty(startTime) && isEmpty(endTime)) {
        evtQuery = new char[26];
        sprintf(evtQuery, "Event/System[EventID=%d]\0", eventId);

    } else if(!isEmpty(startTime) && !isEmpty(endTime)) {
        evtQuery = new char[26 + 62 * 2];
        sprintf(evtQuery, "Event/System[EventID=%d and TimeCreated[@SystemTime>'%s'] and TimeCreated[@SystemTime<'%s']]\0", eventId, startTime, endTime);

    } else if(!isEmpty(startTime)) {
        evtQuery = new char[26 + 62];
        sprintf(evtQuery, "Event/System[EventID=%d and TimeCreated[@SystemTime>'%s']]\0", eventId, startTime);

    } else if(!isEmpty(endTime)) {
        evtQuery = new char[26 + 62];
        sprintf(evtQuery, "Event/System[EventID=%d and TimeCreated[@SystemTime<'%s']]\0", eventId, endTime);
    }
    return toLPWSTR(evtQuery);
}



// 打印查询得到的系统事件列表
DWORD printEvents(EVT_HANDLE hEvents, DWORD limit) {
    DWORD errId = ERROR_SUCCESS;
    DWORD _iterNum = (EVENT_ITERATOR <= limit ? EVENT_ITERATOR : limit);

    DWORD cnt = 0;  // 累计迭代获得的事件数
    while(cnt < limit) {

        DWORD num = 0;   // 本次迭代获得的事件数
        EVT_HANDLE* evtCache = new EVT_HANDLE[_iterNum];  // 缓存

        // 提取事件列表
        if(!EvtNext(hEvents, _iterNum, evtCache, INFINITE, 0, &num)) {
            errId = GetLastError();
            if(errId != ERROR_NO_MORE_ITEMS) {
                wprintf(L"[Error %lu] EvtNext failed.\n", errId);
            }

            delete[] evtCache;
            break;
        }

        // 迭代打印
        for(DWORD i = 0; i < num && cnt < limit; i++, cnt++) {
            errId = printEvent(evtCache[i]);

            if(errId == ERROR_SUCCESS) {
                EvtClose(evtCache[i]);
                evtCache[i] = NULL;

            } else {
                break;
            }
            Sleep(10);
        }

        delete[] evtCache;
        Sleep(10);
    }
    return errId;
}



/* 打印单个系统事件
 *
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385F-C22A-43E0-BF4C-06F5698FFBD9}"/>
    <EventID>1</EventID>
    <Version>5</Version>
    <Level>4</Level>
    <Task>1</Task>
    <Opcode>0</Opcode>
    <Keywords>0x8000000000000000</Keywords>
    <TimeCreated SystemTime="2019-12-17T10:26:56.242881800Z"/>
    <EventRecordID>50077</EventRecordID>
    <Correlation/>
    <Execution ProcessID="1280" ThreadID="1904"/>
    <Channel>Microsoft-Windows-Sysmon/Operational</Channel>
    <Computer>WIN-S1B6IAK3UN2</Computer>
    <Security UserID="S-1-5-18"/>
  </System>
  <EventData>
    <Data Name="RuleName"/>
    <Data Name="UtcTime">2019-12-17 10:26:56.242</Data>
    <Data Name="ProcessGuid">{68E7DA22-AD70-5DF8-0000-0010428D1D01}</Data>
    <Data Name="ProcessId">16256</Data>
    <Data Name="Image">C:\\Program Files\\Sublime Text 3\\sublime_text.exe</Data>
    <Data Name="FileVersion">3188</Data>
    <Data Name="Description">Sublime Text</Data>
    <Data Name="Product">Sublime Text</Data>
    <Data Name="Company">Sublime HQ Pty Ltd</Data>
    <Data Name="OriginalFileName">sublime_text.exe</Data>
    <Data Name="CommandLine">"/C/Program Files/Sublime Text 3/sublime_text.exe" "--crawl" "14516:crawl:11"</Data>
    <Data Name="CurrentDirectory">C:\\Program Files\\Sublime Text 3\\</Data>
    <Data Name="User">WIN-S1B6IAK3UN2\\Administrator</Data>
    <Data Name="LogonGuid">{68E7DA22-383A-5DF8-0000-0020CBFF0200}</Data>
    <Data Name="LogonId">0x2ffcb</Data>
    <Data Name="TerminalSessionId">2</Data>
    <Data Name="IntegrityLevel">High</Data>
    <Data Name="Hashes">SHA256=450AD9A507403C5A3BA42DC6E1910E84E886200AFD190BF4B0B5B95FC066F7E1</Data>
    <Data Name="ParentProcessGuid">{68E7DA22-A908-5DF8-0000-0010A0B40F01}</Data>
    <Data Name="ParentProcessId">14516</Data>
    <Data Name="ParentImage">C:\\Program Files\\Sublime Text 3\\sublime_text.exe</Data>
    <Data Name="ParentCommandLine">"C:\\Program Files\\Sublime Text 3\\sublime_text.exe"</Data>
  </EventData>
</Event>
 */
DWORD printEvent(EVT_HANDLE hEvent) {
    DWORD errId = ERROR_SUCCESS;
    DWORD dwBufferSize = 0;
    DWORD dwBufferUsed = 0;
    DWORD dwPropertyCount = 0;
    LPWSTR pRenderedContent = NULL;

    if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount)) {

        errId = GetLastError();
        if(errId == ERROR_INSUFFICIENT_BUFFER) {
            dwBufferSize = dwBufferUsed;
            pRenderedContent = (LPWSTR) malloc(dwBufferSize);
            if(pRenderedContent) {
                EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);

            } else {
                wprintf(L"[Error %lu] malloc failed.\n", errId);
                errId = ERROR_OUTOFMEMORY;
            }

        } else if(errId != ERROR_SUCCESS) {
            wprintf(L"[Error %lu] EvtRender failed.\n", errId);
        }
    }

    if(pRenderedContent) {
        delUnASCII(pRenderedContent);
        wprintf(L"%ls\n", pRenderedContent);
        wprintf(L"==================\n");
        free(pRenderedContent);
        errId = ERROR_SUCCESS;
    }
    return errId;
}



// 检测字符串是否为空
bool isEmpty(const char* str) {
    return (str == NULL || strlen(str) <= 0);
}



// 比较两个字符串是否相同(忽略大小写)
bool equal(const char* a, const char* b) {
    bool flag = false;
    if(a == NULL && b == NULL) {
        flag = true;

    } else if(a != NULL && b != NULL) {
        flag = (stricmp(a, b) == 0);
    }
    return flag;
}



// ASCII字符 -> 宽字符
LPWSTR toLPWSTR(const char* str) {
    int dwLen = strlen(str) + 1;
    int nwLen = MultiByteToWideChar(CP_ACP, 0, str, dwLen, NULL, 0);
    LPWSTR lpwstr = new WCHAR[dwLen];
    MultiByteToWideChar(CP_ACP, 0, str, dwLen, lpwstr, nwLen);
    return lpwstr;
}



// 把非 ASCII 字符替换成 ?
void delUnASCII(LPWSTR wstr) {
    wchar_t* p = wstr;
    while(*p) {
        if(((int) *p) > 127) {
            *p = '?';
        }
        p++;
    }
}

PowerShell 源码

powershell
# get_sysmon_event.ps1
#
# sysmon事件查询脚本
# Powershell Script 3.0+
# ---------------------------------------------------------------------------------------
# 脚本使用方式:
#
#   .\get_sysmon_event.ps1 -id 1 -limit 10 -h 0 -m -5 -s 0
#
# ---------------------------------------------------------------------------------------

# id: sysmon事件ID (默认值1)
#       1   Process Creation
#       2   Process Changed a File Creation Time
#       3   Network Connection
#       4   Sysmon Service State Changed
#       5   Process Terminated
#       6   Driver Loaded
#       7   Image Loaded
#       8   Create Remote Thread
#       9   Raw Access Read
#       10  Process Access
#       11  File Create
#       12  Registry Event (Object Create and Delete)
#       13  Registry Event (Value Set)
#       14  Registry Event (Key and Value Rename)
#       15  File Create Stream Hash
#       16  Sysmon Configuration Change
#       17  Named Pipe Created
#       18  Named Pipe Connected
#       255 Error
# limit: 限制单次查询最多获取的事件数 (默认值100)
# h: <=0 的整数,标识查询 h 小时内的事件
# m: <=0 的整数,标识查询 m 分钟内的事件
# s: <=0 的整数,标识查询 s 秒内的事件
param([int]$id=1,[int]$limit=100,[int]$h=0,[int]$m=5,[int]$s=0)

if ($id -lt 1) {
  $id=1
}

if ($limit -lt 1) {
  $limit=100
}


$args = @{}
$args.Add("logname", "Microsoft-Windows-Sysmon/Operational")
$args.Add("id", $id)
$args.Add("StartTime", ((Get-Date).AddHours(-$h).AddMinutes(-$m).AddSeconds(-$s)))
$args.Add("EndTime", (Get-Date))


Get-WinEvent -FilterHashtable $args -MaxEvents $limit | Format-Table -Property message -Wrap
# Get-WinEvent -FilterHashtable $args -MaxEvents $limit | Where{$_.Message -notmatch 'keyword'} | Format-Table -Property message -Wrap

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK