Compartir a través de


Comprobador de aplicaciones - Pruebas dentro del comprobador de aplicaciones

Aspectos básicos

Como mínimo, debe ejecutar el comprobador de aplicaciones con la opción Aspectos básicos seleccionada. Cada uno de ellos probará un área que provocará bloqueos u otros escenarios negativos, que tienen un impacto directo y firme de la experiencia del cliente.

  • Excepciones : garantiza que las aplicaciones no ocultan las infracciones de acceso mediante el control de excepciones estructurado
  • Identificadores : pruebas para asegurarse de que la aplicación no intenta usar identificadores no válidos
  • Montones : comprueba si hay problemas de daños en la memoria en el montón
  • Pérdida : detecta pérdidas mediante el seguimiento de los recursos realizados por un archivo DLL que no están liberados por el momento en que se descargó el archivo dll.
  • Bloqueos : comprueba el uso correcto de las secciones críticas.
  • Memoria : garantiza que las API para las manipulaciones de espacio virtual se usan correctamente (por ejemplo, VirtualAlloc, MapViewOfFile)
  • SRWLock : comprueba el uso correcto para bloqueos de lector y escritor finos (SRW).
  • Threadpool : garantiza el uso correcto de las API de threadpool y aplica comprobaciones de coherencia en los estados de worker-thread-states después de una devolución de llamada, como subprocesos de subprocesos sucios y otros problemas relacionados con el grupo de subprocesos.
  • TLS : garantiza que las API de almacenamiento local de subprocesos se usan correctamente.

Para obtener información sobre las excepciones de código de detención generadas por estas pruebas, consulte Application Verifier - Stop Codes and Definitions. Para obtener información sobre cómo depurar estos errores, consulte Application Verifier - Debugging Application Verifier Stops

Compatibilidad

Las pruebas de nivel de comprobación de compatibilidad ayudan a identificar una aplicación que puede tener problemas con el sistema operativo Microsoft Windows. Muchas de estas comprobaciones también se pueden usar para probar los requisitos de logotipo o certificación.

Para obtener información sobre las excepciones de código de detención generadas por estas pruebas, consulte Application Verifier - Stop Codes and Definitions.

HighVersionLie : identifica problemas para algunos de los problemas de compatibilidad de aplicaciones más comunes en Windows. La detección incorrecta de la versión del sistema operativo o el uso de información de versión codificada de forma rígida puede provocar un error en la aplicación en sistemas operativos posteriores.

Cuzz

La capa de comprobación de simultaneidad aproximada (Cuzz) detecta errores de simultaneidad y condiciones de carrera de datos. Cuzz ajusta la programación de subprocesos mediante la inserción de retrasos aleatorios en puntos clave en el código de una aplicación. En el escenario siguiente se muestra el tipo de error de simultaneidad que podría detectar la capa de comprobación de Cuzz.

Una aplicación tiene un subproceso primario y un subproceso secundario. El subproceso primario inicia el subproceso secundario y, a continuación, asigna memoria para una estructura.

// Parent Thread
StartChildThread(...);
g_pointer = ... malloc(...);

El subproceso secundario desreferencia el puntero.

//Child Thread
LONG value = g_pointer->someMember;

El código anterior tiene un error de simultaneidad. Si el subproceso secundario intenta desreferenciar el puntero antes de que el subproceso primario asigne la memoria, el puntero no será válido. Es muy poco probable que el error se manifeste porque, en la mayoría de los casos, el subproceso primario asignará la memoria antes de que se inicie el subproceso secundario. Pero en raras ocasiones, el subproceso secundario podría comenzar e intentar desreferenciar el puntero antes de que el subproceso primario haya asignado la memoria.

La capa de comprobación de Cuzz aumenta la probabilidad de encontrar errores de simultaneidad como el que se muestra en el ejemplo anterior. Cuzz no realiza ninguna comprobación adicional aparte de insertar retrasos. Por lo tanto, no hay paradas de comprobación asociadas directamente a Cuzz. Sin embargo, si habilitar Cuzz da como resultado un manifiesto de errores de simultaneidad en sí mismo, otras capas de comprobación se beneficiarán. Por ejemplo, si una condición de carrera da como resultado un desbordamiento del montón, la capa de comprobación de montones no encontrará el error a menos que la condición de carrera se manifeste en tiempo de ejecución. Al aumentar la probabilidad de que se produzca la condición de carrera, Cuzz mejora la eficacia de la capa de montones para identificar el error.

Para obtener la máxima ventaja de Cuzz, habilite Cuzz en tantas pruebas como sea posible y repita la misma prueba muchas veces. Cuzz se puede habilitar en todas las pruebas, incluidas las pruebas manuales, las pruebas funcionales y las pruebas de esfuerzo. Además, habilite tantas capas de comprobación del comprobador de aplicaciones como sea posible.

Puede aumentar la probabilidad de reproducir un error proporcionando Cuzz con la misma inicialización aleatoria (consulte Propiedades).

Cuzz inserta retrasos solo en las llamadas API de sincronización de Win32.

Propiedades de Cuzz

Las siguientes propiedades están disponibles para la capa de comprobación de Cuzz. Para establecer las propiedades, seleccione la capa Cuzz en la interfaz de usuario del comprobador de aplicaciones y abra la ventana de propiedades.

Propiedad Descripción
FuzzingLevel Controla el nivel de aproximación para Cuzz. Establézcalo en 1 para las aplicaciones críticas para el tiempo y 4 para las aplicaciones normales.
RandomSeed Inicialización aleatoria utilizada por Cuzz al principio. Si establece esto en 0, Cuzz genera una inicialización aleatoria basada en el tiempo.

Simulación de recursos bajos

La simulación de recursos bajos intenta simular un entorno con recursos bajos, como memoria insuficiente. Esta simulación identificará los errores que se producen en condiciones de memoria baja. Esto también se conoce como inyección de errores. Puede simular un entorno bajo recursos bajos, por lo que puede definir un número (0-100) que indique las llamadas de probabilidad de error de:

  • Espere (por ejemplo, la API WaitForXXXX).
  • Heap_Alloc (API de asignación de montón).
  • Virtual_Alloc (API de asignación de memoria virtual).
  • Registro (API del Registro).
  • File (FILE API como CreateFile).
  • Evento (API de eventos como CreateEvent).
  • MapView ( API mapView, como CreateMapView).
  • Ole_Alloc (OLE API como SysAllocString).

