Вопрос или проблема
Я разрабатываю программу мониторинга процессов, которая определяет процессы, требующие повышения прав.
Мой текущий подход включает:
- Поток GUI для обработки пользовательского интерфейса.
- Поток мониторинга использует трассировку событий для Windows, чтобы слушать события создания процессов. Этот поток передает новые идентификаторы процессов, обернутые в классы
Process
, в поток GUI. - Проверка повышения прав: Конструктор класса
Process
сразу же проверяет его манифестный файл на наличие соответствующей информации, включая<requestedExecutionLevel level="requireAdministrator" />
, чтобы определить, требует ли процесс повышения прав.
Это работает для многих процессов, но некоторые исполняемые файлы (например, установщики .msi
) требуют повышения прав, не указывая это явно в своем манифесте (если они его имеют).
Я рассматривал возможность мониторинга вызовов consent.exe
и svchost.exe
:
но проблема возникает, когда несколько процессов, требующих повышения прав, запускают другие процессы.
Если один из этих дочерних процессов запускает constent.exe
, становится сложно определить исходный процесс, ответственный за запрос на повышение прав, что заставило меня рассмотреть подход, подобный Process Explorer, чтобы выявить деревья процессов, но я опасаюсь сложности и потенциальной нагрузки на производительность.
Это разумное направление или есть более простые и эффективные альтернативы для выявления процессов, требующих повышения прав?
В настоящее время я инкапсулировал логику ETW в класс и фильтрационный механизм для идентификации соответствующих процессов:
// Поток слушателя процессов:
void ProcessListener::onRecord(EVENT_RECORD *record) {
if ( record->EventHeader.EventDescriptor.Id == EVENT_TRACE_TYPE_START ) {
EventParser parser( record );
auto &p_info = parser.getTraceEventInfo();
for ( auto i = 0u; i < p_info->TopLevelPropertyCount; i++ ) {
const auto current = p_info->EventPropertyInfoArray[ i ];
const auto property = std::wstring( reinterpret_cast< LPWSTR >( p_info.data() + current.NameOffset ) );
if ( current.nonStructType.InType == TDH_INTYPE_UNICODESTRING ) {
if ( property == L"ImageName" ) {
auto data = parser.getPropertyData( property );
auto path = std::wstring( reinterpret_cast< const wchar_t * >( data.data() ),
data.size() / sizeof( wchar_t ) - 1 );
try {
Process process( record->EventHeader.ProcessId, path );
if ( filter_func != nullptr ) {
if ( filter_func( process ) ) {
queue.push( std::make_unique< Process >( std::move( process ) ) );
}
}
else { queue.push( std::make_unique< Process >( std::move( process ) ) ); }
}
catch ( const std::exception &e ) { spdlog::info(e.what()); }
}
}
}
}
}
// Поток GUI:
psm.setFilter( [] (const ProcessBase &process)-> bool {
return process.getPath().extension() == ".exe" &&
process.needsElevation() && // Проверяет манифестный файл.
process.getPath().wstring().find( L"\\Windows\\System32" ) == std::wstring::npos;
} );
psm.run();
Ответ или решение
Определение требований к повышению прав в только что запущенных процессах
Ваша задача разработки программы мониторинга процессов, которая определяет, какие процессы требуют повышения прав (elevation), представляет собой важную и интересную задачу в области управления процессами и безопасности. Основной подход, который вы описали, включает использование потоков для обслуживания пользовательского интерфейса и мониторинга процессов с помощью Event Tracing for Windows (ETW). Несмотря на то, что ваша реализация уже функционирует для многих типов процессов, вы столкнулись с некоторыми ограничениями, особенно с процессами, которые требуют повышения прав без явного указания этого в их манифестах.
Подход к определению процессов, требующих повышения прав
Ваша реализация на текущий момент включает:
- GUI Поток: для работы с пользовательским интерфейсом.
- Поток мониторинга: использующий ETW для отслеживания событий создания процессов, что позволяет передавать новые идентификаторы процессов на GUI поток.
- Проверка на необходимость повышения прав: конструктор класса
Process
проверяет манифест файла на наличие элемента<requestedExecutionLevel level="requireAdministrator"/>
.
В таком подходе действительно могут оказаться непростыми случаи, например, с установщиками формата .msi
, которые доступ к повышенным привилегиям требуют, даже если это не прописано в их манифестах.
Использование consent.exe и svchost.exe
Вы также упомянули возможность мониторинга процессов consent.exe
и svchost.exe
, чтобы выявить потребность в повышении прав. Однако, как вы уже заметили, это может привести к путанице, когда дочерние процессы вызывают consent.exe
, и становится трудно определить, какой из родительских процессов инициировал запрос на повышение прав.
Рекомендации по улучшению стратегии
-
Отслеживание иерархии процессов: Использование подхода, аналогичного тому, который применяет Process Explorer, для построения дерева процессов может быть реалистичной стратегией. Хотя это добавляет сложность, оно также дает возможность получения более детальной информации о том, какой именно процесс инициировал требование на повышение прав. Для минимизации производительных затрат можно рассмотреть возможность обновления иерархии процессов только при определенных событиях, например, при активных изменениях в процессах.
-
Анализ атрибутов и аргументов командной строки: Некоторые процессы могут требовать повышения прав на основе их параметров. Можно добавить дополнительную проверку на наличие специфичных аргументов командной строки, часто используемых для вызова процессов с повышением привилегий (например,
/a
для установщиков). -
Системные API для проверки прав: В дополнение к проверке манифестов, использование API Windows, таких как
OpenProcessToken
иGetTokenInformation
, может предоставить информацию о правах доступа процессов. Это позволит вам более точно определять, требует ли процесс действительно повышения привилегий в момент его запуска.
Заключение
Ваш первоначальный подход имеет свои преимущества и уже позволяет идентифицировать множество процессов, требующих повышения прав. Однако, для учета случая с процессами, которые не явно указывают свою потребность в повышении, можно рассмотреть предложенные улучшения. Постепенно добавляя более сложные логические проверки и механизмы контроля, вы сможете значительно повысить надежность вашей программы.
Важно помнить о балансе между производительностью и функциональностью: избыточная сложность может негативно сказаться на общей производительности системы, поэтому проанализируйте, какие действия имеют наибольший приоритет для вашей задачи и могут быть эффективно реализованы.