
Исследовательский проект по реверс-инжинирингу COM-интерфейсов Центра безопасности Windows для отслеживания регистрации антивирусов через ATL, vtable, WSCAPI и RPC с проверкой в реальном времени через WMI.
OWN-Defender — это исследовательский проект по безопасности Windows, направленный на понимание того, как Центр безопасности Windows (WSC) представляет и управляет антивирусными продуктами безопасности через свои COM-интерфейсы.
Проект начался как исследование поведения, продемонстрированного в DefendNot, но вместо того, чтобы рассматривать существующую реализацию как «чёрный ящик», я использовал её как отправную точку для независимого реверс-инжиниринга и верификации.
Цель этого проекта — понять полный путь выполнения:
COM
↓
CLSID / IID
↓
CoCreateInstance
↓
QueryInterface
↓
ATL Interface Map
↓
vtable
↓
IWscAVStatus4
↓
CWscIsv
↓
WSCAPI.dll
↓
RPC
↓
Центр безопасности Windows
Проект разрабатывался и тестировался в контролируемой исследовательской среде Windows.
Только для исследований / образовательных целей
Этот проект предназначен для исследования внутренностей Windows, реверс-инжиниринга, обучения безопасности и авторизованного тестирования безопасности. Не используйте его для вмешательства в работу программного обеспечения безопасности на системах, которыми вы не владеете или на тестирование которых у вас нет явного разрешения.
Изначальный вопрос был прост:
Как Центр безопасности Windows узнаёт, что антивирусный продукт существует?
Вместо того чтобы останавливаться на публичной документации API, я хотел понять, что происходит под капотом API.
Это привело к нескольким вопросам:
QueryInterface() разрешает интерфейс?__int64 a1 для метода?Register() на самом деле является функцией регистрации AV?Первым шагом была идентификация COM-класса Центра безопасности Windows.
Проект использует COM-класс WSC:
CLSID_WscIsv
F2102C37-90C3-450C-B3F6-92BE1693BDF2
Реализация также содержит логику динамического поиска CLSID в реестре Windows вместо того, чтобы полагаться исключительно на жёстко заданное значение.
Концептуально:
HKLM
└── SOFTWARE
└── Classes
└── CLSID
└── {CLSID}
└── API ISV Центра безопасности Windows
Это дало первую важную взаимосвязь:
Реестр
↓
CLSID
↓
API ISV Центра безопасности Windows
Следующей задачей было определение того, какой COM-интерфейс следует запрашивать.
Проект использует:
IWscAVStatus4
с:
4DCBAFAC-29BA-46B1-80FC-B8BDE3C0AE4D
Один из важных уроков исследования:
Одного имени GUID недостаточно как доказательства.
Я проверил взаимосвязь через реверс-инжиниринг, а не предполагал, что имя интерфейса и GUID верны.
Исследование включало:
QueryInterface_ATL_INTMAP_ENTRYQueryInterfaceОдним из самых полезных шагов реверса было отслеживание реализации:
CComAggObject<CWscIsv>::QueryInterface()
которая в конечном итоге достигает:
ATL::CComObjectRootBase::InternalQueryInterface()
Карта интерфейсов ATL используется для сравнения запрошенного IID с зарегистрированными записями интерфейсов.
Концептуально:
Запрошенный IID
↓
QueryInterface()
↓
InternalQueryInterface()
↓
Карта интерфейсов ATL
↓
Сравнение GUID
↓
Соответствующий интерфейс
↓
Указатель на интерфейс
Это дало независимое доказательство того, что исследуемый GUID действительно соответствовал ожидаемому COM-интерфейсу.
Register()Одной из самых больших проблем реверса было понимание того, почему IDA/Ghidra не всегда отображали сигнатуру метода, которую я ожидал.
Реконструированный интерфейс содержит:
virtual HRESULT __stdcall Register(
BSTR path,
BSTR name,
unsigned int,
unsigned int
) = 0;
Однако декомпилятор мог показывать реализацию так:
_IWscAVStatus4<CWscIsv>::Register(__int64 a1)
Сначала это выглядело несогласованным.
Дальнейшее исследование показало, что представление декомпилятора описывало обёртку/трамплин и лежащий в основе косвенный вызов vtable, а не полную логическую сигнатуру интерфейса.
Это стало важным уроком:
Вывод декомпилятора — это интерпретация машинного кода, а не исходная истина на уровне исходного кода.
Чтобы разрешить эти расхождения, я сравнил:
Определение COM-интерфейса
↓
Расположение vtable
↓
Ассемблер
↓
Обёртка/трамплин
↓
Соглашение о вызове
↓
Фактическая целевая функция
Register()Ещё одним источником путаницы было наличие нескольких функций с такими именами, как:
IWscAVStatus2::Register
IWscAVStatus4::Register
IWscFWStatus2::Register
RegisterAV
Важным осознанием стало то, что похожие имена не означают идентичные интерфейсы.
Например:
AV
↓
IWscAVStatus4
↓
Регистрация AV
в то время как:
Брандмауэр
↓
IWscFWStatus2
↓
Регистрация брандмауэра
Номер интерфейса и окружающая реализация должны были быть проверены, а не выбирать функцию просто потому, что её имя содержало Register.
Это была одна из самых полезных частей исследования, потому что она заставила меня сопоставить:
Интерфейс
+
IID
+
vtable
+
реализация
+
расположение параметров
+
цель вызова
После идентификации правильного интерфейса я проследил операцию регистрации глубже в бинарном файле.
Наблюдаемый путь был приблизительно таким:
IWscAVStatus4::Register()
↓
CWscIsv
↓
RegisterSecurityProductFunction
↓
wscRegisterSecurityProduct()
↓
WSCAPI.dll
↓
s_wscRegisterSecurityProduct()
↓
NdrClientCall3()
↓
RPC
↓
Центр безопасности Windows
Это было особенно важно, потому что сам COM-метод не был финальной операцией.
Вызов в конечном итоге пересекал границу RPC.
Это изменило мой взгляд на архитектуру:
COM
≠
финальная реализация
Вместо этого:
COM
↓
локальная реализация
↓
API WSC
↓
RPC-клиент
↓
компонент Windows
WSCAPI.dllСледующим слоем был WSCAPI.dll.
Путь, восстановленный реверсом, достигал:
wscRegisterSecurityProduct()
которая в конечном итоге вызывала:
s_wscRegisterSecurityProduct()
а затем:
NdrClientCall3()
Это была точка, где исследование переходило от обычного COM-вызова к RPC-инфраструктуре Windows.
Понимание этого слоя помогло объяснить, почему поведение нельзя было полностью понять, глядя только на исходную COM-DLL.
Статический анализ был лишь частью исследования.
После реконструкции соответствующего интерфейса и пути вызовов я создал собственную контролируемую реализацию и сравнил результирующее поведение с Центром безопасности Windows.
Я использовал информацию Центра безопасности Windows / WMI, такую как:
ROOT\SecurityCenter2
AntiVirusProduct
для независимого наблюдения за зарегистрированной информацией о продукте.