进程检测的方式
1. 进程隐藏 NTOpenProcess(本质就是枚举句柄表)(可能性不大)
2. NTQuerySystemInformation(SystemHandleInformation)(本质就是枚举句柄表)(可能性偏大)
2. NTQuerySystemInformation(SystemProcessesAndTHreadsInformation)(本质就是枚举进程双向链表)(可能性很大)
3. GetWindowThreadPreocessId(可能性一般)
4. EnumWindows得到进入ID(可能性一般)
5. PspCidTable内核未导出的句柄表, 保存所有进程和线程的对象, 可以枚举隐藏进程(本质就是枚举句柄表)(可能性很小, 结构偏移不通用)
6. Csrss进程中的句柄表, 保存着所有的进程列表(本质就是枚举句柄表)(可能性很小, 结构偏移不通用)
7. 暴力搜索内核空间得到Eprocess, 内核开始地址0x80000000, 对比指针是否是PsProcessType(可能性很小, 结构偏移不通用)
8. 创建进程回调PsSetCreateProcessNotifyRoutine(可能性不大,如果先运行od, 则不会被检测到)
隐藏进程一种是断链,还有很多其他的方法:
1. 从双向链表中摘除, 取得进程结构指针,将上一个节点指向中下一个节点, 下一个节点的上一个节点指向上一个本进程的上一个节点
PsLookupProcessByProcessId(processId, &pEprocess)
具体看 30.AGP教程2.2.1(进程隐藏)
2. 从PspCidTable中擦除, 但退出线程和进程时要调用ExDestroryHandle()销毁句柄,擦除前需要先备份句柄的值,卸载驱动时需要关闭这些句柄
通过搜索PsLoopupProcessByProcessId函数,获取PspCidTable的地址,
PsLoopupProcessByProcessId中调用nt!ExEnumHandleTable()函数的第一个参数就是PspCidTable地址
GetPspCidTable(&pPspCidTable)
PsLookupProcessByProcessId(GetCsrssPid(), &pCsrssEprocess)
ObDereferenceObject(pCsrssEprocess)
// 获取ExEnumHandleTable
ExEnumHandleTable = MmGetSystemRoutineAddress(&uniExEnumHandleTableFuncName);
ExEnumHandleTable(pHandleTable, EnumHandleCallback, &EnumParameter, NULL)
// 并把我们指定的对象的Object对象指针清零,
// 使用ExEnumHandleTable遍历所有对象, 并把我们指定的对象的Object对象指针清零,InterlockedExchangedPointer()
InterlockedExchangedPointer(&((PHANDLE_TABLE_ENTRY_EnumParameter)->Object, NULL)
3. 擦除Csrss进程中的句柄, (干掉OpenProcess的方式)
按照上一个方法,将pCsrssEprocess + g_Offset_Eprocess_HandleTable的值传进去进行抹除即可
逆向安全收徒中...