/*++

Module Name:

    process_ioctl.c

Abstract:

    IOCTL handlers for KswordARK process operations.

Environment:

    Kernel-mode Driver Framework

--*/

#include "ark/ark_driver.h"
#include "../../dispatch/ioctl_validation.h"
#include "../../platform/pool_compat.h"

#include <ntstrsafe.h>
#include <stdarg.h>

#ifndef STATUS_PROCESS_IS_TERMINATING
#define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS)0xC000010AL)
#endif

#define KSWORD_ARK_ENUM_RESPONSE_HEADER_SIZE \
    (sizeof(KSWORD_ARK_ENUM_PROCESS_RESPONSE) - sizeof(KSWORD_ARK_PROCESS_ENTRY))

#define KSWORD_ARK_INJECT_REQUEST_HEADER_SIZE \
    FIELD_OFFSET(KSWORD_ARK_INJECT_PROCESS_REQUEST, payload)

#define KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG 'jIsK'

static VOID
KswordARKProcessIoctlLog(
    _In_ WDFDEVICE Device,
    _In_z_ PCSTR LevelText,
    _In_z_ PCSTR FormatText,
    ...
    )
/*++

Routine Description:

    Format and enqueue one process-handler log message.

Arguments:

    Device - WDF device that owns the log channel.
    LevelText - Log level string such as Info/Warn/Error.
    FormatText - printf-style ANSI message template.
    ... - Template arguments.

Return Value:

    None. Formatting or enqueue failures are intentionally ignored.

--*/
{
    CHAR logMessage[KSWORD_ARK_LOG_ENTRY_MAX_BYTES] = { 0 };
    va_list arguments;

    va_start(arguments, FormatText);
    if (NT_SUCCESS(RtlStringCbVPrintfA(
        logMessage,
        sizeof(logMessage),
        FormatText,
        arguments))) {
        (void)KswordARKDriverEnqueueLogFrame(Device, LevelText, logMessage);
    }
    va_end(arguments);
}

NTSTATUS
KswordARKProcessIoctlTerminate(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_TERMINATE_PROCESS. The handler validates the fixed
    request and forwards process termination to the existing process feature.

Arguments:

    Device - WDF device used for logging and feature context.
    Request - Current IOCTL request.
    InputBufferLength - Caller-supplied input length; used by WDF retrieval.
    OutputBufferLength - Caller-supplied output length; unused for this IOCTL.
    BytesReturned - Receives sizeof(request) on success and zero on failure.

Return Value:

    NTSTATUS from validation or KswordARKDriverTerminateProcessByPid.

--*/
{
    KSWORD_ARK_TERMINATE_PROCESS_REQUEST* terminateRequest = NULL;
    PVOID inputBuffer = NULL;
    size_t actualInputLength = 0;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0;

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        sizeof(KSWORD_ARK_TERMINATE_PROCESS_REQUEST),
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 terminate ioctl: input buffer invalid, status=0x%08X", (unsigned int)status);
        return status;
    }

    terminateRequest = (KSWORD_ARK_TERMINATE_PROCESS_REQUEST*)inputBuffer;
    status = KswordARKValidateUserPid((ULONG)terminateRequest->processId);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 terminate ioctl: pid=%lu rejected.", (unsigned long)terminateRequest->processId);
        return status;
    }
    {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_TERMINATE;
        safetyContext.TargetProcessId = (ULONG)terminateRequest->processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            KswordARKProcessIoctlLog(Device, "Warn", "R0 terminate denied by safety policy: pid=%lu, status=0x%08X.", (unsigned long)terminateRequest->processId, (unsigned int)status);
            return status;
        }
    }

    KswordARKProcessIoctlLog(Device, "Info", "R0 terminate ioctl: pid=%lu, exit=0x%08X.", (unsigned long)terminateRequest->processId, (unsigned int)terminateRequest->exitStatus);
    status = KswordARKDriverTerminateProcessByPid(Device, (ULONG)terminateRequest->processId, (NTSTATUS)terminateRequest->exitStatus);
    if (NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Info", "R0 terminate success: pid=%lu.", (unsigned long)terminateRequest->processId);
        *BytesReturned = sizeof(KSWORD_ARK_TERMINATE_PROCESS_REQUEST);
    }
    else if (status == STATUS_PROCESS_IS_TERMINATING) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 terminate pending: pid=%lu, status=0x%08X (still terminating).", (unsigned long)terminateRequest->processId, (unsigned int)status);
    }
    else {
        KswordARKProcessIoctlLog(Device, "Error", "R0 terminate failed: pid=%lu, status=0x%08X.", (unsigned long)terminateRequest->processId, (unsigned int)status);
    }

    return status;
}

