基础入门
本篇教程主要介绍iMonitorSDK基础概念和接入过程。
SDK目录说明
- bin SDK二进制
- inc SDK头文件
- sample SDK示例代码
- build.bat SDK示例代码编译脚本
SDK头文件说明
- iMonitor.h 内核头文件,包括所有的监控消息、内核通讯协议、其他声明等。
- iMonitorSDK.h 应用层SDK声明头文件,包括接口、接口的封装。
- iMonitorSDKExtension.h 应用层扩展能力声明头文件,包括代理引擎、规则引擎等。
- iMonitorProtocol.h 监控消息协议封装,把原始的消息封装成更加容易使用的结构体。
使用的时候,只需要包含iMonitorSDK.h、iMonitorProtocol.h就好了。
#include <iMonitorSDK.h>
#include <iMonitorProtocol.h>
SDK接入过程
继承IMonitorCallback,实现相应的函数,核心是OnCallback函数
所有监控到的消息,都会通过OnCallback通知过来,具体消息的类型、字段可以参考IMonitorMessasge接口
class MonitorCallback : public IMonitorCallback
{
public:
void OnCallback(IMonitorMessage* Message) override
{
}
};
使用MonitorManager对象来启动并注册接口
MonitorManager manager;
MonitorCallback callback;
HRESULT hr = manager.Start(&callback);
如果返回成功,初始化就完成了。
接下来根据实际需要,可以通过cxMSGUserSetMSGConfig设置不同的消息监控,比如要监控进程启动,可以设置下面的参数:
cxMSGUserSetMSGConfig config;
config.Config[emMSGProcessCreate] = emMSGConfigSend;
manager.InControl(config);
cxMSGUserSetMSGConfig的使用说明
所有的监控都通过cxMSGUserSetMSGConfig来设置。
struct cxUserMSGConfig
{
ULONG Config[emMSGMax];
ULONG Fields[emMSGMax];
}
typedef cxMSGUser<emUserSetMSGConfig, cxUserMSGConfig> cxMSGUserSetMSGConfig;
Config说明
字段 | 说明 |
---|---|
emMSGConfigPost | 表示监控是异步消息,不会阻塞操作(也就无法拦截阻断) |
emMSGConfigSend | 表示监控是同步等待,会阻塞操作者,可以在回调里面通过SetBlock拦截操作的发生 |
emMSGConfigIncludeKernelEvent | 表示监控是否要支持内核(System进程)触发的消息,默认不监控 |
注意:如果设置了emMSGConfigSend,最好不要开启调试,不然容易导致系统卡死。(因为同步等待会阻塞其他进程的操作,需要监控程序返回后才能继续执行,而调试器会挂起监控程序,导致没法处理监控消息而卡死系统)
Fields说明
Fields字段表示监控需要哪些字段,各个类型支持的字段可以参考 iMonitorProtocol.h
按需设置不同的字段,某些不需要的字段不设置,这样可以优化一些性能。
全部消息类型
进程相关消息
消息类型 | 说明 |
---|---|
emMSGProcessCreate | 进程创建事件,返回拦截可以阻止进程的创建 |
emMSGProcessExit | 进程退出事件 |
emMSGProcessOpen | 打开进程事件,可以拦截打开用于保护进程 |
emMSGThreadCreate | 线程创建事件 |
emMSGThreadExit | 线程退出事件 |
emMSGThreadOpen | 打开线程事件 |
emMSGImageLoad | 加载模块事件,返回拦截可以阻止某个模块、某个驱动的加载 |
emMSGProcessStart | (模拟事件)进程启动事件 |
emMSGThreadStart | (模拟事件)线程启动事件 |
文件相关消息(带Post的表示动作已经完成)
消息类型 | 说明 |
---|---|
emMSGFileCreate | 打开、创建文件事件,返回拦截可以阻止文件的打开、创建 |
emMSGFilePostCreate | |
emMSGFileQueryOpen | 打开文件事件 |
emMSGFilePostQueryOpen | |
emMSGFileCleanup | |
emMSGFileCreateSection | 映射文件事件 |
emMSGFilePostCreateSection | |
emMSGFileRead | 读取文件事件 |
emMSGFilePostRead | |
emMSGFileWrite | 写文件事件 |
emMSGFilePostWrite | |
emMSGFileCreateHardLink | 创建文件硬链接事件 |
emMSGFilePostCreateHardLink | |
emMSGFileRename | 文件重命名事件 |
emMSGFilePostRename | |
emMSGFileDelete | 删除文件事件 |
emMSGFilePostDelete | |
emMSGFileSetSize | 设置文件大小事件 |
emMSGFilePostSetSize | |
emMSGFileSetBasicInfo | 设置文件基本信息事件 |
emMSGFilePostSetBasicInfo | |
emMSGFileFindFile | 查找文件、遍历文件事件 |
emMSGFilePostFindFile |
注册表相关消息(带Post的表示动作已经完成)
消息类型 | 说明 |
---|---|
emMSGRegCreateKey | 打开、创建注册表键 |
emMSGRegPostCreateKey | |
emMSGRegOpenKey | 打开注册表键 |
emMSGRegPostOpenKey | |
emMSGRegDeleteKey | 删除注册表键 |
emMSGRegPostDeleteKey | |
emMSGRegRenameKey | 重命名注册表键 |
emMSGRegPostRenameKey | |
emMSGRegEnumKey | 查找遍历注册表键 |
emMSGRegPostEnumKey | |
emMSGRegLoadKey | 加载文件映射成注册表键 |
emMSGRegPostLoadKey | |
emMSGRegReplaceKey | 加载文件替换注册表键 |
emMSGRegPostReplaceKey | |
emMSGRegDeleteValue | 删除注册表值 |
emMSGRegPostDeleteValue | |
emMSGRegSetValue | 设置注册表值 |
emMSGRegPostSetValue | |
emMSGRegQueryValue | 查询注册表值内容 |
emMSGRegPostQueryValue |
网络相关消息
基于AFD过滤驱动方式实现,所有操作同socket操作,可以获取套接字的调用回调
消息类型 | 说明 |
---|---|
emMSGSocketCreate | |
emMSGSocketControl | |
emMSGSocketPostControl | |
emMSGSocketConnect | |
emMSGSocketPostConnect | |
emMSGSocketSend | |
emMSGSocketRecv | |
emMSGSocketPostRecv | |
emMSGSocketSendTo | |
emMSGSocketPostSendTo | |
emMSGSocketRecvFrom | |
emMSGSocketPostRecvFrom | |
emMSGSocketListen | |
emMSGSocketPostListen | |
emMSGSocketAccept | |
emMSGSocketPostAccept |
基于WFP过滤驱动实现
消息类型 | 说明 |
---|---|
emMSGWFPTcpConnect | |
emMSGWFPUdpConnect | |
emMSGWFPTcpAccept | |
emMSGWFPUdpAccept | |
emMSGWFPICMPConnect | |
emMSGWFPICMPAccept | |
emMSGWFPSend | |
emMSGWFPRecv | |
emMSGWFPSendTo | |
emMSGWFPRecvFrom | |
emMSGWFPICMPSendTo | |
emMSGWFPICMPRecvFrom |
IMonitorCallback 接口说明
interface IMonitorCallback
{
//
// DisableXxxMonitor: (在驱动启动前设置生效) 表示是否关闭Xxx的监控,如果只需要部分能力,建议关闭其他不需要的监控。一般用于优化性能,解决冲突。
// InternalCallback: 内部使用,接管原始的消息
// ExtensionFieldTable: 消息扩展字段
//
struct GlobalConfig {
bool DisableFileMonitor = false;
bool DisableRegMonitor = false;
bool DisableSocketMonitor= false;
bool DisableWFPMonitor = false;
bool DisableNPMSMonitor = false;
bool InternalCallback = false;
MonitorExtensionFieldTable ExtensionFieldTable;
};
virtual void OnConfig (GlobalConfig& Config) {}
virtual void OnCustomEvent (ULONG Type, PVOID Context) {}
virtual bool OnInternalCallback (cxMSGHeader* Header, HANDLE FilterHandle, ULONGLONG MessageId) { return false; }
virtual void OnCallback (IMonitorMessage* Message) = 0;
};
函数 | 说明 |
---|---|
OnCallback | 【核心】监控消息回调函数,所有的消息都会通过这个回调触发 |
OnInternalCallback | 内部接口,可以获取原始驱动通讯的协议 |
OnCustomEvent | 自定义事件:消息回调都在同一个线程,有时候为了避免多线程,可以通过SendCustomEvent发送事件到消息回调的线程执行 |
OnConfig | 全局配置,可以用于关闭某些监控开关,或者设置字段扩展 |
IMonitorMessage 接口说明
interface IMonitorMessage
{
struct Binary {
PVOID Data;
ULONG Length;
};
//
// 基础字段
//
virtual cxMSGHeader* GetHeader (void) = 0;
inline ULONG GetType (void) { return GetHeader()->Type; }
inline ULONG GetStatus (void) { return GetHeader()->Status; }
inline ULONG GetCurrentProcessId (void) { return GetHeader()->CurrentProcessId; }
inline ULONG GetCurrentThreadId (void) { return GetHeader()->CurrentThreadId; }
virtual IMonitorMessageProcess* GetProcess (void) = 0;
virtual LPCWSTR GetTypeName (void) = 0;
virtual ULONG GetFieldCount (void) = 0;
virtual emMSGDataType GetFieldType (ULONG Index) = 0;
virtual LPCWSTR GetFieldName (ULONG Index) = 0;
virtual ULONG GetFieldIndex (LPCWSTR Name) = 0;
virtual ULONG GetULONG (ULONG Index) = 0;
virtual ULONGLONG GetULONGLONG (ULONG Index) = 0;
virtual cxMSGDataIPRef GetIP (ULONG Index) = 0;
virtual Binary GetBinary (ULONG Index) = 0;
virtual LPCWSTR GetString (ULONG Index) = 0;
virtual LPCWSTR GetFormatedString (ULONG Index) = 0;
virtual bool IsMatch (ULONG Index, LPCWSTR Pattern, bool IgnoreCase = true) = 0;
//
// 扩展字段,由开发者自行定义的字段,这些字段可以用于规则引擎,详细参考MonitorExtensionFieldTable
// HasValue: 表示是否有值,如果没有字段则返回默认值并且HasValue = false
//
virtual ULONGLONG GetNumber (LPCWSTR Name, bool* HasValue = nullptr) = 0;
virtual LPCWSTR GetString (LPCWSTR Name, bool* HasValue = nullptr) = 0;
//
// Action 相关操作,用于返回消息结果给驱动:需要Waiting状态才能设置返回结果
//
virtual bool IsWaiting (void) = 0;
virtual bool SetAction (const cxMSGAction& Action) = 0;
virtual bool SetBlock (void) = 0;
virtual bool SetGrantedAccess (ULONG Access) = 0;
virtual bool SetIPRedirect (ULONG IP, USHORT Port, ULONG ProcessId = ::GetCurrentProcessId()) = 0;
virtual bool SetTerminateProcess (void) = 0;
virtual bool SetTerminateThread (void) = 0;
virtual bool SetInjectDll (LPCWSTR Path) = 0;
virtual bool SetFileRedirect (LPCWSTR Path) = 0;
//
// 异步处理:
// 设置Pending成功后,可以拥有IMonitorMessage的生命周期,允许在回调返回后继续使用。
// 使用完毕,一定需要使用CompletePending来恢复状态,不然内核等待事件需要超时才能返回。
//
// 使用场景:需要弹框交互确认、或者是多线程处理的场景。
//
virtual bool Pending (void) = 0;
virtual void CompletePending (void) = 0;
virtual void SetCustomContext (PVOID Context) = 0;
virtual PVOID GetCustomContext (void) = 0;
};
核心函数说明
函数 | 说明 |
---|---|
GetType | 返回消息类型 |
GetULONG、GetULONGLONG、GetString | 获取消息字段 |
IsWaiting | 判断是否同步消息 |
SetAction | 设置消息响应动作,具体参考cxMSGAction |
SetBlock | 设置拦截,阻止事件发生 |
SetIPRedirect | 设置网络重定向 |
SetTerminateProcess | 结束当前操作进程 |
SetInjectDll | 注入动态库 |
Pending | 设置延迟处理,Pending成功后可以抛到其他线程处理消息,比如异步弹框 |
消息协议
为了更加方便获取消息的各个字段,SDK对所有的消息都进行了封装。
比如emMSGProcessCreate对应的协议封装是cxMSGProcessCreate,转换成协议封装后就可以更加方便获取字段。
void OnCallback(IMonitorMessage* Message) override
{
if (Message->GetType() == emMSGProcessCreate) {
cxMSGProcessCreate* msg = (cxMSGProcessCreate*)Message;
}
}
class cxMSGProcessCreate : public MonitorMessage
{
public:
enum {
emMSGFieldCallstack,
emMSGFieldCurrentProcessCreateTime,
emMSGFieldCurrentProcessName,
emMSGFieldCurrentProcessPath,
emMSGFieldCurrentProcessCommandline,
emMSGFieldPath,
emMSGFieldProcessId,
emMSGFieldCommandline,
emMSGFieldCreateTime,
emMSGFieldParentPath,
emMSGFieldParentProcessId,
emMSGFieldParentCommandline,
emMSGFieldParentCreateTime,
};
public:
auto Path() { return GetPath(emMSGFieldPath); }
auto ProcessId() { return GetULONG(emMSGFieldProcessId); }
auto Commandline() { return GetString(emMSGFieldCommandline); }
auto CreateTime() { return GetTime(emMSGFieldCreateTime); }
auto ParentPath() { return GetPath(emMSGFieldParentPath); }
auto ParentProcessId() { return GetULONG(emMSGFieldParentProcessId); }
auto ParentCommandline() { return GetString(emMSGFieldParentCommandline); }
auto ParentCreateTime() { return GetTime(emMSGFieldParentCreateTime); }
bool IsMatchPath(LPCWSTR Pattern, bool IgnoreCase = true) { return IsMatch(emMSGFieldPath, Pattern, IgnoreCase); }
bool IsMatchCommandline(LPCWSTR Pattern, bool IgnoreCase = true) { return IsMatch(emMSGFieldCommandline, Pattern, IgnoreCase); }
bool IsMatchParentPath(LPCWSTR Pattern, bool IgnoreCase = true) { return IsMatch(emMSGFieldParentPath, Pattern, IgnoreCase); }
bool IsMatchParentCommandline(LPCWSTR Pattern, bool IgnoreCase = true) { return IsMatch(emMSGFieldParentCommandline, Pattern, IgnoreCase); }
};
如果想定制自己的封装,可以通过IDL + 模板的方式自动生成。