La simulación de recursos baja (también conocida como inyección de errores) intenta simular un entorno bajo recursos bajos, por ejemplo, memoria insuficiente. Esto identificará el error en condiciones de memoria baja.

Propiedades de simulación de recursos bajos

Para editar las propiedades, active la casilla Low Resource Simulation (Simulación de recursos bajos) en el área Pruebas, haga clic con el botón derecho y seleccione propiedades:

Propiedad Descripción
Incluir El límite de errores solo se produce en los archivos DLL especificados. Un nombre dll sin ruta de acceso por fila. Si se especifica '*', se producirán errores para todos los módulos.
Exclude Excluya los errores de los módulos especificados. Un nombre dll sin ruta de acceso por fila.
Tiempo de espera Asigne un espacio de tiempo (en milisegundos) cuando no haya ningún error en la inicialización del proceso.
Espera Número [0 – 1000000] que indica la probabilidad de error para la API WaitForXXXX.
Heap_Alloc Número [0 – 1000000] que indica la probabilidad de error para la API de asignación de montón.
Virtual_Alloc Número [0 – 1000000] que indica la probabilidad de error para la API de asignación de memoria virtual.
Registro Número [0 – 1000000] que indica la probabilidad de error para la API del Registro.
Archivo Número [0 – 1000000] que indica la probabilidad de error para la API de archivo, como CreateFile.
Evento Número [0 – 1000000] que indica la probabilidad de error para la API de eventos, como CreateEvent.
MapView Número [0 – 1000000] que indica la probabilidad de error para la API MapView, como CreateMapView.
Ole_Alloc Número [0 – 1000000] que indica la probabilidad de error de ole API como SysAllocString.
Pilas Cada subproceso de aplicación de Windows comienza con una reserva de pila y un tamaño de confirmación de pila. En el uso normal, la confirmación de la pila crece cada vez que se necesita más espacio en la pila. Consulte Creating Threads and Thread Stack Size (Crear subprocesos y tamaño de pila de subprocesos) para obtener más información. Si el sistema experimenta condiciones de memoria baja, es posible que se produzca un error en el crecimiento de la confirmación de la pila. El subproceso que no puede aumentar su pila y toda la aplicación probablemente se bloqueará. Ese tipo de bloqueo es inaceptable para los procesos importantes del sistema (por ejemplo, para los servicios). La comprobación Pilas deshabilitará el crecimiento de la pila para la aplicación que se está comprobando, por lo que simulará los errores de crecimiento de la pila sin necesidad de simular todas las condiciones de memoria baja del sistema. Las excepciones se producirán cuando la aplicación intente expandir la pila. Esto no genera ninguna parada de comprobador.

LuaPriv

Las pruebas de predicción de privilegios de cuenta de usuario limitada (LuaPriv) son predictivas y de diagnóstico y funcionan para exponer problemas relacionados con la ejecución de una aplicación con privilegios administrativos, y si esa aplicación funcionaría también si se ejecutaría con menos privilegios (por lo general, como usuario normal).

También conocido como comprobaciones de UAC, el predictor de privilegios de cuenta de usuario limitado (LuaPriv) tiene dos objetivos principales:

  • Predictivo: al ejecutar una aplicación con privilegios administrativos, prediga si esa aplicación funcionaría también si se ejecuta con menos privilegios (por lo general, como usuario normal). Por ejemplo, si la aplicación escribe en archivos que solo permiten el acceso de los administradores, esa aplicación no podrá escribir en el mismo archivo si se ejecuta como no administrador.

  • Diagnóstico: mientras se ejecuta con privilegios que no son de administrador, identifique los posibles problemas que ya pueden existir con la ejecución actual. Siguiendo con el ejemplo anterior, si la aplicación intenta escribir en un archivo que concede acceso solo a los miembros del grupo de administradores, la aplicación recibirá un error de ACCESS_DENIED. Si la aplicación no funciona correctamente, esta operación puede ser el culpable.

LuaPriv identifica los siguientes tipos de problemas:

Problema potencial Descripción
Espacios de nombres restringidos La creación de un objeto de sincronización con nombre (Event, Semaphore, Mutex, etc.) sin un espacio de nombres puede complicar la ejecución sin privilegios en algunos sistemas operativos, ya que el sistema operativo puede optar por colocar el objeto en un espacio de nombres restringido. La creación de este objeto en un espacio de nombres restringido (como el espacio de nombres Global) requiere SeCreateGlobalPrivilege, que solo se concede a los administradores.
LuaPriv marca ambos problemas si los detecta.
Comprobaciones de administrador estrictas Algunas aplicaciones interrogan el token de seguridad del usuario para averiguar cuánto privilegio tiene. En esos casos, la aplicación puede cambiar su comportamiento en función de los privilegios que cree que tiene el usuario.
LuaPriv marca las llamadas de API que devuelven esta información.
Solicitud de privilegios Una aplicación puede intentar habilitar un privilegio relevante para la seguridad (como SeTcbPrivilege o SeSecurityPrivilege) antes de realizar una operación que lo requiera.
LuaPriv marca los intentos de habilitar privilegios relevantes para la seguridad.
Faltan privilegios Si una aplicación intenta habilitar un privilegio que el usuario no tiene, probablemente señala que la aplicación espera el privilegio, lo que puede provocar diferencias de comportamiento.
LuaPriv marca las solicitudes de privilegios realizadas erróneamente.
Operaciones en archivos INI Los intentos de escritura en archivos INI asignados (WritePrivateProfileSection y API similares) pueden producir un error con un usuario que no es administrador.
LuaPriv marca estas operaciones.
Acceso denegado Si la aplicación intenta acceder a un objeto (Archivo, clave del Registro, etc.), pero se produce un error en el intento debido a un acceso insuficiente, es probable que la aplicación espere ejecutarse con más privilegios de los que tiene.
LuaPriv marca los intentos de apertura de objetos que producen errores de ACCESS_DENIED y errores similares.
Denegación de ACE Si un objeto tiene denegaciones de ACE en su DACL, deniega explícitamente el acceso a entidades específicas.
Esto es poco común y dificulta la predicción, por lo que LuaPriv marca las denegaciones de ACE cuando las encuentra.
Acceso restringido Si una aplicación intenta abrir un objeto para los derechos que no se conceden a los usuarios normales (por ejemplo, intentando escribir en un archivo en el que solo pueden escribir los administradores), es probable que la aplicación no funcione igual cuando se ejecuta como un usuario normal.
LuaPriv marca estas operaciones.
MAXIMUM_ALLOWED Si una aplicación abre un objeto para MAXIMUM_ALLOWED, la comprobación de acceso real en el objeto se producirá en otro lugar. La mayoría del código que hace esto no funciona correctamente y casi sin duda funcionarán de forma diferente cuando se ejecute sin privilegios.
LuaPriv marca por tanto todos los incidentes de MAXIMUM_ALLOWED.