NTSTATUS
KswordARKProcessIoctlSuspend(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_SUSPEND_PROCESS with the same request and completion
    semantics as the previous dispatch switch case.

Arguments:

    Device - WDF device used for logging.
    Request - Current IOCTL request.
    InputBufferLength - Caller input length; used by WDF retrieval.
    OutputBufferLength - Caller output length; unused for this IOCTL.
    BytesReturned - Receives sizeof(request) on success and zero on failure.

Return Value:

    NTSTATUS from validation or KswordARKDriverSuspendProcessByPid.

--*/
{
    KSWORD_ARK_SUSPEND_PROCESS_REQUEST* suspendRequest = NULL;
    PVOID inputBuffer = NULL;
    size_t actualInputLength = 0;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0;

    status = KswordARKRetrieveRequiredInputBuffer(Request, sizeof(KSWORD_ARK_SUSPEND_PROCESS_REQUEST), &inputBuffer, &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 suspend ioctl: input buffer invalid, status=0x%08X", (unsigned int)status);
        return status;
    }

    suspendRequest = (KSWORD_ARK_SUSPEND_PROCESS_REQUEST*)inputBuffer;
    status = KswordARKValidateUserPid((ULONG)suspendRequest->processId);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 suspend ioctl: pid=%lu rejected.", (unsigned long)suspendRequest->processId);
        return status;
    }
    {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_SUSPEND;
        safetyContext.TargetProcessId = (ULONG)suspendRequest->processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            KswordARKProcessIoctlLog(Device, "Warn", "R0 suspend denied by safety policy: pid=%lu, status=0x%08X.", (unsigned long)suspendRequest->processId, (unsigned int)status);
            return status;
        }
    }

    KswordARKProcessIoctlLog(Device, "Info", "R0 suspend ioctl: pid=%lu.", (unsigned long)suspendRequest->processId);
    status = KswordARKDriverSuspendProcessByPid((ULONG)suspendRequest->processId);
    if (NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Info", "R0 suspend success: pid=%lu.", (unsigned long)suspendRequest->processId);
        *BytesReturned = sizeof(KSWORD_ARK_SUSPEND_PROCESS_REQUEST);
    }
    else {
        KswordARKProcessIoctlLog(Device, "Error", "R0 suspend failed: pid=%lu, status=0x%08X.", (unsigned long)suspendRequest->processId, (unsigned int)status);
    }

    return status;
}

NTSTATUS
KswordARKProcessIoctlSetPplLevel(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_SET_PPL_LEVEL by forwarding the requested protection
    byte to the process feature after basic PID validation.

Arguments:

    Device - WDF device used for logging.
    Request - Current IOCTL request.
    InputBufferLength - Caller input length; used by WDF retrieval.
    OutputBufferLength - Caller output length; unused for this IOCTL.
    BytesReturned - Receives sizeof(request) on success and zero on failure.

Return Value:

    NTSTATUS from validation or KswordARKDriverSetProcessPplLevelByPid.

--*/
{
    KSWORD_ARK_SET_PPL_LEVEL_REQUEST* setPplRequest = NULL;
    PVOID inputBuffer = NULL;
    size_t actualInputLength = 0;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0;

    status = KswordARKRetrieveRequiredInputBuffer(Request, sizeof(KSWORD_ARK_SET_PPL_LEVEL_REQUEST), &inputBuffer, &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 set PPL ioctl: input buffer invalid, status=0x%08X", (unsigned int)status);
        return status;
    }

    setPplRequest = (KSWORD_ARK_SET_PPL_LEVEL_REQUEST*)inputBuffer;
    status = KswordARKValidateUserPid((ULONG)setPplRequest->processId);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 set PPL ioctl: pid=%lu rejected.", (unsigned long)setPplRequest->processId);
        return status;
    }
    {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_SET_PROTECTION;
        safetyContext.TargetProcessId = (ULONG)setPplRequest->processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            KswordARKProcessIoctlLog(Device, "Warn", "R0 set PPL denied by safety policy: pid=%lu, status=0x%08X.", (unsigned long)setPplRequest->processId, (unsigned int)status);
            return status;
        }
    }

    KswordARKProcessIoctlLog(Device, "Info", "R0 set PPL ioctl: pid=%lu, level=0x%02X.", (unsigned long)setPplRequest->processId, (unsigned int)setPplRequest->protectionLevel);
    status = KswordARKDriverSetProcessPplLevelByPid((ULONG)setPplRequest->processId, (UCHAR)setPplRequest->protectionLevel);
    if (NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Info", "R0 set PPL success: pid=%lu, level=0x%02X.", (unsigned long)setPplRequest->processId, (unsigned int)setPplRequest->protectionLevel);
        *BytesReturned = sizeof(KSWORD_ARK_SET_PPL_LEVEL_REQUEST);
    }
    else {
        KswordARKProcessIoctlLog(Device, "Error", "R0 set PPL failed: pid=%lu, level=0x%02X, status=0x%08X.", (unsigned long)setPplRequest->processId, (unsigned int)setPplRequest->protectionLevel, (unsigned int)status);
    }

    return status;
}

