Compartilhar via


Application Verifier - Testes dentro do Application Verifier

Suporte ARM64EC

O Verificador de Aplicativos não oferece suporte a ARM64EC.

Noções básicas

No mínimo, você deve executar o Application Verifier com a configuração Básica selecionada. Cada um deles testará uma área que causará falhas ou outros cenários negativos, que tenham um impacto direto e significativo na experiência do cliente.

  • Exceções - Garante que os aplicativos não ocultem violações de acesso usando o tratamento de exceção estruturado
  • Identificadores - Testes para garantir que o aplicativo não esteja tentando usar identificadores inválidos
  • Heaps - Verifica se há problemas de corrupção de memória no heap
  • Vazamento - Detecta vazamentos rastreando os recursos feitos por uma dll que não são liberados no momento em que a dll foi descarregada
  • Bloqueios - Verifica o uso correto para seções críticas
  • Memória – garante que as APIs para manipulações de espaço virtual sejam usadas corretamente (por exemplo, VirtualAlloc, MapViewOfFile)
  • SRWLock - verifica o uso correto de bloqueios de leitor/gravador fino (SRW).
  • Threadpool – garante o uso correto de APIs de threadpool e impõe verificações de consistência em worker-thread-states após um retorno de chamada, como threads de threadpool sujos e outros problemas relacionados ao threadpool.
  • TLS - Garante que as APIs de armazenamento local do Thread sejam usadas corretamente

Para obter informações sobre as exceções de código de interrupção geradas por esses testes, consulte Application Verifier — Códigos de interrupção e definições. Para obter informações sobre como depurar essas falhas, consulte Verificador de Aplicativos – Depurando paradas do Verificador de Aplicativos

Compatibilidade

Os testes da camada de verificação de compatibilidade ajudam a identificar um aplicativo que pode ter problemas com o sistema operacional Microsoft Windows. Muitas dessas verificações também podem ser usadas para testar os requisitos de logotipo/certificação.

Para obter informações sobre as exceções de código de interrupção geradas por esses testes, consulte Application Verifier — Códigos de interrupção e definições.

HighVersionLie — Identifica problemas para alguns dos problemas mais comuns de compatibilidade de aplicativos no Windows. Detectar incorretamente a versão do sistema operacional ou usar informações de versão codificadas pode fazer com que o aplicativo falhe em sistemas operacionais posteriores.

Porque

A camada de verificação de Concurrency Fuzzing (Cuzz) detecta bugs de simultaneidade e condições de corrida de dados. O Cuzz ajusta o agendamento de threads injetando atrasos aleatórios em pontos-chave no código de um aplicativo. O cenário a seguir ilustra o tipo de bug de simultaneidade que pode ser detectado pela camada de verificação Cuzz.

Um aplicativo tem um thread pai e um thread filho. O thread pai inicia o thread filho e, em seguida, aloca memória para uma estrutura.

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

O thread filho desreferencia o ponteiro.

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

O código anterior tem um bug de simultaneidade. Se o thread filho tentar desreferenciar o ponteiro antes que o thread pai aloque a memória, o ponteiro será inválido. É muito improvável que o bug se manifeste, porque, na maioria dos casos, o thread pai alocará a memória antes que o thread filho seja iniciado. Mas, em casos raros, o thread filho pode ser iniciado e tentar desreferenciar o ponteiro antes que o thread pai tenha alocado a memória.

A camada de verificação Cuzz aumenta a probabilidade de encontrar bugs de simultaneidade como o ilustrado no exemplo anterior. Cuzz não executa nenhuma verificação adicional além de inserir atrasos. Como tal, não há paradas de verificação diretamente associadas ao Cuzz. No entanto, se a ativação do Cuzz resultar em um bug de simultaneidade se manifestando, outras camadas de verificação serão beneficiadas. Por exemplo, se uma condição de corrida resultar em um estouro de heap, a camada de verificação de Heaps não encontrará o erro, a menos que a condição de corrida se manifeste em tempo de execução. Ao aumentar a probabilidade de ocorrência da condição de corrida, Cuzz melhora a eficácia da camada Heaps na identificação do erro.

Para obter o máximo benefício do Cuzz, habilite o Cuzz no maior número possível de testes e repita o mesmo teste várias vezes. O Cuzz pode ser ativado em todos os testes, incluindo testes manuais, testes funcionais e testes de estresse. Além disso, habilite o maior número possível de camadas de verificação do Verificador de Aplicativos.

Você pode aumentar a probabilidade de reproduzir um bug fornecendo a Cuzz a mesma semente aleatória (consulte Propriedades).

Cuzz insere atrasos somente em chamadas de API de sincronização Win32.

Propriedades de Cuzz

As propriedades a seguir estão disponíveis para a camada de verificação Cuzz. Para definir as propriedades, selecione a camada Cuzz na interface do usuário do Verificador de Aplicativos e abra a Janela de Propriedades.

Propriedade Descrição
Nível de Dispersão Controla o nível de difuso para Cuzz. Defina como 1 para aplicativos críticos de tempo e 4 para aplicativos regulares.
Semente aleatória A semente aleatória usada por Cuzz no início. Se você definir isso como 0, Cuzz gerará uma semente aleatória baseada em tempo.

