BSOne.SFC/Tocsg.Module/Bs1Flt/bs1flt/bs1flt_process_protect.c

488 lines
14 KiB
C

#include "precomp.h"
typedef struct _TD_CALLBACK_PARAMETERS {
ACCESS_MASK AccessBitsToClear;
ACCESS_MASK AccessBitsToSet;
}TD_CALLBACK_PARAMETERS, * PTD_CALLBACK_PARAMETERS;
typedef struct _TD_CALLBACK_REGISTRATION {
PVOID RegistrationHandle;
PVOID TargetProcess;
HANDLE TargetProcessId;
TD_CALLBACK_PARAMETERS ProcessParams;
TD_CALLBACK_PARAMETERS ThreadParams;
ULONG RegistrationId; // Index in the global TdCallbacks array.
}TD_CALLBACK_REGISTRATION, * PTD_CALLBACK_REGISTRATION;
typedef struct _TD_CALL_CONTEXT
{
PTD_CALLBACK_REGISTRATION CallbackRegistration;
OB_OPERATION Operation;
PVOID Object;
POBJECT_TYPE ObjectType;
}
TD_CALL_CONTEXT, * PTD_CALL_CONTEXT;
static OB_CALLBACK_REGISTRATION s_obRegistration = { 0 };
static OB_OPERATION_REGISTRATION s_operationRegistrations[2] = { { 0 }, { 0 } };
static PVOID s_registrationHandle = NULL;
static TD_CALLBACK_REGISTRATION CallbackRegistration = { 0 };
static BOOLEAN s_callbacksInstalled = FALSE;
#define TD_CALL_CONTEXT_TAG '1bCO'
#define CB_PROCESS_TERMINATE 0x0001
#define CB_THREAD_TERMINATE 0x0001
#define PROCESS_TERMINATE (0x0001)
#define PROCESS_CREATE_THREAD (0x0002)
#define PROCESS_SET_SESSIONID (0x0004)
#define PROCESS_VM_OPERATION (0x0008)
#define PROCESS_VM_READ (0x0010)
#define PROCESS_VM_WRITE (0x0020)
#define PROCESS_DUP_HANDLE (0x0040)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_SET_QUOTA (0x0100)
#define PROCESS_SET_INFORMATION (0x0200)
#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_SUSPEND_RESUME (0x0800)
#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
#define PROCESS_SET_LIMITED_INFORMATION (0x2000)
#define THREAD_TERMINATE (0x0001)
#define THREAD_SUSPEND_RESUME (0x0002)
#define THREAD_GET_CONTEXT (0x0008)
#define THREAD_SET_CONTEXT (0x0010)
#define THREAD_QUERY_INFORMATION (0x0040)
#define THREAD_SET_INFORMATION (0x0020)
#define THREAD_SET_THREAD_TOKEN (0x0080)
#define THREAD_IMPERSONATE (0x0100)
#define THREAD_DIRECT_IMPERSONATION (0x0200)
#define THREAD_SET_LIMITED_INFORMATION (0x0400) // winnt
#define THREAD_QUERY_LIMITED_INFORMATION (0x0800) // winnt
#define THREAD_RESUME (0x1000) // winnt
#define TD_ASSERT(_exp) \
((!(_exp)) ? \
(__annotation(L"Debug", L"AssertFail", L#_exp), \
DbgRaiseAssertionFailure(), FALSE) : \
TRUE)
BOOLEAN IsObExceptProcess(LPWSTR name)
{
static wchar_t* s_obExceptionprocess[] = {
L"MsMpEng.exe",
L"System",
L"csrss.exe",
L"lsm.exe",
L"spoolsv.exe",
L"lsass.exe",
L"services.exe",
L"winlogon.exe",
L"smss.exe",
L"alg.exe",
L"conhost.exe",
L"svchost.exe",
NULL
};
LPWSTR* ep = s_obExceptionprocess;
while (*ep)
{
if (_wcsnicmp(name, *ep, wcslen(name)) == 0)
return TRUE;
++ep;
}
return FALSE;
}
OB_PREOP_CALLBACK_STATUS
PreOperationCallback(
IN PVOID RegistrationContext,
IN OUT POB_PRE_OPERATION_INFORMATION PreInfo
)
{
UNREFERENCED_PARAMETER(RegistrationContext);
OB_PREOP_CALLBACK_STATUS state = OB_PREOP_SUCCESS;
PACCESS_MASK DesiredAccess = NULL;
ACCESS_MASK OriginalDesiredAccess = 0;
HANDLE pid = 0;
HANDLE curPid = PsGetCurrentProcessId();
wchar_t curProcessName[260] = { 0, };
wchar_t curProcessPath[260] = { 0, };
wchar_t processName[260] = { 0, };
wchar_t processPath[260] = { 0, };
HANDLE ProcessIdOfTargetThread;
LPCWSTR ObjectTypeName = NULL;
LPCWSTR OperationName = NULL;
ACCESS_MASK AccessBitsToClear = 0;
ACCESS_MASK InitialDesiredAccess = 0;
BOOLEAN isProtected = FALSE;
//if (PreInfo->Operation != OB_OPERATION_HANDLE_CREATE)
// return state;
if (!g_bs1Flt.IsProcessProtect)
return state;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
return state;
if (PreInfo->ObjectType == *PsProcessType)
{
if (PreInfo->Object == PsGetCurrentProcess())
return OB_PREOP_SUCCESS;
ObjectTypeName = L"PsProcessType";
AccessBitsToClear = PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME;
pid = PsGetProcessId(PreInfo->Object);
}
else if (PreInfo->ObjectType == *PsThreadType)
{
ProcessIdOfTargetThread = PsGetThreadProcessId((PETHREAD)PreInfo->Object);
if (ProcessIdOfTargetThread == curPid)
return OB_PREOP_SUCCESS;
ObjectTypeName = L"PsThreadType";
AccessBitsToClear = THREAD_TERMINATE | THREAD_SUSPEND_RESUME;
pid = ProcessIdOfTargetThread;
}
else
{
KLogEx(DEBUG_TRACE_ERROR, "unexpected object type\n");
return OB_PREOP_SUCCESS;
}
switch (PreInfo->Operation) {
case OB_OPERATION_HANDLE_CREATE:
DesiredAccess = &PreInfo->Parameters->CreateHandleInformation.DesiredAccess;
OriginalDesiredAccess = PreInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess;
if (!FlagOn(*DesiredAccess, (PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME)))
{
return OB_PREOP_SUCCESS;
}
OperationName = L"OB_OPERATION_HANDLE_CREATE";
break;
case OB_OPERATION_HANDLE_DUPLICATE:
DesiredAccess = &PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
OriginalDesiredAccess = PreInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
if (!FlagOn(*DesiredAccess, (THREAD_TERMINATE | THREAD_SUSPEND_RESUME)))
{
return OB_PREOP_SUCCESS;
}
OperationName = L"OB_OPERATION_HANDLE_DUPLICATE";
break;
default:
KLogEx(DEBUG_TRACE_ERROR, "unexpected object type\n");
return state;
}
if (PreInfo->KernelHandle == 1) {
return OB_PREOP_SUCCESS;
}
if (curPid == pid)
return OB_PREOP_SUCCESS;
InitialDesiredAccess = *DesiredAccess;
state = UGetProcessFullPathFromPid(curPid, curProcessPath, sizeof(curProcessPath), curProcessName, sizeof(curProcessName));
if (!NT_SUCCESS(state))
{
KLogEx(DEBUG_TRACE_ERROR, "UGetProcessFullPathFromPid:: cur stats %x\n", state);
return OB_PREOP_SUCCESS;
}
if(IsObExceptProcess(curProcessName))
return OB_PREOP_SUCCESS;
state = UGetProcessFullPathFromPid(pid, processPath, sizeof(processPath), processName, sizeof(processName));
if (!NT_SUCCESS(state))
{
KLogEx(DEBUG_TRACE_ERROR, "UGetProcessFullPathFromPid:: tag stats %x\n", state);
return OB_PREOP_SUCCESS;
}
KLogEx(DEBUG_TRACE_ERROR, "curProcessName(%S), processName(%S)\n", curProcessName, processName);
isProtected = TRUE;
if (_wcsicmp(processName, L"bs1fltputool.exe") == 0)
{
//PreInfo->Parameters->CreateHandleInformation.DesiredAccess = 0;
}
else if (PgGetProtectPidState(HandleToULong(pid)) == PG_PID_PROTECT)
{
//KLogEx(DEBUG_TRACE_INFO, "PgGetProtectPidState(%S)\n", processName);
}
else if (IsProcessProtectList(PG_PID_PROTECT, processName, (ULONG)wcslen(processName) * (ULONG)sizeof(WCHAR)) == PG_PID_PROTECT)
{
//KLogEx(DEBUG_TRACE_INFO, "IsProcessProtectList(%S)\n", pocessName);
}
else
{
isProtected = FALSE;
}
if(isProtected)
{
*DesiredAccess &= ~AccessBitsToClear;
SetLog(NULL,NULL,LOG_PROCESS_PROTECT,HandleToULong(pid),HandleToULong(curPid),InitialDesiredAccess,curProcessPath,processPath);
KLogEx(DEBUG_TRACE_ERROR, "[PROTECT] tried to kill Target\n");
}
KLogEx(DEBUG_TRACE_ERROR,
" Client Id: %p:%p:%p\n"
" Object: %p\n"
" Type: %ls\n"
" Operation: %ls (KernelHandle=%d)\n"
" OriginalDesiredAccess: 0x%x\n"
" DesiredAccess (in): 0x%x\n"
" DesiredAccess (out): 0x%x\n",
pid,
curPid,
PsGetCurrentThreadId(),
PreInfo->Object,
ObjectTypeName,
OperationName,
PreInfo->KernelHandle,
OriginalDesiredAccess,
InitialDesiredAccess,
*DesiredAccess
);
/*
if (PreInfo->Operation == OB_OPERATION_HANDLE_CREATE)
{
DesiredAccess = &PreInfo->Parameters->CreateHandleInformation.DesiredAccess;
OriginalDesiredAccess = PreInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess;
if (0x0001 | 0x800 & PreInfo->Parameters->CreateHandleInformation.DesiredAccess) // TERMINATE_PROCESS
{
if ((PreInfo->ObjectType == *PsProcessType) || (PreInfo->ObjectType == *PsThreadType))
{
if (PreInfo->ObjectType == *PsProcessType)
{
pid = PsGetProcessId(PreInfo->Object);
}
if (PreInfo->ObjectType == *PsThreadType)
{
pid = PsGetThreadProcessId((PETHREAD)PreInfo->Object);
}
if (curPid == pid)
return state;
UGetProcessNameFormPid(curProcessName, curPid);
if (_stricmp(curProcessName, "MsMpEng.exe") == 0
|| _stricmp(curProcessName, "System") == 0
|| _stricmp(curProcessName, "csrss.exe") == 0
|| _stricmp(curProcessName, "lsm.exe") == 0
|| _stricmp(curProcessName, "spoolsv.exe") == 0
|| _stricmp(curProcessName, "lsass.exe") == 0
|| _stricmp(curProcessName, "services.exe") == 0
|| _stricmp(curProcessName, "winlogon.exe") == 0
|| _stricmp(curProcessName, "smss.exe") == 0
|| _stricmp(curProcessName, "alg.exe") == 0
|| _stricmp(curProcessName, "conhost.exe") == 0)
{
//KLogEx(DEBUG_TRACE_INFO, "OB_PREOP_SUCCESS\n");
return OB_PREOP_SUCCESS;
}
UGetProcessNameFormPid(processName, pid);
KLogEx(DEBUG_TRACE_INFO, "curProcessName(%s)(%s)\n", curProcessName, processName);
if (_stricmp(processName, "bs1flt_tool.ex") == 0)
{
PreInfo->Parameters->CreateHandleInformation.DesiredAccess = 0;
KLogEx(DEBUG_TRACE_INFO, "CREATE PROTECT curProcessName(%s), processName(%s), (%x)\n", curProcessName, processName,
(ULONG)*DesiredAccess, OriginalDesiredAccess);
}
}
}
}
else if (PreInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
DesiredAccess = &PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
OriginalDesiredAccess = PreInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
if ((PreInfo->ObjectType == *PsProcessType) || (PreInfo->ObjectType == *PsThreadType))
{
if (PreInfo->ObjectType == *PsProcessType)
{
pid = PsGetProcessId(PreInfo->Object);
}
if (PreInfo->ObjectType == *PsThreadType)
{
pid = PsGetThreadProcessId((PETHREAD)PreInfo->Object);
}
if (curPid == pid)
return state;
UGetProcessNameFormPid(curProcessName, curPid);
UGetProcessNameFormPid(processName, pid);
KLogEx(DEBUG_TRACE_INFO, "DUPLICATE PROTECT curProcessName(%s), processName(%s), (%x)\n", curProcessName, processName,
(ULONG)*DesiredAccess, OriginalDesiredAccess);
}
}
*/
return state;
}
void TdCheckAndFreeCallContext(
IN OUT POB_POST_OPERATION_INFORMATION PostInfo,
IN PTD_CALLBACK_REGISTRATION _CallbackRegistration
)
{
PTD_CALL_CONTEXT CallContext = (PTD_CALL_CONTEXT)PostInfo->CallContext;
if (CallContext != NULL)
{
TD_ASSERT(CallContext->CallbackRegistration == _CallbackRegistration);
TD_ASSERT(CallContext->Operation == PostInfo->Operation);
TD_ASSERT(CallContext->Object == PostInfo->Object);
TD_ASSERT(CallContext->ObjectType == PostInfo->ObjectType);
ExFreePoolWithTag(CallContext, TD_CALL_CONTEXT_TAG);
}
}
VOID
PostOperationCallback(
IN PVOID RegistrationContext,
IN POB_POST_OPERATION_INFORMATION PostInfo
)
{
PTD_CALLBACK_REGISTRATION CallbackRegistration_ = (PTD_CALLBACK_REGISTRATION)RegistrationContext;
TdCheckAndFreeCallContext(PostInfo, CallbackRegistration_);
if (PostInfo->ObjectType == *PsProcessType) {
//
// Ignore requests for processes other than our target process.
//
if (CallbackRegistration_->TargetProcess != NULL &&
CallbackRegistration_->TargetProcess != PostInfo->Object
) {
return;
}
//
// Also ignore requests that are trying to open/duplicate the current
// process.
//
if (PostInfo->Object == PsGetCurrentProcess()) {
return;
}
}
else if (PostInfo->ObjectType == *PsThreadType) {
HANDLE ProcessIdOfTargetThread = PsGetThreadProcessId((PETHREAD)PostInfo->Object);
//
// Ignore requests for threads belonging to processes other than our
// target process.
//
if (CallbackRegistration_->TargetProcess != NULL &&
CallbackRegistration_->TargetProcessId != ProcessIdOfTargetThread
) {
return;
}
//
// Also ignore requests for threads belonging to the current processes.
//
if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) {
return;
}
}
else {
TD_ASSERT(FALSE);
}
}
NTSTATUS InstallProcessProtect() {
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING altitude = { 0 };
if(s_callbacksInstalled)
{
KLogEx(DEBUG_TRACE_INFO, "OB callbacks already installed\n");
return STATUS_SUCCESS;
}
g_bs1Flt.IsProcessProtect = TRUE;
s_operationRegistrations[0].ObjectType = PsProcessType;
s_operationRegistrations[0].Operations |= OB_OPERATION_HANDLE_CREATE;
s_operationRegistrations[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
s_operationRegistrations[0].PreOperation = PreOperationCallback;
s_operationRegistrations[0].PostOperation = PostOperationCallback;
s_operationRegistrations[1].ObjectType = PsThreadType;
s_operationRegistrations[1].Operations |= OB_OPERATION_HANDLE_CREATE;
s_operationRegistrations[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
s_operationRegistrations[1].PreOperation = PreOperationCallback;
s_operationRegistrations[1].PostOperation = PostOperationCallback;
RtlInitUnicodeString(&altitude, OBJECT_ALTITUDE);
s_obRegistration.Version = OB_FLT_REGISTRATION_VERSION;
s_obRegistration.OperationRegistrationCount = 2;
s_obRegistration.Altitude = altitude;
s_obRegistration.RegistrationContext = &CallbackRegistration;
s_obRegistration.OperationRegistration = s_operationRegistrations;
status = ObRegisterCallbacks(&s_obRegistration, &s_registrationHandle);
if (!NT_SUCCESS(status)) {
KLogEx(DEBUG_TRACE_INFO, "ObRegisterCallbacks: installing OB callbacks failed status (%x)\n", status);
return status;
}
s_callbacksInstalled = TRUE;
KLogEx(DEBUG_TRACE_INFO, "Sucess\n");
return STATUS_SUCCESS;
}
VOID UnInstallProcessProtect()
{
if (!s_callbacksInstalled)
return;
if (!s_registrationHandle)
return;
g_bs1Flt.IsProcessProtect = FALSE;
ObUnRegisterCallbacks(s_registrationHandle);
KLogEx(DEBUG_TRACE_ERROR, "Sucess\n");
}