0

ユーザーレベルのプロセスからのネットワーク接続試行を許可またはブロックできる単純なファイアウォール アプリケーションをコーディングしようとしています。

そのために、WFPStarterKitチュートリアルに従って、FWPM_LAYER_OUTBOUND_TRANSPORT_V4 レイヤーでデータをインターセプトするように設定された WFP ドライバーを作成しました。

ClassifyFn コールバック関数は、接続試行をインターセプトし、許可または拒否します。

ClassifyFn コールバックがヒットすると、 FltSendMessage関数を介して、パケットの ProcessID が他のいくつかの情報とともにユーザーレベルのプロセスに送信されます。

ユーザーレベルのプロセスは、メッセージを受信し、ProcessID をチェックして、ブール値の許可/拒否コマンドをドライバーに返信します。

このアプローチは最初のパケットをブロックするときに機能しますが、場合によっては (特に複数のパケットを許可する場合)、コードはINVALID_PROCESS_ATTACH_ATTEMPTエラー コードで BSOD を生成します。エラーは、FltSendMessage の呼び出しでトリガーされます。

私はまだ正確な問題を特定することはできませんが、コールアウト スレッドを (FltSendMessage を介して) ユーザーレベルからの応答を待機させると、状況によってはこの BSOD エラーが発生する可能性があるようです。

正しい方向に向けていただければ幸いです。

コールアウトを登録する関数は次のとおりです。

    NTSTATUS register_example_callout(DEVICE_OBJECT * wdm_device)
{
    NTSTATUS status = STATUS_SUCCESS;
    FWPS_CALLOUT s_callout = { 0 };
    FWPM_CALLOUT m_callout = { 0 };
    FWPM_DISPLAY_DATA display_data = { 0 };

    if (filter_engine_handle == NULL)
        return STATUS_INVALID_HANDLE;

    display_data.name = EXAMPLE_CALLOUT_NAME;
    display_data.description = EXAMPLE_CALLOUT_DESCRIPTION;

    // Register a new Callout with the Filter Engine using the provided callout functions
    s_callout.calloutKey = EXAMPLE_CALLOUT_GUID;
    s_callout.classifyFn = example_classify;
    s_callout.notifyFn = example_notify;
    s_callout.flowDeleteFn = example_flow_delete;
    status = FwpsCalloutRegister((void *)wdm_device, &s_callout, &example_callout_id);
    if (!NT_SUCCESS(status)) {
        DbgPrint("Failed to register callout functions for example callout, status 0x%08x", status);
        goto Exit;
    }

    // Setup a FWPM_CALLOUT structure to store/track the state associated with the FWPS_CALLOUT
    m_callout.calloutKey = EXAMPLE_CALLOUT_GUID;
    m_callout.displayData = display_data;
    m_callout.applicableLayer = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
    m_callout.flags = 0;
    status = FwpmCalloutAdd(filter_engine_handle, &m_callout, NULL, NULL);
    if (!NT_SUCCESS(status)) {
        DbgPrint("Failed to register example callout, status 0x%08x", status);
    }
    else {
        DbgPrint("Example Callout Registered");
    }

Exit:
    return status;
}

コールアウト関数は次のとおりです。

    /*************************
ClassifyFn Function
**************************/
void example_classify(
    const FWPS_INCOMING_VALUES * inFixedValues,
    const FWPS_INCOMING_METADATA_VALUES * inMetaValues,
    void * layerData,
    const void * classifyContext,
    const FWPS_FILTER * filter,
    UINT64 flowContext,
    FWPS_CLASSIFY_OUT * classifyOut)
{
    UNREFERENCED_PARAMETER(layerData);
    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(flowContext);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(inMetaValues);

    NETWORK_ACCESS_QUERY AccessQuery;
    BOOLEAN SafeToOpen = TRUE;
    classifyOut->actionType = FWP_ACTION_PERMIT;

    AccessQuery.remote_address = inFixedValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS].value.uint32;
    AccessQuery.remote_port = inFixedValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_PORT].value.uint16;

    // Get Process ID
    AccessQuery.ProcessId = (UINT64)PsGetCurrentProcessId();

    if (!AccessQuery.ProcessId) 
    {
        return;
    }

    // Here we connect to our userlevel application using FltSendMessage.
    // Some checks are done and the SafeToOpen variable is populated with a BOOLEAN which indicates if to allow or block the packet.
    // However, sometimes, a BSOD is generated with an INVALID_PROCESS_ATTACH_ATTEMPT error on the FltSendMessage call
    QueryUserLevel(QUERY_NETWORK, &AccessQuery, sizeof(NETWORK_ACCESS_QUERY), &SafeToOpen, NULL, 0);

    if (!SafeToOpen) {
        classifyOut->actionType = FWP_ACTION_BLOCK;
    }

    return;
}
4

2 に答える 2