Simulação de poucos recursos

A simulação de poucos recursos tenta simular um ambiente com poucos recursos, como falta de memória. Essa simulação identificará bugs que ocorrem em condições de pouca memória. Isso também é conhecido como Injeção de Falha. Você pode simular um ambiente com poucos recursos, por meio do qual você pode definir um número (0–100) que indica as chamadas de probabilidade de falha de:

  • Aguarde (por exemplo, a API WaitForXXXX).
  • Heap_Alloc (API de alocação de heap).
  • Virtual_Alloc (API de alocação de memória virtual).
  • Registro (API do Registro).
  • File (API de arquivo, como CreateFile).
  • Evento (API de Evento, como CreateEvent).
  • MapView (API MapView, como CreateMapView).
  • Ole_Alloc (API Ole, como SysAllocString).

A simulação de poucos recursos (também conhecida como injeção de falhas) tenta simular um ambiente com poucos recursos, por exemplo, sem memória. Isso identificará o bug em condições de pouca memória.

Propriedades de simulação de baixo recurso

Para editar as propriedades, marque a caixa de seleção Simulação de Poucos Recursos na área Testes, clique com o botão direito do mouse e selecione as propriedades:

Propriedade Descrição
Incluir As falhas de limite ocorrem somente nas dlls especificadas. Um nome de dll sem caminho por linha. Se '*' for especificado, ocorrerão falhas em todos os módulos.
Excluir Exclua falhas para os módulos especificados. Um nome de dll sem caminho por linha.
Timeout Forneça um intervalo de tempo (em milissegundos) quando não houver falha na inicialização do processo.
Aguardar Um número [0 – 1000000] que indica a probabilidade de falha para a API WaitForXXXX.
Heap_Alloc Um número [0 – 1000000] que indica a probabilidade de falha para a API de Alocação de Heap.
Virtual_Alloc Um número [0 – 1000000] que indica a probabilidade de falha para a API de alocação de Memória Virtual.
Registro Um número [0 – 1000000] que indica a probabilidade de falha para a API do Registro.
Arquivo Um número [0 – 1000000] que indica a probabilidade de falha para a API de Arquivo, como CreateFile.
Evento Um número [0 – 1000000] que indica a probabilidade de falha para a API de Eventos, como CreateEvent
MapView Um número [0 – 1000000] que indica a probabilidade de falha para a API MapView, como CreateMapView.
Ole_Alloc Um número [0 – 1000000] que indica a probabilidade de falha para a API Ole, como SysAllocString.
Pilhas Cada thread de aplicativo do Windows começa com uma reserva de pilha e um tamanho de confirmação de pilha. Em uso normal, a confirmação da pilha cresce sempre que há necessidade de mais espaço na pilha. Consulte Criando threads e Tamanho da pilha de threads para obter mais informações. Se o sistema estiver enfrentando condições de pouca memória, o crescimento de confirmação da pilha poderá falhar. O thread que não consegue aumentar sua pilha e todo o aplicativo provavelmente falhará. Esse tipo de travamento é inaceitável para processos importantes do sistema (por exemplo, para serviços). A verificação de pilhas desabilitará qualquer crescimento de pilha para o aplicativo que está sendo verificado para simular as falhas de crescimento de pilha sem a necessidade de simular as condições de pouca memória de todo o sistema. Exceções serão geradas quando o aplicativo tentar expandir a pilha. Nenhuma parada de verificador é gerada por isso.

LuaPriv

Os testes de Preditor de Privilégio de Conta de Usuário Limitado (LuaPriv) são preditivos e diagnósticos e funcionam para revelar problemas relacionados à execução de um aplicativo com privilégio administrativo e se esse aplicativo funcionaria tão bem se executado com menos privilégios (geralmente, como um usuário normal).

Também conhecido como verificações de UAC, o LuaPriv (Preditor de Privilégios de Conta de Usuário Limitado) tem dois objetivos principais:

  • Preditivo: ao executar um aplicativo com privilégio administrativo, preveja se esse aplicativo funcionaria tão bem se executado com menos privilégios (geralmente, como um usuário normal). Por exemplo, se o aplicativo gravar em arquivos que só permitem o acesso de Administradores, esse aplicativo não poderá gravar no mesmo arquivo se executado como um não-administrador.

  • Diagnóstico: durante a execução com privilégio de não administrador, identifique possíveis problemas que podem já existir com a execução atual. Continuando o exemplo anterior, se o aplicativo tentar gravar em um arquivo que concede acesso somente aos membros do grupo Administrador, o aplicativo receberá um erro ACCESS_DENIED. Se o aplicativo não funcionar corretamente, essa operação pode ser a culpada.

O LuaPriv identifica os seguintes tipos de problemas:

