进程监控
本篇教程主要介绍iMonitorSDK的进程监控相关功能。
进程监控全部消息
消息类型 | 说明 |
---|---|
emMSGProcessCreate | 进程创建事件,返回拦截可以阻止进程的创建 |
emMSGProcessExit | 进程退出事件 |
emMSGProcessOpen | 打开进程事件,可以拦截打开用于保护进程 |
emMSGThreadCreate | 线程创建事件 |
emMSGThreadExit | 线程退出事件 |
emMSGThreadOpen | 打开线程事件 |
emMSGImageLoad | 加载模块事件,返回拦截可以阻止某个模块、某个驱动的加载 |
emMSGProcessStart | (模拟事件)进程启动事件 |
emMSGThreadStart | (模拟事件)线程启动事件 |
emMSGProcessCreate
字段
struct ProcessCreate {
Path : Path; // 进程路径
ProcessId : ULONG; // 进程PID
Commandline : String; // 进程命令行
CreateTime : Time; // 创建时间
ParentPath : Path; // 父进程的路径(注意:父进程有可能不是当前操作进程)
ParentProcessId : ULONG; // 父进程PID
ParentCommandline : String; // 父进程命令行
ParentCreateTime : Time; // 父进程创建时间
}
使用场景
进程创建事件是非常重要的一个事件,很多场景都会使用到。比如杀毒软件要拦截病毒进程启动、企业管理员禁止员工玩游戏、云游戏只允许信任的进程运行、EDR追踪进程创建信息等等。
class MonitorCallback : public IMonitorCallback
{
public:
void OnCallback(IMonitorMessage* Message) override
{
if (Message->GetType() != emMSGProcessCreate)
return;
cxMSGProcessCreate* msg = (cxMSGProcessCreate*)Message;
//
// 禁止进程名 cmd.exe 的进程启动
//
if (msg->IsMatchPath(L"*\\cmd.exe")) {
msg->SetBlock();
}
}
};
大部分场景,都是通过判断进程路径来做拦截,可以直接使用IsMatchPath来快速匹配。
如果需要获取进程相关的其他信息、比如进程签名、进程文件属性等,可以通过FindProcess查询到进程对应的信息来操作。
CComPtr<IMonitorProcess> process;
if (manager.FindProcess(msg->ProcessId(), &process)) {
process->GetCompanyName();
}
interface IMonitorMessageProcess
{
enum emProcessType {
emProcessUnknown,
emProcessServices,
emProcessCsrss,
emProcessSvchost,
emProcessExplorer,
};
virtual ULONG GetProcessId (void) = 0;
virtual ULONG GetParentProcessId (void) = 0;
virtual ULONG GetCreatorProcessId (void) = 0;
virtual LPCWSTR GetProcessName (void) = 0;
virtual LPCWSTR GetProcessPath (void) = 0;
virtual LPCWSTR GetCommandline (void) = 0;
virtual LPCWSTR GetCompanyName (void) = 0;
virtual LPCWSTR GetProductName (void) = 0;
virtual LPCWSTR GetFileDescription (void) = 0;
virtual LPCWSTR GetSigner (void) = 0;
virtual bool IsSignerVerified (void) = 0;
virtual LPCWSTR GetCatalogSigner (void) = 0;
virtual bool IsCatalogSignerVerified(void) = 0;
virtual ULONGLONG GetCreateTime (void) = 0;
virtual emProcessType GetProcessType (void) = 0;
virtual bool GetMD5 (UCHAR Hash[16]) = 0;
virtual LPCWSTR GetMD5String (void) = 0;
};
注意字段 | 说明 |
---|---|
GetSigner | 进程内嵌签名(不支持Catalog、没有验证签名的有效性),一般用于黑名单模式 |
IsSignerVerified | 进程内嵌签名是否有效,GetSigner只查询签名,如果还需要校验有效性需要配合这个使用 |
GetCatalogSigner | 对于Windows等文件,签名信息可能不是直接内嵌的,这时候可以通过这个接口获取签名,这个性能会比较差 |
IsCatalogSignerVerified | 判断GetCatalogSigner返回的签名是否有效,这个性能会比较差,而且可能存在联网查询,除非白名单模式,否则不建议使用 |
GetMD5、GetMD5String | 查询签名、查询MD5都是异步的,超时5秒,如果对应大文件或者存在其他安全软件拦截的情况,查询可能或返回失败。 |
emMSGProcessExit
字段
struct ProcessExit {
Path : Path;
ProcessId : ULONG;
}
使用场景
如果使用者维持了所有活动进程的状态,那么可以根据进程退出事件来清理退出的进程。
emMSGProcessOpen
字段
struct ProcessOpen {
Path : Path;
ProcessId : ULONG;
ParentProcessId : ULONG;
DesiredAccess : ProcessAccess; // 打开的权限:这里可以判断是否存在结束、操作内存的权限
Duplicate : Bool; // 是否通过DuplicateHandle的方式打开
}
使用场景
通过拦截进程打开,可以用于保护进程不被结束、防止进程被远程线程注入、防止内存被修改、禁止调试器调试进程等。
进程打开除了直接拦截以外,还可以返回修改后的权限。
void OnCallback(IMonitorMessage* Message) override
{
if (Message->GetType() != emMSGProcessOpen)
return;
Message->SetGrantedAccess(PROCESS_QUERY_INFORMATION);
}
emMSGThreadCreate
字段
struct ThreadCreate {
Path : Path;
ProcessId : ULONG;
ThreadId : ULONG;
StartAddress : ULONGLONG; // 线程的行入口
RemoteThread : Bool; // 是否远程线程(表示创建者并不是当前进程)
}
使用场景
多用于判断是否远程线程注入。
emMSGThreadOpen
参考 emMSGProcessOpen,行为和使用场景比较类似
emMSGImageLoad
字段
struct ImageLoad {
Path : Path;
ProcessId : ULONG;
ImageBase : ULONGLONG;
ImageSize : ULONGLONG;
IsKernelImage : Bool; // 表示是否驱动(也可以通过进程来判断)
}
使用场景
模块加载事件,可以用于病毒分析、EDR检测。模块的加载支持返回SetBlock拦截,可以用于拦截动态库的加载、也可以拦截驱动(IsKernelImage = TRUE)的加载。
除了拦截,还可以通过SetInjectDll来注入动态库。为什么选择在ImageLoad的时候注入动态库,是因为注入动态库需要调用ntdll的某些函数,所以需要监控ntdll 模块加载完成后,才开始注入。(对于wow64的还需要监控wow64的ntdll,或者直接根据kernel32来判断。如果使用内置的自动注入功能,就不需要自己来判断这些逻辑)
void OnCallback(IMonitorMessage* Message) override
{
if (Message->GetType() != emMSGImageLoad)
return;
cxMSGImageLoad* msg = (cxMSGImageLoad*)Message;
if (!msg->IsMatchCurrentProcessName(L"notepad.exe"))
return;
if (msg->IsMatchPath(L"*\\kernel32.dll")) {
msg->SetInjectDll(L"D:\\test.dll");
}
}