Hindering Filter Deletion

The following example code demonstrates how to make a filter difficult to delete by setting a DACL.

#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <fwpmu.h>
#include <stdio.h>

#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "advapi32.lib")

#define EXIT_ON_ERROR(fnName) \
   if (result != ERROR_SUCCESS) \
   { \
      printf(#fnName " = 0x%08X\n", result); \
      goto CLEANUP; \
   }

DWORD HinderFilterDeletion(
         __in HANDLE engine,
         __in const GUID* filterKey
         )
{
   DWORD result = ERROR_SUCCESS;
   EXPLICIT_ACCESS_W access;
   SID worldSid =
   {
      SID_REVISION,
      1,
      SECURITY_WORLD_SID_AUTHORITY,
      { SECURITY_WORLD_RID }
   };
   PACL acl = NULL;

   // Deny certain access rights to the world:
   //    DELETE - prevents the object from being deleted.
   //    WRITE_DAC - prevents someone from granting themselves DELETE access.
   //       Note that the owner always has WRITE_DAC access.
   //    WRITE_OWNER - prevents someone from taking ownership. Note that anyone
   //       with the TakeOwnership privilege enabled always has WRITE_OWNER
   //       access.
   access.grfAccessPermissions = ( DELETE | WRITE_DAC | WRITE_OWNER );
   access.grfAccessMode = DENY_ACCESS;
   access.grfInheritance = 0;
   BuildTrusteeWithSid(&(access.Trustee), &worldSid);

   result = SetEntriesInAcl(1, &access, NULL, &acl);
   EXIT_ON_ERROR(SetEntriesInAcl);

   // We don't protect the new DACL because we still want the default ACEs to
   // be inherited. The deny ACE we're setting will come before (and thus
   // override) the inherited ACEs.
   result = FwpmFilterSetSecurityInfoByKey0(
               engine,
               filterKey,
               DACL_SECURITY_INFORMATION,
               NULL,
               NULL,
               acl,
               NULL
               );
   EXIT_ON_ERROR(FwpmFilterSetSecurityInfo0);

CLEANUP:
   LocalFree(acl);
   return result;
}

DWORD wmain(int argc,
            wchar_t* argv[])
{
   UNREFERENCED_PARAMETER(argc);
   UNREFERENCED_PARAMETER(argv);
   static const GUID guid = 
    { 0x836a4ff0, 0x7c26, 0x47d2, { 0xb9, 0x6d, 0x68, 0x70, 0xa, 0x98, 0x31, 0x18 } };
   
   // Open a session to the filter engine
   HANDLE engineHandle = 0;

   // Use dynamic sessions for efficiency and safety:
   //  - All objects associated with the dynamic session are deleted with one call.
   //  - Filtering policy objects are deleted even when the application crashes. 
   FWPM_SESSION0 session;
   memset(&session, 0, sizeof(session));
   session.flags = FWPM_SESSION_FLAG_DYNAMIC;

   DWORD result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engineHandle);
   EXIT_ON_ERROR(FwpmEngineOpen0);      
   
   // Add a filter
   FWPM_FILTER0 filter;
   memset(&filter, 0, sizeof(filter));
   filter.filterKey = guid;
   filter.displayData.name = L"MihaelaTestFilter";
   filter.action.type = FWP_ACTION_BLOCK;
   filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V4;
   result = FwpmFilterAdd0(engineHandle, &filter, NULL, NULL);
   EXIT_ON_ERROR(FwpmFilterAdd0);   

   // Block the removal of the filter    
   result = HinderFilterDeletion(engineHandle, &guid);

CLEANUP:
   if (result != ERROR_SUCCESS)
   {
       printf("Error: %x\n", result);
   }
   else
   {
       printf("Success");
   }

   return result;
}