Possível Problemas Descrição
Namespaces restritos A criação de um objeto de sincronização nomeado (Event, Semaphore, Mutex, etc.) sem um namespace pode complicar a execução sem privilégio em alguns sistemas operacionais porque o sistema operacional pode optar por colocar o objeto em um namespace restrito. A criação desse objeto em um namespace restrito (como o namespace Global) requer SeCreateGlobalPrivilege, que é concedido somente a administradores.
O LuaPriv sinaliza esses dois problemas se os detectar.
Verificações fixas do Administrador Alguns aplicativos interrogam o token de segurança do usuário para descobrir quanto privilégio ele tem. Nesses casos, o aplicativo pode mudar seu comportamento dependendo de quanto poder ele acha que o usuário tem.
O LuaPriv sinaliza chamadas de API que retornam essas informações.
Solicitando privilégios Um aplicativo pode tentar habilitar um privilégio relevante à segurança (como SeTcbPrivilege ou SeSecurityPrivilege) antes de executar uma operação que o exija.
LuaPriv sinaliza tentativas de habilitar privilégios relevantes para segurança.
Privilégios ausentes Se um aplicativo tentar habilitar um privilégio que o usuário não tem, ele provavelmente sinaliza que o aplicativo espera o privilégio, o que pode causar diferenças de comportamento.
O LuaPriv sinaliza solicitações de privilégio com falha.
Operações de arquivo INI As tentativas de gravar em arquivos INI mapeados (WritePrivateProfileSection e APIs semelhantes) podem falhar como um usuário não administrador.
LuaPriv sinaliza tais operações.
Acesso negado Se o aplicativo tentar acessar um objeto (arquivo, chave do Registro, etc.), mas a tentativa falhar devido ao acesso insuficiente, o aplicativo provavelmente espera estar sendo executado com mais privilégios do que tem.
O LuaPriv sinaliza tentativas de abertura de objeto que falham com ACCESS_DENIED e erros semelhantes.
Negar ACEs Se um objeto tiver Negar ACEs em sua DACL, ele negará explicitamente o acesso a entidades específicas.
Isso é incomum e dificulta a previsão, então o LuaPriv sinaliza Negar ACEs quando os encontra.
Acesso Restrito Se um aplicativo tentar abrir um objeto para direitos que não são concedidos a usuários normais (por exemplo, tentando gravar em um arquivo que só pode ser gravado por administradores), o aplicativo provavelmente não funcionará da mesma forma quando executado como um usuário normal.
LuaPriv sinaliza tais operações.
MAXIMUM_ALLOWED Se um aplicativo abrir um objeto para MAXIMUM_ALLOWED, a verificação de acesso real no objeto ocorrerá em outro lugar. A maioria dos códigos que fazem isso não funcionam corretamente e quase certamente funcionarão de forma diferente quando executados sem privilégio.
LuaPriv sinaliza todos os incidentes de MAXIMUM_ALLOWED.

Diversos

Problemas comumente negligenciados são capturados nos testes diversos.

  • APIs perigosas — Rastreia para ver se o aplicativo está usando as seguintes ações não seguras:
    • Chamada perigosa para TerminateThread.
    • Estouro de pilha potencial em condições de pouca memória.
    • Processo de saída chamado enquanto vários threads ainda estão em execução.
    • LoadLibrary é chamado durante DllMain.
    • FreeLibrary é chamado durante DllMain.
  • Pilhas Sujas preenche (periodicamente) a parte não utilizada da pilha com um padrão de memória. Isso pode ajudar a detectar variáveis não inicializadas em chamadas de função futuras no contexto desse thread.
  • TimeRollOver força as APIs GetTickCount e TimeGetTime a serem substituídas mais rapidamente do que normalmente fariam. Isso permite que os aplicativos testem seu tratamento de rolagem de tempo com mais facilidade.

Propriedades diversas

A verificação de APIs perigosas tem uma propriedade que pode ser alterada:

DllMainCheck - Verifique a chamada LoadLibrary/FreeLibrary quando DllMain está ativo.

Rede

Os testes de rede procuram o uso indevido de APIs do WinSock. Por exemplo, se uma API de sistema de rede foi chamada antes de uma WSAStartup() bem-sucedida ou depois de uma chamada WSACleanup() bem-sucedida de balanceamento ter sido feita. Para obter mais informações sobre o WinSock, consulte o cabeçalho winsock.h e o Windows Sockets 2.

Propriedades

As propriedades a seguir estão disponíveis para a camada de verificação de rede. Para definir as propriedades, selecione o provedor de rede na interface do usuário do Verificador de Aplicativos e abra a Janela de Propriedades.

Propriedade Descrição
FragmentsEnabled Permite a fragmentação de fluxos de dados recebidos por soquetes TCP IPv4 e IPv6.
Tamanho do fragmento Especifica o número máximo de bytes retornados em um buffer para qualquer chamada à API de recebimento do Winsock.

A propriedade FragmentsEnabled habilita a funcionalidade no provedor verificador de rede para facilitar o teste e a verificação de um aplicativo que analisa fluxos TCP de uma rede. Depois de habilitadas, todas as chamadas para Winsock para receber dados receberão apenas até bytes FragmentSize, a menos que o aplicativo exija especificamente todo o buffer preenchido antes de retornar (controlado pelo sinalizador MSG_WAITALL). Como nem o protocolo TCP nem o Winsock fornecem garantias sobre o número de bytes possivelmente retornados em um buffer, habilitar essa verificação facilitará a verificação de que o código que analisa o fluxo de dados da rede o faz corretamente, independentemente do número de bytes recebidos por chamada para o Winsock. Problemas em analisadores de fluxo têm sido uma fonte de bugs de alto perfil, e essas propriedades são fornecidas para facilitar a verificação da correção, pois isso é particularmente difícil de testar. Nota: Isso não altera os dados retornados – apenas os torna mais lentos em uma taxa específica: o aplicativo deve se comportar exatamente da mesma maneira com isso ativado ou desativado.

