0x00 Abstract

Application whitelisting and blacklisting is an interesting topic because depending on how it has been configured this can drastically increase the difficulty of an attacker to gain initial code execution. With Windows XP and Windows Server 2013, Microsoft released Software Restriction Policy (SRP), which was a great idea but a massive pain to configure with little to no flexibility. This is where AppLocker is coming into play, this is the successor of SRP. AppLocker has been introduced in Windows 10, originally only for Enterprise and Education versions.

AppLocker offers a lot of flexibility because the allow/deny rules are set to a SID and therefore can be applied to any security principal (i.e. user, groups). AppLocker has also multiple rule types, which are as follows:

  • Executable rules, for executable files (e.g. C:\Windows\System32\cmd.exe);
  • Windows Installer rules, for installation files (e.g. C:\Users\Public\myinstaller.msi);
  • Script rules, for Windows Script Host (WSH) scripts (e.g. C:\Windows\System32\winrm.vbs); and
  • Packaged app rules, for new Microsoft Store installation packages (e.g. C:\Users\Public\myapp.appx)

Besides, having different rule types, the restriction (i.e. allow or deny) can be set based on the program’s path, publisher or hash. Finally, AppLocker can be configured via Group Policies (GPO), which is incredibly helpful for maintaining and updating rules across an estate.

Most of the examples, if not all the examples online are using the Get-AppLockerPolicy PowerShell Cmdlet but more recently @Flangvik and @Jean_Maes_1994 released a tooled named SharpAppLocker to list AppLocker policies. Despite being an interesting implementation in C#, they are using the following two Assembly Types:

  • AppLockerPolicy; and
  • PolicyManager

As a result, the following four Assemblies are loaded into the default application domain:

  • Microsoft.Security.ApplicationId.PolicyManagement.PolicyEngineApi.Interop;
  • Microsoft.Security.ApplicationId.PolicyManagement.PolicyManager;
  • Microsoft.Security.ApplicationId.PolicyManagement.PolicyModel; and
  • Microsoft.Security.ApplicationId.PolicyManagement.XmlHelper

In terms of operational security, there is no need to load and use theses Assemblies when they are only wrappers around a COM interface, as we will see later. I submitted a pull request to their project in order to use the COM interface instead of the aforementioned Assembly Types.

Ultimately, the reason why I’m writing this blog post is because I think it is interesting to provide an example of how it is possible to use a COM interface when the definition of the interface is not provided by Microsoft. You can find the source code of the application in my Windows System Programming Experiments (WSPE) repository on GitHub: List AppLocker Policies.

0x01 Identifying the Culprit

According to the Microsoft documentation, the Get-AppLockerPolicy is the PowerShell Cmdlets that can be used to list all the policies. Under the hood this Cmdlet is loading and using Types from a .NET Framework Assembly. To get the Assembly we can execute the following PowerShell Cmdlet:

Get-Command Get-AppLockerPolicy | Select-Object Dll

In my case this will return the path of the Assembly, in the form of a DLL, from the Global Assembly Cache (GAC):

C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.Security.ApplicationId.PolicyManagement.Cmdlets\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.Security.ApplicationId.PolicyManagement.Cmdlets.dll

.NET applications are known to be easy to reverse engineer, at least when they are not obfuscated. The reason behind that is that .NET application are compiled into Microsoft Intermediate Language (MSIL) instead of machine code. In this case I used the dnSpy to reverse engineer the Assembly.

As shown, the PowerShell cmdlet use the AppLockerPolicy and PolicyManager Types. In this case we are only interested by the PolicyManager Type and especially the GetLocalPolicy, GetDomainPolicy and GetEffectivePolicy static methods. This Type is defined within the Microsoft.Security.ApplicationId.PolicyManagement.PolicyManager Assembly.

As shown, the static methods are instantiating an interface named IAppIdPolicyHandler via a class factory named AppIdPolicyHandlerClass.

