如何检测触发UAC的实际程序名?

问题描述 投票:0回答:1

我正在开发一个 C++ 程序,以使用

Toolhelp32Snapshot
API 跟踪新启动的进程。这是相关的代码片段:

std::optional<Process> getNewProcess() {
        static DWORD last_created_process_id = 0;
        DWORD newest_process_id = 0;
        FILETIME newest_creation_time = {};

        HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hSnapshot == INVALID_HANDLE_VALUE) {
            return std::nullopt;
        }

        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);

        if (!Process32First(hSnapshot, &pe32)) {
            CloseHandle(hSnapshot);
            return std::nullopt;
        }

        do {
            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
            if (hProcess) {
                FILETIME creation_time, exit_time, kernel_time, user_time;
                if (GetProcessTimes(hProcess, &creation_time, &exit_time, &kernel_time, &user_time)) {
                    if (CompareFileTime(&creation_time, &newest_creation_time) > 0) {
                        newest_creation_time = creation_time;
                        newest_process_id = pe32.th32ProcessID;
                    }
                }
                CloseHandle(hProcess);
            }
        } while (Process32Next(hSnapshot, &pe32));

        CloseHandle(hSnapshot);

        if (newest_process_id == 0) {
            return std::nullopt;
        } else {
            if (newest_process_id != last_created_process_id && newest_process_id != GetCurrentProcessId()) {
                last_created_process_id = newest_process_id;
                return Process(newest_process_id);
            } else {
                return std::nullopt;
            }
        }
    }
}

这对于大多数情况都很有效。但是,当启动的程序触发 UAC 提示时,我的代码检测到“consent.exe”和“ctfmon.exe”,而不是启动 UAC 提示的实际程序。

我还在探索使用挂钩来监视 CreateFile 调用并从

lpFileName
中提取程序名称的可能性。然而,我还没有成功地实现这一点。

有没有办法可靠地识别导致UAC提示的程序路径? 谢谢!

c++ winapi uac
1个回答
0
投票

我找到了两种解决方案,可以在提示 UAC 之前了解用户何时启动应用程序。

  1. 内核模式驱动程序:编写内核模式驱动程序以使用PsSetCreateProcessNotifyRoutineEx订阅进程创建事件,并使用IOCTL与用户模式应用程序通信。我在网上找到了一个例子here
  2. Windows 事件跟踪 (ETW): 使用 ETW 消费来自
    Microsoft-Windows-Kernel-Process
    提供程序的事件,该提供程序监视进程、线程和图像活动。 Pavel Yosifovich 的 Windows 10 系统编程,第 1 部分有很好的解释。

我为我的项目选择了 ETW 解决方案。 ETW 为我提供了所需的性能,而无需编写内核驱动程序的复杂性和潜在漏洞。

我写了一个非常简单的例子来说明如何实现ETW流程事件的消费:

#include <iostream>
#include <thread>
#include <ranges>
#include <functional>
#include <string>
#include <vector>

#define INITGUID
#include <guiddef.h>
#include <wbemidl.h>
#include <wmistr.h>
#include <evntrace.h>
#include <comdef.h>
#include <guiddef.h>
#include <tdh.h>
#pragma comment(lib, "tdh.lib")

// logman query providers
DEFINE_GUID( Microsoft_Windows_Kernel_Process,
             0x22fb2cd6,
             0x0e7b,
             0x422b,
             0xa0, 0xc7, 0x2f, 0xad, 0x1f, 0xd0, 0xe7, 0x16 );

class Tracer {
public:
    Tracer(std::wstring name, const DWORD flags)
        : session_name( std::move( name ) ) {

        buffer.resize( sizeof( EVENT_TRACE_PROPERTIES ) + ( session_name.length() + 1 ) * sizeof(
                           std::wstring::value_type ), 0 );
        // Trace Session
        auto &props = *reinterpret_cast< EVENT_TRACE_PROPERTIES * >( buffer.data() );
        props.Wnode.BufferSize = buffer.size();
        props.Wnode.ClientContext = 1;
        props.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
        props.LoggerNameOffset = sizeof( EVENT_TRACE_PROPERTIES );

        auto status = StartTraceW( &handler, session_name.data(), &props );
        if ( status == ERROR_ALREADY_EXISTS ) {
            Tracer::stop();
            status = StartTraceW( &handler, session_name.data(), &props );
        }

        if ( status != ERROR_SUCCESS ) {
            std::cerr << "StartTraceW failed with error " << status << std::endl;
            Tracer::stop();
            return;
        }

        ENABLE_TRACE_PARAMETERS params{};
        params.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
        status = EnableTraceEx2( handler, &Microsoft_Windows_Kernel_Process, EVENT_CONTROL_CODE_ENABLE_PROVIDER,
                                 TRACE_LEVEL_VERBOSE, flags, 0, 0, &params );
        if ( status != ERROR_SUCCESS ) {
            std::cerr << "EnableTraceEx2 failed with error " << status << std::endl;
            Tracer::stop();
            return;
        }

        // Establish a session
        EVENT_TRACE_LOGFILEW trace{};
        trace.LoggerName = session_name.data();
        trace.LogFileName = nullptr;
        trace.Context = this;
        trace.EventRecordCallback = [] (auto *record) {
            if ( record->UserContext ) static_cast< Tracer * >( record->UserContext )->process_trace( record );
        };
        trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_REAL_TIME;

        handler = OpenTraceW( &trace );
        if ( handler == INVALID_PROCESSTRACE_HANDLE ) {
            const auto err = GetLastError();
            std::cerr << "OpenTraceW failed with error " << err << std::endl;
            Tracer::stop();
            throw err;
        }

    }