A linha de comando a seguir permite a fragmentação de todos os fluxos TCP de entrada para todos os soquetes TCP IPv4 e IPv6 criados em myApp.exe e todos os binários carregados pelo myApp.exe.

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

Extensão do depurador !avrf

!avrf -net -socket count - Exibe a contagem de identificadores de soquete aberto e fechado

!avrf -net -socket dump [-v] [HANDLE] - exibe a(s) alça(s) de soquete, detalhadamente ou não.

!avrf -net -wsastacks - exibe a contagem de inicialização atual do WSA e a lista cronológica de rastreamentos de pilha para WSAStartup/WSACleanup.

!avrf -net -wsastacks count - exibe a contagem de inicialização atual do WSA.

!avrf -net -socket count - Este comando fornecerá o número total de identificadores de soquete que estão sendo rastreados, abertos e fechados. Observe que eles são rastreados em uma fila circular, portanto, há um teto para o total que está sendo rastreado. Os soquetes são adicionados à lista aberta quando uma das APIs do Winsock que aloca um identificador de soquete é chamada. Por exemplo, socket(), WSASocket(), accept(). Os soquetes são movidos da lista aberta para a lista fechada quando a função closesocket() é chamada nesse identificador de soquete.

!avrf -net -socket dump [-v] [HANDLE] - Esse comando enumerará os identificadores de soquete. "-socket dump" listará todos os identificadores de soquete abertos e fechados rastreados por seus valores SOCKET. O sinalizador -v opcional imprimirá adicionalmente a pilha de chamadas de abertura ou fechamento imediatamente após a impressão de cada valor SOCKET. O campo HANDLE opcional listará apenas o identificador SOCKET especificado e sua pilha de chamadas de abertura ou fechamento.

Aqui estão exemplos das várias opções de uso 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]

O Winsock exige que os desenvolvedores de aplicativos chamem o WSAStartup() pelo menos uma vez antes de fazer qualquer chamada do Winsock. Isso é rastreado pelo Winsock em todo o processo. A contagem de referência inicial instrui uma biblioteca Winsock (ws2_32.dll) a inicializar e carregar o catálogo e os provedores do Winsock. Outras chamadas para WSAStartup incrementam essa contagem de referência. O Winsock também exige que os desenvolvedores de aplicativos chamem WSACleanup() quando tiverem 'terminado' de chamar o Winsock. As chamadas para WSACleanup devem ser emparelhadas corretamente com uma chamada anterior para WSAStartup(). A chamada para WSACleanup() diminui a contagem de referência em todo o processo. Quando a contagem de referência cai para zero, o Winsock libera seus recursos e descarrega o catálogo e os provedores do Winsock.

Esse comando fornecerá o valor geral da contagem de referência da rotina de inicialização "WSAStartup" atual e listará as pilhas de chamadas para chamadas para WSAStartup e WSACleanup feitas dentro do processo. Observe que isso é mantido dentro de uma fila circular fixa, portanto, não é garantido que seja concluído - apenas as N chamadas mais recentes.

Aqui estão exemplos das várias opções 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

Esse plug-in do Verificador de Aplicativos monitora as chamadas de um processo individual para as APIs de autenticação AcquireCredentialsHandle e InitializeSecurityContext para detectar usos do protocolo NTLM. O NTLM é um protocolo de autenticação desatualizado com falhas que potencialmente comprometem a segurança das aplicações e do sistema operacional e não deve ser usado.

Risco de autenticação NTLM

A falha mais importante do protocolo de autenticação NTLM desatualizado é a falta de autenticação do servidor, o que pode permitir que um invasor engane os usuários para que se conectem a um servidor falsificado. Como corolário da falta de autenticação do servidor, os aplicativos que usam NTLM também podem ser vulneráveis a um tipo de ataque conhecido como ataque de "reflexão". Este último permite que um invasor sequestre a conversa de autenticação de um usuário para um servidor legítimo e use-a para autenticar o invasor no computador do usuário. As vulnerabilidades do NTLM e as formas de explorá-las são alvo de uma crescente atividade de pesquisa na comunidade de segurança.

Embora o Kerberos esteja disponível há muitos anos, muitos aplicativos ainda são escritos para usar apenas NTLM. Isso reduz desnecessariamente a segurança dos aplicativos. No entanto, o Kerberos não pode substituir o NTLM em todos os cenários – principalmente aqueles em que um cliente precisa se autenticar em sistemas que não estão associados a um domínio (uma rede doméstica talvez seja a mais comum delas). O pacote de segurança Negotiate permite um comprometimento compatível com versões anteriores que usa Kerberos sempre que possível e só reverte para NTLM quando não há outra opção. Alternar o código para usar Negotiate em vez de NTLM aumentará significativamente a segurança para nossos clientes, ao mesmo tempo em que introduzirá poucas ou nenhuma compatibilidade de aplicativos. Negociar por si só não é uma bala de prata – há casos em que um invasor pode forçar o downgrade para NTLM, mas estes são significativamente mais difíceis de explorar. No entanto, uma melhoria imediata é que os aplicativos escritos para usar o Negotiate corretamente são automaticamente imunes a ataques de reflexão NTLM.