NTSTATUS
KswordARKProcessIoctlSetIntegrity(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_SET_PROCESS_INTEGRITY. 中文说明：handler 只负责
    访问校验、固定包解析与 safety policy；后端先通过 Zw* token API 设置
    TokenIntegrityLevel，API 拒绝时可在 DynData/PDB 校验后执行 Token SID
    原地覆盖兜底。

Arguments:

    Device - WDF device used for logging and safety policy.
    Request - Current IOCTL request.
    InputBufferLength - Input length; validated through WDF helper.
    OutputBufferLength - Output length; validated through WDF helper.
    BytesReturned - Receives sizeof(response) when output is available.

Return Value:

    STATUS_SUCCESS once the response packet is valid. Per-target operation
    status is reported in response->status/lastStatus.

--*/
{
    KSWORD_ARK_SET_PROCESS_INTEGRITY_REQUEST* integrityRequest = NULL;
    KSWORD_ARK_SET_PROCESS_INTEGRITY_REQUEST integrityRequestSnapshot;
    KSWORD_ARK_SET_PROCESS_INTEGRITY_RESPONSE* integrityResponse = NULL;
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0U;
    size_t actualOutputLength = 0U;
    NTSTATUS status = STATUS_SUCCESS;
    NTSTATUS operationStatus = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0U;

    status = KswordARKValidateDeviceIoControlWriteAccess(Request);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 process-integrity denied: write access required, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_INTEGRITY_REQUEST),
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-integrity ioctl: input invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    /*
     * METHOD_BUFFERED can expose the same system buffer for input and output.
     * Snapshot the request before the response buffer is zeroed; otherwise
     * clearing the response aliases and erases processId/integrityRid.
     */
    integrityRequest = (KSWORD_ARK_SET_PROCESS_INTEGRITY_REQUEST*)inputBuffer;
    RtlCopyMemory(&integrityRequestSnapshot, integrityRequest, sizeof(integrityRequestSnapshot));

    status = KswordARKRetrieveRequiredOutputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_INTEGRITY_RESPONSE),
        &outputBuffer,
        &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-integrity ioctl: output invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    integrityResponse = (KSWORD_ARK_SET_PROCESS_INTEGRITY_RESPONSE*)outputBuffer;
    RtlZeroMemory(integrityResponse, sizeof(*integrityResponse));
    integrityResponse->size = sizeof(*integrityResponse);
    integrityResponse->version = KSWORD_ARK_PROCESS_INTEGRITY_PROTOCOL_VERSION;
    integrityResponse->processId = integrityRequestSnapshot.processId;
    integrityResponse->integrityRid = integrityRequestSnapshot.integrityRid;
    integrityResponse->status = KSWORD_ARK_PROCESS_INTEGRITY_STATUS_FAILED;
    integrityResponse->lastStatus = STATUS_INVALID_PARAMETER;
    *BytesReturned = sizeof(*integrityResponse);

    if (integrityRequestSnapshot.size != sizeof(integrityRequestSnapshot) ||
        integrityRequestSnapshot.version != KSWORD_ARK_PROCESS_INTEGRITY_PROTOCOL_VERSION) {
        KswordARKProcessIoctlLog(
            Device,
            "Warn",
            "R0 process-integrity ioctl: protocol rejected, size=%lu, version=%lu.",
            (unsigned long)integrityRequestSnapshot.size,
            (unsigned long)integrityRequestSnapshot.version);
        return STATUS_SUCCESS;
    }

    status = KswordARKValidateUserPid((ULONG)integrityRequestSnapshot.processId);
    if (!NT_SUCCESS(status)) {
        integrityResponse->lastStatus = status;
        KswordARKProcessIoctlLog(Device, "Warn", "R0 process-integrity ioctl: pid=%lu rejected.", (unsigned long)integrityRequestSnapshot.processId);
        return STATUS_SUCCESS;
    }

    {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_SET_PROTECTION;
        safetyContext.TargetProcessId = (ULONG)integrityRequestSnapshot.processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            integrityResponse->lastStatus = status;
            KswordARKProcessIoctlLog(Device, "Warn", "R0 process-integrity denied by safety policy: pid=%lu, status=0x%08X.", (unsigned long)integrityRequestSnapshot.processId, (unsigned int)status);
            return STATUS_SUCCESS;
        }
    }

    operationStatus = KswordARKDriverSetProcessIntegrityByPid(
        (ULONG)integrityRequestSnapshot.processId,
        (ULONG)integrityRequestSnapshot.integrityRid);
    integrityResponse->lastStatus = operationStatus;
    integrityResponse->status = NT_SUCCESS(operationStatus)
        ? KSWORD_ARK_PROCESS_INTEGRITY_STATUS_APPLIED
        : KSWORD_ARK_PROCESS_INTEGRITY_STATUS_FAILED;

    {
        CHAR diagnosticText[512] = { 0 };
        if (NT_SUCCESS(KswordARKDriverDescribeLastProcessIntegrityAttempt(
            diagnosticText,
            sizeof(diagnosticText)))) {
            KswordARKProcessIoctlLog(
                Device,
                NT_SUCCESS(operationStatus) ? "Info" : "Warn",
                "R0 process-integrity detail: %s",
                diagnosticText);
        }
    }

    if (NT_SUCCESS(operationStatus)) {
        KswordARKProcessIoctlLog(
            Device,
            "Info",
            "R0 process-integrity success: pid=%lu, rid=0x%08lX.",
            (unsigned long)integrityRequestSnapshot.processId,
            (unsigned long)integrityRequestSnapshot.integrityRid);
    }
    else {
        KswordARKProcessIoctlLog(
            Device,
            "Error",
            "R0 process-integrity failed: pid=%lu, rid=0x%08lX, status=0x%08X.",
            (unsigned long)integrityRequestSnapshot.processId,
            (unsigned long)integrityRequestSnapshot.integrityRid,
            (unsigned int)operationStatus);
    }

    return STATUS_SUCCESS;
}
NTSTATUS
KswordARKProcessIoctlEnumProcess(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_ENUM_PROCESS. Optional input keeps the old default
    scan-CID-table behavior; output parsing and feature call remain unchanged.

Arguments:

    Device - WDF device used for logging.
    Request - Current IOCTL request.
    InputBufferLength - Supplied input bytes; shorter input selects defaults.
    OutputBufferLength - Supplied output bytes; checked by WDF output retrieval.
    BytesReturned - Receives the feature-written response byte count.

Return Value:

    NTSTATUS from buffer retrieval or KswordARKDriverEnumerateProcesses.

--*/
{
    KSWORD_ARK_ENUM_PROCESS_REQUEST* enumRequest = NULL;
    KSWORD_ARK_ENUM_PROCESS_REQUEST requestSnapshot = { 0 };
    KSWORD_ARK_ENUM_PROCESS_REQUEST defaultRequest = { 0 };
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0;
    size_t actualOutputLength = 0;
    BOOLEAN hasInput = FALSE;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0;

    status = KswordARKRetrieveOptionalInputBuffer(
        Request,
        InputBufferLength,
        sizeof(KSWORD_ARK_ENUM_PROCESS_REQUEST),
        &inputBuffer,
        &actualInputLength,
        &hasInput);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 enum-process ioctl: input buffer invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    if (hasInput) {
        /* Preserve METHOD_BUFFERED input before output retrieval exposes the shared buffer. */
        RtlCopyMemory(
            &requestSnapshot,
            inputBuffer,
            sizeof(requestSnapshot));
        enumRequest = &requestSnapshot;
    }
    else {
        enumRequest = &defaultRequest;
        enumRequest->flags = KSWORD_ARK_ENUM_PROCESS_FLAG_SCAN_CID_TABLE;
        enumRequest->startPid = 0UL;
        enumRequest->endPid = 0UL;
        enumRequest->reserved = 0UL;
    }

    status = KswordARKRetrieveRequiredOutputBuffer(Request, KSWORD_ARK_ENUM_RESPONSE_HEADER_SIZE, &outputBuffer, &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 enum-process ioctl: output buffer invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKDriverEnumerateProcesses(outputBuffer, actualOutputLength, enumRequest, BytesReturned);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 enum-process failed: status=0x%08X, outBytes=%Iu.", (unsigned int)status, *BytesReturned);
        return status;
    }

    if (*BytesReturned >= KSWORD_ARK_ENUM_RESPONSE_HEADER_SIZE) {
        KSWORD_ARK_ENUM_PROCESS_RESPONSE* responseHeader = (KSWORD_ARK_ENUM_PROCESS_RESPONSE*)outputBuffer;
        KswordARKProcessIoctlLog(
            Device,
            "Info",
            "R0 enum-process success: total=%lu, returned=%lu, outBytes=%Iu.",
            (unsigned long)responseHeader->totalCount,
            (unsigned long)responseHeader->returnedCount,
            *BytesReturned);
    }
    else {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 enum-process success: outBytes=%Iu (header partial).", *BytesReturned);
    }

    return status;
}

NTSTATUS
KswordARKProcessIoctlSetVisibility(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    处理 IOCTL_KSWORD_ARK_SET_PROCESS_VISIBILITY。中文说明：该 IOCTL 执行
    Ksword 管理的 ActiveProcessLinks 可恢复摘链/恢复；handler 负责写访问、
    safety policy 和固定包校验，后端不接受 R3 传入内核地址。

Arguments:

    Device - WDF 设备对象，用于日志。
    Request - 当前 IOCTL 请求。
    InputBufferLength - 输入长度；必须包含固定请求。
    OutputBufferLength - 输出长度；必须容纳固定响应。
    BytesReturned - 返回写入字节数。

Return Value:

    NTSTATUS from validation or feature backend.

--*/
{
    KSWORD_ARK_SET_PROCESS_VISIBILITY_REQUEST* visibilityRequest = NULL;
    KSWORD_ARK_SET_PROCESS_VISIBILITY_RESPONSE* visibilityResponse = NULL;
    KSWORD_ARK_SET_PROCESS_VISIBILITY_REQUEST visibilityRequestValue;
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0U;
    size_t actualOutputLength = 0U;
    ULONG visibilityStatus = KSWORD_ARK_PROCESS_VISIBILITY_STATUS_UNKNOWN;
    ULONG hiddenCount = 0UL;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0U;

    status = KswordARKValidateDeviceIoControlWriteAccess(Request);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 process visibility denied: write access required, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_VISIBILITY_REQUEST),
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process visibility ioctl: input invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredOutputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_VISIBILITY_RESPONSE),
        &outputBuffer,
        &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process visibility ioctl: output invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    visibilityRequest = (KSWORD_ARK_SET_PROCESS_VISIBILITY_REQUEST*)inputBuffer;
    RtlZeroMemory(&visibilityRequestValue, sizeof(visibilityRequestValue));
    RtlCopyMemory(&visibilityRequestValue, visibilityRequest, sizeof(visibilityRequestValue));
    visibilityResponse = (KSWORD_ARK_SET_PROCESS_VISIBILITY_RESPONSE*)outputBuffer;
    RtlZeroMemory(visibilityResponse, sizeof(*visibilityResponse));
    visibilityResponse->version = KSWORD_ARK_ENUM_PROCESS_PROTOCOL_VERSION;
    visibilityResponse->processId = visibilityRequestValue.processId;

    if (visibilityRequestValue.action == KSWORD_ARK_PROCESS_VISIBILITY_ACTION_HIDE) {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_KERNEL_PATCH;
        safetyContext.TargetProcessId = (ULONG)visibilityRequestValue.processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            visibilityResponse->status = KSWORD_ARK_PROCESS_VISIBILITY_STATUS_UNKNOWN;
            visibilityResponse->hiddenCount = 0UL;
            visibilityResponse->lastStatus = status;
            *BytesReturned = sizeof(*visibilityResponse);
            KswordARKProcessIoctlLog(
                Device,
                "Warn",
                "R0 process visibility denied by safety policy: pid=%lu, action=%lu, status=0x%08X.",
                (unsigned long)visibilityRequestValue.processId,
                (unsigned long)visibilityRequestValue.action,
                (unsigned int)status);
            return status;
        }
    }

    status = KswordARKDriverSetProcessVisibility(
        (ULONG)visibilityRequestValue.processId,
        (ULONG)visibilityRequestValue.action,
        (ULONG)visibilityRequestValue.flags,
        &visibilityStatus,
        &hiddenCount);

    visibilityResponse->status = visibilityStatus;
    visibilityResponse->hiddenCount = hiddenCount;
    visibilityResponse->lastStatus = status;
    *BytesReturned = sizeof(*visibilityResponse);

    if (NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(
            Device,
            "Info",
            "R0 process visibility updated: pid=%lu, action=%lu, flags=0x%08lX, status=%lu, hiddenCount=%lu.",
            (unsigned long)visibilityRequestValue.processId,
            (unsigned long)visibilityRequestValue.action,
            (unsigned long)visibilityRequestValue.flags,
            (unsigned long)visibilityStatus,
            (unsigned long)hiddenCount);
    }
    else {
        KswordARKProcessIoctlLog(
            Device,
            "Error",
            "R0 process visibility failed: pid=%lu, action=%lu, flags=0x%08lX, status=0x%08X.",
            (unsigned long)visibilityRequestValue.processId,
            (unsigned long)visibilityRequestValue.action,
            (unsigned long)visibilityRequestValue.flags,
            (unsigned int)status);
    }

    return status;
}