Varios

Los problemas que se suelen pasar por alto se capturan en las pruebas varias.

  • API peligrosas: realiza un seguimiento para ver si la aplicación usa las siguientes acciones no seguras:
    • Llamada peligrosa a TerminateThread.
    • Posible desbordamiento de pila en condiciones de memoria baja.
    • Proceso de salida al que se llama mientras se están ejecutando varios subprocesos.
    • Se llama a LoadLibrary durante DllMain.
    • Se llama a FreeLibrary durante DllMain.
  • Las pilas sucias rellenan (periódicamente) la parte no utilizada de la pila con un patrón de memoria. Esto puede ayudar a detectar variables no inicializadas en futuras llamadas de función en el contexto de ese subproceso.
  • TimeRollOver obliga a las API GetTickCount y TimeGetTime a pasar más rápido de lo normal. Esto permite a las aplicaciones probar su control de la sustitución de tiempo con mayor facilidad.

Propiedades varias

La comprobación de API peligrosas tiene una propiedad que se puede modificar:

DllMainCheck : compruebe la llamada LoadLibrary/FreeLibrary cuando DllMain esté activo.

Redes

Las pruebas de red buscan un uso incorrecto de las API de WinSock. Por ejemplo, si se llama a una API de red antes de que se realice una llamada WSAStartup() correcta o después de realizar una llamada WSACleanup() correcta. Para obtener más información sobre WinSock, consulta encabezado winsock.h y Windows Sockets 2.

Propiedades

Las siguientes propiedades están disponibles para la capa de comprobación net. Para establecer las propiedades, seleccione el proveedor de redes en la interfaz de usuario del comprobador de aplicaciones y abra la ventana de propiedades.

Propiedad Descripción
FragmentsEnabled Habilita la fragmentación de flujos de datos recibidos por sockets TCP IPv4 e IPv6.
FragmentSize Especifica el número máximo de bytes devueltos en un búfer a cualquier llamada API de recepción de Winsock.

La propiedad FragmentsEnabled permite la funcionalidad en el proveedor del comprobador de redes para facilitar las pruebas y la comprobación de un análisis de las secuencias TCP de una aplicación fuera de una red. Una vez habilitada, todas las llamadas a Winsock para recibir datos solo recibirán hasta FragmentSize bytes a menos que la aplicación requiera específicamente el búfer completo rellenado antes de devolver (controlado por la marca de MSG_WAITALL). Dado que ni el protocolo TCP ni Winsock proporcionan ninguna garantía sobre el número de bytes que posiblemente se devuelven en un búfer, habilitar esta comprobación facilitará la comprobación de que el código que analiza el flujo de datos de la red lo hace correctamente, independientemente del número de bytes recibidos por llamada a Winsock. Los problemas en los analizadores de flujos han sido un origen de errores de alto perfil y estas propiedades se proporcionan para facilitar la comprobación de la corrección, ya que esto es especialmente difícil de probar. Nota: Esto no cambia los datos devueltos: solo lo ralentiza a una velocidad específica: la aplicación debe comportarse exactamente de la misma manera con esta habilitada o deshabilitada.

La siguiente línea de comandos habilita la fragmentación de todos los flujos TCP entrantes en todos los sockets IPv4 e IPv6 TCP creados en myApp.exe y todos los archivos binarios cargados por myApp.exe.

appverif -enable Networking -for myApp.exe -with Networking.FragmentsEnabled=True Networking.FragmentSize=10

!avrf Debugger Extensión

!avrf -net -socket count : muestra el recuento de identificadores de socket abierto y cerrado.

!avrf -net -socket dump [-v] [HANDLE] : muestra identificadores de socket, detallados o no.

!avrf -net -wsastacks : muestra el recuento de iniciales de WSA actual y la lista cronológica de seguimientos de pila para WSAStartup/WSACleanup.

!avrf -net -wsastacks count : muestra el recuento de inicialización de WSA actual.

!avrf -net -socket count : este comando proporcionará el número total de identificadores de socket que se están realizando el seguimiento, tanto abiertos como cerrados. Tenga en cuenta que se realiza un seguimiento en una cola circular, por lo que hay un límite máximo en el total del que se realiza el seguimiento. Los sockets se agregan a la lista abierta cuando se llama a una de las API de Winsock que asigna un identificador de socket. Por ejemplo, socket(), WSASocket(), accept(). Los sockets se mueven de la lista abierta a la lista cerrada cuando se llama a la función closesocket() en ese identificador de socket.

!avrf -net -socket dump [-v] [HANDLE] : este comando enumerará los identificadores de socket. "-socket dump" enumerará todos los identificadores de socket abiertos y cerrados por sus valores SOCKET. La marca opcional -v imprimirá además la pila de llamadas abierta o cerrada inmediatamente después de imprimir cada valor socket. El campo HANDLE opcional mostrará solo el identificador SOCKET especificado y su pila de llamadas abierta o cerrada.

Este es un ejemplo de las distintas opciones de uso de sockets:

0:008> !avrf -net -socket count
Number of open socket handles   = 16
Number of closed socket handles = 12
 