A título de uma palavra final de cautela contra o uso de NTLM: No Windows, é possível desabilitar o uso de NTLM no nível do sistema operacional. Se os aplicativos tiverem uma dependência rígida do NTLM, eles simplesmente não serão autenticados quando o NTLM estiver desabilitado.

Quais fatores fazem com que o NTLM seja "codificado" em um aplicativo?

Há dois fatores que causarão uma dependência rígida do NTLM. A primeira é selecionar explicitamente NTLM como o pacote de autenticação a ser usado pelo aplicativo. Para alguns protocolos e APIs, a escolha do NTLM é óbvia, como na chamada para a API AcquireCredentialsHandle (). Para outros protocolos, pode não ser tão óbvio. Por exemplo, o pacote de autenticação padrão do RPC (RPC_C_AUTHN_DEFAULT) é, na verdade, um alias para NTLM quando o RPC é usado na rede e até mesmo o sinalizador explícito para selecionar NTLM não tem a abreviação NTLM em nenhum lugar (RPC_C_AUTH_WINNT). Esse tipo de construção facilita a seleção de NTLM sem necessariamente saber que você fez isso.

No lugar do NTLM, os desenvolvedores devem usar outros métodos de autenticação, por exemplo, o pacote Negotiate (às vezes também chamado de pacote SPNEGO ou SNEGO). A seleção de pacotes precisa corresponder aos componentes do cliente e do servidor para que o Negotiate possa tentar usar o Kerberos - portanto, as partes do cliente e do servidor do aplicativo precisam usar o Negotiate. Se qualquer um dos lados usar NTLM (como pode ser o caso com versões legadas), o Negotiate ainda funcionará, mas sempre será revertido para NTLM. A forma de dizer ao seu aplicativo para usar o Negotiate varia de acordo com o protocolo. Alguns dos protocolos mais comuns (RPC, LDAP, DCOM, HTTP) são abordados em detalhes posteriormente no tópico 5000 – O aplicativo selecionou explicitamente o pacote NTLM.

O segundo fator que resulta no uso do NTLM é quando o cliente não fornece um nome de destino de servidor válido para o processo de autenticação. Em protocolos que suportam ou exigem autenticação mútua (como Kerberos), o nome de destino é o que é usado para obter autenticação mútua. As APIs de autenticação (como InitializeSecurityContext) usam um parâmetro opcional, geralmente chamado de algo como "TargetName", "PrincipalName" ou "ServerPrincipalName". Esse é o identificador usado pelos controladores de domínio para selecionar a conta de domínio correta para obter credenciais para o serviço de destino. Como o NTLM não tem nenhum conceito de autenticação de servidor, esse parâmetro não é necessário para que o NTLM seja autenticado com êxito. O Kerberos, por outro lado, exige que um cliente obtenha um tíquete de serviço válido para o serviço no qual o cliente está se autenticando. A autenticação Kerberos sempre falhará se nenhum nome de destino ou um nome de destino inválido for especificado. Quando Negotiate é selecionado como o pacote, não fornecer nenhum nome de destino (ou um nome de destino inválido) fará com que o Kerberos seja ignorado completamente e o NTLM seja usado. A maioria das APIs de autenticação tem o nome de destino como um parâmetro opcional que aceitará se NULL sem erro. A menos que o desenvolvedor substitua isso e forneça um nome de destino explícito, o NTLM (e, além disso, o NTLM refletido) é o resultado.

Como funciona o plug-in NTLM

O plugue do Verificador detecta os seguintes erros:

  • O pacote NTLM é especificado diretamente na chamada para AcquireCredentialsHandle (ou API de wrapper de nível superior).

  • O nome de destino na chamada para InitializeSecurityContext é NULL. Nesse caso, Negotiate retorna diretamente ao NTLM.

  • O nome de destino na chamada para InitializeSecurityContext não é um nome de domínio no estilo SPN, UPN ou NetBIOS formado corretamente. Nesse caso, o controlador de domínio retorna um erro "entidade de segurança não encontrada", o que faz com que Negotiate volte para NTLM.

O plug-in também registra avisos quando detecta downgrades para NTLM; por exemplo, quando um SPN não é encontrado pelo Controlador de Domínio. Eles são registrados apenas como avisos, pois geralmente são casos legítimos – por exemplo, ao autenticar em um sistema que não está ingressado no domínio.

Configurando opções de parada de plug-in

Por padrão, todos os eventos categorizados como Erro são definidos para causar uma interrupção de depuração. Todos os eventos de aviso são definidos para registrar apenas os detalhes do evento.

Eventos de erro causam uma parada/interrupção:

  • 5000 – O aplicativo selecionou explicitamente o pacote NTLM

  • 5001 – Negociar lista de pacotes Inclui apenas NTLM

  • 5002 – Negociar lista de pacotes com exclusão NTLM errada

  • 5003 – Nenhum nome de destino ou nome de destino malformado para o servidor

Eventos de aviso registrados:

  • 5010 – Downgrade para NTLM detectado

Paradas NTLM