Without too much surprises, this is a COM interface. At this point this means that instead of using the Get-AppLockerPolicy or the AppLockerPolicy and PolicyManager Types to get the AppLocker policies we can directly use the COM interface. With dnSpy we can get the Global Unique Identifier (GUID) of the interface and class factory, which are as follows:

  • F1ED7D4C-F863-4DE6-A1CA-7253EFDEE1F3 - AppIdPolicyHandlerClass
  • B6FEA19E-32DD-4367-B5B7-2F5DA140E87D - IAppIdPolicyHandler

At first I’ve tried to implement IAppIdPolicyHandler COM interface with the data I gathered from the OleViewDotnet tool from James Forshaw. However, that tool was returning the high level C# implementation of the interface.

After further research and a chat with odzhan he pointed me to the OleWoo tool, which was required in order to get the proper low level definition of the interface. To find the DLL in which the COM interface is define, we just need to search for the InterServer32 key in the Windows Registry. Note that in this case we are using the GUID of the class factory of the interface: {F1ED7D4C-F863-4DE6-A1CA-7253EFDEE1F3}.

After analysing the DLL with OleWoo we can find that the Interface inherits from IDispatch which inherits from IUnknown. We can also find the different methods that are exposed: SetPolicy, GetPolicy, GetEffectivePolicy, IsFileAllowed and IsPackageAllowed.

At this point we have all we need to define the interface in C.

0x02 Defining the COM Interface

First thing to know is that we will implement a C++-style class in C, which means that we will need to implement two structures. The first structure will define all the methods of the interface, methods from the the inherited interfaces included. The second structure will define the virtual method table (i.e. vtable), which is nothing more than a pointer to the first structure with all the methods.

The first interface will be defined as follows:

typedef struct AppIdPolicyHandlerVtbl {
	BEGIN_INTERFACE

	/**
	 * @brief QueryInterface method from IUnknown
	*/
	HRESULT(STDMETHODCALLTYPE* QueryInterface) (
		_In_  IAppIdPolicyHandler* This,
		_In_  REFIID               riid,
		_Out_ PVOID*               ppvObject
	);

	/**
	 * @brief AddRef from IUnknown
	*/
	ULONG(STDMETHODCALLTYPE* AddRef)(
		_In_ IAppIdPolicyHandler* This
	);

	/**
	 * @brief Release from IUnknown
	*/
	ULONG(STDMETHODCALLTYPE* Release)(
		_In_ IAppIdPolicyHandler* This
	);

	/**
	 * @brief GetTypeInfoCount from IDispatch
	*/
	HRESULT(STDMETHODCALLTYPE* GetTypeInfoCount)(
		_In_  IAppIdPolicyHandler* This,
		_Out_ PUINT                pctinfo
	);

	/**
	 * @brief GetTypeInfo from IDispatch
	*/
	HRESULT(STDMETHODCALLTYPE* GetTypeInfo)(
		_In_  IAppIdPolicyHandler* This,
		_In_  UINT                 itinfo,
		_In_  ULONG                lcid,
		_Out_ LPVOID*              pptinfo
	);

	/**
	 * @brief GetIDsOfNames from IDispatch
	*/
	HRESULT(STDMETHODCALLTYPE* GetIDsOfNames)(
		_In_  IAppIdPolicyHandler* This, 
		_In_  LPIID                riid,
		_In_  LPOLESTR*            rgszNames,
		_In_  UINT                 cNames,
		_In_  LCID                 lcid,
		_Out_ DISPID*              rgdispid
	);

	/**
	 * @brief Invoke from IDispatch
	*/
	HRESULT(STDMETHODCALLTYPE* Invoke)(
		_In_  IAppIdPolicyHandler* This,
		_In_  DISPID               dispidMember,
		_In_  LPIID                riid,
		_In_  LCID                 lcid,
		_In_  WORD                 wFlags,
		_In_  DISPPARAMS*          pdispparams,
		_In_  LPVARIANT            pvarResult,
		_Out_ LPEXCEPINFO          pexcepinfo,
		_Out_ PUINT                puArgErr
	);

	/**
	 * @brief SetPolicy from IAppIdPolicyHandler
	*/
	HRESULT(STDMETHODCALLTYPE* SetPolicy)(
		_In_ IAppIdPolicyHandler* This,
		_In_ BSTR bstrLdapPath,
		_In_ BSTR bstrXmlPolicy
	);

	/**
	 * @brief GetPolicy from IAppIdPolicyHandler
	*/
	HRESULT(STDMETHODCALLTYPE *GetPolicy)(
		_In_  IAppIdPolicyHandler* This,
		_In_  BSTR                 bstrLdapPath,
		_Out_ LPBSTR               pbstrXmlPolicy
	);

	/**
	 * @brief GetEffectivePolicy from IAppIdPolicyHandler
	*/
	HRESULT(STDMETHODCALLTYPE *GetEffectivePolicy)(
		_In_  IAppIdPolicyHandler* This,
		_Out_ LPBSTR               pbstrXmlPolicies
	);

	/**
	 * @brief IsFileAllowed from IAppIdPolicyHandler
	*/
	HRESULT(STDMETHODCALLTYPE *IsFileAllowed)(
		_In_  IAppIdPolicyHandler* This,
		_In_  BSTR                 bstrXmlPolicy,
		_In_  BSTR                 bstrFilePath,
		_In_  BSTR                 bstrUserSid,
		_Out_ LPGUID               pguidResponsibleRuleId,
		_Out_ PLONG                pbStatus
	);

	/**
	 * @brief IsPackageAllowed from IAppIdPolicyHandler
	*/
	HRESULT(STDMETHODCALLTYPE *IsPackageAllowed)(
		_In_  IAppIdPolicyHandler* This,
		_In_  BSTR                 bstrXmlPolicy,
		_In_  BSTR                 bstrPublisherName,
		_In_  BSTR                 bstrPackageName,
		_In_  ULONG                ullPackageVersion,
		_In_  BSTR                 bstrUserSid,
		_Out_ LPGUID               pguidResponsibleRuleId,
		_Out_ PLONG                pbStatus
	);

	END_INTERFACE
} AppIdPolicyHandlerVtbl;

