Files
hfiref0x-UACME/Source/Yuubari/comobj.c
T
hfiref0x a6d45efcc8 Yuubari update
1.4.5 - VF list (ElevatedFactoryServer. CreateElevatedObject etc).
2019-10-22 11:43:02 +07:00

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);
}
}