How to program the Rules that shows up in Windows Defender rules ( Inbound, Outbound)

Prokash Sinha 81 Reputation points
2022-03-23T21:57:04.447+00:00

Hello,

For all rules ( somewhere between 20 to over 100 ), I gave the name of the filter, and descriptions, some strings. I created provider....

I can see the rules are added ( by looking at the Registry & matching Guid with the PROVIDER_KEY I gave.

If I dump I can see the filters ( I use netsh wfp show filters ).

But I CAN NOT SEE IN THE DEFENDER FIREWALL APP ( THIS IS FOR USER/ADMIN TO LOOK AT )....
Platform is Win 7

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 <wfpdiag>
3 <filters>
4 <item>
5 <filterKey>{c831a7b4-716f-4e7a-b4e3-cc19e071553e}</filterKey>
6 <displayData>
7 <name>CT_FWAPI</name>
8 <description>API CT-FWAPI</description>
9 </displayData>
10 <flags numItems="1">
11 <item>FWPM_FILTER_FLAG_PERSISTENT</item>
12 </flags>
13 <providerKey>{6fb216a8-e2e8-4024-b853-391a4168641e}</providerKey>
14 <providerData/>
15 <layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_V4</layerKey>
16 <subLayerKey>FWPM_SUBLAYER_UNIVERSAL</subLayerKey>
17 <weight>
18 <type>FWP_EMPTY</type>
19 </weight>
20 <filterCondition numItems="3">
21 <item>
22 <fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>
23 <matchType>FWP_MATCH_RANGE</matchType>
24 <conditionValue>
25 <type>FWP_RANGE_TYPE</type>
26 <....>

Windows development Windows API - Win32
0 comments No comments
{count} votes

Accepted answer
  1. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2022-03-25T01:24:54.107+00:00

    I doubt WFP API can effect the WindowsFirewall UI But you can try simplewall instead.


3 additional answers

Sort by: Most helpful
  1. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2022-03-24T05:23:15.95+00:00

    Hello,

    Welcome to Microsoft Q&A!

    Adding an Outbound Rule adds an outbound rule using the Windows Firewall with Advanced Security APIs.

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Prokash Sinha 81 Reputation points
    2022-03-24T14:24:23.81+00:00

    // 5fb216a8-e2e8-4024-b853-391a4168641e
    const GUID PROVIDER_KEY =
    {
    0x5fb216a8,
    0xe2e8,
    0x4024,
    { 0xb8, 0x53, 0x39, 0x1a, 0x41, 0x68, 0x64, 0x1e }
    };

    define SESSION_NAME L"Prokash SDK Examples"

    HANDLE CTWindowsFirewall::Install(
    __in const GUID* providerKey,
    __in PCWSTR providerName,
    __in const GUID* subLayerKey,
    __in PCWSTR subLayerName
    )
    {
    DWORD result = ERROR_SUCCESS;
    HANDLE engine = NULL;
    FWPM_SESSION0 session;
    FWPM_PROVIDER0 provider;
    //FWPM_SUBLAYER0 subLayer;

    memset(&session, 0, sizeof(session));
    // The session name isn't required but may be useful for diagnostics.
    session.displayData.name = SESSION_NAME;
    // Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT
    // errors while waiting to acquire the transaction lock.
    session.txnWaitTimeoutInMSec = INFINITE;
    
    // The authentication service should always be RPC_C_AUTHN_DEFAULT.
    result = FwpmEngineOpen0(
        NULL,
        RPC_C_AUTHN_DEFAULT,
        NULL,
        &session,
        &engine
    );
    EXIT_ON_ERROR(FwpmEngineOpen0);
    
    // We add the provider and sublayer from within a single transaction to make
    // it easy to clean up partial results in error paths.
    result = FwpmTransactionBegin0(engine, 0);
    EXIT_ON_ERROR(FwpmTransactionBegin0);
    
    memset(&provider, 0, sizeof(provider));
    // The provider and sublayer keys are going to be used repeatedly when
    // adding filters and other objects. It's easiest to use well-known GUIDs
    // defined in a header somewhere, rather than having BFE generate the keys.
    provider.providerKey = *providerKey;
    // For MUI compatibility, object names should be indirect strings. See
    // SHLoadIndirectString for details.
    provider.displayData.name = (PWSTR)providerName;
    provider.displayData.description = L" CT_FWAPI Description";
    // Since we always want the provider and sublayer to be present, it's
    // easiest to add them as persistent objects during install.  Alternatively,
    // we could add non-persistent objects every time our service starts.
    provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;
    provider.serviceName = L"CT_FWAPI serviceName ";
    
    result = FwpmProviderAdd(engine, &provider, NULL);
    // Ignore FWP_E_ALREADY_EXISTS. This allows install to be re-run as needed
    // to repair a broken configuration.
    if (result != FWP_E_ALREADY_EXISTS)
    {
        EXIT_ON_ERROR(FwpmProviderAdd0);
    }
    //SubLayer_.subLayerKey = 0;
    //this->subLayer_.subLayerKey = 0;
    

    // memset(&subLayer_, 0, sizeof(subLayer_));
    SubLayer_.subLayerKey = subLayerKey;
    SubLayer_.displayData.name = (PWSTR)subLayerName;
    SubLayer_.flags = FWPM_SUBLAYER_FLAG_PERSISTENT;
    // Link all our other objects to our provider. When multiple providers are
    // installed on a computer, this makes it easy to determine who added what.
    SubLayer_.providerKey = (GUID
    )providerKey;
    // We don't care what our sublayer weight is, so we pick a weight in the
    // middle and let BFE assign the closest available.
    SubLayer_.weight = 0x8000;

    result = FwpmSubLayerAdd0(engine, &SubLayer_, NULL);
    if (result != FWP_E_ALREADY_EXISTS)
    {
        EXIT_ON_ERROR(FwpmSubLayerAdd0);
    }
    
    // Once all the adds have succeeded, we commit the transaction to persist
    // the new objects.
    result = FwpmTransactionCommit0(engine);
    EXIT_ON_ERROR(FwpmTransactionCommit0);
    

    CLEANUP:
    // FwpmEngineClose0 accepts null engine handles, so we needn't precheck for
    // null. Also, when closing an engine handle, any transactions still in
    // progress are automatically aborted, so we needn't explicitly abort the
    // transaction in error paths.
    ///FwpmEngineClose0(engine);

    return engine;
    

    }

    void CTWindowsFirewall::AddARule(const string & Rule) {

    DWORD  result = ERROR_SUCCESS;
    DWORD fwpTxStatus = ERROR_SUCCESS;
    FWPM_FILTER0      fwpFilter;
    std::vector<FWPM_FILTER_CONDITION0> conds;
    FWPM_FILTER_CONDITION0 * filter_conds = nullptr;
    FWPM_FILTER_CONDITION0 cond_array[1024] = { 0 };
    FWP_RANGE0 port_range[2];
    UINT16 nbFilterConds = 0;
    RSJresource rule_in_json(Rule);
    bool isLocal;
    int len = 0;
    

    if 1

    //FWPM_FILTER_CONDITION0 a_fw_cond;
    //a_fw_cond = conds.front();
    
    //Massage the rule
    RtlZeroMemory(&fwpFilter, sizeof(FWPM_FILTER0));
    build_fwfilter(&fwpFilter, conds, port_range, Rule);
    

    define STACK_ALLOC

    ifdef STACK_ALLOC

    unsigned index = 0;
    for (auto it = conds.begin(); it != conds.end(); ++it) {
        // -- stack allocation works
        cond_array[index++] = *it;
    
    }
    fwpFilter.numFilterConditions = conds.size();  //1;
    fwpFilter.filterCondition = cond_array;
    

    else

    fwpFilter.numFilterConditions = conds.size();  //1;
    fwpFilter.filterCondition = cond_array;
    

    endif

    std::string action = rule_in_json["action"].as<std::string>();
    std::string direction = rule_in_json["direction"].as<std::string>();
    ////RtlZeroMemory(&fwpFilter, sizeof(FWPM_FILTER0));
    fwpFilter.layerKey = (direction == "out") ? FWPM_LAYER_OUTBOUND_TRANSPORT_V4: FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
    fwpFilter.action.type = (action == "allow") ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK;
    fwpFilter.weight.type = FWP_EMPTY;
    fwpFilter.flags |= FWPM_FILTER_FLAG_PERSISTENT;
    
    fwpFilter.displayData.name = L"CT_FWAPI";
    fwpFilter.displayData.description = L"API CT-FWAPI";
    fwpFilter.subLayerKey = SubLayer_.subLayerKey;
    fwpFilter.providerKey = (LPGUID)&PROVIDER_KEY;
    

    // fwpFilter.providerData = "What";

    endif

    if (EngineHandle_ == nullptr)
    {
        cout << "No engine opened !" << endl;
        return;
    }
    
    
    
    
    //Open a transaction
    
    fwpTxStatus = FwpmTransactionBegin0(EngineHandle_, NULL);
    if (fwpTxStatus != ERROR_SUCCESS)
    {
        printf("FwpmTransactionBegin0 failed (%d).\n", fwpTxStatus);
        return;
    }
    
    UINT64 filterId;
    
    result = FwpmFilterAdd0(EngineHandle_, &fwpFilter, NULL, &filterId);
    if (result != ERROR_SUCCESS)
    {
        std::string  err;
        err = "FwpmEngineOpen0() failed error = " + result;
        throw std::runtime_error(err);
    
        return;
    }
    else
    {
        //cache the filterId
        FilterId_.push_back(filterId);
    }
    //Commit the transaction
    result = FwpmTransactionCommit0(EngineHandle_);
    if (result != ERROR_SUCCESS)
    {
        printf("FwpmTransactionCommit0 failed (%d).\n", result);
        return;
    }
    
    //free(fwpFilter.filterCondition);
    

    }

    0 comments No comments

  3. Prokash Sinha 81 Reputation points
    2022-03-24T15:38:19.177+00:00

    So basically (Using WFP Apis Fwpm* ) --

    I can add Persitent firewall rules

    I can create Sublayer/Provider Context.

    I can see the fw entries are created. registry gets populated.

    WHAT I NEED IS TO CONNECT IT WITH WINDOWS DEFENDER FIREWALL APPLICATION (IN THE SENSE THAT THE Application show those inbound/outbound rules in a human readable way, just like Microsoft being a provider, I can see on the desktop ).

    Note:: Using COM interface, the product already works, and Windows Defender firewall shows the (IN/OUT)bound rules.

    I'm blocked here, any help ?

    Prokash

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.