mirror of https://github.com/hfiref0x/UACME.git
486 lines
13 KiB
C
486 lines
13 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2014 - 2019
|
|
*
|
|
* TITLE: MAIN.C
|
|
*
|
|
* VERSION: 1.40
|
|
*
|
|
* DATE: 19 Mar 2019
|
|
*
|
|
* Program entry point.
|
|
*
|
|
* 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 "Shlobj.h"
|
|
|
|
BOOL g_VerboseOutput = FALSE;
|
|
ULONG g_NtBuildNumber = 0;
|
|
HANDLE g_LogFile = INVALID_HANDLE_VALUE;
|
|
|
|
/*
|
|
* AppInfoDataOutputCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Output callback for AppInfo scan.
|
|
*
|
|
*/
|
|
VOID AppInfoDataOutputCallback(
|
|
UAC_AI_DATA *Data
|
|
)
|
|
{
|
|
LPWSTR lpLog = NULL, Text = NULL;
|
|
SIZE_T sz = 0;
|
|
|
|
if (Data == NULL)
|
|
return;
|
|
|
|
sz = (_strlen(Data->Name) * sizeof(WCHAR)) + MAX_PATH;
|
|
lpLog = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz);
|
|
if (lpLog) {
|
|
switch (Data->Type) {
|
|
case AiSnapinFile:
|
|
Text = TEXT("SnapinFile: ");
|
|
break;
|
|
case AiManagementConsole:
|
|
Text = TEXT("ManagementConsole: ");
|
|
break;
|
|
case AiAutoApproveEXE:
|
|
Text = TEXT("AutoApproveEXE: ");
|
|
break;
|
|
case AiIncludedPFDirs:
|
|
Text = TEXT("IncludedPFDir: ");
|
|
break;
|
|
case AiIncludedSystemDirs:
|
|
Text = TEXT("IncludedSystemDir: ");
|
|
break;
|
|
case AiExemptedAutoApproveExes:
|
|
Text = TEXT("ExemptedAutoApproveExe: ");
|
|
break;
|
|
case AilpIncludedWindowsDirs:
|
|
Text = TEXT("IncludedWindowsDirs: ");
|
|
break;
|
|
case AiExcludedWindowsDirs:
|
|
Text = TEXT("ExcludedWindowsDir: ");
|
|
break;
|
|
default:
|
|
Text = TEXT("Unknown ");
|
|
break;
|
|
}
|
|
_strcpy(lpLog, Text);
|
|
_strcat(lpLog, Data->Name);
|
|
LoggerWrite(g_LogFile, lpLog, TRUE);
|
|
|
|
cuiPrintText(lpLog, TRUE);
|
|
HeapFree(GetProcessHeap(), 0, lpLog);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* BasicDataOutputCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Output callback for basic UAC settings scan.
|
|
*
|
|
*/
|
|
VOID WINAPI BasicDataOutputCallback(
|
|
UAC_BASIC_DATA *Data
|
|
)
|
|
{
|
|
LPWSTR lpLog = NULL;
|
|
SIZE_T sz = 0;
|
|
|
|
if (Data == NULL)
|
|
return;
|
|
|
|
sz = (_strlen(Data->Name) * sizeof(WCHAR)) + MAX_PATH;
|
|
lpLog = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz);
|
|
if (lpLog) {
|
|
_strcpy(lpLog, Data->Name);
|
|
_strcat(lpLog, TEXT("="));
|
|
if (Data->IsValueBool) {
|
|
if (Data->Value == 0)
|
|
_strcat(lpLog, TEXT("Disabled"));
|
|
else
|
|
_strcat(lpLog, TEXT("Enabled"));
|
|
}
|
|
else {
|
|
ultostr(Data->Value, _strend(lpLog));
|
|
}
|
|
LoggerWrite(g_LogFile, lpLog, TRUE);
|
|
cuiPrintText(lpLog, TRUE);
|
|
HeapFree(GetProcessHeap(), 0, lpLog);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RegistryOutputCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Output callback for registry autoelevated objects scan.
|
|
*
|
|
*/
|
|
VOID WINAPI RegistryOutputCallback(
|
|
UAC_REGISTRY_DATA *Data
|
|
)
|
|
{
|
|
UAC_INTERFACE_DATA *InterfaceData;
|
|
LPOLESTR OutputString = NULL;
|
|
|
|
if (Data == NULL)
|
|
return;
|
|
|
|
|
|
if (Data->DataType == UacCOMDataCommonType) {
|
|
//
|
|
// Output current registry key to show that we are alive.
|
|
//
|
|
LoggerWrite(g_LogFile, Data->Name, TRUE);
|
|
cuiPrintText(Data->Key, TRUE);
|
|
LoggerWrite(g_LogFile, Data->AppId, TRUE);
|
|
LoggerWrite(g_LogFile, Data->LocalizedString, TRUE);
|
|
LoggerWrite(g_LogFile, Data->Key, TRUE);
|
|
LoggerWrite(g_LogFile, TEXT("\r\n"), TRUE);
|
|
}
|
|
|
|
if (Data->DataType == UacCOMDataInterfaceType) {
|
|
|
|
InterfaceData = (UAC_INTERFACE_DATA*)(PVOID)Data;
|
|
|
|
LoggerWrite(g_LogFile, InterfaceData->Name, TRUE);
|
|
cuiPrintText(InterfaceData->Name, TRUE);
|
|
|
|
if (StringFromCLSID(&InterfaceData->Clsid, &OutputString) == S_OK) {
|
|
LoggerWrite(g_LogFile, TEXT("CLSID"), TRUE);
|
|
LoggerWrite(g_LogFile, OutputString, TRUE);
|
|
cuiPrintText(OutputString, TRUE);
|
|
CoTaskMemFree(OutputString);
|
|
}
|
|
if (StringFromIID(&InterfaceData->IID, &OutputString) == S_OK) {
|
|
LoggerWrite(g_LogFile, TEXT("IID"), TRUE);
|
|
LoggerWrite(g_LogFile, OutputString, TRUE);
|
|
cuiPrintText(OutputString, TRUE);
|
|
CoTaskMemFree(OutputString);
|
|
}
|
|
LoggerWrite(g_LogFile, TEXT("\r\n"), TRUE);
|
|
cuiPrintText(TEXT("\r\n"), TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* FusionOutputCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Output callback for autoelevated applications scan.
|
|
*
|
|
*/
|
|
VOID WINAPI FusionOutputCallback(
|
|
UAC_FUSION_DATA *Data
|
|
)
|
|
{
|
|
LPWSTR lpText;
|
|
LPWSTR lpLog = NULL;
|
|
SIZE_T sz = 0;
|
|
UAC_FUSION_DATA_DLL *Dll;
|
|
|
|
if (Data == NULL)
|
|
return;
|
|
|
|
if (Data->DataType == UacFusionDataCommonType) {
|
|
|
|
//
|
|
// Display only binaries with autoelevation flags if not in verbose output
|
|
//
|
|
if ((Data->AutoElevateState == AutoElevateUnspecified) && (g_VerboseOutput == FALSE))
|
|
return;
|
|
|
|
//
|
|
// Output current filename
|
|
//
|
|
LoggerWrite(g_LogFile, TEXT("\r\n"), FALSE);
|
|
LoggerWrite(g_LogFile, Data->Name, TRUE);
|
|
cuiPrintText(Data->Name, TRUE);
|
|
|
|
//
|
|
// If application has autoElevate attribute, report full info
|
|
//
|
|
if (Data->IsFusion) {
|
|
switch (Data->RunLevel.RunLevel) {
|
|
case ACTCTX_RUN_LEVEL_AS_INVOKER:
|
|
lpText = TEXT("asInvoker");
|
|
break;
|
|
case ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE:
|
|
lpText = TEXT("highestAvailable");
|
|
break;
|
|
case ACTCTX_RUN_LEVEL_REQUIRE_ADMIN:
|
|
lpText = TEXT("requireAdministrator");
|
|
break;
|
|
case ACTCTX_RUN_LEVEL_UNSPECIFIED:
|
|
default:
|
|
lpText = TEXT("unspecified");
|
|
break;
|
|
}
|
|
//RequestedExecutionLevel
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
|
|
if (Data->RunLevel.UiAccess > 0) {
|
|
lpText = TEXT("uiAccess=TRUE");
|
|
}
|
|
else {
|
|
lpText = TEXT("uiAccess=FALSE");
|
|
}
|
|
//UIAccess state
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
|
|
//autoElevate state
|
|
if (Data->AutoElevateState != AutoElevateUnspecified) {
|
|
switch (Data->AutoElevateState) {
|
|
case AutoElevateEnabled:
|
|
lpText = TEXT("autoElevate=TRUE");
|
|
break;
|
|
case AutoElevateDisabled:
|
|
lpText = TEXT("autoElevate=FALSE");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
}
|
|
}
|
|
else {
|
|
// no embedded manifest
|
|
lpText = TEXT("Binary without embedded manifest");
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
if (Data->IsOSBinary) {
|
|
if (Data->IsSignatureValidOrTrusted == FALSE) {
|
|
lpText = TEXT("Warning: signature not valid or trusted");
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
}
|
|
else {
|
|
lpText = TEXT("OS binary with valid digital signature");
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
}
|
|
}
|
|
}
|
|
if (Data->IsDotNet) {
|
|
lpText = TEXT("DotNet");
|
|
LoggerWrite(g_LogFile, lpText, TRUE);
|
|
}
|
|
}
|
|
if (Data->DataType == UacFusionDataRedirectedDllType) {
|
|
Dll = (UAC_FUSION_DATA_DLL*)Data;
|
|
sz = _strlen(Dll->DllName) + _strlen(Dll->FileName) + MAX_PATH;
|
|
lpLog = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz * sizeof(WCHAR));
|
|
if (lpLog) {
|
|
_strcpy(lpLog, TEXT("DllRedirection: "));
|
|
_strcat(lpLog, Dll->FileName);
|
|
_strcat(lpLog, TEXT(" -> "));
|
|
_strcat(lpLog, Dll->DllName);
|
|
LoggerWrite(g_LogFile, lpLog, TRUE);
|
|
HeapFree(GetProcessHeap(), 0, lpLog);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ListBasicSettings
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Scan basic UAC settings.
|
|
*
|
|
*/
|
|
VOID ListBasicSettings(
|
|
VOID
|
|
)
|
|
{
|
|
cuiPrintText(T_BASIC_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_BASIC_HEAD, TRUE);
|
|
ScanBasicUacData((OUTPUTCALLBACK)BasicDataOutputCallback);
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
}
|
|
|
|
/*
|
|
* ListCOMFromRegistry
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Scan HKEY_CLASSES_ROOT for autoelevated COM objects.
|
|
*
|
|
*/
|
|
VOID ListCOMFromRegistry(
|
|
VOID
|
|
)
|
|
{
|
|
cuiPrintText(T_COM_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_COM_HEAD, TRUE);
|
|
CoListInformation((OUTPUTCALLBACK)RegistryOutputCallback);
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
|
|
|
|
//
|
|
// AutoApproval COM list added since RS1.
|
|
//
|
|
if (g_NtBuildNumber >= 14393) {
|
|
cuiPrintText(T_COM_APPROVE_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_COM_APPROVE_HEAD, TRUE);
|
|
CoScanAutoApprovalList((OUTPUTCALLBACK)RegistryOutputCallback);
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ListFusion
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Scan Windows directory for autoelevated apps.
|
|
*
|
|
*/
|
|
VOID ListFusion(
|
|
VOID
|
|
)
|
|
{
|
|
HMODULE hModule;
|
|
WCHAR szPath[MAX_PATH * 2];
|
|
|
|
RtlSecureZeroMemory(szPath, sizeof(szPath));
|
|
_strcpy(szPath, USER_SHARED_DATA->NtSystemRoot);
|
|
_strcat(szPath, TEXT("\\system32\\wintrust.dll"));
|
|
|
|
hModule = LoadLibraryEx(szPath, NULL, 0);
|
|
if (hModule != NULL) {
|
|
WTGetSignatureInfo = (ptrWTGetSignatureInfo)GetProcAddress(hModule, "WTGetSignatureInfo");
|
|
}
|
|
|
|
//scan Windows first
|
|
cuiPrintText(T_WINFILES_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_WINFILES_HEAD, TRUE);
|
|
|
|
#ifdef _DEBUG
|
|
FusionScanDirectory(L"C:\\sxs", (OUTPUTCALLBACK)FusionOutputCallback);
|
|
return;
|
|
#else
|
|
FusionScanDirectory(USER_SHARED_DATA->NtSystemRoot, (OUTPUTCALLBACK)FusionOutputCallback);
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
|
|
//scan program files next
|
|
cuiPrintText(T_PFDIRFILES_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_PFDIRFILES_HEAD, TRUE);
|
|
|
|
RtlSecureZeroMemory(szPath, sizeof(szPath));
|
|
if (SUCCEEDED(SHGetFolderPath(NULL,
|
|
CSIDL_PROGRAM_FILES,
|
|
NULL,
|
|
SHGFP_TYPE_CURRENT,
|
|
(LPWSTR)&szPath)))
|
|
{
|
|
FusionScanDirectory(szPath, (OUTPUTCALLBACK)FusionOutputCallback);
|
|
}
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* ListAppInfo
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Scan memory of appinfo.dll.
|
|
*
|
|
*/
|
|
VOID ListAppInfo(
|
|
VOID
|
|
)
|
|
{
|
|
WCHAR szFileName[MAX_PATH * 2];
|
|
|
|
cuiPrintText(T_APPINFO_HEAD, TRUE);
|
|
LoggerWrite(g_LogFile, T_APPINFO_HEAD, TRUE);
|
|
|
|
#ifndef _DEBUG
|
|
_strcpy(szFileName, USER_SHARED_DATA->NtSystemRoot);
|
|
_strcat(szFileName, TEXT("\\system32\\appinfo.dll"));
|
|
#else
|
|
_strcpy(szFileName, TEXT("C:\\appinfo\\18361.dll"));
|
|
#endif
|
|
ScanAppInfo(szFileName, (OUTPUTCALLBACK)AppInfoDataOutputCallback);
|
|
|
|
LoggerWrite(g_LogFile, T_SPLIT, TRUE);
|
|
}
|
|
|
|
/*
|
|
* main
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Program entry point.
|
|
*
|
|
*/
|
|
VOID main()
|
|
{
|
|
ULONG l = 0;
|
|
WCHAR szBuffer[MAX_PATH];
|
|
|
|
__security_init_cookie();
|
|
|
|
HeapSetInformation(GetProcessHeap(), HeapEnableTerminationOnCorruption, NULL, 0);
|
|
|
|
cuiInitialize(FALSE, NULL);
|
|
|
|
cuiPrintText(T_PROGRAM_TITLE, TRUE);
|
|
|
|
g_NtBuildNumber = 0;
|
|
supQueryNtBuildNumber(&g_NtBuildNumber);
|
|
|
|
if (g_NtBuildNumber < YUUBARI_MIN_SUPPORTED_NT_BUILD) {
|
|
cuiPrintText(TEXT("[UacView] Unsupported Windows version."), TRUE);
|
|
ExitProcess(0);
|
|
}
|
|
if (g_NtBuildNumber > YUUBARI_MAX_SUPPORTED_NT_BUILD) {
|
|
cuiPrintText(TEXT("\r\n[UacView] Not all features available for this build\r\n"), TRUE);
|
|
}
|
|
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
GetCommandLineParam(GetCommandLine(), 1, (LPWSTR)&szBuffer, MAX_PATH * sizeof(WCHAR), &l);
|
|
if (_strcmpi(szBuffer, TEXT("/?")) == 0) {
|
|
MessageBox(GetDesktopWindow(), T_HELP, T_PROGRAM_NAME, MB_ICONINFORMATION);
|
|
ExitProcess(0);
|
|
}
|
|
else {
|
|
g_VerboseOutput = (_strcmpi(szBuffer, TEXT("/v")) == 0);
|
|
}
|
|
|
|
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
|
|
_strcpy(szBuffer, TEXT("uac"));
|
|
ultostr(g_NtBuildNumber, _strend(szBuffer));
|
|
_strcat(szBuffer, TEXT(".log"));
|
|
|
|
g_LogFile = LoggerCreate(szBuffer);
|
|
if (g_LogFile != INVALID_HANDLE_VALUE) {
|
|
cuiPrintText(TEXT("Output will be logged to the file"), TRUE);
|
|
cuiPrintText(szBuffer, TRUE);
|
|
}
|
|
|
|
//#ifndef _DEBUG
|
|
ListBasicSettings();
|
|
ListCOMFromRegistry();
|
|
//#endif
|
|
ListAppInfo();
|
|
ListFusion();
|
|
|
|
if (g_LogFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(g_LogFile);
|
|
|
|
ExitProcess(0);
|
|
}
|