5000 – O aplicativo selecionou explicitamente o pacote NTLM

Gravidade – Erro

O aplicativo ou subsistema seleciona explicitamente NTLM em vez de Negotiate na chamada para AcquireCredentialsHandle. Embora seja possível que o cliente e o servidor se autentiquem usando Kerberos, isso é impedido pela seleção explícita de NTLM.

Como corrigir este erro

A correção para esse erro é selecionar o pacote Negotiate no lugar de NTLM. A forma como isso é feito dependerá do subsistema de rede específico que está sendo usado pelo cliente ou servidor. A seguir, são apresentados alguns exemplos. Você deve consultar a documentação sobre a biblioteca específica ou o conjunto de APIs que está usando.

APIs(parâmetro) usadas pelo aplicativo Valor incorreto Valor correto Observações
AcquireCredentialsHandle (pszPackage) "NTLM" NEGOSSP_NAME ou "Negociar"
Cliente RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) Servidor RPC: RPCServerRegisterAuthInfo(AuthnSvc) RPC_C_AUTHN_WINNT ou RPC_C_AUTH_DEFAULT RPC_C_AUTH_GSS_NEGOTIATE Não é um erro para um servidor RPC registrar o pacote NTLM/WINNT. Isso geralmente é necessário para dar suporte a clientes mais antigos que dão suporte apenas a NTLM. É um erro se apenas o pacote NTLM estiver registrado, pois isso força todos os clientes a usar o NTLM, mesmo que sejam capazes de usar o Kerberos.
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passado como membro dwAuthnSvc da estrutura COAUTHINFO, que por sua vez é um membro da estrutura COSERVERINFO passada para a API) RPC_C_AUTHN_WINNT RPC_C_AUTHN_DEFAULT ou RPC_C_AUTHN_GSS_NEGOTIATE Negotiate só deve ser usado se a comunicação sempre ocorrer em uma rede. Se a chamada DCOM ocorrer entre cliente e servidor na mesma máquina, você deverá usar DEFAULT e permitir que o DCOM escolha o pacote correto a ser usado.
LDAP: ldap_bind_s (método) LDAP_AUTH_NTLM LDAP_AUTH_NEGOTIATE
HTTP WinHTTPSetCredentials (AuthScheme) WINHTTP_AUTH_SCHEME_NTLM WINHTTP_AUTH_SCHEME_NEGOTIATE

5001 – Negociar lista de pacotes Inclui apenas NTLM

Gravidade – Erro

Ao usar AcquireCredentialsHandle, é possível fornecer uma lista de pacotes a serem usados ou ignorados pelo Negotiate. Dependendo da lista especificada, isso pode substituir a lógica incorporada ao Negotiate para escolher o pacote de autenticação mais apropriado e seguro. Se a lista de pacotes incluir apenas NTLM ou excluir Kerberos, o resultado será idêntico a ignorar Negotiate completamente e selecionar explicitamente o pacote SSP NTLM diretamente.

Especificar uma lista de subpacotes só é possível ao chamar AcquireCredentialsHandle diretamente, pois a maioria das APIs de camada superior (como RPC) não permite que o chamador controle a lista de pacotes Negotiate.

A Microsoft não recomenda que os aplicativos tentem manipular a lista de pacotes Negotiate dessa maneira.

Como corrigir este erro

Use o pacote Negotiate sem especificar uma lista de subpacotes ou verifique se o Kerberos está incluído.

APIs(parâmetro) usadas pelo aplicativo Valor incorreto Valor correto
AcquireCredentialsHandle (membro PackageList de SEC_WINNT_AUTH_IDENTITY_EX struct passado como parâmetro pAuthData) “! Kerberos" ou "NTLM" NULL ou "Kerberos, NTLM" ou "Kerberos, ! NTLM" ou "! NTLM"

5002 – Negociar lista de pacotes com exclusão NTLM errada

Gravidade - Aviso

Ao chamar AcquireCredentialsHandle, o aplicativo tentou excluir o NTLM da lista de pacotes compatíveis com o Negotiate. No entanto, a sintaxe errada foi usada para excluir o NTLM, portanto, ele permanece na lista.

Como corrigir este erro Use a seguinte sintaxe para excluir o pacote NTLM de Negotiate:

APIs(parâmetro) usadas pelo aplicativo Valor incorreto Valor correto
AcquireCredentialsHandle (membro PackageList de SEC_WINNT_AUTH_IDENTITY_EX struct passado como parâmetro pAuthData) "-NTLM" “! NTLM"

5003 – Nenhum nome de destino ou nome de destino malformado para o servidor

Gravidade – Erro

Ao usar o pacote Negotiate, fornecer um nome de destino nulo ou inválido (às vezes chamado de nome principal) fará com que o Kerberos falhe e o NTLM seja usado em seu lugar. Você sempre deve especificar um nome de destino válido ao fazer uma chamada de autenticação. O nome de destino é um identificador exclusivo que permite que um controlador de domínio obtenha os detalhes da conta do servidor no qual seu aplicativo está tentando se autenticar. Depois que o controlador de domínio tiver essas informações, ele poderá criar tíquetes Kerberos apropriados que serão compreendidos (descriptografáveis) pelo cliente e pelo servidor.

Como corrigir este erro

