// ke_process.c - process model #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- // Global process list // --------------------------------------------------------------------------- static LIST_ENTRY gProcessList; static SPINLOCK gProcessListLock; static uint32_t gNextProcessId = 1; static void ProcessInit(void) { static int inited = 0; if (!inited) { LIST_INIT(&gProcessList); gProcessListLock = (SPINLOCK)SPINLOCK_INIT; inited = 1; } } LIST_ENTRY* KeGetProcessList(void) { return &gProcessList; } PROCESS* KeGetCurrentProcess(void) { THREAD* currentThread = KeGetCurrentThread(); if (currentThread) { return currentThread->Owner; } return NULL; } // --------------------------------------------------------------------------- // Destructor (called by ObDereferenceObject when RefCount hits zero) // --------------------------------------------------------------------------- static void ProcessDestroy(OBJECT* obj) { PROCESS* proc = CONTAINING_RECORD(obj, PROCESS, Header); // Release all remaining handles. for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { if (proc->Handles[i]) { ObDereferenceObject(proc->Handles[i]); proc->Handles[i] = (OBJECT *)0; } } // Release the main executable image. if (proc->ImageBase && proc->ImageSize) { MmFreeUserMemory((void *)proc->ImageBase, proc->ImageSize); proc->ImageBase = 0; proc->ImageSize = 0; } // Release per-process modules. for (uint32_t i = 0; i < proc->ModuleCount; i++) { if (proc->Modules[i].Base && proc->Modules[i].Size) { MmFreeUserMemory((void *)proc->Modules[i].Base, proc->Modules[i].Size); } proc->Modules[i].Base = 0; proc->Modules[i].Size = 0; proc->Modules[i].Name[0] = '\0'; } proc->ModuleCount = 0; // Release the user command line buffer. if (proc->UserCmdlineBase && proc->UserCmdlineSize) { MmFreeUserMemory((void *)proc->UserCmdlineBase, proc->UserCmdlineSize); proc->UserCmdlineBase = 0; proc->UserCmdlineSize = 0; } // Release the exit event. if (proc->ExitEvent) { ObDereferenceObject(&proc->ExitEvent->Header); proc->ExitEvent = (EVENT *)0; } // Remove from global list. uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); ListRemove(&proc->GlobalLink); KeReleaseSpinlock(&gProcessListLock, flags); // Memory for the struct itself is freed by ObDereferenceObject after // Destroy returns. } // --------------------------------------------------------------------------- // KeCreateProcess // --------------------------------------------------------------------------- KSTATUS KeCreateProcess(const char* name, PROCESS **out) { ProcessInit(); if (!name || !out) return STATUS_INVALID_PARAMETER; PROCESS* proc = (PROCESS *)ObAllocateObject(ObjectTypeProcess, sizeof(PROCESS)); if (!proc) return STATUS_NO_MEMORY; proc->Header.Destroy = ProcessDestroy; proc->ProcessId = _InterlockedExchangeAdd((volatile long *)&gNextProcessId, 1); strncpy(proc->Name, name, PROCESS_NAME_MAX - 1); proc->Name[PROCESS_NAME_MAX - 1] = '\0'; LIST_INIT(&proc->ThreadList); proc->ThreadCount = 0; proc->HandleLock = (SPINLOCK)SPINLOCK_INIT; proc->ExitCode = 0; proc->ImageBase = 0; proc->ImageSize = 0; proc->UserCmdlineBase = 0; proc->UserCmdlineSize = 0; proc->ModuleCount = 0; // Slot 0 is the invalid handle - leave it NULL. memset(proc->Handles, 0, sizeof(proc->Handles)); LIST_INIT(&proc->GlobalLink); // Create the manual-reset exit event (initially unsignaled). if (!KSUCCESS(KeEventCreate(EventManualReset, 0, &proc->ExitEvent))) { ObDereferenceObject(&proc->Header); return STATUS_NO_MEMORY; } uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); ListInsertTail(&gProcessList, &proc->GlobalLink); KeReleaseSpinlock(&gProcessListLock, flags); *out = proc; return STATUS_SUCCESS; } // --------------------------------------------------------------------------- // KeExitProcess // --------------------------------------------------------------------------- void KeExitProcess(PROCESS* process, int exitCode) { if (!process) return; process->ExitCode = exitCode; // Wake any threads waiting for this process to finish. if (process->ExitEvent) KeSignalEvent(process->ExitEvent); // The last thread exiting via KeExitThread will drop the process refcount. // This function is a policy hook; actual cleanup is in ProcessDestroy. ObDereferenceObject(&process->Header); } // --------------------------------------------------------------------------- // KeGetProcessExitCode // --------------------------------------------------------------------------- KSTATUS KeGetProcessExitCode(PROCESS* process, int* exitCodeOut) { if (!process || !exitCodeOut) return STATUS_INVALID_PARAMETER; *exitCodeOut = process->ExitCode; return STATUS_SUCCESS; } // --------------------------------------------------------------------------- // Handle table // --------------------------------------------------------------------------- KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut) { if (!process || !object || !handleOut) return STATUS_INVALID_PARAMETER; uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { if (!process->Handles[i]) { ObReferenceObject(object); process->Handles[i] = object; *handleOut = (uint32_t)i; KeReleaseSpinlock(&process->HandleLock, flags); return STATUS_SUCCESS; } } KeReleaseSpinlock(&process->HandleLock, flags); return STATUS_NO_MEMORY; } void KeCloseHandle(PROCESS* process, uint32_t handle) { if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return; uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); OBJECT* obj = process->Handles[handle]; if (obj) { process->Handles[handle] = (OBJECT *)0; KeReleaseSpinlock(&process->HandleLock, flags); ObDereferenceObject(obj); return; } KeReleaseSpinlock(&process->HandleLock, flags); } OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) { if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return (OBJECT *)0; uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); OBJECT* obj = process->Handles[handle]; if (obj) ObReferenceObject(obj); KeReleaseSpinlock(&process->HandleLock, flags); return obj; } PROCESS* KeGetProcessById(uint32_t pid) { uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); LIST_ENTRY* head = &gProcessList; LIST_ENTRY* node = head->Fwd; while (node != head) { PROCESS* p = CONTAINING_RECORD(node, PROCESS, GlobalLink); if (p->ProcessId == pid) { ObReferenceObject(&p->Header); KeReleaseSpinlock(&gProcessListLock, flags); return p; } node = node->Fwd; } KeReleaseSpinlock(&gProcessListLock, flags); return (PROCESS*)0; }