获取 Sysmon 事件信息


相关资源

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 源码

# 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

文章作者: EXP
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EXP !
 上一篇
使用 GitBook 在 Github 搭建个人网站 使用 GitBook 在 Github 搭建个人网站
前言传统的个人网站在某个知名门户下面注册一个子域名,定制个性化内容。 例如 QQ空间、 博客园、 CSDN 等等。 优点: 无技术门槛 免费 缺点: 站点风格受限: 只能使用有限的模板布置站点 文章数据无法直接迁移: 即使某些门户支持
2020-02-13
下一篇 
获取 Windows 进程信息 获取 Windows 进程信息
相关资源 PROCESSENTRY32 结构: https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32 MODULEENT
2019-12-15
  目录