0:008> !avrf -net -socket dump
CLOSED SOCKET HANDLE - 0x47c
CLOSED SOCKET HANDLE - 0x2cc
CLOSED SOCKET HANDLE - 0x8c4
CLOSED SOCKET HANDLE - 0x6bc
CLOSED SOCKET HANDLE - 0x44c
CLOSED SOCKET HANDLE - 0x578
CLOSED SOCKET HANDLE - 0x6f4
CLOSED SOCKET HANDLE - 0x5b4
CLOSED SOCKET HANDLE - 0x4d8
CLOSED SOCKET HANDLE - 0x3cc
CLOSED SOCKET HANDLE - 0x4fc
CLOSED SOCKET HANDLE - 0x4e0
OPEN SOCKET HANDLE - 0xfd4
OPEN SOCKET HANDLE - 0x7d8
OPEN SOCKET HANDLE - 0xf8c
OPEN SOCKET HANDLE - 0xf88
OPEN SOCKET HANDLE - 0xae0
OPEN SOCKET HANDLE - 0xe58
OPEN SOCKET HANDLE - 0xdfc
OPEN SOCKET HANDLE - 0xcf8
OPEN SOCKET HANDLE - 0xa18
OPEN SOCKET HANDLE - 0x7a0
OPEN SOCKET HANDLE - 0x7b0
OPEN SOCKET HANDLE - 0x534
OPEN SOCKET HANDLE - 0xcdc
OPEN SOCKET HANDLE - 0x1f0
OPEN SOCKET HANDLE - 0x444
OPEN SOCKET HANDLE - 0x8bc
 
0:008> !avrf -net -socket dump -v 0x47c
 
The socket handle is closed
 
vfNet!VfHookclosesocket
WININET!ICSocket::_UnSafeCloseSocket
WININET!ICSocket::Dereference
WININET!CFsm_GetConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm
WININET!CFsm_OpenConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection
WININET!HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm
WININET!CFsm_MakeConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm
WININET!CFsm_SendRequest::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start
WININET!CFsm_HttpSendRequest::RunSM
WININET!CFsm::Run
WININET!CFsm::RunWorkItem
SHLWAPI!ExecuteWorkItemThreadProc
vfbasics!AVrfpRtlWorkerCallback
ntdll!RtlpTpWorkCallback
ntdll!TppWorkerThread
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart

!avrf -net -wsastacks [count]

Winsock requiere que los desarrolladores de aplicaciones llamen a WSAStartup() al menos una vez antes de realizar llamadas a Winsock. Se realiza un seguimiento de esto en todo el proceso de Winsock. El recuento de referencias inicial indica a una biblioteca de Winsock (ws2_32.dll) que inicialice y cargue el catálogo y los proveedores de Winsock. Otras llamadas a WSAStartup incrementan ese recuento de referencias. Winsock también requiere que los desarrolladores de aplicaciones llamen a WSACleanup() cuando hayan "terminado" llamando a Winsock. Las llamadas a WSACleanup deben emparejarse correctamente con una llamada anterior a WSAStartup(). La llamada a WSACleanup() disminuye el recuento de referencias de todo el proceso. Cuando el recuento de referencias cae a cero, Winsock libera sus recursos y descarga el catálogo y los proveedores de Winsock.

Este comando proporcionará el valor de recuento de referencias general de la rutina de inicialización "WSAStartup" actual y enumera las pilas de llamadas a las llamadas a WSAStartup y WSACleanup realizadas en el proceso. Tenga en cuenta que esto se mantiene dentro de una cola circular fija, por lo que no se garantiza que se complete, solo las N llamadas más recientes.

Este es un ejemplo de las distintas opciones de uso de -wsastacks:

0:008> !avrf -net -wsastacks count
 
Current WSARefCount: 1 (WSAStartup call count minus WSACleanup call count for the target process)
 
 
0:008> !avrf -net -wsastacks
 
Current WSARefCount: 1 (WSAStartup call count minus WSACleanup call count for the target process)
 
 
THREAD ID: 0xe4c called WSAStartup
vfNet!WSAInitStacks<NetAllocatorViaPrivateHeap>::AddWSAStackTrace
vfNet!VfHookWSAStartup
WININET!LoadWinsock
WININET!GlobalDataInitialize
WININET!InternetSetOptionA
WININET!InternetSetOptionW
IEFRAME!LCIEUpdateSessionStartTime
IEFRAME!LCIETab_ThreadProc
iertutil!_IsoThreadProc
vfbasics!AVrfpStandardThreadFunction
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart

NTLM

Este complemento Comprobador de aplicaciones supervisa las llamadas de un proceso individual a las API de autenticación AcquireCredentialsHandle e InitializeSecurityContext para detectar los usos del protocolo NTLM. NTLM es un protocolo de autenticación obsoleto con defectos que potencialmente ponen en peligro la seguridad de las aplicaciones y el sistema operativo y no se deben usar.

Riesgo de autenticación NTLM

El protocolo de autenticación NTLM obsoleto más importante es la falta de autenticación del servidor, lo que podría permitir a un atacante engañar a los usuarios para conectarse a un servidor suplantado. Como corolario de la autenticación de servidor que falta, las aplicaciones que usan NTLM también pueden ser vulnerables a un tipo de ataque conocido como ataque de "reflexión". Esto último permite a un atacante secuestrar la conversación de autenticación de un usuario en un servidor legítimo y usarlo para autenticar al atacante en el equipo del usuario. Las vulnerabilidades de NTLM y las formas de aprovecharlas son el objetivo de aumentar la actividad de investigación en la comunidad de seguridad.

Aunque Kerberos ha estado disponible durante muchos años, muchas aplicaciones todavía están escritas para usar NTLM únicamente. Esto reduce innecesariamente la seguridad de las aplicaciones. Kerberos no puede reemplazar NTLM en todos los escenarios, principalmente aquellos en los que un cliente necesita autenticarse en sistemas que no están unidos a un dominio (quizás una red doméstica sea la más común de estos). El paquete de seguridad Negotiate permite un compromiso compatible con versiones anteriores que usa Kerberos siempre que sea posible y solo vuelve a NTLM cuando no hay ninguna otra opción. Cambiar el código para usar Negotiate en lugar de NTLM aumentará significativamente la seguridad de nuestros clientes al introducir pocas o ninguna compatibilidad de aplicaciones. Negociar por sí mismo no es una bala de plata: hay casos en los que un atacante puede forzar la degradación a NTLM, pero son significativamente más difíciles de aprovechar. Sin embargo, una mejora inmediata es que las aplicaciones escritas para usar Negotiate correctamente son inmunes automáticamente a los ataques de reflexión NTLM.

Mediante una última palabra de precaución contra el uso de NTLM: en Windows es posible deshabilitar el uso de NTLM en el nivel de sistema operativo. Si las aplicaciones tienen una dependencia fuerte en NTLM, simplemente no se podrán autenticar cuando NTLM esté deshabilitado.

¿Qué factores hacen que NTLM sea "codificado de forma rígida" en una aplicación?

Hay dos factores que provocarán una dependencia difícil en NTLM. La primera consiste en seleccionar explícitamente NTLM como paquete de autenticación que usará la aplicación. Para algunos protocolos y API, la elección de NTLM es obvia, como en la llamada a la API AcquireCredentialsHandle (). En el caso de otros protocolos, puede que no sea tan obvio. Por ejemplo, el paquete de autenticación predeterminado de RPC (RPC_C_AUTHN_DEFAULT) es realmente un alias para NTLM cuando se usa RPC a través de la red e incluso la marca explícita para seleccionar NTLM no tiene la abreviatura NTLM en ningún lugar de ella (RPC_C_AUTH_WINNT). Este tipo de construcción facilita la selección de NTLM sin saber necesariamente que lo ha hecho.

En lugar de NTLM, los desarrolladores deben usar otros métodos de autenticación, por ejemplo, el paquete Negotiate (esto también se conoce a veces como el paquete SPNEGO o SNEGO). La selección de paquetes debe coincidir tanto en los componentes de cliente como en el servidor para que Negotiate pueda intentar usar Kerberos, por lo que las partes cliente y servidor de la aplicación deben usar Negotiate. Si cualquiera de los lados usa NTLM (como podría ser el caso con versiones heredadas), Negotiate seguirá funcionando, pero siempre revertirá a NTLM. Cómo indicar a la aplicación que use Negotiate varía según el protocolo. Algunos de los protocolos más comunes (RPC, LDAP, DCOM, HTTP) se tratan en detalle más adelante en el tema 5000: la aplicación ha seleccionado explícitamente paquete NTLM.

El segundo factor que da como resultado que NTLM se use es cuando el cliente no proporciona un nombre de destino de servidor válido al proceso de autenticación. En los protocolos que admiten o requieren autenticación mutua (como Kerberos), el nombre de destino es lo que se usa para lograr la autenticación mutua. Las API de autenticación (como InitializeSecurityContext) toman un parámetro opcional, normalmente denominado algo como "TargetName", "PrincipalName" o "ServerPrincipalName". Este es el identificador que usan los controladores de dominio para seleccionar la cuenta de dominio correcta para obtener credenciales para el servicio de destino. Dado que NTLM no tiene ningún concepto de autenticación del servidor, este parámetro no es necesario para que NTLM se autentique correctamente. Kerberos, por otro lado, requiere que un cliente obtenga un vale de servicio válido para el servicio al que se autentica el cliente. La autenticación Kerberos siempre producirá un error si no se especifica ningún nombre de destino o un nombre de destino no válido. Cuando Se selecciona Negotiate como paquete, proporcionar ningún nombre de destino (o un nombre de destino no válido) hará que Kerberos se omita por completo y se use NTLM. La mayoría de las API de autenticación tienen el nombre de destino como parámetro opcional aceptará si NULL sin error. A menos que el desarrollador invalide esto y proporcione un nombre de destino explícito, NTLM (y, por otra parte, NTLM reflectable) es el resultado.

Funcionamiento del complemento NTLM

El conector comprobador detecta los siguientes errores:

  • El paquete NTLM se especifica directamente en la llamada a AcquireCredentialsHandle (o api contenedora de nivel superior).

  • El nombre de destino de la llamada a InitializeSecurityContext es NULL. En este caso, Negotiate vuelve directamente a NTLM.

  • El nombre de destino de la llamada a InitializeSecurityContext no es un nombre de dominio de estilo SPN, UPN o NetBIOS correcto. En este caso, el controlador de dominio devuelve un error de "entidad de seguridad no encontrada", lo que hace que Negotiate vuelva a NTLM.

El complemento también registra advertencias cuando detecta degradaciones a NTLM; por ejemplo, cuando el controlador de dominio no encuentra un SPN. Solo se registran como advertencias, ya que a menudo son casos legítimos, por ejemplo, al autenticarse en un sistema que no está unido a un dominio.

Configuración de las opciones de detención del complemento

De forma predeterminada, todos los eventos clasificados como Error se establecen para provocar una interrupción de depuración. Todos los eventos de advertencia se establecen para registrar solo los detalles del evento.

Los eventos de error provocan una detención o interrupción:

  • 5000: la aplicación ha seleccionado explícitamente el paquete NTLM

  • 5001: La lista de paquetes de negociación incluye solo NTLM

  • 5002: negociación de la lista de paquetes con exclusión NTLM incorrecta

  • 5003: ningún nombre de destino o nombre de destino con formato incorrecto para el servidor

Eventos de advertencia registrados:

  • 5010: degradación a NTLM detectado

NtLM se detiene

5000: la aplicación ha seleccionado explícitamente el paquete NTLM

Gravedad: error

La aplicación o subsistema selecciona explícitamente NTLM en lugar de Negotiate en la llamada a AcquireCredentialsHandle. Aunque sea posible que el cliente y el servidor se autentiquen mediante Kerberos, esto se impide mediante la selección explícita de NTLM.

Cómo corregir este error

La corrección de este error es seleccionar el paquete Negotiate en lugar de NTLM. La forma en que esto se hace dependerá del subsistema de red concreto que usa el cliente o el servidor. A continuación se proporcionan algunos ejemplos. Debe consultar la documentación sobre la biblioteca o el conjunto de API concretos que está usando.

API(parámetro) usadas por la aplicación Valor incorrecto Valor correcto Notas
AcquireCredentialsHandle (pszPackage) "NTLM" NEGOSSP_NAME o "Negociar"
Cliente RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) Servidor RPC: RPCServerRegisterAuthInfo(AuthnSvc) RPC_C_AUTHN_WINNT o RPC_C_AUTH_DEFAULT RPC_C_AUTH_GSS_NEGOTIATE No es un error para que un servidor RPC registre el paquete NTLM/WINNT. Esto suele ser necesario para admitir clientes más antiguos que solo admiten NTLM. Se trata de un error si solo se registra el paquete NTLM, ya que esto obliga a todos los clientes a usar NTLM incluso si son capaces de usar Kerberos.
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (pasado como miembro dwAuthnSvc de la estructura COAUTHINFO, que es miembro del struct COSERVERINFO pasado a la API) RPC_C_AUTHN_WINNT RPC_C_AUTHN_DEFAULT o RPC_C_AUTHN_GSS_NEGOTIATE Negotiate solo debe usarse si la comunicación siempre se produce a través de una red. Si alguna vez se produce la llamada DCOM entre el cliente y el servidor en la misma máquina, debe usar DEFAULT y permitir que DCOM elija el paquete correcto que se va a usar.
LDAP: ldap_bind_s (método) LDAP_AUTH_NTLM LDAP_AUTH_NEGOTIATE
HTTP WinHTTPSetCredentials (AuthScheme) WINHTTP_AUTH_SCHEME_NTLM WINHTTP_AUTH_SCHEME_NEGOTIATE

5001: La lista de paquetes de negociación incluye solo NTLM

Gravedad: error

Cuando se usa AcquireCredentialsHandle, es posible proporcionar una lista de paquetes que Negotiate usará o omitirá. Dependiendo de la lista especificada, esto puede invalidar la lógica integrada en Negotiate para elegir el paquete de autenticación más adecuado y seguro. Si la lista de paquetes incluye solo NTLM o excluye Kerberos, el resultado es idéntico a omitir Negotiate por completo y seleccionar explícitamente el paquete SSP NTLM directamente.

Especificar una lista de subcompletares solo es posible al llamar directamente a AcquireCredentialsHandle, ya que la mayoría de las API de nivel superior (como RPC) no permiten al autor de la llamada controlar la lista de paquetes Negotiate.

Microsoft no recomienda que las aplicaciones intenten manipular la lista de paquetes Negotiate de esta manera.

Cómo corregir este error

Use el paquete Negotiate sin especificar una lista de subpaquetes o asegúrese de que Se incluye Kerberos.

API(parámetro) usadas por la aplicación Valor incorrecto Valor correcto
AcquireCredentialsHandle (miembro PackageList de SEC_WINNT_AUTH_IDENTITY_EX estructura pasada como parámetro pAuthData) "! Kerberos" o "NTLM" NULL o "Kerberos, NTLM" o "Kerberos, ! NTLM" o "! NTLM"

5002: negociación de la lista de paquetes con exclusión NTLM incorrecta

Gravedad: advertencia

Al llamar a AcquireCredentialsHandle, la aplicación ha intentado excluir NTLM de la lista de paquetes admitidos por Negotiate. Sin embargo, se ha usado la sintaxis incorrecta para excluir NTLM, por lo que permanece en la lista.

Cómo corregir este error Use la siguiente sintaxis para excluir el paquete NTLM de Negotiate:

API(parámetro) usadas por la aplicación Valor incorrecto Valor correcto
AcquireCredentialsHandle (miembro PackageList de SEC_WINNT_AUTH_IDENTITY_EX estructura pasada como parámetro pAuthData) "-NTLM" "! NTLM"

5003: ningún nombre de destino o nombre de destino con formato incorrecto para el servidor

Gravedad: error

Al usar el paquete Negotiate, proporcionar un nombre de destino nulo o no válido (a veces denominado nombre principal) hará que Kerberos produzca un error y NTLM se use en su lugar. Siempre debe especificar un nombre de destino válido al realizar una llamada de autenticación. El nombre de destino es un identificador único que permite a un controlador de dominio obtener los detalles de la cuenta del servidor al que la aplicación intenta autenticarse. Una vez que el controlador de dominio tiene esta información, puede compilar vales Kerberos adecuados que se comprenderán (descifrables) tanto el cliente como el servidor.

Cómo corregir este error

Los nombres de destino se pueden especificar en tres formatos diferentes, cada uno de los cuales los controladores de dominio pueden usar para localizar el objeto de cuenta de servidor correcto. Estos formatos son nombre principal de servicio (SPN), nombre principal de usuario (UPN) y nombre de dominio\cuenta de netBIOS de dos partes. El SPN es la forma más común y la más interoperable con otras implementaciones de Kerberos. Una explicación completa de los SPN está fuera del ámbito de este documento, pero el formulario de SPN más sencillo y común tiene dos partes: una clase de servicio y un nombre de host. La clase de servicio identifica el tipo de aplicación de servidor (por ejemplo, tipo de aplicación específico como http o ldap o como genérico como host). La segunda parte es el nombre de dominio completo o el nombre plano (NetBIOS) del servidor. Los clientes y servidores de Windows registran automáticamente los SPN para el "host" para el FQDN y los nombres planos. Los controladores de dominio también asignarán alrededor de 40 clases de servicio específicas de la aplicación en el SPN "host" para cosas como "http", "ldap", "rpc", "tapi", etc.

o especifique un nombre de destino para una aplicación que se ejecuta en el contexto del sistema operativo del servidor (por ejemplo, sistema local, servicio de red o servicio local) las aplicaciones cliente pueden usar el SPN "host" registrado automáticamente o uno de sus alias. Para autenticarse en una aplicación que se ejecuta en el contexto de una cuenta de usuario de dominio, debe registrar un SPN para esa cuenta.

En el caso de las cuentas de usuario, también puede usar el formulario UPN implícito que se creó a partir del nombre de la cuenta de usuario y el dominio en el que reside la cuenta: useraccountname@domain.dom. Aunque puede crear UPN adicionales para la cuenta de usuario (con los sufijos UPN que se pueden crear para cada dominio), estos no funcionarán como nombres de destino kerberos, solo el UPN correspondiente al nombre de cuenta de inicio de sesión real y al dominio real donde se puede usar la cuenta.

Por último, todavía puede usar el dominio\nombredeusuario de estilo NT4 (o dominio\nombreDeEquipo en el caso de los servicios que se ejecutan como sistema local, servicio de red o local). Esto funciona para destinos que se ejecutan en el contexto de cuentas de usuario de dominio o cuentas de equipo.

API(parámetro) usadas por la aplicación Parámetro para establecer el nombre de destino Notas
InitializeSecurityContext pszTargetName
Cliente RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) ServerPrincipalName Debe ser el nombre de destino de la cuenta en la que se ejecuta el servidor o el servicio. No tiene que ser el mismo que el valor establecido en RPCServerRegisterAuthInfo.
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (pasado como miembro dwAuthnSvc de la estructura COAUTHINFO, que es miembro del struct COSERVERINFO pasado a la API) pServerPrincName Puede usar COLE_DEFAULT_PRINCIPAL para permitir que COM seleccione automáticamente el nombre de la información de enlace.
LDAP: ninguno Generado automáticamente por el cliente LDAP.
HTTP none WinHTTP y WinInet proporcionan el nombre de destino del nombre del servidor de direcciones URL.

5010: degradación a NTLM detectado

Gravedad: advertencia

Aunque la aplicación específica Negotiate y usó un nombre de destino con formato correcto, algo ocurrió para hacer que Negotiate cambie a NTLM. Dependiendo de cuáles eran las circunstancias, esto puede indicar un error o un comportamiento esperado. Por ejemplo, cuando un equipo no forma parte de un dominio o se usa en una ubicación donde no se puede acceder a un controlador de dominio, se espera que Negotiate cambie de forma silenciosa para permitir que la aplicación se autentique mediante NTLM. Sin embargo, si esta detención se produce cuando un controlador de dominio está disponible y normalmente esperaría que Kerberos se usara casi sin duda indica que algo está mal.

Cómo corregir este error

Suponiendo que ha determinado que Se debe haber utilizado Kerberos y no NTLM en esta circunstancia, hay una serie de posibilidades por las que tuvo lugar la degradación:

• El nombre de destino, aunque puede haber estado en el formato correcto, no existía en el dominio (o bosque).

o Debe comprobar que va a crear el nombre de destino correcto en la aplicación cliente. ¿La clase de servicio es correcta? ¿El nombre de host es correcto?

o Es el proceso de servidor que se ejecuta en el contexto del equipo u otra cuenta de dominio. En el primer caso, los SPN se registran automáticamente, en este último caso es posible que tenga que registrar el SPN o usar un formulario alternativo, como un UPN implícito o un nombre plano.

o ¿Podría haber problemas de conectividad de red que impidan la comunicación con un controlador de dominio o un servidor DNS?

o ¿Está registrado el SPN de destino en más de una cuenta? Esto hará que el controlador de dominio rechace los intentos de autenticación.

Impresión

El Comprobador de impresión ayuda a encontrar y solucionar problemas que pueden producirse cuando una aplicación llama al subsistema de impresión. El comprobador de impresión tiene como destino las dos capas del subsistema de impresión, la capa PrintAPI y la capa PrintDriver.

Capa de API de impresión

El comprobador de impresión prueba la interfaz entre un programa y Winspool.drv y prntvpt.dll y prueba las interfaces de esos archivos DLL. Puede revisar las reglas para llamar a funciones en esta interfaz en la sección de ayuda de MSDN para las API exportadas por winspool.drv y prntvpt.dll.

Capa de controlador de impresión

El comprobador de impresión también prueba la interfaz entre un controlador de impresión principal, como UNIDRV.DLL, UNIDRUI.DLL, PSCRIPT5.DLL, PS5UI.DLL o MXDWDRV.DLL y los complementos del controlador de impresión. Puede encontrar información sobre esta interfaz en MSDN y WDK.

Normalmente, solo las versiones de depuración ejecutan el comprobador de aplicaciones, por lo que el rendimiento no suele ser un problema. Si surgen problemas de rendimiento debidos al uso de esto, o cualquier otra comprobación del comprobador de aplicaciones, ejecute una comprobación cada vez hasta que haya realizado todas las comprobaciones necesarias.

Servicios web

Capa de comprobación de la API de servicios web de Windows (WWSAPI)

El complemento WWSAPI permite a los desarrolladores detectar instancias de:

  • Se llama a UNA WWSAPI que hace referencia a un objeto WWSAPI intrínseco no válido.

  • Se llama a UNA WWSAPI que hace referencia a un único objeto subproceso que ya está en uso.

  • Objeto intrínseco liberado con una llamada asincrónica pendiente.

  • Llamar a las API de bloqueo desde subprocesos cortos.

Además, este complemento:

  • Realiza un seguimiento del uso de objetos desde la creación de instancias hasta la eliminación.

  • Forzar llamadas que se pueden completar de forma asincrónica para que se completen de forma sincrónica. Esto es para evitar que las aplicaciones en función de un comportamiento determinado de una llamada realicen una WS_ASYNC_CONTEXT.

  • Proporciona una descripción legible cuando una API pasa un objeto incorrecto o un objeto está en uso mediante la extensión !avrf –ws –obj debugger (que se muestra a continuación)

  • En el caso del canal, el proxy de servicio y el host de servicio, cada llamada con seguimiento mostrará el estado actual del objeto.

De forma predeterminada, se habilitan los siguientes comprobadores:

Property NameDescriptionValidateObjectValidates que el objeto intrínseco es válidoTrackObjectTrackTracks el uso de un objeto a través de su duración

Otros comprobadores que se pueden habilitar en este proveedor a través de la interfaz de usuario de propiedades son:

Nombre de propiedadDescriptionCheckTimeoutValidates que se completan las funciones asincrónicas dentro del tiempo de espera, especificado como TimeoutValForceSyncForce, la ruta de acceso de sincronización que se debe tomar cuando se proporciona un contexto WS_ASYNC_CONTEXT a una API.

Se proporciona una extensión del depurador (!avrf –ws –obj) que muestra objetos WWSAPI intrínsecos abiertos y cerrados. Si un objeto sufijo esta extensión, mostrará información detallada sobre el uso de este objeto.

!avrf -ws –obj

Este comando muestra los objetos WWSAPI intrínsecos a los que se realiza el seguimiento, tanto creados como cerrados. Tenga en cuenta que los objetos cerrados se almacenan en una cola circular, por lo que hay un límite máximo para el número total de objetos de los que se realiza el seguimiento.

Los objetos se agregan cuando se completan correctamente las siguientes API: WsCreateChannel(), WsCreateChannelForListener(), WsCreateServiceHost(), WsCreateServiceProxy(), WsCreateServiceProxyFromTemplate(), WsCreateError(), WsCreateHeap(), WsCreateListener(), WsCreateMetadata(), WsCreateMessage(), WsCreateMessageForChannel(), WsCreateReader(), WsCreateWriter(), WsCreateXmlBuffer(), WsReadXmlBuffer(), WsReadXmlBufferFromBytes()

Los objetos se mueven de la lista creada a la lista libre cuando se llama a la función WsFree*() correspondiente y se completa.

!avrf –ws –obj [OBJECT]

Este comando muestra el uso de un objeto WWSAPI intrínseco. La información de uso incluye la pila cuando se creó el objeto, se usó y liberó. Si el objeto es un canal, host de servicio o proxy de servicio, mostrará el estado del objeto antes de que se llame a la API mediante el objeto .

Este es un ejemplo de las opciones de uso de !avrf –ws –obj:

0:001> !avrf -ws -obj
Objects dependent on internal objects allocated:


Objects currently allocated:

 0x00000000048566C0 (Type=Heap, Thread=0x000001bc, Pending Operations=0)
 0x0000000001BE6780 (Type=Error, Thread=0x000001bc, Pending Operations=0)
 0x0000000001C13580 (Type=Service Proxy, Thread=0x000001bc, Pending Operations=0)

Freed objects:

 0x0000000001C17170 (Type=Service Proxy, Thread=0x000001bc)
 0x0000000004856730 (Type=Heap, Thread=0x000001bc)
 0x0000000001BE6820 (Type=Error, Thread=0x000001bc)

0:001> !avrf -ws -obj 0x0000000001C13580

Object @ 0x0000000001C13580
        Type = Service Proxy
        Thread = 0x000001bc
        Internal Reference = 0x00000000026C5E80

Created stack:
  vfnws!VfHookWsCreateServiceProxy+0x00aa
  BLUESTONE!WST_WebServices::WsCreateServiceProxy+0x00d8
  BLUESTONE!ServiceProxy::Connect+0x0116
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d

Last 4 operations

Operation #1 created in thread 0x00000000000001BC

Service proxy state before operation = Created

Callstack:
  vfnws!VfHookWsGetServiceProxyProperty+0x0053
  BLUESTONE!WST_WebServices::WsGetServiceProxyProperty+0x009b
  BLUESTONE!ServiceProxy::GetState+0x004b
  BLUESTONE!ServiceProxy::VerifyState+0x001c
  BLUESTONE!ServiceProxy::Connect+0x01c7
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d

Operation #2 created in thread 0x00000000000001BC

Service proxy state before operation = Created

Callstack:
  vfnws!VfHookWsOpenServiceProxy+0x0079
  BLUESTONE!WST_WebServices::WsOpenServiceProxy+0x0092
  BLUESTONE!ServiceProxy::Connect+0x03d3
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d

Operation #3 created in thread 0x00000000000001BC

Service proxy state before operation = Open

Callstack:
  vfnws!VfHookWsGetServiceProxyProperty+0x0053
  BLUESTONE!WST_WebServices::WsGetServiceProxyProperty+0x009b
  BLUESTONE!ServiceProxy::GetState+0x004b
  BLUESTONE!ServiceProxy::VerifyState+0x001c
  BLUESTONE!ServiceProxy::Connect+0x0484
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d

Operation #4 created in thread 0x00000000000001BC

Service proxy state before operation = Open

Callstack:
  vfnws!VfHookWsCall+0x00a6
  BLUESTONE!DefaultBinding_ICalculator_Add+0x008b
  BLUESTONE!ServiceModelTestGroup_Simple_Function+0x010a
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x069a
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d

Asynchronous Callback = BLUESTONE!ServiceModelTestGroup_Simple_Callback
Asynchronous CallbackState = 0x0000000005EBDC30

Completed asynchronously with HRESULT=0x00000000 in thread 0x00000000000001BC

Asynchronous callback stack:
  vfnws!VfHookWsCall+0x00e3
  BLUESTONE!DefaultBinding_ICalculator_Add+0x008b
  BLUESTONE!ServiceModelTestGroup_Simple_Function+0x010a
  BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x069a
  BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
  BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
  BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
  BLUESTONE!fnsMsgProc+0x02d6
  BLUESTONE!fnsRunTestsWorkerThread+0x085f
  KERNEL32!BaseThreadInitThunk+0x000d
  ntdll!RtlUserThreadStart+0x001d


Closed stack:

0:001>

Servicios

Las pruebas de servicios comprueban el uso adecuado de los servicios de Windows. Por ejemplo, que los servicios se inician y se detienen correctamente. Para obtener información sobre las excepciones de código de detención generadas por estas pruebas, consulte Application Verifier - Stop Codes - Services.

Perf

Las pruebas de rendimiento comprueban el uso eficaz de las API que afectan al rendimiento del sistema y al consumo de energía, como llamar a una función de Windows que usa un período de espera incorrecto. Para obtener información sobre las excepciones de código de detención generadas por estas pruebas, consulte Application Verifier - Stop Codes - Perf.

Cuelga

Bloquea las pruebas para el uso de las API que hacen que el sistema deje de responder, por ejemplo, cuando el subproceso DllMain está esperando otro subproceso bloqueado. Para obtener información sobre las excepciones de código de detención generadas por estas pruebas, consulte Application Verifier - Stop Codes - Hangs (Comprobador de aplicaciones: códigos de detención: bloqueos).

compatibilidad con ARM64EC

Los siguientes proveedores no admiten ARM64EC y, por lo tanto, bloquearán un programa que se ejecute en ARM64EC:

Consulte también

Comprobador de aplicaciones: información general

Comprobador de aplicaciones: características

Comprobador de aplicaciones: pruebas de aplicaciones

Comprobador de aplicaciones: códigos de detención y definiciones

Comprobador de aplicaciones: depuración de las paradas del comprobador de aplicaciones

Comprobador de aplicaciones: preguntas más frecuentes