
Proyecto de investigación de ingeniería inversa de las interfaces COM de Windows Security Center para rastrear el registro de AV a través de ATL, vtable, WSCAPI y RPC, con verificación en tiempo de ejecución mediante WMI.
OWN-Defender es un proyecto de investigación de seguridad de Windows centrado en comprender cómo el Centro de seguridad de Windows (WSC) representa y gestiona los productos de seguridad antivirus a través de sus interfaces COM.
El proyecto comenzó como una investigación sobre el comportamiento demostrado por DefendNot, pero en lugar de tratar la implementación existente como una caja negra, lo utilicé como punto de partida para una ingeniería inversa independiente y su verificación.
El objetivo de este proyecto es comprender la ruta de ejecución completa:
COM
↓
CLSID / IID
↓
CoCreateInstance
↓
QueryInterface
↓
Mapa de interfaces ATL
↓
vtable
↓
IWscAVStatus4
↓
CWscIsv
↓
WSCAPI.dll
↓
RPC
↓
Centro de seguridad de Windows
El proyecto se desarrolló y probó en un entorno de investigación de Windows controlado.
Solo para investigación / uso educativo
Este proyecto está destinado a la investigación de internals de Windows, ingeniería inversa, educación en seguridad y pruebas de seguridad autorizadas. No lo utilices para interferir con software de seguridad en sistemas que no poseas o para los que no tengas permiso explícito de prueba.
La pregunta inicial era simple:
¿Cómo sabe el Centro de seguridad de Windows que existe un producto antivirus?
En lugar de detenerme en la documentación pública de la API, quería entender qué ocurre debajo de la API.
Esto llevó a varias preguntas:
QueryInterface() la interfaz?__int64 a1 para un método?Register() es realmente la función de registro de AV?El primer paso fue identificar la clase COM del Centro de seguridad de Windows.
El proyecto utiliza la clase COM de WSC:
CLSID_WscIsv
F2102C37-90C3-450C-B3F6-92BE1693BDF2
La implementación también contiene lógica para localizar el CLSID dinámicamente desde el registro de Windows en lugar de depender exclusivamente de un valor codificado.
Conceptualmente:
HKLM
└── SOFTWARE
└── Classes
└── CLSID
└── {CLSID}
└── API ISV del Centro de seguridad de Windows
Esto proporcionó la primera relación importante:
Registro
↓
CLSID
↓
API ISV del Centro de seguridad de Windows
El siguiente desafío fue determinar qué interfaz COM debía solicitarse.
El proyecto utiliza:
IWscAVStatus4
con:
4DCBAFAC-29BA-46B1-80FC-B8BDE3C0AE4D
Una de las lecciones importantes de la investigación fue:
Un nombre de GUID por sí solo no es evidencia suficiente.
Verifiqué la relación mediante ingeniería inversa en lugar de asumir que el nombre de la interfaz y el GUID eran correctos.
La investigación incluyó:
QueryInterface_ATL_INTMAP_ENTRYQueryInterfaceUno de los pasos de reversión más útiles fue seguir la implementación de:
CComAggObject<CWscIsv>::QueryInterface()
que finalmente llega a:
ATL::CComObjectRootBase::InternalQueryInterface()
El mapa de interfaces ATL se utiliza para comparar el IID solicitado con las entradas de interfaz registradas.
Conceptualmente:
IID solicitado
↓
QueryInterface()
↓
InternalQueryInterface()
↓
Mapa de interfaces ATL
↓
Comparación de GUID
↓
Interfaz coincidente
↓
Puntero de interfaz
Esto proporcionó evidencia independiente de que el GUID investigado correspondía realmente a la interfaz COM esperada.
Register()Uno de los mayores desafíos de la reversión fue comprender por qué IDA/Ghidra no siempre mostraba la firma del método que esperaba.
La interfaz reconstruida contiene:
virtual HRESULT __stdcall Register(
BSTR path,
BSTR name,
unsigned int,
unsigned int
) = 0;
Sin embargo, el descompilador podría mostrar una implementación como:
_IWscAVStatus4<CWscIsv>::Register(__int64 a1)
Al principio esto parecía inconsistente.
Una investigación más profunda mostró que la representación del descompilador describía un wrapper/thunk y la llamada indirecta subyacente a la vtable, en lugar de presentar la firma lógica completa de la interfaz.
Esto se convirtió en una lección importante:
La salida del descompilador es una interpretación del código máquina, no la verdad original a nivel de código fuente.
Para resolver estas discrepancias, comparé:
Definición de la interfaz COM
↓
Diseño de la vtable
↓
Ensamblador
↓
Wrapper/thunk
↓
Convención de llamada
↓
Función objetivo real
Register()Otra fuente de confusión fue la presencia de múltiples funciones con nombres como:
IWscAVStatus2::Register
IWscAVStatus4::Register
IWscFWStatus2::Register
RegisterAV
La comprensión importante fue que nombres similares no significan interfaces idénticas.
Por ejemplo:
AV
↓
IWscAVStatus4
↓
Registro de AV
mientras que:
Firewall
↓
IWscFWStatus2
↓
Registro de firewall
El número de interfaz y la implementación circundante tuvieron que verificarse en lugar de seleccionar una función simplemente porque su nombre contenía Register.
Esta fue una de las partes más útiles de la investigación porque me obligó a correlacionar:
Interfaz
+
IID
+
vtable
+
implementación
+
diseño de parámetros
+
objetivo de llamada
Después de identificar la interfaz correcta, rastreé la operación de registro más profundamente en el binario.
La ruta observada fue aproximadamente:
IWscAVStatus4::Register()
↓
CWscIsv
↓
RegisterSecurityProductFunction
↓
wscRegisterSecurityProduct()
↓
WSCAPI.dll
↓
s_wscRegisterSecurityProduct()
↓
NdrClientCall3()
↓
RPC
↓
Centro de seguridad de Windows
Esto fue particularmente importante porque el método COM en sí no era la operación final.
La llamada finalmente cruzaba un límite de RPC.
Eso cambió mi forma de ver la arquitectura:
COM
≠
implementación final
En su lugar:
COM
↓
implementación local
↓
API de WSC
↓
cliente RPC
↓
componente de Windows
WSCAPI.dllLa siguiente capa era WSCAPI.dll.
La ruta con ingeniería inversa alcanzó:
wscRegisterSecurityProduct()
que finalmente invocaba:
s_wscRegisterSecurityProduct()
y luego:
NdrClientCall3()
Este fue el punto donde la investigación pasó de una llamada COM normal a la infraestructura RPC de Windows.
Comprender esta capa ayudó a explicar por qué el comportamiento no podía entenderse completamente mirando solo el DLL COM original.
El análisis estático fue solo una parte de la investigación.