Os nomes de destino podem ser especificados em três formatos diferentes, cada um dos quais pode ser usado por controladores de domínio para localizar o objeto de conta de servidor correto. Esses formatos são SPN (Nome da Entidade de Serviço), UPN (Nome da Entidade de Usuário) e nome de conta\domínio de duas partes NetBIOS. O SPN é a forma mais comum e a mais interoperável com outras implementações Kerberos. Uma discussão completa sobre SPNs está além do escopo deste documento, mas a forma de SPN mais simples e comum tem duas partes – uma classe de serviço e um nome de host. A classe de serviço identifica o tipo de aplicativo de servidor (por exemplo, tipo de aplicativo específico como http ou ldap ou tão genérico quanto host). A segunda parte é o nome de domínio totalmente qualificado ou o nome simples (NetBIOS) do servidor. Os clientes e servidores Windows registram automaticamente SPNs para "host" para o FQDN e nomes simples. Os controladores de domínio também mapearão cerca de 40 classes de serviço específicas do aplicativo para o SPN "host" para coisas como "http", "ldap", "rpc", "tapi" etc.

o especificar um nome de destino para um aplicativo em execução no contexto do sistema operacional do servidor (por exemplo, localsystem, network service ou localservice) os aplicativos cliente podem usar o SPN "host" registrado automaticamente ou um de seus aliases. Para autenticar em um aplicativo em execução no contexto de uma conta de usuário de domínio, você deve registrar um SPN para essa conta.

Para contas de usuário, você também pode usar o formulário UPN implícito criado a partir do nome da conta de usuário e do domínio em que a conta reside: useraccountname@domain.dom. Embora você possa criar UPNs adicionais para a conta de usuário (usando os sufixos UPN que podem ser criados para cada domínio), eles não funcionarão como nomes de destino Kerberos – somente o UPN correspondente ao nome da conta de logon real e ao domínio real em que a conta reside pode ser usado.

Finalmente, você ainda pode usar o domínio\nome de usuário no estilo NT4 (ou domínio\nome do computador no caso de serviços executados como localsystem, networkservice ou localservice). Isso funciona para destinos que estão sendo executados no contexto de contas de usuário de domínio ou contas de computador.

APIs(parâmetro) usadas pelo aplicativo Parâmetro para definir o nome do destino Observações
InitializeSecurityContext pszTargetName
Cliente RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) ServerPrincipalName Esse deve ser o nome de destino da conta na qual o servidor/serviço está sendo executado. Não precisa ser o mesmo que o valor definido em RPCServerRegisterAuthInfo
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passado como membro dwAuthnSvc da estrutura COAUTHINFO, que por sua vez é um membro da estrutura COSERVERINFO passada para a API) pServerPrincName Pode usar COLE_DEFAULT_PRINCIPAL para permitir que o COM selecione automaticamente o nome das informações de associação
LDAP: nenhum Gerado automaticamente pelo cliente LDAP.
Nenhum HTTP WinHTTP e WinInet fornecem o nome de destino do nome do servidor de URL

5010 – Downgrade para NTLM detectado

Gravidade - Aviso

Embora o Negotiate específico do aplicativo tenha usado um nome de destino formatado corretamente, algo ocorreu para fazer com que Negotiate fizesse downgrade para NTLM. Dependendo de quais foram as circunstâncias, isso pode indicar um erro ou comportamento esperado. Por exemplo, quando um computador não faz parte de um domínio ou está sendo usado em um local onde um controlador de domínio não está acessível, espera-se que o Negotiate faça o downgrade silenciosamente para permitir que o aplicativo seja autenticado usando NTLM. No entanto, se essa parada ocorrer quando um controlador de domínio estiver disponível e você normalmente esperaria que o Kerberos fosse usado, isso quase certamente indicaria que algo está errado.

Como corrigir esse erro

Supondo que você tenha determinado que o Kerberos deveria ter sido usado e não o NTLM nessa circunstância, há várias possibilidades de que o downgrade ocorreu:

• O nome do alvo, mesmo que estivesse no formato correto, não existia no domínio (ou floresta).

o Você deve verificar se está criando o nome de destino correto no aplicativo cliente. A classe de serviço está correta? O nome do host está correto?

o É o processo do servidor em execução no contexto do computador ou de outra conta de domínio. No primeiro caso, os SPNs são registrados automaticamente, no último caso, talvez seja necessário registrar o SPN ou usar um formulário alternativo, como um UPN implícito ou um nome simples.

o Pode haver problemas de conectividade de rede impedindo a comunicação com um controlador de domínio ou servidor DNS?

o O SPN de destino está registrado em mais de uma conta? Isso fará com que o controlador de domínio rejeite tentativas de autenticação para ele.

Imprimindo

O Verificador de Impressão ajuda a localizar e solucionar problemas que podem ocorrer quando um aplicativo chama o subsistema de impressão. O Verificador de Impressão tem como alvo as duas camadas do subsistema de impressão, a camada PrintAPI e a camada PrintDriver.

Camada da API de Impressão

O Verificador de Impressão testa a interface entre um programa e Winspool.drv e prntvpt.dll e testa as interfaces dessas DLLs. Você pode revisar as regras para chamar funções nessa interface na seção de ajuda do MSDN para APIs exportadas por winspool.drv e prntvpt.dll.