    void run(const std::function< void(EVENT_RECORD *) > &func) {
        process_trace = func;

        const auto status = ProcessTrace( &handler, 1, 0, 0 );
        if ( status != ERROR_SUCCESS && status != ERROR_CANCELLED ) {
            std::cerr << "ProcessTrace() failed: " << status << std::endl;
            Tracer::stop();
        }
    }

    void stop() {
        ControlTraceW( 0, session_name.data(), reinterpret_cast< EVENT_TRACE_PROPERTIES * >( buffer.data() ),
                       EVENT_TRACE_CONTROL_STOP );
        CloseTrace( handler );
    }

    ~Tracer() { Tracer::stop(); }

private:
    std::vector< std::uint8_t > buffer;
    std::wstring session_name;
    TRACEHANDLE handler = 0;
    std::function< void(EVENT_RECORD *) > process_trace;
};

void recordFunction(EVENT_RECORD *record) {
    if ( IsEqualGUID( record->EventHeader.ProviderId, Microsoft_Windows_Kernel_Process ) &&
         record->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO ) { return; }

    std::vector< std::uint8_t > buffer( sizeof( TRACE_EVENT_INFO ) );
    TRACE_EVENT_INFO *p_info = nullptr;
    TDHSTATUS status = 0;

    for ( const auto i: std::views::iota( 0, 2 ) ) {
        auto buffer_size = static_cast< DWORD >( buffer.size() );
        p_info = reinterpret_cast< TRACE_EVENT_INFO * >( buffer.data() );

        status = TdhGetEventInformation( record, 0, nullptr, p_info, &buffer_size );
        if ( status == ERROR_INSUFFICIENT_BUFFER && i == 0 ) { buffer.resize( buffer_size ); }
    }

    if ( status != ERROR_SUCCESS ) {
        std::cerr << "TdhGetEventInformation failed with error " << status << std::endl;
        return;
    }

    for ( auto i = 0; i < p_info->TopLevelPropertyCount; i++ ) {
        const auto info = p_info->EventPropertyInfoArray[ i ];
        auto property = std::wstring(
            reinterpret_cast< LPWSTR >( reinterpret_cast< BYTE * >( p_info ) + info.NameOffset ) );

        if ( property == L"ImageName" ) {
            PROPERTY_DATA_DESCRIPTOR descriptor;
            descriptor.ArrayIndex = 0;
            descriptor.PropertyName = reinterpret_cast< ULONGLONG >( property.data() );
            ULONG data_size;
            auto result = TdhGetPropertySize( record, 0, nullptr, 1, &descriptor, &data_size );
            if ( result != ERROR_SUCCESS ) {
                std::cerr << "TdhGetPropertySize failed with error " << result << std::endl;
                return;
            }

            std::vector< BYTE > data( data_size );
            descriptor = PROPERTY_DATA_DESCRIPTOR{};
            descriptor.ArrayIndex = 0;
            descriptor.PropertyName = reinterpret_cast< ULONGLONG >( property.data() );
            result = TdhGetProperty( record, 0, nullptr, 1, &descriptor, data.size(),
                                     data.data() );
            if ( result != ERROR_SUCCESS ) {
                std::cerr << "TdhGetProperty failed with error " << result << std::endl;
                return;
            }

            std::wcout << "Process ID: " << record->EventHeader.ProcessId << std::endl;

            std::cout << "Image Name: ";
            if ( info.nonStructType.InType == TDH_INTYPE_ANSISTRING ) {
                std::cout << std::string( data.begin(), data.end() - 1 ) << std::endl;
            }
            else if ( info.nonStructType.InType == TDH_INTYPE_UNICODESTRING ) {
                std::wcout << std::wstring( reinterpret_cast< const wchar_t * >( data.data() ),
                                            ( data.size() - 1 ) / sizeof( wchar_t ) ) << std::endl;
            }
            else { std::cout << "Unknown" << std::endl; }
        }
    }
}

int main() {
    static constexpr auto WinEvent_Process = 0x10u;
    static constexpr auto WinEvent_Thread = 0x20u;
    static constexpr auto WinEvent_Image = 0x40u;
    Tracer tracer( L"Agent", WinEvent_Process | WinEvent_Thread | WinEvent_Image );

    std::thread th( [&tracer]() { tracer.run( recordFunction ); } );
    th.join();
}

结果是: enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.