The second structure will be defined as follows:

typedef struct IAppIdPolicyHandler {
	CONST_VTBL struct AppIdPolicyHandlerVtbl* lpVtbl;
};

Finally, you may have noticed that in the first structure AppIdPolicyHandlerVtbl, I added a pointer to the second structure IAppIdPolicyHandler as first parameter. The reason is pretty simple, this is what C++ is “using” under the hood when you are using the this keyword, which can be used to access class properties in case you have any.

0x03 Listing the AppLocker Policies

The class factory GUID and the interface GUID can be defined as follows:

/**
 * @brief GUID of the IAppIdPolicyHandler COM interface: B6FEA19E-32DD-4367-B5B7-2F5DA140E87D
*/
CONST IID IID_IAppIdPolicyHandler = { 0xB6FEA19E, 0x32DD, 0x4367, {0xB5, 0xB7, 0x2F, 0x5D, 0xA1, 0x40, 0xE8, 0x7D} };

/**
 * @brief GUID of the IAppIdPolicyHandler class factory: F1ED7D4C-F863-4DE6-A1CA-7253EFDEE1F3
*/
CONST IID CLSID_AppIdPolicyHandlerClass = { 0xF1ED7D4C, 0xF863, 0x4DE6, {0xA1, 0xCA, 0x72, 0x53, 0xEF, 0xDE, 0xE1, 0xF3} };

The CoInitialize and CoCreateInstance Windows APIs can be used to respectively initialise the COM library in the current running thread and then initialise the interface. Example with error handling omitted:

HRESULT Result = CoInitialize(NULL);

IAppIdPolicyHandler* pIAppIdPolicyHandler = NULL;
Result = CoCreateInstance(&CLSID_AppIdPolicyHandlerClass, NULL, CLSCTX_INPROC_SERVER, &IID_IAppIdPolicyHandler, &pIAppIdPolicyHandler);

Finally, either GetPolicy or GetEffectivePolicy can be invoked to get the AppLocker policies. Example with error handling omitted:

BSTR bstrPolicies = NULL;
result = pIAppIdPolicyHandler->lpVtbl->GetEffectivePolicy(pIAppIdPolicyHandler, &bstrPolicies);
printf("Policies: \n\n%S\n", bstrPolicies);

Example of the program that you can find in my GitHub repository: