Share via


Vérificateur d’application - Tests dans Application Verifier

Concepts de base

Au minimum, vous devez exécuter Application Verifier avec le paramètre De base sélectionné. Chacun d’eux teste une zone qui provoquera des incidents ou d’autres scénarios négatifs, qui ont un impact direct et signififant sur l’expérience client.

  • Exceptions : garantit que les applications ne masquent pas les violations d’accès à l’aide de la gestion structurée des exceptions
  • Handles - Tests pour vérifier que l’application ne tente pas d’utiliser des handles non valides
  • Tas - Vérification des problèmes d’altération de la mémoire dans le tas
  • Fuite : détecte les fuites en suivant les ressources effectuées par une dll qui ne sont pas libérées par le moment où la dll a été déchargée
  • Verrous - Vérifie l’utilisation correcte pour les sections critiques
  • Mémoire : garantit que les API pour les manipulations d’espace virtuel sont utilisées correctement (par exemple, VirtualAlloc, MapViewOfFile)
  • SRWLock : vérifie l’utilisation correcte pour les verrous de lecteur/enregistreur (SRW).
  • Threadpool : garantit l’utilisation correcte des API de threadpool et applique des case activée de cohérence sur les états worker-thread après un rappel tel que sale threads threadpool et d’autres problèmes liés au threadpool.
  • TLS : garantit que les API de Stockage locales de thread sont utilisées correctement

Pour plus d’informations sur les exceptions de code d’arrêt générées par ces tests, consultez Application Verifier - Stop Codes and Definitions. Pour plus d’informations sur le débogage de ces échecs, consultez Application Verifier - Débogage des arrêts du vérificateur d’application

Compatibilité

Les tests de la couche de vérification de compatibilité permettent d’identifier une application susceptible de rencontrer des problèmes avec le système d’exploitation Microsoft Windows. La plupart de ces case activée peuvent également être utilisées pour tester les exigences de logo/certification.

Pour plus d’informations sur les exceptions de code d’arrêt générées par ces tests, consultez Application Verifier - Stop Codes and Definitions.

HighVersionLie : identifie les problèmes liés à certains des problèmes de compatibilité des applications les plus courants dans Windows. La détection incorrecte de la version du système d’exploitation ou l’utilisation d’informations sur la version codée en dur peut entraîner l’échec de l’application sur les systèmes d’exploitation ultérieurs.

Cuzz

La couche de vérification de la concurrence (Cuzz) détecte les bogues d’accès concurrentiel et les conditions de concurrence des données. Cuzz ajuste la planification des threads en injectant des retards aléatoires aux points clés dans le code d’une application. Le scénario suivant illustre le type de bogue d’accès concurrentiel qui peut être détecté par la couche de vérification Cuzz.

Une application a un thread parent et un thread enfant. Le thread parent démarre le thread enfant, puis alloue de la mémoire pour une structure.

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

Le thread enfant déréférence le pointeur.

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

Le code précédent contient un bogue d’accès concurrentiel. Si le thread enfant tente de déréférencer le pointeur avant que le thread parent alloue la mémoire, le pointeur n’est pas valide. Le bogue est très peu probable pour se manifester, car dans la plupart des cas, le thread parent alloue la mémoire avant le démarrage du thread enfant. Toutefois, dans de rares cas, le thread enfant peut commencer et tenter de déréférencer le pointeur avant que le thread parent n’ait alloué la mémoire.

La couche de vérification Cuzz augmente la probabilité de trouver des bogues d’accès concurrentiel comme celui illustré dans l’exemple précédent. Cuzz n’effectue aucune case activée supplémentaire en dehors de l’insertion de retards. Par conséquent, aucune vérification n’est directement associée à Cuzz. Toutefois, si l’activation de Cuzz entraîne un bogue d’accès concurrentiel se manifeste lui-même, d’autres couches de vérification bénéficieront. Par exemple, si une condition de race entraîne un dépassement de mémoire, la couche de vérification des tas ne trouve pas l’erreur, sauf si la condition de course se manifeste elle-même au moment de l’exécution. En augmentant la probabilité de la condition de race, Cuzz améliore l’efficacité de la couche Tass pour identifier l’erreur.

Pour bénéficier au maximum de Cuzz, activez Cuzz sur autant de tests que possible et répétez le même test plusieurs fois. Cuzz peut être activé sur tous les tests, y compris les tests manuels, les tests fonctionnels et les tests de contrainte. Activez également autant de couches de vérification d’application que possible.

Vous pouvez augmenter la probabilité de reproduire un bogue en fournissant à Cuzz la même valeur de départ aléatoire (voir Propriétés).

Cuzz insère des retards uniquement sur les appels d’API de synchronisation Win32.

Cuzz, propriétés

Les propriétés suivantes sont disponibles pour la couche de vérification Cuzz. Pour définir les propriétés, sélectionnez la couche Cuzz dans l’interface utilisateur du vérificateur d’application, puis ouvrez la fenêtre de propriété.

Propriété Description
FuzzingLevel Contrôle le niveau de flou pour Cuzz. Définissez cette valeur sur 1 pour les applications critiques et 4 pour les applications régulières.
RandomSeed Valeur initiale aléatoire utilisée par Cuzz au début. Si vous définissez cette valeur sur 0, Cuzz génère une valeur initiale aléatoire basée sur le temps.

Simulation de ressources faible

La simulation de ressources faible tente de simuler un environnement sous de faibles ressources, telles que la mémoire insuffisante. Cette simulation identifie les bogues qui se produisent dans des conditions de mémoire faible. Il s’agit également de l’injection de pannes. Vous pouvez simuler un environnement sous de faibles ressources, par lequel vous pouvez définir un nombre (0 à 100) qui indique les appels de probabilité d’erreur de :

  • Wait (par exemple, l’API WaitForXXXX).
  • Heap_Alloc (API d’allocation de tas).
  • Virtual_Alloc (API d’allocation de mémoire virtuelle).
  • Registre (API de Registre).
  • Fichier (API de fichier telle que CreateFile).
  • Événement (API d’événement, telle que CreateEvent).
  • MapView ( API MapView telle que CreateMapView).
  • Ole_Alloc (API Ole comme SysAllocString).

La simulation de ressources faible (également appelée injection d’erreurs) tente de simuler un environnement sous de faibles ressources, par exemple en dehors de la mémoire. Cela permet d’identifier le bogue dans des conditions de mémoire insuffisantes.

Propriétés de simulation de ressources faibles

Pour modifier les propriétés, case activée la zone Case activée de simulation de ressource faible dans la zone Tests, cliquez avec le bouton droit et sélectionnez les propriétés :

Propriété Description
Inclure Les erreurs de limite se produisent uniquement dans les dll spécifiées. Un nom dll sans chemin d’accès par ligne. Si '*' est spécifié, les erreurs se produisent pour tous les modules.
Exclure Excluez les erreurs pour les modules spécifiés. Un nom dll sans chemin d’accès par ligne.
Délai d'expiration Donnez un intervalle de temps (en millisecondes) lorsqu’il n’y a aucune erreur lors de l’initialisation du processus.
Wait Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API WaitForXXXX.
Heap_Alloc Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API d’allocation de tas.
Virtual_Alloc Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API d’allocation de mémoire virtuelle.
Registre Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API de Registre.
File Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API Fichier, telle que CreateFile.
Événement Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API d’événement, telle que CreateEvent
MKMapView Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API MapView, telle que CreateMapView.
Ole_Alloc Nombre [0 – 10000000] qui indique la probabilité d’erreur pour l’API Ole, telle que SysAllocString.
Piles Chaque thread d’application Windows commence par une réserve de pile et une taille de validation de pile. En cas d’utilisation normale, la validation de la pile augmente chaque fois qu’il y a besoin d’espace supplémentaire sur la pile. Pour plus d’informations, consultez Création de threads et de taille de pile de threads. Si le système rencontre des conditions de mémoire faible, la croissance de la validation de la pile peut échouer. Le thread qui ne parvient pas à développer sa pile et l’ensemble de l’application se bloque probablement. Ce type d’incident est inacceptable pour les processus système importants (par exemple, pour les services). Les case activée Stacks désactivent toute croissance de pile pour l’application en cours de vérification afin qu’elle simule les échecs de croissance de la pile sans avoir besoin de simuler l’ensemble des conditions de mémoire faible du système. Les exceptions sont levées lorsque l’application tente de développer la pile. Aucun arrêt du vérificateur n’est généré par cela.

LuaPriv

Les tests LuaPriv (User Account Privilege Predictor) limités sont à la fois prédictifs et diagnostiques et fonctionnent pour exposer des problèmes liés à l’exécution d’une application avec des privilèges d’administration, et si cette application fonctionne également si elle s’exécute avec moins de privilèges (généralement, en tant qu’utilisateur normal).

Également appelé UAC case activée s, le prédicteur de privilèges de compte d’utilisateur limité (LuaPriv) a deux objectifs principaux :

  • Prédictif : lors de l’exécution d’une application avec un privilège administratif, prédit si cette application fonctionnerait aussi bien si elle s’exécutait avec moins de privilège (généralement, en tant qu’utilisateur normal). Par exemple, si l’application écrit dans des fichiers qui autorisent uniquement l’accès Administrateurs, cette application ne pourra pas écrire dans le même fichier si elle est exécutée en tant qu’utilisateur non administrateur.

  • Diagnostic : lors de l’exécution avec un privilège non administrateur, identifie les problèmes potentiels qui peuvent déjà exister avec l’exécution actuelle. En continuant l’exemple précédent, si l’application tente d’écrire dans un fichier qui accorde uniquement l’accès aux membres du groupe Administrateur, l’application obtient une erreur ACCESS_DENIED. Si l’application ne fonctionne pas correctement, cette opération peut être la coupable.

LuaPriv identifie les types de problèmes suivants :

Problème potentiel Description
Espaces de noms restreints La création d’un objet de synchronisation nommé (Événement, Sémaphore, Mutex, etc.) sans espace de noms peut compliquer l’exécution sans privilège sur certains systèmes d’exploitation, car le système d’exploitation peut choisir de placer l’objet dans un espace de noms restreint. La création d’un tel objet dans un espace de noms restreint (tel que l’espace de noms global) nécessite SeCreateGlobalPrivilege, qui est accordé uniquement aux administrateurs.
LuaPriv signale ces deux problèmes s’il les détecte.
Vérifications administrateur en dur Certaines applications interrogent le jeton de sécurité des utilisateurs pour savoir combien de privilèges ils ont. Dans ces cas, l’application peut modifier son comportement en fonction de la puissance estimée de l’utilisateur.
LuaPriv signale les appels d’API qui retournent ces informations.
Demande de privilèges Une application peut tenter d’activer un privilège pertinent en matière de sécurité (par exemple, SeTcbPrivilege ou SeSecurityPrivilege) avant d’effectuer une opération qui l’exige.
LuaPriv signale les tentatives d’activation de privilèges pertinents pour la sécurité.
Privilèges manquants Si une application tente d’activer un privilège que l’utilisateur n’a pas, il signale probablement que l’application attend le privilège, ce qui peut entraîner des différences de comportement.
LuaPriv signale les échecs de demande de privilèges.
Opérations de fichier INI Les tentatives d’écriture dans des fichiers INI mappés (WritePrivateProfileSection et API similaires) peuvent échouer en tant qu’utilisateur non administrateur.
LuaPriv signale ces opérations.
accès refusé Si l’application tente d’accéder à un objet (fichier, clé de Registre, etc.), mais que la tentative échoue en raison d’un accès insuffisant, l’application s’attend probablement à s’exécuter avec plus de privilèges qu’elle ne dispose.
LuaPriv signale les tentatives d’ouverture d’objet qui échouent avec ACCESS_DENIED et des erreurs similaires.
ACE Refuser Si un objet a des ACE Refuser dans sa DACL, il refuse explicitement l’accès à des entités spécifiques.
Cela est rare et rend la prédiction difficile, de sorte que LuaPriv signale les ACE Refuser quand il les trouve.
Accès restreint Si une application tente d’ouvrir un objet pour les droits qui ne sont pas accordés aux utilisateurs normaux (par exemple, en essayant d’écrire dans un fichier qui est uniquement accessible en écriture par les administrateurs), l’application ne fonctionnera probablement pas de la même façon lorsqu’elle est exécutée en tant qu’utilisateur normal.
LuaPriv signale ces opérations.
MAXIMUM_ALLOWED Si une application ouvre un objet pour MAXIMUM_ALLOWED, la vérification d’accès réelle sur l’objet se produit ailleurs. La plupart du code qui effectue cette opération ne fonctionne pas correctement, et fonctionnera presque certainement différemment lors de l’exécution sans privilège.
LuaPriv signale donc tous les incidents de MAXIMUM_ALLOWED.

Divers

Les problèmes couramment négligés sont capturés dans les tests Divers.

  • API dangereuses : effectue le suivi pour voir si l’application utilise les actions non sécurisées suivantes :
    • Appel dangereux à TerminateThread.
    • Dépassement de capacité de pile potentiel dans des conditions de mémoire insuffisantes.
    • Processus de sortie appelé pendant l’exécution de plusieurs threads.
    • LoadLibrary est appelé pendant DllMain.
    • FreeLibrary est appelé pendant DllMain.
  • Les piles sales remplissent (périodiquement) la partie inutilisée de la pile avec un modèle de mémoire. Cela peut aider à détecter les variables non initialisées dans les appels de fonction futurs dans le contexte de ce thread.
  • TimeRollOver force les API GetTickCount et TimeGetTime à basculer plus rapidement que normalement. Cela permet aux applications de tester plus facilement leur gestion du basculement du temps.

Propriétés diverses

Les API dangereuses case activée possèdent une propriété qui peut être modifiée :

DllMainCheck : vérifiez l’appel LoadLibrary/FreeLibrary lorsque DllMain est actif.

Mise en réseau

Les tests réseau recherchent une utilisation incorrecte des API WinSock. Par exemple, si une API réseau appelée avant un WSAStartup() réussi ou après un appel WSACleanup() réussi a été effectué. Pour plus d’informations sur WinSock, consultez l’en-tête winsock.h et Windows Sockets 2.

Propriétés

Les propriétés suivantes sont disponibles pour la couche de vérification net. Pour définir les propriétés, sélectionnez le fournisseur réseau dans l’interface utilisateur du vérificateur d’application, puis ouvrez la fenêtre de propriété.

Propriété Description
FragmentsEnabled Active le fragmentage des flux de données reçus par les sockets TCP IPv4 et IPv6.
FragmentSize Spécifie le nombre maximal d’octets retournés dans une mémoire tampon pour n’importe quel appel d’API Winsock.

La propriété FragmentsEnabled permet aux fonctionnalités du fournisseur du vérificateur de mise en réseau de faciliter le test et la vérification d’une application analysant les flux TCP hors d’un réseau. Une fois activé, tous les appels à Winsock pour recevoir des données ne recevront que jusqu’à FragmentSize des octets, sauf si l’application requiert spécifiquement l’intégralité de la mémoire tampon remplie avant de retourner (contrôlée par l’indicateur MSG_WAITALL). Étant donné que ni le protocole TCP ni Winsock ne fournissent de garanties sur le nombre d’octets éventuellement retournés dans une mémoire tampon, l’activation de cette case activée facilite la vérification que le code analyse le flux de données hors du réseau le fait correctement, indépendamment du nombre d’octets reçus par appel à Winsock. Les problèmes dans les analyseurs de flux ont été une source de bogues à profil élevé, et ces propriétés sont fournies pour faciliter la vérification de l’exactitude, car cela est particulièrement difficile à tester. Remarque : Cela ne modifie pas les données retournées : elle le ralentit uniquement à un débit spécifique : l’application doit se comporter exactement de la même manière que celle activée ou désactivée.

La ligne de commande suivante permet la fragmentation de tous les flux TCP entrants vers tous les sockets TCP IPv4 et IPv6 créés dans myApp.exe et tous les fichiers binaires chargés par myApp.exe.

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

!avrf Debugger Extension

!avrf -net -socket count - affiche le nombre de handles de socket ouvert et fermé

!avrf -net -socket dump [-v] [HANDLE] - affiche le ou les handles de socket, de manière détaillée ou non.

!avrf -net -wsastacks - affiche le nombre actuel d’init WSA et la liste chronologique des traces de pile pour WSAStartup/WSACleanup.

!avrf -net -wsastacks count - affiche le nombre actuel d’init WSA.

!avrf -net -socket count - Cette commande donne le nombre global de handles de socket qui sont suivis, à la fois ouverts et fermés. Notez qu’ils sont suivis dans une file d’attente circulaire, il existe donc un plafond pour le total suivi. Les sockets sont ajoutés à la liste ouverte quand l’une des API Winsock qui alloue un handle de socket est appelée. Par exemple, socket(), WSASocket(), accept(). Les sockets sont déplacés de la liste ouverte à la liste fermée lorsque la fonction closesocket() est appelée sur ce handle de socket.

!avrf -net -socket dump [-v] [HANDLE] - Cette commande énumère les handles de socket. « Vidage de socket » répertorie tous les handles de socket ouverts et fermés suivis par leurs valeurs SOCKET. L’indicateur facultatif -v imprime également la pile des appels ouverts ou fermés immédiatement après l’impression de chaque valeur SOCKET. Le champ HANDLE facultatif répertorie uniquement le handle SOCKET spécifié et sa pile d’appels ouverte ou fermée.

Voici un exemple des différentes options d’utilisation de socket :

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 exige que les développeurs d’applications appellent WSAStartup() au moins une fois avant d’effectuer des appels Winsock. Ceci est suivi par winsock process-wide. Le nombre de références initial indique à une bibliothèque Winsock (ws2_32.dll) d’initialiser et de charger le catalogue et les fournisseurs Winsock. D’autres appels à WSAStartup incrémentent ce nombre de références. Winsock exige également que les développeurs d’applications appellent WSACleanup() lorsqu’ils ont « terminé » l’appel à Winsock. Les appels à WSACleanup doivent être correctement couplés avec un appel antérieur à WSAStartup(). L’appel à WSACleanup() décrémente le nombre de références à l’échelle du processus. Lorsque le nombre de références tombe à zéro, Winsock libère ses ressources et décharge le catalogue et les fournisseurs Winsock.

Cette commande donne la valeur globale du nombre de références de la routine d’initialisation « WSAStartup » actuelle et répertorie les piles d’appels aux appels à WSAStartup et WSACleanup effectués dans le processus. Notez qu’il est conservé dans une file d’attente circulaire fixe. Il n’est donc pas garanti qu’il soit terminé . Seuls les appels les plus récents sont effectués.

Voici un exemple des différentes options d’utilisation 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

Ce plug-in Application Verifier surveille les appels d’un processus individuel aux API d’authentification AcquireCredentialsHandle et InitializeSecurityContext afin de détecter les utilisations du protocole NTLM. La NTLM est un protocole d’authentification obsolète avec des défauts susceptibles de compromettre la sécurité des applications et du système d’exploitation et ne doit pas être utilisé.

Risque d’authentification NTLM

Le protocole d’authentification NTLM obsolète est le manque d’authentification du serveur, ce qui pourrait permettre à un attaquant de se connecter à un serveur usurpé. En tant que corollaire de l’authentification serveur manquante, les applications utilisant NTLM peuvent également être vulnérables à un type d’attaque appelé attaque « réflexion ». Cette dernière permet à un attaquant de détourner la conversation d’authentification d’un utilisateur sur un serveur légitime et de l’utiliser pour authentifier l’attaquant sur l’ordinateur de l’utilisateur. Les vulnérabilités et les méthodes d’exploitation de NTLM sont la cible d’une activité de recherche croissante dans la communauté de sécurité.

Bien que Kerberos ait été disponible depuis de nombreuses années, de nombreuses applications sont toujours écrites pour utiliser NTLM uniquement. Cela réduit inutilement la sécurité des applications. Kerberos ne peut toutefois pas remplacer NTLM dans tous les scénarios : principalement ceux où un client doit s’authentifier auprès de systèmes qui ne sont pas joints à un domaine (un réseau domestique étant peut-être le plus courant de ces derniers). Le package de sécurité Negotiate permet une compromission rétrocompatible qui utilise Kerberos dans la mesure du possible et ne revient à NTLM qu’en l’absence d’autre option. Le changement de code pour utiliser Negotiate au lieu de NTLM augmente considérablement la sécurité de nos clients tout en introduisant peu ou pas de compatibilité d’application. Négocier par lui-même n’est pas une balle d’argent : il existe des cas où un attaquant peut forcer la rétrogradation vers NTLM, mais ceux-ci sont beaucoup plus difficiles à exploiter. Toutefois, une amélioration immédiate est que les applications écrites pour utiliser Negotiate sont automatiquement immunitaires aux attaques de réflexion NTLM.

Par le biais d’un dernier mot de prudence contre l’utilisation de NTLM : Dans Windows, il est possible de désactiver l’utilisation de NTLM au niveau du système d’exploitation. Si les applications ont une dépendance difficile sur NTLM, elles ne parviennent pas simplement à s’authentifier quand NTLM est désactivé.

Quels facteurs NTLM sont-ils « codés en dur » dans une application ?

Il existe deux facteurs qui entraînent une dépendance difficile à NTLM. La première consiste à sélectionner explicitement NTLM comme package d’authentification à utiliser par l’application. Pour certains protocoles et API, le choix de NTLM est évident, par exemple dans l’appel à l’API AcquireCredentialsHandle (). Pour d’autres protocoles, il peut ne pas être si évident. Par exemple, le package d’authentification par défaut de RPC (RPC_C_AUTHN_DEFAULT) est en fait un alias pour NTLM lorsque RPC est utilisé sur le réseau et même l’indicateur explicite pour sélectionner NTLM n’a pas l’abréviation NTLM n’importe où dans celle-ci (RPC_C_AUTH_WINNT). Ce type de construction facilite la sélection de NTLM sans nécessairement savoir que vous l’avez fait.

À la place de NTLM, les développeurs doivent utiliser d’autres méthodes d’authentification, par exemple le package Negotiate (il s’agit parfois du package SPNEGO ou SNEGO). La sélection de package doit correspondre à la fois sur les composants client et serveur afin que Negotiate puisse tenter d’utiliser Kerberos. Par conséquent, les parties client et serveur de l’application doivent utiliser Negotiate. Si l’un des deux côtés utilise NTLM (comme c’est le cas avec les versions héritées), Negotiate fonctionne toujours, mais revient toujours à NTLM. Comment indiquer à votre application d’utiliser Negotiate varie selon le protocole. Certains des protocoles les plus courants (RPC, LDAP, DCOM, HTTP) sont abordés plus en détail plus loin dans la rubrique 5000 : l’application a sélectionné explicitement le package NTLM.

Le deuxième facteur qui entraîne l’utilisation de NTLM est que le client ne fournit pas de nom cible de serveur valide au processus d’authentification. Dans les protocoles qui prennent en charge ou nécessitent une authentification mutuelle (par exemple Kerberos), le nom cible est ce qui est utilisé pour obtenir l’authentification mutuelle. Les API d’authentification (telles que InitializeSecurityContext) prennent un paramètre facultatif, généralement appelé « TargetName », « PrincipalName » ou « ServerPrincipalName ». Il s’agit de l’identificateur utilisé par les contrôleurs de domaine pour sélectionner le compte de domaine approprié pour obtenir des informations d’identification pour le service cible. Étant donné que NTLM n’a pas de concept d’authentification serveur, ce paramètre n’est pas nécessaire pour que NTLM s’authentifie correctement. Kerberos, d’autre part, exige qu’un client obtienne un ticket de service valide pour le service auquel le client s’authentifie. L’authentification Kerberos échoue toujours si aucun nom cible ou nom cible non valide n’est spécifié. Lorsque Negotiate est sélectionné comme package, l’attribution d’aucun nom cible (ou d’un nom cible non valide) entraîne l’utilisation de Kerberos et de NTLM. La plupart des API d’authentification ont le nom cible en tant que paramètre facultatif acceptera si NULL sans erreur. Sauf si le développeur remplace cela et fournit un nom cible explicite, NTLM (et bien plus, NTLM répercutable) est le résultat.

Fonctionnement du plug-in NTLM

Le plug-in de vérificateur détecte les erreurs suivantes :

  • Le package NTLM est directement spécifié dans l’appel à AcquireCredentialsHandle (ou l’API wrapper de niveau supérieur).

  • Le nom cible dans l’appel à InitializeSecurityContext est NULL. Dans ce cas, Negotiate revient directement à NTLM.

  • Le nom cible dans l’appel à InitializeSecurityContext n’est pas un nom de domaine de type SPN, UPN ou NetBIOS correctement formé. Dans ce cas, le contrôleur de domaine retourne une erreur « principal introuvable », ce qui fait que Negotiate revient à NTLM.

Le plug-in enregistre également les avertissements lorsqu’il détecte les rétrogradations vers NTLM ; par exemple, lorsqu’un SPN est introuvable par le contrôleur de domaine. Ces avertissements sont enregistrés uniquement en tant qu’avertissements, car ils sont souvent des cas légitimes, par exemple lors de l’authentification auprès d’un système qui n’est pas joint à un domaine.

Configuration des options d’arrêt de plug-in

Par défaut, tous les événements classés comme Erreur sont définis pour provoquer un arrêt de débogage. Tous les événements d’avertissement sont définis pour journaliser uniquement les détails de l’événement.

Les événements d’erreur provoquent un arrêt/arrêt :

  • 5000 : l’application a sélectionné explicitement le package NTLM

  • 5001 – Négocier la liste des packages inclut uniquement NTLM

  • 5002 - Négocier une liste de packages incorrecte exclusion NTLM

  • 5003 – Aucun nom cible ou nom cible mal formé pour le serveur

Événements d’avertissement enregistrés :

  • 5010 – Rétrograder vers NTLM Détecté

Arrêts NTLM

5000 : l’application a sélectionné explicitement le package NTLM

Gravité – Erreur

L’application ou le sous-système sélectionne explicitement NTLM au lieu de Negotiate dans l’appel à AcquireCredentialsHandle. Même s’il est possible que le client et le serveur s’authentifient à l’aide de Kerberos, cela est empêché par la sélection explicite de NTLM.

Guide pratique pour corriger cette erreur

Le correctif de cette erreur consiste à sélectionner le package Negotiate à la place de NTLM. La façon dont cela est effectué dépend du sous-système réseau particulier utilisé par le client ou le serveur. Voici quelques exemples. Vous devez consulter la documentation sur la bibliothèque ou l’ensemble d’API particulier que vous utilisez.

API(paramètre) utilisées par l’application Valeur incorrecte Valeur correcte Notes
AcquireCredentialsHandle (pszPackage) « NTLM » NEGOSSP_NAME ou « Négocier »
Client RPC : RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) SERVEUR RPC : RPCServerRegisterAuthInfo(AuthnSvc) RPC_C_AUTHN_WINNT ou RPC_C_AUTH_DEFAULT RPC_C_AUTH_GSS_NEGOTIATE Il n’est pas une erreur pour un serveur RPC d’inscrire le package NTLM/WINNT. Cela est souvent nécessaire pour prendre en charge les clients plus anciens qui prennent uniquement en charge NTLM. Il s’agit d’une erreur si seul le package NTLM est inscrit, car cela force tous les clients à utiliser NTLM même s’ils sont capables d’utiliser Kerberos.
DCOM : SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passé en tant que membre dwAuthnSvc de la structure COAUTHINFO, qui est lui-même membre du struct COSERVERINFO transmis à l’API) RPC_C_AUTHN_WINNT RPC_C_AUTHN_DEFAULT ou RPC_C_AUTHN_GSS_NEGOTIATE La négociation ne doit être utilisée que si la communication se produit toujours sur un réseau. Si l’appel DCOM se produit entre le client et le serveur sur le même ordinateur, vous devez utiliser DEFAULT et autoriser DCOM à choisir le package approprié à utiliser.
LDAP : ldap_bind_s (méthode) LDAP_AUTH_NTLM LDAP_AUTH_NEGOTIATE
HTTP WinHTTPSetCredentials (AuthScheme) WINHTTP_AUTH_SCHEME_NTLM WINHTTP_AUTH_SCHEME_NEGOTIATE

5001 – Négocier la liste des packages inclut uniquement NTLM

Gravité – Erreur

Lorsque vous utilisez AcquireCredentialsHandle, il est possible de fournir une liste de packages à utiliser ou ignorés par Negotiate. Selon la liste spécifiée, cela peut remplacer la logique intégrée à Negotiate pour choisir le package d’authentification le plus approprié et sécurisé. Si la liste des packages inclut uniquement NTLM ou exclut Kerberos, le résultat est identique au contournement total de Negotiate et sélectionne explicitement le package SSP NTLM directement.

La spécification d’une liste de sous-packages n’est possible que lorsque vous appelez AcquireCredentialsHandle directement, car la plupart des API de couche supérieure (telles que RPC) n’autorisent pas l’appelant à contrôler la liste des packages Negotiate.

Microsoft ne recommande pas que les applications tentent de manipuler la liste des packages Negotiate de cette façon.

Guide pratique pour corriger cette erreur

Utilisez le package Negotiate sans spécifier une liste de sous-packages ou vérifiez que Kerberos est inclus.

API(paramètre) utilisées par l’application Valeur incorrecte Valeur correcte
AcquireCredentialsHandle (membre PackageList de SEC_WINNT_AUTH_IDENTITY_EX struct passé en tant que paramètre pAuthData) "! Kerberos » ou « NTLM » NULL ou « Kerberos, NTLM » ou « Kerberos , ! NTLM » ou « ! NTLM "

5002 - Négocier une liste de packages incorrecte exclusion NTLM

Gravité - Avertissement

Lors de l’appel d’AcquireCredentialsHandle, l’application a tenté d’exclure NTLM de la liste des packages pris en charge par Negotiate. Toutefois, la syntaxe incorrecte a été utilisée pour exclure NTLM. Elle reste donc dans la liste.

Comment corriger cette erreur Utilisez la syntaxe suivante pour exclure le package NTLM de Negotiate :

API(paramètre) utilisées par l’application Valeur incorrecte Valeur correcte
AcquireCredentialsHandle (membre PackageList de SEC_WINNT_AUTH_IDENTITY_EX struct passé en tant que paramètre pAuthData) « -NTLM » "! NTLM "

5003 – Aucun nom cible ou nom cible mal formé pour le serveur

Gravité – Erreur

Lorsque vous utilisez le package Negotiate, l’attribution d’un nom cible null ou non valide (parfois appelé nom de principal) entraîne l’échec de Kerberos et l’utilisation de NTLM à sa place. Vous devez toujours spécifier un nom cible valide lors de l’appel d’authentification. Le nom cible est un identificateur unique qui permet à un contrôleur de domaine d’obtenir les détails du compte du serveur auquel votre application tente de s’authentifier. Une fois que le contrôleur de domaine dispose de ces informations, il peut générer des tickets Kerberos appropriés qui seront compris (déchiffrables) par le client et le serveur.

Guide pratique pour corriger cette erreur

Les noms cibles peuvent être spécifiés dans trois formats différents, chacun pouvant être utilisé par les contrôleurs de domaine pour localiser l’objet de compte de serveur approprié. Ces formats sont le nom du principal du service (SPN), le nom d’utilisateur principal (UPN) et le nom de domaine\compte en deux parties NetBIOS. Le SPN est le formulaire le plus courant et le plus interopérable avec d’autres implémentations Kerberos. Une discussion complète sur les noms de principal de service est au-delà de l’étendue de ce document, mais le formulaire SPN le plus simple et le plus courant comporte deux parties : une classe de service et un nom d’hôte. La classe de service identifie le type d’application serveur (par exemple, un type d’application spécifique tel que http ou ldap ou générique en tant qu’hôte). La deuxième partie est le nom de domaine complet ou le nom de domaine plat (NetBIOS) du serveur. Les clients et serveurs Windows inscrivent automatiquement les noms spN pour « hôte » pour les noms de domaine complets et plats. Les contrôleurs de domaine mappent également environ 40 classes de service spécifiques à l’application sur le SPN « hôte » pour des éléments tels que « http », « ldap », « rpc », « tapi », etc.

o spécifiez un nom cible pour une application s’exécutant dans le contexte du système d’exploitation serveur (par exemple, localsystem, service réseau ou service local) les applications clientes peuvent utiliser le SPN « hôte » inscrit automatiquement ou l’un de ses alias. Pour vous authentifier auprès d’une application s’exécutant dans le contexte d’un compte d’utilisateur de domaine, vous devez inscrire un SPN pour ce compte.

Pour les comptes d’utilisateur, vous pouvez également utiliser le formulaire UPN implicite généré à partir du nom du compte d’utilisateur et du domaine dans lequel réside le compte : useraccountname@domain.dom. Bien que vous puissiez créer des UPN supplémentaires pour le compte d’utilisateur (à l’aide des suffixes UPN qui peuvent être créés pour chaque domaine), ceux-ci ne fonctionnent pas en tant que noms cibles Kerberos , seul l’UPN correspondant au nom de compte d’ouverture de session réel et au domaine réel où le compte vit peut être utilisé.

Enfin, vous pouvez toujours utiliser le domaine de style NT4\username (ou domain\computername dans le cas des services s’exécutant en tant que localsystem, networkservice ou localservice). Cela fonctionne pour les cibles qui s’exécutent dans le contexte du compte d’utilisateur de domaine ou des comptes d’ordinateur.

API(paramètre) utilisées par l’application Paramètre pour définir le nom de la cible Notes
InitializeSecurityContext pszTargetName
Client RPC : RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) ServerPrincipalName Il doit s’agir du nom cible du compte sous lequel le serveur/service est en cours d’exécution. Il ne doit pas être identique à la valeur définie dans RPCServerRegisterAuthInfo
DCOM : SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passé en tant que membre dwAuthnSvc de la structure COAUTHINFO, qui est lui-même membre du struct COSERVERINFO transmis à l’API) pServerPrincName Peut utiliser COLE_DEFAULT_PRINCIPAL pour permettre à COM de sélectionner automatiquement le nom dans les informations de liaison
LDAP : aucun Généré automatiquement par le client LDAP.
HTTP none WinHTTP et WinInet fournissent le nom cible à partir du nom du serveur d’URL

5010 – Rétrograder vers NTLM Détecté

Gravité - Avertissement

Même si l’application spécifique à Negotiate et a utilisé un nom cible correctement mis en forme, quelque chose s’est produit pour que Negotiate passe à NTLM. Selon les circonstances, cela peut indiquer une erreur ou un comportement attendu. Par exemple, lorsqu’un ordinateur ne fait pas partie d’un domaine ou qu’il est utilisé dans un emplacement où un contrôleur de domaine n’est pas accessible, il est prévu que Negotiate effectue une rétrogradation silencieuse pour permettre à l’application de s’authentifier à l’aide de NTLM. Toutefois, si cet arrêt se produit lorsqu’un contrôleur de domaine est disponible et que vous vous attendez normalement à ce que Kerberos soit utilisé, il indique presque certainement que quelque chose est incorrect.

Comment corriger cette erreur

En supposant que vous avez déterminé que Kerberos aurait dû être utilisé et non NTLM dans ce cas, il existe plusieurs possibilités pour lesquelles la rétrogradation a eu lieu :

• Le nom cible, même s’il était peut-être au format correct, n’existait pas dans le domaine (ou la forêt).

o Vous devez case activée que vous générez le nom cible approprié dans l’application cliente. La classe de service est-elle correcte ? Le nom d’hôte est-il correct ?

o Le processus serveur s’exécute dans le contexte de l’ordinateur ou d’un autre compte de domaine. Dans l’ancien cas, les spN sont automatiquement inscrits, dans ce dernier cas, vous devrez peut-être inscrire le SPN ou utiliser un autre formulaire tel qu’un UPN implicite ou un nom plat.

O Peut-il y avoir des problèmes de connectivité réseau empêchant la communication avec un contrôleur de domaine ou un serveur DNS ?

o Le SPN cible est-il inscrit sur plusieurs comptes ? Cela entraîne le rejet par le contrôleur de domaine des tentatives d’authentification.

Impression

Le vérificateur d’impression permet de trouver et de résoudre les problèmes qui peuvent se produire lorsqu’une application appelle le sous-système d’impression. Le vérificateur d’impression cible les deux couches du sous-système d’impression, la couche PrintAPI et la couche PrintDriver.

Couche d’API d’impression

Le vérificateur d’impression teste l’interface entre un programme et Winspool.drv et prntvpt.dll et teste les interfaces de ces DLL. Vous pouvez passer en revue les règles d’appel de fonctions dans cette interface dans la section d’aide MSDN pour les API exportées par winspool.drv et prntvpt.dll.

Couche de pilote d’impression

Le vérificateur d’impression teste également l’interface entre un pilote d’impression principal tel que UNIDRV.DLL, UNIDRUI.DLL, PSCRIPT5.DLL, PS5UI.DLL ou MXDWDRV.DLL et les plug-ins de pilote d’impression. Vous trouverez des informations sur cette interface dans MSDN et WDK.

En règle générale, seules les versions de débogage exécutent Application Verifier. Les performances ne sont donc pas généralement un problème. Si des problèmes de performances proviennent de l’utilisation de cette vérification ou d’une autre vérification d’Application Verifier, exécutez une vérification à la fois jusqu’à ce que vous ayez effectué toutes les vérifications nécessaires.

WebServices

Couche de vérification de l’API Webservices Windows (WWSAPI)

Le plug-in WWSAPI permet aux développeurs d’intercepter les instances de :

  • WWSAPI appelé qui fait référence à un objet WWSAPI intrinsèque non valide.

  • WWSAPI appelé qui fait référence à un seul objet thread déjà utilisé.

  • Objet intrinsèque libéré avec un appel asynchrone en attente.

  • Appel d’API bloquantes à partir de threads courts.

En outre, ce plug-in :

  • Effectue le suivi de l’utilisation d’objets de l’instanciation à la suppression.

  • Forcez les appels qui peuvent être terminés de façon asynchrone pour qu’ils soient terminés de façon synchrone. Cela permet d’empêcher les applications en fonction d’un comportement particulier d’un appel prenant un WS_ASYNC_CONTEXT.

  • Fournit une description lisible humaine lorsqu’une API est passée à un objet incorrect ou qu’un objet est en cours d’utilisation à l’aide de l’extension !avrf –ws –obj debugger (illustré ci-dessous)

  • Pour le canal, le proxy de service et l’hôte de service, chaque appel suivi affiche l’état actuel de l’objet.

Par défaut, les case activée ers suivants sont activés :

Property NameDescriptionValidateObjectValidates que l’objet intrinsèque est validTrackObjectTracks l’utilisation d’un objet par le biais de sa durée de vie

Les autres case activée ers qui peuvent être activés dans ce fournisseur via l’interface utilisateur des propriétés sont les suivants :

Property NameDescriptionCheckTimeoutValidates que les fonctions asynchrones sont terminées dans le délai d’expiration, spécifié en tant que TimeoutValForceSyncForce, chemin de synchronisation à prendre lorsqu’un contexte WS_ASYNC_CONTEXT est fourni à une API.

Une extension de débogueur est fournie ( !avrf –ws –obj) qui affiche les objets WWSAPI intrinsèques ouverts et fermés. Si cette extension est suffixee par un objet, elle affiche des informations détaillées sur l’utilisation de cet objet.

!avrf -ws –obj

Cette commande affiche les objets WWSAPI intrinsèques qui sont suivis, créés et fermés. Notez que les objets fermés sont stockés dans une file d’attente circulaire. Il existe donc un plafond pour le nombre total d’objets suivis.

Les objets sont ajoutés lorsque les API suivantes se terminent correctement : WsCreateChannel(), WsCreateChannelForListener(), WsCreateServiceHost(), WsCreateServiceProxy(), WsCreateServiceProxyFromTemplate(), WsCreateError(), WsCreateHeap(), WsCreateHeap(), WsCreateListener(), WsCreateMetadata(), WsCreateMessage(), WsCreateMessageForChannel(), WsCreateReader(), WsCreateWriter(), WsCreateXmlBuffer(), WsReadXmlBuffer(), WsReadXmlBufferFromBytes()

Les objets sont déplacés de la liste créée à la liste libérée lorsque la fonction WsFree*() correspondante est appelée et terminée.

!avrf –ws –obj [OBJECT]

Cette commande affiche l’utilisation d’un objet WWSAPI intrinsèque. Les informations d’utilisation incluent la pile lorsque l’objet a été créé, utilisé et libéré. Si l’objet est un canal, un hôte de service ou un proxy de service, il affiche l’état de l’objet avant l’API à l’aide de l’objet est appelé.

Voici un exemple des options d’utilisation !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>

Services

Les services testent case activée pour l’utilisation appropriée des services Windows. Par exemple, les services sont démarrés et arrêtés correctement. Pour plus d’informations sur les exceptions de code d’arrêt générées par ces tests, consultez Application Verifier - Stop Codes - Services.

Perf

Les tests Perf case activée pour une utilisation efficace des API qui affectent les performances du système et la consommation d’énergie, telles que l’appel d’une fonction Windows qui utilise une période d’attente incorrecte. Pour plus d’informations sur les exceptions de code d’arrêt générées par ces tests, consultez Application Verifier - Stop Codes - Perf.

Se bloque

Les tests hangs pour l’utilisation d’API qui empêchent le système de répondre, par exemple lorsque le thread DllMain attend un autre thread bloqué. Pour plus d’informations sur les exceptions de code d’arrêt générées par ces tests, consultez Application Verifier - Stop Codes - Hangs.

ARM64EC Support

Les fournisseurs suivants ne prennent pas en charge ARM64EC, et par conséquent, bloquent un programme s’exécutant dans ARM64EC :

Voir aussi

Vérificateur d’application - Vue d’ensemble

Vérificateur d’application - Fonctionnalités

Vérificateur d’application - Test d’applications

Vérificateur d’application - Codes et définitions d’arrêt

Vérificateur d’application - Débogage des arrêts du vérificateur d’application

Vérificateur d’application - Forum aux questions