NTSTATUS
KswordARKProcessIoctlSetSpecialFlags(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    处理 IOCTL_KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS。中文说明：handler 负责
    写访问、安全策略和固定包校验，具体 BreakOnTermination/APC 写入在
    process_flags.c 中完成。

Arguments:

    Device - WDF 设备对象，用于日志和 safety policy。
    Request - 当前 IOCTL 请求。
    InputBufferLength - 输入长度；必须包含固定请求。
    OutputBufferLength - 输出长度；必须容纳固定响应。
    BytesReturned - 返回响应字节数。

Return Value:

    NTSTATUS from validation, safety policy or feature backend.

--*/
{
    KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_REQUEST* specialRequest = NULL;
    KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_RESPONSE* specialResponse = NULL;
    KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_REQUEST specialRequestValue;
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0U;
    size_t actualOutputLength = 0U;
    ULONG operationStatus = KSWORD_ARK_PROCESS_SPECIAL_STATUS_UNKNOWN;
    ULONG appliedFlags = 0UL;
    ULONG touchedThreadCount = 0UL;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0U;

    status = KswordARKValidateDeviceIoControlWriteAccess(Request);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 process-special denied: write access required, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_REQUEST),
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-special ioctl: input invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredOutputBuffer(
        Request,
        sizeof(KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_RESPONSE),
        &outputBuffer,
        &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-special ioctl: output invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    specialRequest = (KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_REQUEST*)inputBuffer;
    RtlZeroMemory(&specialRequestValue, sizeof(specialRequestValue));
    RtlCopyMemory(&specialRequestValue, specialRequest, sizeof(specialRequestValue));
    specialResponse = (KSWORD_ARK_SET_PROCESS_SPECIAL_FLAGS_RESPONSE*)outputBuffer;
    RtlZeroMemory(specialResponse, sizeof(*specialResponse));
    specialResponse->version = KSWORD_ARK_ENUM_PROCESS_PROTOCOL_VERSION;
    specialResponse->processId = specialRequestValue.processId;
    specialResponse->action = specialRequestValue.action;

    status = KswordARKValidateUserPid((ULONG)specialRequestValue.processId);
    if (NT_SUCCESS(status)) {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_SET_PROTECTION;
        safetyContext.TargetProcessId = (ULONG)specialRequestValue.processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
    }

    if (NT_SUCCESS(status)) {
        status = KswordARKDriverSetProcessSpecialFlags(
            (ULONG)specialRequestValue.processId,
            (ULONG)specialRequestValue.action,
            (ULONG)specialRequestValue.flags,
            &operationStatus,
            &appliedFlags,
            &touchedThreadCount);
    }
    else {
        operationStatus = KSWORD_ARK_PROCESS_SPECIAL_STATUS_OPERATION_FAILED;
    }

    specialResponse->status = operationStatus;
    specialResponse->appliedFlags = appliedFlags;
    specialResponse->touchedThreadCount = touchedThreadCount;
    specialResponse->lastStatus = status;
    *BytesReturned = sizeof(*specialResponse);

    KswordARKProcessIoctlLog(
        Device,
        NT_SUCCESS(status) ? "Info" : "Error",
        "R0 process-special result: pid=%lu, action=%lu, status=%lu, touched=%lu, nt=0x%08X.",
        (unsigned long)specialRequestValue.processId,
        (unsigned long)specialRequestValue.action,
        (unsigned long)operationStatus,
        (unsigned long)touchedThreadCount,
        (unsigned int)status);
    return status;
}

NTSTATUS
KswordARKProcessIoctlDkomProcess(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    处理 IOCTL_KSWORD_ARK_DKOM_PROCESS。中文说明：当前只提供从 PspCidTable
    删除目标 PID 对应 EPROCESS 的高危动作，地址均由 R0 自行解析。

Arguments:

    Device - WDF 设备对象，用于日志和 safety policy。
    Request - 当前 IOCTL 请求。
    InputBufferLength - 输入长度；必须包含固定请求。
    OutputBufferLength - 输出长度；必须容纳固定响应。
    BytesReturned - 返回响应字节数。

Return Value:

    NTSTATUS from validation, safety policy or feature backend.

--*/
{
    KSWORD_ARK_DKOM_PROCESS_REQUEST* dkomRequest = NULL;
    KSWORD_ARK_DKOM_PROCESS_RESPONSE* dkomResponse = NULL;
    KSWORD_ARK_DKOM_PROCESS_REQUEST dkomRequestValue;
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0U;
    size_t actualOutputLength = 0U;
    ULONG operationStatus = KSWORD_ARK_PROCESS_DKOM_STATUS_UNKNOWN;
    ULONG removedEntries = 0UL;
    ULONG64 pspCidTableAddress = 0ULL;
    ULONG64 processObjectAddress = 0ULL;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0U;

    status = KswordARKValidateDeviceIoControlWriteAccess(Request);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 process-dkom denied: write access required, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        sizeof(KSWORD_ARK_DKOM_PROCESS_REQUEST),
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-dkom ioctl: input invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredOutputBuffer(
        Request,
        sizeof(KSWORD_ARK_DKOM_PROCESS_RESPONSE),
        &outputBuffer,
        &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 process-dkom ioctl: output invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    dkomRequest = (KSWORD_ARK_DKOM_PROCESS_REQUEST*)inputBuffer;
    RtlZeroMemory(&dkomRequestValue, sizeof(dkomRequestValue));
    RtlCopyMemory(&dkomRequestValue, dkomRequest, sizeof(dkomRequestValue));
    dkomResponse = (KSWORD_ARK_DKOM_PROCESS_RESPONSE*)outputBuffer;
    RtlZeroMemory(dkomResponse, sizeof(*dkomResponse));
    dkomResponse->version = KSWORD_ARK_ENUM_PROCESS_PROTOCOL_VERSION;
    dkomResponse->processId = dkomRequestValue.processId;
    dkomResponse->action = dkomRequestValue.action;

    status = KswordARKValidateUserPid((ULONG)dkomRequestValue.processId);
    if (NT_SUCCESS(status)) {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_KERNEL_PATCH;
        safetyContext.TargetProcessId = (ULONG)dkomRequestValue.processId;
        safetyContext.ContextFlags = KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
    }

    if (NT_SUCCESS(status)) {
        status = KswordARKDriverDkomProcess(
            (ULONG)dkomRequestValue.processId,
            (ULONG)dkomRequestValue.action,
            (ULONG)dkomRequestValue.flags,
            &operationStatus,
            &removedEntries,
            &pspCidTableAddress,
            &processObjectAddress);
    }
    else {
        operationStatus = KSWORD_ARK_PROCESS_DKOM_STATUS_OPERATION_FAILED;
    }

    dkomResponse->status = operationStatus;
    dkomResponse->removedEntries = removedEntries;
    dkomResponse->lastStatus = status;
    dkomResponse->pspCidTableAddress = pspCidTableAddress;
    dkomResponse->processObjectAddress = processObjectAddress;
    *BytesReturned = sizeof(*dkomResponse);

    KswordARKProcessIoctlLog(
        Device,
        NT_SUCCESS(status) ? "Info" : "Error",
        "R0 process-dkom result: pid=%lu, action=%lu, status=%lu, removed=%lu, cid=0x%I64X, nt=0x%08X.",
        (unsigned long)dkomRequestValue.processId,
        (unsigned long)dkomRequestValue.action,
        (unsigned long)operationStatus,
        (unsigned long)removedEntries,
        pspCidTableAddress,
        (unsigned int)status);
    return status;
}

NTSTATUS
KswordARKProcessIoctlInjectProcess(
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST Request,
    _In_ size_t InputBufferLength,
    _In_ size_t OutputBufferLength,
    _Out_ size_t* BytesReturned
    )
/*++

Routine Description:

    Handle IOCTL_KSWORD_ARK_INJECT_PROCESS. The METHOD_BUFFERED input carries a
    variable-length DLL path or shellcode blob, so the handler copies it before
    retrieving the output buffer.

Arguments:

    Device - WDF device used for logging and safety policy.
    Request - Current IOCTL request.
    InputBufferLength - Input length supplied by WDF; validation uses the
        retrieved buffer length.
    OutputBufferLength - Output length supplied by WDF; validation uses the
        retrieved buffer length.
    BytesReturned - Receives sizeof(KSWORD_ARK_INJECT_PROCESS_RESPONSE) when a
        semantic response is produced.

Return Value:

    STATUS_SUCCESS when the response contains the semantic injection status, or
    validation/safety NTSTATUS when the request cannot be executed.

--*/
{
    KSWORD_ARK_INJECT_PROCESS_REQUEST* injectRequest = NULL;
    KSWORD_ARK_INJECT_PROCESS_REQUEST* injectRequestCopy = NULL;
    KSWORD_ARK_INJECT_PROCESS_RESPONSE* injectResponse = NULL;
    PVOID inputBuffer = NULL;
    PVOID outputBuffer = NULL;
    size_t actualInputLength = 0U;
    size_t actualOutputLength = 0U;
    size_t requiredInputLength = 0U;
    size_t bytesWritten = 0U;
    const ULONG allowedFlags =
        KSWORD_ARK_PROCESS_INJECT_FLAG_UI_CONFIRMED |
        KSWORD_ARK_PROCESS_INJECT_FLAG_WAIT_THREAD;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    if (BytesReturned == NULL) {
        return STATUS_INVALID_PARAMETER;
    }
    *BytesReturned = 0U;

    status = KswordARKValidateDeviceIoControlWriteAccess(Request);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 inject denied: write access required, status=0x%08X.", (unsigned int)status);
        return status;
    }

    status = KswordARKRetrieveRequiredInputBuffer(
        Request,
        KSWORD_ARK_INJECT_REQUEST_HEADER_SIZE,
        &inputBuffer,
        &actualInputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 inject ioctl: input invalid, status=0x%08X.", (unsigned int)status);
        return status;
    }

    injectRequest = (KSWORD_ARK_INJECT_PROCESS_REQUEST*)inputBuffer;
    if (injectRequest->version != KSWORD_ARK_PROCESS_INJECT_PROTOCOL_VERSION ||
        (injectRequest->flags & ~allowedFlags) != 0UL ||
        (injectRequest->injectType != KSWORD_ARK_PROCESS_INJECT_TYPE_DLL_PATH &&
            injectRequest->injectType != KSWORD_ARK_PROCESS_INJECT_TYPE_SHELLCODE) ||
        injectRequest->payloadBytes == 0UL ||
        injectRequest->payloadBytes > KSWORD_ARK_PROCESS_INJECT_MAX_PAYLOAD_BYTES ||
        (SIZE_T)injectRequest->payloadBytes > (MAXSIZE_T - KSWORD_ARK_INJECT_REQUEST_HEADER_SIZE)) {
        KswordARKProcessIoctlLog(
            Device,
            "Warn",
            "R0 inject ioctl: request rejected, pid=%lu, type=%lu, flags=0x%08X, bytes=%lu.",
            (unsigned long)injectRequest->processId,
            (unsigned long)injectRequest->injectType,
            (unsigned int)injectRequest->flags,
            (unsigned long)injectRequest->payloadBytes);
        return STATUS_INVALID_PARAMETER;
    }

    status = KswordARKValidateUserPid((ULONG)injectRequest->processId);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Warn", "R0 inject ioctl: pid rejected, pid=%lu.", (unsigned long)injectRequest->processId);
        return status;
    }

    requiredInputLength =
        KSWORD_ARK_INJECT_REQUEST_HEADER_SIZE +
        (SIZE_T)injectRequest->payloadBytes;
    if (actualInputLength < requiredInputLength) {
        KswordARKProcessIoctlLog(
            Device,
            "Warn",
            "R0 inject ioctl: input truncated, actual=%Iu, required=%Iu.",
            actualInputLength,
            requiredInputLength);
        return STATUS_INVALID_PARAMETER;
    }

    injectRequestCopy = (KSWORD_ARK_INJECT_PROCESS_REQUEST*)KswordARKAllocateNonPagedPool(
        requiredInputLength,
        KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG);
    if (injectRequestCopy == NULL) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 inject ioctl: input copy allocation failed, bytes=%Iu.", requiredInputLength);
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlCopyMemory(injectRequestCopy, injectRequest, requiredInputLength);
    injectRequest = injectRequestCopy;

    status = KswordARKRetrieveRequiredOutputBuffer(
        Request,
        sizeof(KSWORD_ARK_INJECT_PROCESS_RESPONSE),
        &outputBuffer,
        &actualOutputLength);
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(Device, "Error", "R0 inject ioctl: output invalid, status=0x%08X.", (unsigned int)status);
        ExFreePoolWithTag(injectRequestCopy, KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG);
        return status;
    }

    {
        KSWORD_ARK_SAFETY_CONTEXT safetyContext;
        RtlZeroMemory(&safetyContext, sizeof(safetyContext));
        safetyContext.Operation = KSWORD_ARK_SAFETY_OPERATION_PROCESS_INJECT;
        safetyContext.TargetProcessId = (ULONG)injectRequest->processId;
        safetyContext.ContextFlags =
            ((injectRequest->flags & KSWORD_ARK_PROCESS_INJECT_FLAG_UI_CONFIRMED) != 0UL) ?
            KSWORD_ARK_SAFETY_CONTEXT_FLAG_UI_CONFIRMED :
            0UL;
        status = KswordARKSafetyEvaluate(Device, &safetyContext);
        if (!NT_SUCCESS(status)) {
            KswordARKProcessIoctlLog(
                Device,
                "Warn",
                "R0 inject denied by safety policy: pid=%lu, type=%lu, status=0x%08X.",
                (unsigned long)injectRequest->processId,
                (unsigned long)injectRequest->injectType,
                (unsigned int)status);
            ExFreePoolWithTag(injectRequestCopy, KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG);
            return status;
        }
    }

    injectResponse = (KSWORD_ARK_INJECT_PROCESS_RESPONSE*)outputBuffer;
    status = KswordARKDriverInjectProcess(
        injectResponse,
        actualOutputLength,
        injectRequest,
        requiredInputLength,
        &bytesWritten);
    *BytesReturned = bytesWritten;
    if (!NT_SUCCESS(status)) {
        KswordARKProcessIoctlLog(
            Device,
            "Error",
            "R0 inject backend failed: pid=%lu, type=%lu, status=0x%08X.",
            (unsigned long)injectRequest->processId,
            (unsigned long)injectRequest->injectType,
            (unsigned int)status);
        ExFreePoolWithTag(injectRequestCopy, KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG);
        return status;
    }

    if (*BytesReturned >= sizeof(KSWORD_ARK_INJECT_PROCESS_RESPONSE)) {
        KswordARKProcessIoctlLog(
            Device,
            injectResponse->status == KSWORD_ARK_PROCESS_INJECT_STATUS_INJECTED ? "Info" : "Error",
            "R0 inject result: pid=%lu, type=%lu, status=%lu, written=%lu, remote=0x%I64X, nt=0x%08X.",
            (unsigned long)injectResponse->processId,
            (unsigned long)injectResponse->injectType,
            (unsigned long)injectResponse->status,
            (unsigned long)injectResponse->bytesWritten,
            injectResponse->remoteBaseAddress,
            (unsigned int)injectResponse->lastStatus);
    }

    ExFreePoolWithTag(injectRequestCopy, KSWORD_ARK_PROCESS_INJECT_IOCTL_POOL_TAG);
    return STATUS_SUCCESS;
}