Camada do Driver de Impressão

O Verificador de Impressão também testa a interface entre um driver de impressão principal, como UNIDRV.DLL, UNIDRUI.DLL, PSCRIPT5.DLL, PS5UI.DLL ou MXDWDRV.DLL e os plug-ins do driver de impressão. Você pode encontrar informações sobre essa interface no MSDN e no WDK.

Normalmente, apenas as versões de depuração executam o Application Verifier, portanto, o desempenho geralmente não é um problema. Se surgirem problemas de desempenho decorrentes do uso dessa ou de qualquer outra verificação do Application Verifier, execute uma verificação de cada vez até que você tenha executado todas as verificações necessárias.

Serviços Web

Camada de verificação da API de serviços Web do Windows (WWSAPI)

O plug-in WWSAPI permite que os desenvolvedores capturem instâncias de:

  • Um WWSAPI sendo chamado que faz referência a um objeto WWSAPI intrínseco inválido.

  • Um WWSAPI sendo chamado que faz referência a um único objeto encadeado já em uso.

  • Um objeto intrínseco liberado com uma chamada assíncrona pendente.

  • Chamando APIs de bloqueio de threads curtos.

Além disso, este plug-in:

  • Controla o uso de objetos desde a instanciação até a exclusão.

  • Force chamadas que podem ser concluídas de forma assíncrona para serem concluídas de forma síncrona. Isso é para evitar que os aplicativos dependam de um comportamento específico de uma chamada que está tomando um WS_ASYNC_CONTEXT.

  • Fornece uma descrição legível quando uma API recebe um objeto inválido ou um objeto está em uso usando a extensão do depurador !avrf –ws –obj (mostrada abaixo)

  • Para canal, proxy de serviço e host de serviço, cada chamada rastreada mostrará o estado atual do objeto.

Por padrão, os seguintes verificadores estão habilitados:

Nome da propriedadeDescriçãoValidateObjectValida se o objeto intrínseco é válidoTrackObjectRastreia o uso de um objeto durante seu tempo de vida

Outros verificadores que podem ser habilitados neste provedor por meio da interface do usuário de propriedades são:

Nome da propriedadeDescriptionCheckTimeoutValida se as funções assíncronas são concluídas dentro do tempo limite, especificado como TimeoutValForceSyncForce, o caminho de sincronização a ser seguido quando um contexto WS_ASYNC_CONTEXT é fornecido a uma API.

Uma extensão do depurador é fornecida (!avrf –ws –obj) que exibe objetos WWSAPI intrínsecos abertos e fechados. Se essa extensão tiver o sufixo de um objeto, ela exibirá informações detalhadas sobre o uso desse objeto.

!avrf -ws –obj

Este comando exibe os objetos WWSAPI intrínsecos que estão sendo rastreados, criados e fechados. Observe que os objetos fechados são armazenados em uma fila circular, portanto, há um teto para o número total de objetos rastreados.

Os objetos são adicionados quando as seguintes APIs são concluídas com êxito: WsCreateChannel(), WsCreateChannelForListener(), WsCreateServiceHost(), WsCreateServiceProxy(), WsCreateServiceProxyFromTemplate(), WsCreateError(), WsCreateHeap(), WsCreateListener(), WsCreateMetadata(), WsCreateMessage(), WsCreateMessageForChannel(), WsCreateReader(), WsCreateWriter(), WsCreateXmlBuffer(), WsReadXmlBuffer(), WsReadXmlBufferFromBytes()

Os objetos são movidos da lista criada para a lista liberada quando a função WsFree*() correspondente é chamada e concluída.

!avrf –ws –obj [OBJECT]

Esse comando exibe o uso de um objeto WWSAPI intrínseco. As informações de uso incluem a pilha quando o objeto foi criado, usado e liberado. Se o objeto for um canal, host de serviço ou proxy de serviço, ele exibirá o estado do objeto antes que a API usando o objeto seja chamada.

Aqui está um exemplo das opções de uso !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>

Serviços

Os testes de serviços, verificam o uso adequado dos Serviços do Windows. Por exemplo, se os serviços estão sendo iniciados e interrompidos corretamente. Para obter informações sobre as exceções de código de parada geradas por esses testes, consulte Verificador de Aplicativos – Códigos de Parada – Serviços.

Perf

Os testes de desempenho verificam o uso eficiente de APIs que afetam o desempenho do sistema e o consumo de energia, como chamar uma função Windows que usa um período de espera incorreto. Para obter informações sobre as exceções de código de parada geradas por esses testes, consulte Verificador de Aplicativos – Códigos de Parada – Perf.

Trava

O Hangs testa o uso de APIs que fazem com que o sistema pare de responder, por exemplo, quando o thread DllMain está aguardando outro thread que foi bloqueado. Para obter informações sobre as exceções de código de parada geradas por esses testes, consulte Verificador de Aplicativos – Códigos de Parada – Trava.

Confira também

Application Verifier — Visão geral

Application Verifier - Recursos

Application Verifier - Testando aplicativos

Application Verifier - Códigos de parada e definições

Application Verifier -Depurando paradas do Application Verifier

Application Verifier - Perguntas frequentes