mirror of
https://github.com/hfiref0x/UACME
synced 2026-06-08 14:39:53 +00:00
a6d45efcc8
1.4.5 - VF list (ElevatedFactoryServer. CreateElevatedObject etc).
646 lines
18 KiB
C
646 lines
18 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2014 - 2019
|
|
*
|
|
* TITLE: COMOBJ.C
|
|
*
|
|
* VERSION: 1.45
|
|
*
|
|
* DATE: 22 Oct 2019
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
#include "global.h"
|
|
#include <Shlwapi.h>
|
|
#include <shlobj.h>
|
|
#include <Rpc.h>
|
|
#pragma comment(lib, "Shlwapi.lib")
|
|
#pragma comment(lib, "Rpcrt4.lib")
|
|
|
|
VOID CopScanRegistry(
|
|
_In_ HKEY RootKey,
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList);
|
|
|
|
/*
|
|
* CopRunOutputCallbackForInterface
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Output interface information.
|
|
*
|
|
*/
|
|
VOID CopRunOutputCallbackForInterface(
|
|
_In_ ULONG DataType,
|
|
_In_ INTERFACE_INFO *Interface,
|
|
_In_ CLSID clsid,
|
|
_In_ OUTPUTCALLBACK OutputCallback
|
|
)
|
|
{
|
|
UAC_INTERFACE_DATA Data;
|
|
|
|
RtlSecureZeroMemory(&Data, sizeof(Data));
|
|
Data.DataType = DataType;
|
|
Data.Name = Interface->szInterfaceName;
|
|
Data.Clsid = clsid;
|
|
Data.IID = Interface->iid;
|
|
OutputCallback((PVOID)&Data);
|
|
}
|
|
|
|
/*
|
|
* CopLocateInterfaceByCLSID
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Search for interface by CLSID.
|
|
*
|
|
*/
|
|
INTERFACE_INFO* CopLocateInterfaceByCLSID(
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList,
|
|
_In_ CLSID clsid
|
|
)
|
|
{
|
|
IUnknown *Interface = NULL;
|
|
IUnknown *TestObject = NULL;
|
|
|
|
ULONG i;
|
|
|
|
INTERFACE_INFO* Result = NULL;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IUnknown, (LPVOID)&Interface)))
|
|
{
|
|
for (i = 0; i < InterfaceList->cEntries; i++) {
|
|
Interface->lpVtbl->QueryInterface(Interface, &InterfaceList->List[i].iid, &TestObject);
|
|
if (TestObject != NULL) {
|
|
TestObject->lpVtbl->Release(TestObject);
|
|
Result = &InterfaceList->List[i];
|
|
break;
|
|
}
|
|
}
|
|
Interface->lpVtbl->Release(Interface);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* CopQuerySubKey
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query subkey elevated COM object name.
|
|
*
|
|
*/
|
|
VOID CopQuerySubKey(
|
|
_In_ HKEY RootKey,
|
|
_In_ LPWSTR lpKeyName,
|
|
_In_ BOOL ElevationKey,
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
LRESULT lRet;
|
|
HKEY hSubKey = NULL, hAppIdKey = NULL, hServerObjectsKey = NULL;
|
|
DWORD dwDataSize, dwEnabled = 0;
|
|
LPWSTR lpName = NULL, lpAppId = NULL, lpAppIdName = NULL, lpLocalizedString = NULL, t = NULL, lpValue = NULL;
|
|
|
|
ULONG i, cValues = 0, cMaxLength = 0, cchValue;
|
|
|
|
CLSID clsid;
|
|
|
|
UAC_REGISTRY_DATA Data;
|
|
INTERFACE_INFO *LookupInterface;
|
|
|
|
BOOLEAN VirtualFactory = FALSE;
|
|
|
|
//open each sub key
|
|
lRet = RegOpenKeyEx(RootKey, lpKeyName, 0, KEY_READ, &hSubKey);
|
|
if ((lRet == ERROR_SUCCESS) && (hSubKey != NULL)) {
|
|
if (ElevationKey) {
|
|
|
|
do {
|
|
|
|
dwDataSize = sizeof(DWORD);
|
|
dwEnabled = 0;
|
|
|
|
//query elevation enabled
|
|
lRet = RegQueryValueEx(hSubKey, TEXT("Enabled"), NULL,
|
|
NULL,
|
|
(LPBYTE)&dwEnabled,
|
|
&dwDataSize
|
|
);
|
|
|
|
if (lRet != ERROR_SUCCESS)
|
|
break;
|
|
|
|
if (dwEnabled != 1)
|
|
break;
|
|
|
|
//
|
|
// Check virtual factory.
|
|
//
|
|
lRet = RegOpenKeyEx(RootKey, TEXT("VirtualServerObjects"), 0, KEY_READ, &hServerObjectsKey);
|
|
VirtualFactory = ((lRet == ERROR_SUCCESS) && (hServerObjectsKey != NULL));
|
|
|
|
//query object name
|
|
lpName = supReadKeyString(RootKey, TEXT(""), &dwDataSize);
|
|
|
|
//query localized string and convert it
|
|
dwDataSize = 0;
|
|
t = supReadKeyString(RootKey, TEXT("LocalizedString"), &dwDataSize);
|
|
if (t) {
|
|
lpLocalizedString = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)MAX_PATH * 2);
|
|
if (lpLocalizedString) {
|
|
SHLoadIndirectString(t, lpLocalizedString, MAX_PATH, NULL);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, t);
|
|
}
|
|
|
|
//check if AppId present
|
|
dwDataSize = 0;
|
|
t = supReadKeyString(RootKey, TEXT("AppId"), &dwDataSize);
|
|
if (t) {
|
|
lpAppId = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)dwDataSize + 32);
|
|
if (lpAppId) {
|
|
_strcpy(lpAppId, TEXT("AppId\\"));
|
|
_strcat(lpAppId, t);
|
|
|
|
//open AppId key
|
|
lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, lpAppId, 0,
|
|
KEY_READ, &hAppIdKey);
|
|
if (lRet == ERROR_SUCCESS) {
|
|
//check if AccessPermisions present
|
|
lRet = RegQueryValueEx(hAppIdKey, TEXT("AccessPermission"),
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
if (lRet == ERROR_SUCCESS) {
|
|
//if they found query name
|
|
dwDataSize = 0;
|
|
lpAppIdName = supReadKeyString(hAppIdKey, TEXT(""), &dwDataSize);
|
|
}
|
|
RegCloseKey(hAppIdKey);
|
|
}
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, t);
|
|
}
|
|
|
|
//
|
|
// Write output
|
|
//
|
|
RtlSecureZeroMemory(&Data, sizeof(Data));
|
|
|
|
if (lpName) {
|
|
Data.Name = lpName;
|
|
}
|
|
else {
|
|
Data.Name = TEXT("undefined");
|
|
}
|
|
|
|
if (lpAppIdName) {
|
|
Data.AppId = lpAppIdName;
|
|
}
|
|
else {
|
|
if (lpAppId) {
|
|
Data.AppId = lpAppId;
|
|
}
|
|
else {
|
|
Data.AppId = TEXT("undefined");
|
|
}
|
|
}
|
|
|
|
if (lpLocalizedString) {
|
|
Data.LocalizedString = lpLocalizedString;
|
|
}
|
|
else {
|
|
Data.LocalizedString = TEXT("undefined");
|
|
}
|
|
|
|
Data.Key = (LPWSTR)supQueryKeyName(RootKey, NULL);
|
|
|
|
if (VirtualFactory)
|
|
Data.DataType = UacCOMDataVirtualFactory;
|
|
else
|
|
Data.DataType = UacCOMDataCommonType;
|
|
|
|
OutputCallback((PVOID)&Data);
|
|
|
|
if (Data.Key) {
|
|
HeapFree(GetProcessHeap(), 0, Data.Key);
|
|
}
|
|
|
|
//
|
|
// Output virtual server objects.
|
|
//
|
|
if (VirtualFactory) {
|
|
|
|
lRet = RegQueryInfoKey(hServerObjectsKey, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
&cValues, &cMaxLength, NULL, NULL, NULL);
|
|
|
|
if (lRet == ERROR_SUCCESS) {
|
|
|
|
cMaxLength = (DWORD)((cMaxLength + 1) * sizeof(WCHAR));
|
|
lpValue = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cMaxLength);
|
|
if (lpValue) {
|
|
|
|
for (i = 0; i < cValues; i++) {
|
|
cchValue = (DWORD)(cMaxLength / sizeof(WCHAR));
|
|
if (RegEnumValue(hServerObjectsKey, i, lpValue, &cchValue, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
if (CLSIDFromString(lpValue, &clsid) == S_OK) {
|
|
LookupInterface = CopLocateInterfaceByCLSID(InterfaceList, clsid);
|
|
if (LookupInterface) {
|
|
|
|
CopRunOutputCallbackForInterface(
|
|
UacCOMDataInterfaceTypeVF,
|
|
LookupInterface,
|
|
clsid,
|
|
OutputCallback);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpValue);
|
|
}
|
|
}
|
|
RegCloseKey(hServerObjectsKey);
|
|
}
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
if (lpAppIdName)
|
|
HeapFree(GetProcessHeap(), 0, lpAppIdName);
|
|
|
|
if (lpAppId != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpAppId);
|
|
|
|
if (lpName != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpName);
|
|
}
|
|
else {
|
|
CopScanRegistry(hSubKey, OutputCallback, InterfaceList);
|
|
}
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* CopEnumSubKey
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Enumerate key subkeys, check elevation flag.
|
|
*
|
|
*/
|
|
VOID CopEnumSubKey(
|
|
_In_ HKEY hKey,
|
|
_In_ DWORD dwKeyIndex,
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
BOOL bElevation = FALSE;
|
|
LRESULT lRet;
|
|
DWORD dwcbName = 0, cch;
|
|
LPTSTR lpKeyName = NULL;
|
|
|
|
do {
|
|
dwcbName = 32 * 1024;
|
|
lpKeyName = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwcbName);
|
|
if (lpKeyName == NULL)
|
|
break;
|
|
|
|
cch = dwcbName / sizeof(WCHAR);
|
|
lRet = RegEnumKeyEx(hKey, dwKeyIndex,
|
|
lpKeyName, &cch, NULL, NULL, NULL, NULL);
|
|
if (lRet == ERROR_MORE_DATA) {
|
|
dwcbName *= 2;
|
|
HeapFree(GetProcessHeap(), 0, lpKeyName);
|
|
lpKeyName = NULL;
|
|
continue;
|
|
}
|
|
if (lRet == ERROR_SUCCESS) {
|
|
//skip wow64 shit
|
|
if (_strcmpi(lpKeyName, TEXT("Wow6432Node")) == 0)
|
|
break;
|
|
|
|
if (_strcmpi(lpKeyName, TEXT("Elevation")) == 0)
|
|
bElevation = TRUE;
|
|
|
|
CopQuerySubKey(hKey, lpKeyName, bElevation, OutputCallback, InterfaceList);
|
|
}
|
|
|
|
} while (lRet == ERROR_MORE_DATA);
|
|
|
|
if (lpKeyName != NULL)
|
|
HeapFree(GetProcessHeap(), 0, lpKeyName);
|
|
|
|
}
|
|
|
|
/*
|
|
* CopScanRegistry
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Recursively scan registry looking for autoelevated COM entries.
|
|
*
|
|
*/
|
|
VOID CopScanRegistry(
|
|
_In_ HKEY RootKey,
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
HKEY hKey = NULL;
|
|
LRESULT lRet;
|
|
DWORD dwcSubKeys = 0, i;
|
|
|
|
do {
|
|
//open root key for enumeration
|
|
lRet = RegOpenKeyEx(RootKey, NULL, 0, KEY_READ, &hKey);
|
|
if ((lRet != ERROR_SUCCESS) || (hKey == NULL))
|
|
break;
|
|
|
|
//query subkeys count
|
|
lRet = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwcSubKeys,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if ((lRet != ERROR_SUCCESS) || (dwcSubKeys == 0))
|
|
break;
|
|
|
|
for (i = 0; i < dwcSubKeys; i++)
|
|
CopEnumSubKey(hKey, i, OutputCallback, InterfaceList);
|
|
|
|
} while (FALSE);
|
|
|
|
if (hKey != NULL)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
/*
|
|
* CoEnumInterfaces
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Remember list of available interfaces, excluding IUnknown.
|
|
*
|
|
*/
|
|
BOOL CoEnumInterfaces(
|
|
_Inout_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HKEY hKey = NULL;
|
|
LRESULT lRet;
|
|
RPC_STATUS RpcStatus = 0;
|
|
LPWSTR lpKeyName = NULL;
|
|
SIZE_T k;
|
|
DWORD i, cSubKeys = 0, cMaxLength = 0, cchKey;
|
|
IID iid;
|
|
|
|
INTERFACE_INFO *infoBuffer;
|
|
|
|
__try {
|
|
|
|
lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("Interface"), 0, KEY_READ, &hKey);
|
|
if (lRet != ERROR_SUCCESS)
|
|
__leave;
|
|
|
|
lRet = RegQueryInfoKey(hKey, NULL, NULL, NULL, &cSubKeys, &cMaxLength, NULL,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
if ((lRet != ERROR_SUCCESS) || (cSubKeys == 0))
|
|
__leave;
|
|
|
|
infoBuffer = (INTERFACE_INFO*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cSubKeys * sizeof(INTERFACE_INFO));
|
|
if (infoBuffer == NULL)
|
|
__leave;
|
|
|
|
cMaxLength = (DWORD)((cMaxLength + 1) * sizeof(WCHAR));
|
|
lpKeyName = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cMaxLength);
|
|
if (lpKeyName == NULL)
|
|
__leave;
|
|
|
|
for (k = 0, i = 0; i < cSubKeys; i++) {
|
|
|
|
cchKey = (DWORD)(cMaxLength / sizeof(WCHAR));
|
|
if (RegEnumKeyEx(hKey, i, lpKeyName, &cchKey, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
if (IIDFromString(lpKeyName, &iid) == S_OK) {
|
|
|
|
//skip IUnknown
|
|
if (UuidCompare((UUID*)&iid, (UUID*)&IID_IUnknown, &RpcStatus) == 0)
|
|
continue;
|
|
|
|
cchKey = MAX_PATH * sizeof(WCHAR);
|
|
infoBuffer[k].iid = iid;
|
|
|
|
RegGetValue(hKey, lpKeyName, TEXT(""), RRF_RT_REG_SZ, NULL,
|
|
(LPWSTR)&infoBuffer[k].szInterfaceName, &cchKey);
|
|
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
InterfaceList->cEntries = (ULONG)k;
|
|
InterfaceList->List = infoBuffer;
|
|
bResult = TRUE;
|
|
}
|
|
__finally {
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (lpKeyName)
|
|
HeapFree(GetProcessHeap(), 0, lpKeyName);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* CoScanAutoApprovalList
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query list of autoapproval COM objects used by OOBE ICreateObject interface.
|
|
*
|
|
*/
|
|
VOID CoScanBrokerApprovalList(
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
HKEY hKey = NULL, hSubKey = NULL;
|
|
LRESULT lRet;
|
|
LPWSTR lpSubKey = NULL;
|
|
DWORD i, cSubKeys = 0, cMaxLength = 0, cchSubKey, dwType, dwData, cbData;
|
|
|
|
CLSID clsid;
|
|
|
|
INTERFACE_INFO *LookupInterface;
|
|
|
|
__try {
|
|
|
|
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, T_UAC_BROKER_APPROVAL_LIST, 0, KEY_READ, &hKey);
|
|
if (lRet != ERROR_SUCCESS)
|
|
__leave;
|
|
|
|
lRet = RegQueryInfoKey(hKey, NULL, NULL, NULL, &cSubKeys, &cMaxLength, NULL,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
if ((lRet != ERROR_SUCCESS) || (cSubKeys == 0))
|
|
__leave;
|
|
|
|
cMaxLength = (DWORD)((cMaxLength + 1) * sizeof(WCHAR));
|
|
lpSubKey = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cMaxLength);
|
|
if (lpSubKey == NULL)
|
|
__leave;
|
|
|
|
for (i = 0; i < cSubKeys; i++) {
|
|
cchSubKey = (DWORD)(cMaxLength / sizeof(WCHAR));
|
|
if (RegEnumKeyEx(hKey, i, lpSubKey, &cchSubKey, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Check AutoElevationAllowed
|
|
//
|
|
if (RegOpenKey(hKey, lpSubKey, &hSubKey) == ERROR_SUCCESS) {
|
|
|
|
dwType = REG_DWORD;
|
|
cbData = sizeof(DWORD);
|
|
dwData = 0;
|
|
|
|
if (RegQueryValueEx(hSubKey,
|
|
TEXT("AutoElevationAllowed"),
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)&dwData,
|
|
&cbData) == ERROR_SUCCESS)
|
|
{
|
|
if ((cbData == sizeof(DWORD)) && (dwData == 1)) {
|
|
|
|
//
|
|
// Find interface and output to the callback.
|
|
//
|
|
if (CLSIDFromString(lpSubKey, &clsid) == S_OK) {
|
|
LookupInterface = CopLocateInterfaceByCLSID(InterfaceList, clsid);
|
|
if (LookupInterface) {
|
|
|
|
CopRunOutputCallbackForInterface(
|
|
UacCOMDataInterfaceType,
|
|
LookupInterface,
|
|
clsid,
|
|
OutputCallback);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (lpSubKey)
|
|
HeapFree(GetProcessHeap(), 0, lpSubKey);
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* CoScanAutoApprovalList
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query list of autoapproval COM objects.
|
|
* This key was added in RS1 specially for consent.exe comfort
|
|
*
|
|
*/
|
|
VOID CoScanAutoApprovalList(
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
HKEY hKey = NULL;
|
|
LRESULT lRet;
|
|
LPWSTR lpValue = NULL;
|
|
DWORD i, cValues = 0, cMaxLength = 0, cchValue;
|
|
|
|
CLSID clsid;
|
|
|
|
INTERFACE_INFO *LookupInterface;
|
|
|
|
__try {
|
|
|
|
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, T_UAC_COM_AUTOAPPROVAL_LIST, 0, KEY_READ, &hKey);
|
|
if (lRet != ERROR_SUCCESS)
|
|
__leave;
|
|
|
|
lRet = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
&cValues, &cMaxLength, NULL, NULL, NULL);
|
|
if ((lRet != ERROR_SUCCESS) || (cValues == 0))
|
|
__leave;
|
|
|
|
cMaxLength = (DWORD)((cMaxLength + 1) * sizeof(WCHAR));
|
|
lpValue = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cMaxLength);
|
|
if (lpValue == NULL)
|
|
__leave;
|
|
|
|
for (i = 0; i < cValues; i++) {
|
|
cchValue = (DWORD)(cMaxLength / sizeof(WCHAR));
|
|
if (RegEnumValue(hKey, i, lpValue, &cchValue, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
if (CLSIDFromString(lpValue, &clsid) == S_OK) {
|
|
LookupInterface = CopLocateInterfaceByCLSID(InterfaceList, clsid);
|
|
if (LookupInterface) {
|
|
|
|
CopRunOutputCallbackForInterface(
|
|
UacCOMDataInterfaceType,
|
|
LookupInterface,
|
|
clsid,
|
|
OutputCallback);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (lpValue)
|
|
HeapFree(GetProcessHeap(), 0, lpValue);
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* CoListInformation
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Scan registry looking for autoelevated COM.
|
|
*
|
|
*/
|
|
VOID CoListInformation(
|
|
_In_ OUTPUTCALLBACK OutputCallback,
|
|
_In_ INTERFACE_INFO_LIST *InterfaceList
|
|
)
|
|
{
|
|
if (OutputCallback) {
|
|
CopScanRegistry(HKEY_CLASSES_ROOT, OutputCallback, InterfaceList);
|
|
}
|
|
}
|