📄 process.c
字号:
/*
* Copyright (c) 2004 Security Architects Corporation. All rights reserved.
*
* Module Name:
*
* process.c
*
* Abstract:
*
* This module defines various types used by process and thread hooking routines.
*
* Author:
*
* Eugene Tsyrklevich 23-Feb-2004
*
* Revision History:
*
* None.
*/
#include <NTDDK.h>
#include "process.h"
#include "driver.h"
#include "policy.h"
#include "hookproc.h"
#include "userland.h"
#include "procname.h"
#include "accessmask.h"
#include "learn.h"
#include "misc.h"
#include "i386.h"
#include "log.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, InitProcessEntries)
#pragma alloc_text (PAGE, ProcessPostBootup)
#endif
fpZwCreateProcess OriginalNtCreateProcess = NULL;
fpZwCreateProcessEx OriginalNtCreateProcessEx = NULL;
fpZwOpenProcess OriginalNtOpenProcess = NULL;
fpZwCreateThread OriginalNtCreateThread = NULL;
fpZwOpenThread OriginalNtOpenThread = NULL;
BOOLEAN AllowProcessesWithPoliciesOnly = FALSE;
WCHAR OzoneInstallPath[MAX_PATH];
USHORT OzoneInstallPathSize = 0;
/* XXX this will not work on 64-bit architectures, due to assumption of size of ulong, pointers, etc */
typedef struct _CONTROL_AREA { // must be quadword sized.
ULONG data[9];
PFILE_OBJECT FilePointer;
} CONTROL_AREA, *PCONTROL_AREA;
typedef struct _SEGMENT {
struct _CONTROL_AREA *ControlArea;
} SEGMENT, *PSEGMENT;
typedef struct _SECTION {
ULONG_PTR data[5];
PSEGMENT Segment;
} SECTION, *PSECTION;
/*
* rand()
*
* Description:
* Returns a random number that is calculated by XOR'ing together often changing system values.
*
* Parameters:
* randval - An optional random value.
*
* Returns:
* A random ULONG value.
*/
ULONG
rand(ULONG randval)
{
LARGE_INTEGER perf, TickCount;
ULONG r;
KeQueryPerformanceCounter(&perf);
// KdPrint(("perf: %d %d\n", perf.LowPart, perf.HighPart));
KeQueryTickCount(&TickCount);
// KdPrint(("tick: %d %d\n", TickCount.LowPart, TickCount.HighPart));
// KdPrint(("int: %I64d\n", KeQueryInterruptTime()));
r = randval ^
perf.LowPart ^ perf.HighPart ^
TickCount.HighPart ^ TickCount.LowPart ^
(ULONG) KeQueryInterruptTime();
// KdPrint(("rand = %x\n", r));
return r;
}
/*
* PostProcessNtCreateProcess()
*
* Description:
* This function is called by the mediated NtCreateProcess() system service.
* It is responsible for saving the information about the newly created process in a
* global process hash table.
*
* Parameters:
* ProcessHandle - process object handle initialized by NtCreateProcess().
* SectionHandle - specifies a handle to an image section that grants SECTION_MAP_EXECUTE
* access. If this value is zero, the new process inherits the address space from the process
* referred to by InheritFromProcessHandle. In Windows 2000 the lowest bit specifies
* (when set) that the process should not be associated with the job of the
* InheritFromProcessHandle process.
*
* Returns:
* ULONG indicating an action to take (ACTION_DENY to disallow process createion, ACTION_PERMIT to allow).
*/
ULONG
PostProcessNtCreateProcess(PHANDLE ProcessHandle, HANDLE SectionHandle)
{
NTSTATUS status, rc;
PIMAGE_PID_ENTRY p, prev, NewProcess;
ULONG ProcessId, Size;
PULONG_PTR Base;
UNICODE_STRING usPath;
ANSI_STRING asPath;
KIRQL irql;
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
CHAR ProcessPathUnresolved[MAX_PATH];
CHAR PROCESSNAME[MAX_PATH];
PCHAR FunctionName = "PostProcessNtCreateProcess";
if (ProcessHandle == NULL)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%s: ProcessHandle is NULL\n", FunctionName));
return ACTION_NONE;
}
/*
* Try to retrieve the image name from a section object
*/
if (!SectionHandle)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%s: SectionHandle is NULL\n", FunctionName));
return ACTION_NONE;
}
do
{
PSECTION SectionToMap;
PSEGMENT seg;
PCONTROL_AREA pca;
PFILE_OBJECT pfo;
status = ObReferenceObjectByHandle(
SectionHandle,
0,
0,
KernelMode,
(PSECTION *) &SectionToMap,
NULL
);
/* macro shortcut for bailing out of PostProcessNtCreateProcess do {} while loop in case of an error */
#define ABORT_PostProcessNtCreateProcess(msg) \
{ \
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("Error occurred in %s:", FunctionName)); \
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, (msg)); \
return ACTION_NONE; /* XXX */ \
}
if (! NT_SUCCESS(status))
ABORT_PostProcessNtCreateProcess(("ObReferenceObjectByHandle(SectionHandle) failed"));
if (SectionToMap == NULL)
ABORT_PostProcessNtCreateProcess(("SectionToMap is NULL"));
if ( (seg = ((PSECTION)SectionToMap)->Segment) == NULL)
ABORT_PostProcessNtCreateProcess(("Segment is NULL"));
if ( (pca = seg->ControlArea) == NULL)
ABORT_PostProcessNtCreateProcess(("ControlArea is NULL"));
if ( (pfo = pca->FilePointer) == NULL)
ABORT_PostProcessNtCreateProcess(("FilePointer is NULL"));
usPath = pfo->FileName;
if (usPath.Length == 0)
ABORT_PostProcessNtCreateProcess(("FileName length is 0"));
_snprintf(ProcessPathUnresolved, MAX_PATH, "%S", usPath.Buffer);
ProcessPathUnresolved[MAX_PATH - 1] = 0;
ObDereferenceObject(SectionToMap);
} while (0);
/*
* Now verify the executable name against the security policy
*/
VerifyExecutableName(ProcessPathUnresolved);
if (LearningMode == FALSE)
{
ACTION_TYPE Action;
VerifyUserReturnAddress();
FixupFilename(ProcessPathUnresolved, PROCESSNAME, MAX_PATH);
/*
* We manually inc/dec HookedRoutineRunning since POLICY_CHECK_OPTYPE_NAME() can call
* HOOK_ROUTINE_EXIT() which will decrement HookedRoutineRunning and then it will get
* decremented the second time in HookedNtCreateProcess()
*/
#if DBG
InterlockedIncrement(&HookedRoutineRunning);
#endif
POLICY_CHECK_OPTYPE_NAME(PROCESS, OP_PROC_EXECUTE);
#if DBG
InterlockedDecrement(&HookedRoutineRunning);
#endif
}
else
{
// learning mode
AddRule(RULE_PROCESS, ProcessPathUnresolved, OP_PROC_EXECUTE);
}
/*
* retrieve the Process ID
*/
status = ZwQueryInformationProcess(*ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo, sizeof(ProcessBasicInfo), &Size);
if (! NT_SUCCESS(status))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: ZwQueryInformationProcess failed with status %x\n", status));
return ACTION_NONE;
}
ProcessId = ProcessBasicInfo.UniqueProcessId;
/*
* On win2k ProcessId is not available at this stage yet.
* ProcessId of 0 will get replaced by a real value in CreateProcessNotifyProc.
*/
/* once winlogon.exe executes, we consider the boot process to be complete */
if (BootingUp == TRUE)
{
PCHAR ProcessName;
ProcessName = strrchr(ProcessPathUnresolved, '\\');
if (ProcessName == NULL)
ProcessName = ProcessPathUnresolved;
else
++ProcessName; /* skip past the slash */
if (_strnicmp(ProcessName, "winlogon.exe", 12) == 0)
{
BootingUp = FALSE;
InitPostBootup();
}
}
/*
* Now create a new process entry and load the associated security policy (if any)
*/
NewProcess = CreateNewProcessEntry(ProcessId, CURRENT_PROCESS_PID, &usPath, TRUE);
if (ProcessInsertImagePidEntry(ProcessId, NewProcess) == FALSE)
{
ExFreePoolWithTag(NewProcess, _POOL_TAG);
return ACTION_NONE;
}
/*
* Now find and load appropriate security policy.
*
* Look for a per-user policy first. To do that, we send an SID resolve request
* to userland Ozone Agent Service.
*/
if (LearningMode == FALSE)
{
PSID_RESOLVE_REPLY pSidResolveReply = NULL;
PWSTR UserName = NULL;
if (IssueUserlandSidResolveRequest(NewProcess) != FALSE)
{
if (NewProcess->UserlandReply)
{
pSidResolveReply = (PSID_RESOLVE_REPLY) NewProcess->UserlandReply;
if (pSidResolveReply->UserNameLength)
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess: SID resolved to %S\n", pSidResolveReply->UserName));
UserName = pSidResolveReply->UserName;
}
else
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_DEBUG, ("PostProcessNtCreateProcess(): SID resolve error\n"));
}
}
}
if (! FindAndLoadSecurityPolicy(&NewProcess->SecPolicy, usPath.Buffer, UserName))
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%d PostProcessNtCreateProcess(): no policy, %d, %S\n", CURRENT_PROCESS_PID, ProcessId, usPath.Buffer));
//XXX have an option where only processes with existing policies (even if they are empty.. policy_default: allow) are allowed to run
//interactive session is excluded?!?!
if (AllowProcessesWithPoliciesOnly == TRUE)
{
ExFreePoolWithTag(NewProcess, _POOL_TAG);
return ACTION_DENY;
}
}
else
{
LOG(LOG_SS_PROCESS, LOG_PRIORITY_WARNING, ("%d PostProcessNtCreateProcess(): with policy, %d, %S\n", CURRENT_PROCESS_PID, ProcessId, usPath.Buffer));
}
if (NewProcess->UserlandReply)
{
ExFreePoolWithTag(NewProcess->UserlandReply, _POOL_TAG);
NewProcess->UserlandReply = NULL;
}
}
/*
* Stack Buffer Overflow Protection (Part 1).
*
* 1. Allocate/reserve a random (< 0x4000000) chunk of virtual memory starting at 0xFFFF.
* This causes the stack of the main thread to be moved by a random amount.
*
* (note1: first 64K of memory are allocated as a guard against NULL pointers dereferencing).
* (note2: main() is mapped at 0x4000000 and thus we cannot allocate anything that will cause the
* stack of the main thread to move past the 0x400000 boundary).
*
*
* Stack Buffer Overflow Protection (Part 2).
*
* 2. Allocate a random (> 4 Megs && < 10 Megs) chunk of virtual memory after the process code segment.
* This causes the heap and stacks non-main threads to be moved by a random amount.
*
* (note: as mentioned above, main() is mapped at 0x4000000, by reserving a large chunk of virtual
* we force Windows to find the first available address beyond the code segment and reserve
* a random amount of memory past it causing other thread stacks and heaps to shift).
*/
#define ONE_MEGABYTE (1024 * 1024)
if (IS_OVERFLOW_PROTECTION_ON(gSecPolicy) && IS_OVERFLOW_PROTECTION_ON(NewProcess->SecPolicy) && LearningMode == FALSE && BootingUp == FALSE)
{
//XXX verify that the image entry is actually at 4 meg (not true for most of system processes)
/*
* allocate up to 3 megs of virtual address space before the code segment,
* this affects main thread stack as well as some heaps
*/
#define FIRST_AVAILABLE_ADDRESS 0xFFFF
Size = PAGE_SIZE + (rand(ProcessId) % (3 * ONE_MEGABYTE));
Base = (PULONG_PTR) FIRST_AVAILABLE_ADDRESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -