Средство проверки приложений — тесты в средство проверки приложений

Основные сведения

Как минимум, необходимо запустить средство проверки приложений с выбранным параметром "Основные сведения". Каждый из них будет тестироваться на область, которая приведет к сбоям или другим негативным сценариям, которые имеют прямое и признаки влияния на взаимодействие с клиентом.

  • Исключения. Гарантирует, что приложения не скрывают нарушения доступа с помощью структурированной обработки исключений
  • Обработка — тесты , чтобы убедиться, что приложение не пытается использовать недопустимые дескрипторы
  • Куча — проверяет наличие проблем с повреждением памяти в куче
  • Утечка — обнаруживает утечки путем отслеживания ресурсов, сделанных библиотекой DLL, которая не освобождается по времени выгрузки библиотеки DLL.
  • Блокировки. Проверяет правильное использование критически важных разделов
  • Память . Обеспечивает правильное использование API для манипуляций с виртуальным пространством (например, VirtualAlloc, MapViewOfFile)
  • SRWLock — проверяет правильное использование блокировок средства чтения и записи (SRW).
  • Threadpool — обеспечивает правильное использование API threadpool и обеспечивает согласованность проверка в рабочих потоках после обратного вызова, например грязное потоков потоков и других проблем, связанных с потоком.
  • TLS — гарантирует правильность использования API локальных служба хранилища потока

Сведения об исключениях кода остановки, созданных этими тестами, см. в разделе "Проверка приложений" — "Коды остановки" и "Определения". Сведения об отладке этих сбоев см. в разделе "Проверка приложений" — остановки отладчика приложений

Совместимость

Тесты уровня проверки совместимости помогают определить приложение, которое может иметь проблемы с операционной системой Microsoft Windows. Многие из этих проверка также можно использовать для тестирования требований к логотипу или сертификации.

Сведения об исключениях кода остановки, созданных этими тестами, см. в разделе "Проверка приложений" — "Коды остановки" и "Определения".

HighVersionLie — определяет проблемы для некоторых наиболее распространенных проблем совместимости приложений в Windows. Неправильное обнаружение версии операционной системы или использование жестко закодированных сведений о версии может привести к сбою приложения в последующих операционных системах.

Cuzz

Уровень проверки нечеткости параллелизма (Cuzz) обнаруживает ошибки параллелизма и условия гонки данных. Cuzz настраивает планирование потоков путем внедрения случайных задержек в ключевые точки в коде приложения. Следующий сценарий иллюстрирует тип ошибки параллелизма, которая может быть обнаружена уровнем проверки Cuzz.

Приложение имеет родительский поток и дочерний поток. Родительский поток запускает дочерний поток, а затем выделяет память для структуры.

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

Дочерний поток разыменовывает указатель.

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

Предыдущий код содержит ошибку параллелизма. Если дочерний поток пытается расшифровать указатель, прежде чем родительский поток выделяет память, указатель будет недопустимым. Ошибка вряд ли будет манифестироваться, так как в большинстве случаев родительский поток выделяет память до начала дочернего потока. Но в редких случаях дочерний поток может начать работу и попытаться разыменовать указатель, прежде чем родительский поток выделил память.

Уровень проверки Cuzz повышает вероятность обнаружения ошибок параллелизма, как в приведенном выше примере. Cuzz не выполняет никаких дополнительных проверка, кроме вставки задержек. Таким образом, нет никаких остановок проверки, напрямую связанных с Cuzz. Однако если включение Cuzz приводит к возникновению ошибки параллелизма, то другие уровни проверки помогут вам воспользоваться. Например, если состояние гонки приводит к переполнению кучи, уровень проверки кучи не найдет ошибку, если состояние гонки не проявляется во время выполнения. Увеличив вероятность возникновения состояния гонки, Cuzz улучшает эффективность слоя куч при выявлении ошибки.

Чтобы получить максимальное преимущество Cuzz, включите Cuzz на максимально возможном количестве тестов и повторите один и тот же тест много раз. Cuzz можно включить во всех тестах, включая ручные тесты, функциональные тесты и стресс-тесты. Кроме того, включите максимальное количество уровней проверки проверки приложений.

Вы можете увеличить вероятность воспроизведения ошибки, предоставив Cuzz с тем же случайным начальным значением (см. раздел "Свойства").

Cuzz вставляет задержки только при вызовах API синхронизации Win32.

Свойства Cuzz

Следующие свойства доступны для уровня проверки Cuzz. Чтобы задать свойства, выберите слой Cuzz в пользовательском интерфейсе проверяющего приложения и откройте окно свойств.

Свойство Description
Нечеткоеlevel Управляет уровнем нечеткости для Cuzz. Установите значение 1 для критически важных приложений и 4 для обычных приложений.
RandomSeed Случайное начальное значение, используемое Cuzz. Если задано значение 0, Cuzz создает случайное начальное значение на основе времени.

Моделирование низких ресурсов

Низкое моделирование ресурсов пытается имитировать среду под низкими ресурсами, например из памяти. Это моделирование определяет ошибки, возникающие в условиях низкой памяти. Это также называется внедрением ошибок. Вы можете имитировать среду под низкими ресурсами, в которой можно определить число (0–100), указывающее вызовы вероятности сбоя:

  • Подождите (например, API WaitForXXXX).
  • Heap_Alloc (API выделения кучи).
  • Virtual_Alloc (API выделения виртуальной памяти).
  • Реестр (API реестра).
  • Файл (API файлов, например CreateFile).
  • Событие (API событий, например CreateEvent).
  • MapView (API MapView, например CreateMapView).
  • Ole_Alloc (OLE API, например SysAllocString).

Низкое моделирование ресурсов (также известное как внедрение ошибок) пытается имитировать среду под низкими ресурсами, например из памяти. Это позволит определить ошибку в условиях низкой памяти.

Свойства моделирования низких ресурсов

Чтобы изменить свойства, проверка поле проверка "Моделирование низких ресурсов" в области "Тесты", щелкните правой кнопкой мыши и выберите свойства:

Свойство Description
Включение Ограничение ошибок происходит только в указанных библиотеках DLL. Одно имя библиотеки DLL без пути для каждой строки. Если задано значение "*", ошибки будут возникать для всех модулей.
Исключить Исключите ошибки для указанных модулей. Одно имя библиотеки DLL без пути для каждой строки.
Время ожидания Предоставьте интервал времени (в миллисекундах) при отсутствии сбоя при инициализации процесса.
Wait Число [0 – 10000000], указывающее вероятность сбоя ДЛЯ API WaitForXXXXX.
Heap_Alloc Число [0 – 10000000], указывающее вероятность сбоя для API распределения кучи.
Virtual_Alloc Число [0 – 1000000], указывающее вероятность сбоя для API выделения виртуальной памяти.
Реестр Число [0 – 10000000], указывающее вероятность сбоя ДЛЯ API реестра.
Файлы Число [0 –1000000], указывающее вероятность сбоя ДЛЯ API файлов, таких как CreateFile.
Мероприятие Число [0 – 10000000], указывающее вероятность сбоя для API событий, например CreateEvent
MapView Число [0 – 10000000], указывающее вероятность сбоя ДЛЯ API MapView, например CreateMapView.
Ole_Alloc Число [0 – 1000000], указывающее вероятность сбоя для OLE API, например SysAllocString.
Стеки Каждый поток приложения Windows начинается с резервирования стека и размера фиксации стека. При обычном использовании фиксация стека растет всякий раз, когда требуется больше места в стеке. Дополнительные сведения см. в статье "Создание потоков и размер стека потоков". Если в системе возникают проблемы с низкой памятью, рост фиксации стека может завершиться ошибкой. Поток, который не может расти его стек, и все приложение, скорее всего, завершится сбоем. Такой сбой неприемлем для важных системных процессов (например, для служб). Стеки проверка отключают любой рост стека для проверяемого приложения, чтобы он имитировал сбои роста стека без необходимости имитировать все условия низкой памяти системы. Исключения будут возникать при попытке приложения развернуть стек. Никакие остановки проверки не создаются этим.

LuaPriv

Тесты с ограниченными привилегиями учетной записи пользователей (LuaPriv) — это прогнозный и диагностический, и работа над проблемами, связанными с запуском приложения с правами администратора, а также о том, будет ли это приложение работать с меньшими привилегиями (как правило, как обычный пользователь).

Также известный как UAC проверка, прогнозирование привилегий учетной записи ограниченного пользователя (LuaPriv) имеет две основные цели:

  • Прогнозный: при запуске приложения с правами администратора прогнозируйте, будет ли это приложение работать так же, если выполняться с меньшими привилегиями (как правило, как обычный пользователь). Например, если приложение записывает в файлы, которые разрешают доступ только Администратор istrator, то это приложение не сможет записывать в тот же файл, если выполняется как неадминистратор.

  • Диагностика. При выполнении с правами неадминистратора определите потенциальные проблемы, которые уже могут существовать с текущим запуском. Продолжая предыдущий пример, если приложение пытается записать в файл, предоставляющий доступ только к членам группы Администратор istrator, приложение получит ошибку ACCESS_DENIED. Если приложение работает неправильно, эта операция может быть виновником.

LuaPriv определяет следующие типы проблем:

Потенциальная проблема Description
Ограниченные пространства имен Создание именованного объекта синхронизации (Event, Semaphore, Mutex и т. д.) без пространства имен может усложнить выполнение без привилегий в некоторых операционных системах, так как операционная система может выбрать размещение объекта в ограниченном пространстве имен. Для создания такого объекта в ограниченном пространстве имен (например, в глобальном пространстве имен) требуется SeCreateGlobalPrivilege, который предоставляется только администраторам.
LuaPriv флаги обоих этих проблем, если он обнаруживает их.
Жесткие проверки Администратор istrator Некоторые приложения допросят маркер безопасности пользователя, чтобы узнать, сколько привилегий у него есть. В таких случаях приложение может изменить его поведение в зависимости от того, сколько мощности он думает, что у пользователя.
Вызовы API LuaPriv, возвращающие эти сведения.
Запрос привилегий Приложение может попытаться включить привилегию, относящуюся к безопасности (например, SeTcbPrivilege или SeSecurityPrivilege) перед выполнением операции, требующей ее.
Флаги LuaPriv пытаются включить привилегии, относящиеся к безопасности.
Отсутствующие привилегии Если приложение пытается включить привилегию, у которой у пользователя нет, он, вероятно, сигнализирует о том, что приложение ожидает привилегии, что может вызвать различия в поведении.
Флаги LuaPriv завершили сбой запросов привилегий.
Операции INI-File Попытки записи в сопоставленные файлы INI (WritePrivateProfileSection и аналогичные API) могут завершиться ошибкой в качестве пользователя, не являющегося администратором.
LuaPriv флаги таких операций.
доступ запрещен Если приложение пытается получить доступ к объекту (файл, раздел реестра и т. д.), но попытка завершается ошибкой из-за недостаточного доступа, приложение, вероятно, ожидает, что работает с более привилегированными правами, чем у него есть.
LuaPriv помечает попытки открытия объекта, которые завершаются ошибкой с ACCESS_DENIED и аналогичными ошибками.
Запретить доступ к aces Если в daCL объекта есть запретить доступ к определенным сущностям, он явно запрещает доступ к определенным сущностям.
Это редко, и делает прогноз трудным, поэтому LuaPriv флаги запретить acEs при их обнаружении.
Доступ ограничен Если приложение пытается открыть объект для прав, которые не предоставляются обычным пользователям (например, пытается записать в файл, доступный только администраторам), приложение, вероятно, не будет работать так же, как и при выполнении обычного пользователя.
LuaPriv флаги таких операций.
MAXIMUM_ALLOWED Если приложение открывает объект для MAXIMUM_ALLOWED, фактический проверка доступа к объекту будет происходить в другом месте. Большинство кода, который делает это не работает правильно, и почти наверняка будет работать по-разному при выполнении без привилегий.
LuaPriv таким образом помечает все инциденты MAXIMUM_ALLOWED.

Разное

Часто пропущенные проблемы фиксируются в других тестах.

  • Опасные API— отслеживает, использует ли приложение следующие небезопасные действия:
    • Опасный вызов TerminateThread.
    • Потенциальный переполнение стека в условиях низкой памяти.
    • Процесс выхода вызывается во время выполнения нескольких потоков.
    • LoadLibrary вызывается во время DllMain.
    • FreeLibrary вызывается во время DllMain.
  • Грязные стеки заполняются (периодически) неиспользуемой частью стека с шаблоном памяти. Это может помочь обнаружить неинициализированные переменные в будущих вызовах функций в контексте этого потока.
  • TimeRollOver заставляет API GetTickCount и TimeGetTime выполнять переключение быстрее, чем обычно. Это позволяет приложениям легко тестировать обработку времени отката времени.

Прочие свойства

Опасные API проверка имеют одно свойство, которое можно изменить:

DllMainCheck — проверка вызова LoadLibrary/FreeLibrary при активной активности DllMain.

Сеть

Сетевые тесты ищут неправильное использование API WinSock. Например, если сетевой API вызывается до успешного вызова WSAStartup() или после успешного вызова WSACleanup(). Дополнительные сведения о WinSock см. в заголовке winsock.h и сокетах Windows 2.

Свойства

Следующие свойства доступны для уровня проверки Net. Чтобы задать свойства, выберите поставщика сетей в пользовательском интерфейсе средства проверки приложений и откройте окно свойств.

Свойство Description
ФрагментыEnabled Позволяет фрагментировать потоки данных, полученные сокетами TCP IPv4 и IPv6.
Фрагментизация Указывает максимальное количество байтов, возвращаемых в буфер для любого вызова API приема Winsock.

Свойство FragmentsEnabled позволяет использовать функциональные возможности в поставщике средства проверки сети для упрощения тестирования и проверки потоков TCP для анализа TCP-потоков приложения из сети. После включения все вызовы Winsock для получения данных будут получать только до байтов FragmentSize, если приложению не требуется весь буфер, заполненный перед возвратом (контролируемым флагом MSG_WAITALL). Так как ни протокол TCP, ни Winsock не предоставляют никаких гарантий о количестве байтов, возможно, возвращенных в буфер, что позволяет этому проверка упростить проверку правильности анализа потока данных из сети независимо от количества байтов, полученных для каждого вызова Winsock. Проблемы синтаксического анализа потоков были источником громких ошибок, и эти свойства предоставляются для упрощения проверки правильности, так как это особенно трудно проверить. Примечание. Это не изменяет возвращаемые данные— это только замедляется с определенной скоростью: приложение должно вести себя точно так же, как и с включенным или отключенным.

Следующая командная строка позволяет фрагментировать все входящие потоки TCP ко всем сокетам TCP IPv4 и IPv6, созданным в myApp.exe, и всем двоичным файлам, загруженным myApp.exe.

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

Расширение отладчика !avrf

!avrf -net -socket count — отображает количество открытых и закрытых дескрипторов сокета

!avrf -net -socket dump [-v] [HANDLE] — отображает дескриптор сокета, подробно или нет.

!avrf -net -wsastacks — отображает текущий список инициализации WSA и хронологический список трассировок стека для WSAStartup/WSACleanup.

!avrf -net -wsastacks count — отображает текущее число инициализации WSA.

!avrf -net -socket count — Эта команда даст общее количество дескрипторов сокетов, отслеживаемых как открытых, так и закрытых. Обратите внимание, что они отслеживаются в циклической очереди, поэтому есть потолок к общему объему отслеживания. Сокеты добавляются в открытый список, когда вызывается один из API Winsock, который выделяет дескриптор сокета. Например, socket(), WSASocket(), accept(). Сокеты перемещаются из открытого списка в закрытый список при вызове функции closesocket() в этот дескриптор сокета.

!avrf -net -socket dump [-v] [HANDLE] — Эта команда перечисляет дескриптор сокета. "Дамп сокета" выводит список всех отслеживаемых и закрытых дескрипторов сокета по их значениям SOCKET. Необязательный флаг -v дополнительно выводит открытый или закрывающий стек вызовов сразу после печати каждого значения SOCKET. Необязательное поле HANDLE будет содержать только указанный дескриптор 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 требует от разработчиков приложений вызывать WSAStartup() по крайней мере один раз перед выполнением вызовов Winsock. Это отслеживается процессом Winsock по всему процессу. Начальное число ссылок указывает библиотеке Winsock (ws2_32.dll) инициализировать и загрузить каталог и поставщики Winsock. Дальнейшие вызовы К WSAStartup увеличивает количество ссылок. Winsock также требует от разработчиков приложений вызывать WSACleanup() после завершения вызова в Winsock. Вызовы WSACleanup должны быть связаны правильно с предыдущим вызовом WSAStartup(). Вызов WSACleanup() уменьшает число ссылок на уровне процесса. Когда количество ссылок падает до нуля, Winsock освобождает свои ресурсы и выгружает каталог и поставщики Winsock.

Эта команда предоставит общее значение счетчика ссылок текущей подпрограммы инициализации WSAStartup и выводит стеки вызовов для вызовов WSAStartup и WSACleanup, сделанных в процессе. Обратите внимание, что это поддерживается в фиксированной циклической очереди, поэтому она не гарантируется завершением — только последние вызовы N.

Ниже приведен пример различных вариантов использования 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

Этот подключаемый модуль проверки приложений отслеживает вызовы отдельного процесса к API проверки подлинности AcquireCredentialsHandle и InitializeSecurityContext для обнаружения использования протокола NTLM. NTLM — это устаревший протокол проверки подлинности с недостатками, которые потенциально компрометирует безопасность приложений и операционной системы и не должны использоваться.

Риск проверки подлинности NTLM

Наиболее важным недостатком устаревшего протокола проверки подлинности NTLM является отсутствие проверки подлинности сервера, что может позволить злоумышленнику обмануть пользователей подключаться к спуфингому серверу. Как совместное использование проверки подлинности сервера, приложения, использующие NTLM, также могут быть уязвимы к типу атаки, известной как "отражение". Это позволяет злоумышленнику перехватывать беседу проверки подлинности пользователя на законный сервер и использовать его для проверки подлинности злоумышленника на компьютере пользователя. Уязвимости NTLM и способы их использования являются целью повышения исследовательской деятельности в сообществе безопасности.

Хотя Kerberos уже много лет доступен, многие приложения по-прежнему записываются только для использования NTLM. Это не обязательно снижает безопасность приложений. Kerberos не может заменить NTLM во всех сценариях— в основном те, где клиент должен пройти проверку подлинности в системах, которые не присоединены к домену (домашняя сеть, возможно, наиболее распространенная из них). Пакет безопасности "Согласование" позволяет компрометации, совместимой с обратной совместимостью, которая использует Kerberos каждый раз, когда это возможно, и только отменить изменения в NTLM, если нет другого варианта. Переключение кода на использование "Согласование" вместо NTLM значительно повышает безопасность для наших клиентов при внедрении нескольких или отсутствие совместимости приложений. Переговоры сами по себе не серебряный маркер - есть случаи, когда злоумышленник может принудительно снизить уровень ДО NTLM, но это значительно сложнее использовать. Однако одним из непосредственных улучшений является то, что приложения, написанные для правильного использования ведения переговоров, автоматически защищены от атак отражения NTLM.

В последнем слове предостережения против использования NTLM: в Windows можно отключить использование NTLM на уровне операционной системы. Если приложения имеют жесткую зависимость от NTLM, они просто не смогут пройти проверку подлинности при отключении NTLM.

Какие факторы приводят к тому, что NTLM будет "жестко закодирован" в приложении?

Существует два фактора, которые вызывают жесткую зависимость от NTLM. Первое — явно выбрать NTLM в качестве пакета проверки подлинности, который будет использоваться приложением. Для некоторых протоколов и API выбор NTLM очевиден, например при вызове API AcquireCredentialsHandle (). Для других протоколов это может быть не так очевидно. Например, пакет проверки подлинности по умолчанию RPC (RPC_C_AUTHN_DEFAULT) фактически является псевдонимом NTLM, если RPC используется по сети, и даже явный флаг для выбора NTLM не имеет аббревиации NTLM в любом месте (RPC_C_AUTH_WINNT). Такой вид конструкции упрощает выбор NTLM, не обязательно зная, что вы сделали это.

Вместо NTLM разработчики должны использовать другие методы проверки подлинности, например пакет "Согласование" (иногда это также называется пакетом SPNEGO или SNEGO). Выбор пакета должен соответствовать как на клиентских, так и на серверных компонентах, чтобы переговоры могли пытаться использовать Kerberos, поэтому как клиентские, так и серверные части приложения должны использовать "Согласование". Если обе стороны используют NTLM (как это может быть в случае с устаревшими версиями) Согласование по-прежнему будет работать, но всегда будет отменить изменения NTLM. Как сообщить приложению, что использовать согласование зависит от протокола. Некоторые из наиболее распространенных протоколов (RPC, LDAP, DCOM, HTTP) подробно рассматриваются далее в разделе 5000 . Приложение явно выбрало пакет NTLM.

Второй фактор, который приводит к использованию NTLM, заключается в том, что клиент не предоставляет допустимое имя целевого сервера процессу проверки подлинности. В протоколах, которые поддерживают или требуют взаимной проверки подлинности (например, Kerberos), целевое имя используется для обеспечения взаимной проверки подлинности. API проверки подлинности (например, InitializeSecurityContext) принимают необязательный параметр, обычно называемый как TargetName, PrincipalName или ServerPrincipalName. Это идентификатор, используемый контроллерами домена для выбора правильной учетной записи домена для получения учетных данных для целевой службы. Так как NTLM не имеет концепции проверки подлинности сервера, этот параметр не требуется для успешной проверки подлинности NTLM. С другой стороны, Kerberos требует, чтобы клиент получил билет на обслуживание, действительный для службы, в которую клиент выполняет проверку подлинности. Проверка подлинности Kerberos всегда завершается ошибкой, если целевое имя не указано или недопустимое целевое имя. Если согласование выбрано в качестве пакета, предоставление целевого имени (или недопустимое целевое имя) приведет к тому, что Kerberos будет пропускаться полностью, а NTLM будет использоваться. Большинство API проверки подлинности имеют целевое имя в качестве необязательного параметра, если значение NULL без ошибки. Если разработчик не переопределяет это и предоставляет явное целевое имя, NTLM (и более того, отражает NTLM) является результатом.

Как работает подключаемый модуль NTLM

Подключаемый модуль проверки обнаруживает следующие ошибки:

  • Пакет NTLM напрямую указывается в вызове AcquireCredentialsHandle (или API оболочки более высокого уровня).

  • Целевое имя в вызове InitializeSecurityContext равно NULL. В этом случае переговоры возвращаются к NTLM напрямую.

  • Целевое имя в вызове InitializeSecurityContext не является должным образом сформированным доменным именем субъекта-службы, имени участника-пользователя или NetBIOS. В этом случае контроллер домена возвращает ошибку "субъект не найден", которая приводит к тому, что согласование возвращается к NTLM.

Подключаемый модуль также регистрирует предупреждения при обнаружении понижения до NTLM; Например, если имя субъекта-службы не найдено контроллером домена. Они регистрируются только как предупреждения, так как они часто являются законными случаями, например при проверке подлинности в системе, которая не присоединена к домену.

Настройка параметров остановки подключаемого модуля

По умолчанию все события, классифицированные как "Ошибка", задаются для прерывания отладки. Все события предупреждения задаются только для регистрации сведений о событии.

События ошибок вызывают остановку или разрыв:

  • 5000 — приложение явно выбрало пакет NTLM

  • 5001 — список пакетов "Согласование" включает только NTLM

  • 5002 — согласование списка пакетов неправильное исключение NTLM

  • 5003 — целевое имя или неправильно сформированное целевое имя сервера

События предупреждения регистрируются:

  • 5010 — понижение до обнаруженного NTLM

Остановки NTLM

5000 — приложение явно выбрало пакет NTLM

Серьезность — ошибка

Приложение или подсистема явно выбирает NTLM вместо "Согласование" в вызове AcquireCredentialsHandle. Несмотря на то, что клиент и сервер могут пройти проверку подлинности с помощью Kerberos, это предотвращается явным выбором NTLM.

Исправление этой ошибки

Исправление этой ошибки заключается в выборе пакета "Согласование" вместо NTLM. Как это сделать, зависит от конкретной сетевой подсистемы, используемой клиентом или сервером. Несколько примеров приведено ниже. Обратитесь к документации по определенной библиотеке или набору API, который вы используете.

API(параметр) Используется приложением Неправильное значение Правильное значение Примечания.
AcquireCredentialsHandle (pszPackage) "NTLM" NEGOSSP_NAME или "Переговоры"
Клиент RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) RPC Server: RPCServerRegisterAuthInfo(AuthnSvc) RPC_C_AUTHN_WINNT или RPC_C_AUTH_DEFAULT RPC_C_AUTH_GSS_NEGOTIATE Это не ошибка для сервера RPC для регистрации пакета NTLM/WINNT. Это часто требуется для поддержки старых клиентов, которые поддерживают только NTLM. Это ошибка, если зарегистрирован только пакет NTLM, так как это заставляет всех клиентов использовать NTLM, даже если они способны использовать Kerberos.
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (передан как член dwAuthnSvc структуры COAUTHINFO, которая сама является членом структуры COSERVERINFO, переданной в API) RPC_C_AUTHN_WINNT RPC_C_AUTHN_DEFAULT или RPC_C_AUTHN_GSS_NEGOTIATE Согласование должно использоваться только в том случае, если связь всегда выполняется в сети. Если вызов DCOM когда-либо происходит между клиентом и сервером на одном компьютере, необходимо использовать DEFAULT и разрешить DCOM выбрать правильный пакет для использования.
LDAP: ldap_bind_s (метод) LDAP_AUTH_NTLM LDAP_AUTH_NEGOTIATE
HTTP WinHTTPSetCredentials (AuthScheme) WINHTTP_AUTH_SCHEME_NTLM WINHTTP_AUTH_SCHEME_NEGOTIATE

5001 — список пакетов "Согласование" включает только NTLM

Серьезность — ошибка

При использовании AcquireCredentialsHandle можно указать список пакетов, которые следует использовать или игнорировать с помощью переговоров. В зависимости от указанного списка это может переопределить логику, встроенную в "Согласование" для выбора наиболее подходящего и безопасного пакета проверки подлинности. Если список пакетов включает только NTLM или исключает Kerberos результат идентичен обходу переговоров полностью и явно выбирает пакет NTLM SSP напрямую.

Указание списка вложенных пакетов возможно только при вызове AcquireCredentialsHandle напрямую, так как большинство API более высокого уровня (например, RPC) не позволяют вызывающему объекту управлять списком пакетов "Согласование".

Корпорация Майкрософт не рекомендует, чтобы приложения пытались управлять списком пакетов "Согласование" таким образом.

Исправление этой ошибки

Используйте пакет "Согласование" без указания списка подпакетов или убедитесь, что Kerberos включен.

API(параметр) Используется приложением Неправильное значение Правильное значение
AcquireCredentialsHandle (член PackageList структуры SEC_WINNT_AUTH_IDENTITY_EX, переданной в качестве параметра pAuthData) "! Kerberos или NTLM NULL или Kerberos, NTLM или Kerberos, ! NTLM или "! NTLM"

5002 — согласование списка пакетов неправильное исключение NTLM

Серьезность — предупреждение

При вызове AcquireCredentialsHandle приложение попыталось исключить NTLM из списка пакетов, поддерживаемых согласованием. Однако неправильный синтаксис использовался для исключения NTLM, поэтому он остается в списке.

Как устранить эту ошибку, используйте следующий синтаксис, чтобы исключить пакет NTLM из "Согласование".

API(параметр) Используется приложением Неправильное значение Правильное значение
AcquireCredentialsHandle (член PackageList структуры SEC_WINNT_AUTH_IDENTITY_EX, переданной в качестве параметра pAuthData) "-NTLM" "! NTLM"

5003 — целевое имя или неправильно сформированное целевое имя сервера

Серьезность — ошибка

При использовании пакета "Согласование" при указании значения NULL или недопустимого целевого имени (иногда называемого главным именем) Kerberos завершится сбоем, и NTLM будет использоваться на его месте. При вызове проверки подлинности всегда следует указать допустимое целевое имя. Целевое имя — это уникальный идентификатор, позволяющий контроллеру домена получить сведения об учетной записи сервера, на который приложение пытается пройти проверку подлинности. После того как контроллер домена содержит эти сведения, он может создать соответствующие билеты Kerberos, которые будут поняты (расшифровываются) как клиентом, так и сервером.

Исправление этой ошибки

Целевые имена можно указать в трех разных форматах, каждый из которых может использоваться контроллерами домена для поиска правильного объекта учетной записи сервера. Эти форматы представляют собой имя субъекта-службы (SPN), имя участника-пользователя (UPN) и имя домена\учетной записи NetBIOS с двумя частью. Имя субъекта-службы — это наиболее распространенная форма и наиболее совместимая с другими реализациями Kerberos. Полное обсуждение имен субъектов-служб выходит за рамки область этого документа, но самая простая и наиболее распространенная форма субъекта-службы состоит из двух частей — класса службы и имени узла. Класс службы определяет тип серверного приложения (например, конкретный тип приложения, например http или ldap или как универсальный как узел). Вторая часть — полное доменное имя или неструктурированное (NetBIOS) имя сервера. Клиенты и серверы Windows автоматически регистрируют имена субъектов-служб для полного доменного имени и неструктурированных имен. Контроллеры домена также сопоставляют около 40 классов служб, относящихся к приложению, с идентификатором субъекта-службы узла для таких объектов, как http, ldap, rpc, tapi и т. д.

o укажите целевое имя для приложения, работающего в контексте серверной операционной системы (например, localsystem, сетевой службы или localservice), клиентские приложения могут использовать автоматически зарегистрированное имя субъекта-службы или одно из его псевдонимов. Чтобы выполнить проверку подлинности в приложении, работающем в контексте учетной записи пользователя домена, необходимо зарегистрировать имя субъекта-службы для этой учетной записи.

Для учетных записей пользователей можно также использовать неявную форму участника-пользователя, созданную из имени учетной записи пользователя и домена, в котором находится учетная запись: useraccountname@domain.dom Хотя вы можете создать дополнительные имена участника-пользователя для учетной записи пользователя (с помощью суффиксов имени участника-пользователя, которые можно создать для каждого домена), они не будут работать как целевые имена Kerberos — только имя участника-пользователя, соответствующее фактическому имени учетной записи входа и фактическому домену, в котором может использоваться учетная запись.

Наконец, вы по-прежнему можете использовать домен nt4-style\username (или domain\computername в случае служб, работающих как localsystem, networkservice или localservice). Это работает для целевых объектов, работающих в контексте учетной записи пользователя домена или учетных записей компьютера.

API(параметр) Используется приложением Параметр для задания целевого имени Примечания.
InitializeSecurityContext pszTargetName
Клиент RPC: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) ServerPrincipalName Это должно быть целевое имя учетной записи, в которой выполняется сервер или служба. Он не должен совпадать со значением, заданным в RPCServerRegisterAuthInfo.
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (передан как член dwAuthnSvc структуры COAUTHINFO, которая сама является членом структуры COSERVERINFO, переданной в API) pServerPrincName Может использовать COLE_DEFAULT_PRINCIPAL для автоматического выбора имени COM из сведений о привязке
LDAP: нет Автоматически создается клиентом LDAP.
HTTP нет WinHTTP и WinInet предоставляют целевое имя из имени URL-сервера.

5010 — понижение до обнаруженного NTLM

Серьезность — предупреждение

Несмотря на то, что конкретное приложение "Согласование" и использовало правильно отформатированное целевое имя, что-то произошло, чтобы привести к понижению уровня "Согласование" до NTLM. В зависимости от того, какие обстоятельства были это, может указывать на ошибку или ожидаемое поведение. Например, если компьютер не является частью домена или используется в расположении, где контроллер домена недоступен, ожидается, что согласование будет автоматически понижено, чтобы позволить приложению проходить проверку подлинности с помощью NTLM. Однако если эта остановка возникает, когда контроллер домена доступен, и обычно предполагается, что Kerberos будет использоваться почти наверняка, указывает на то, что что-то не так.

Как исправить эту ошибку

Предположим, что вы определили, что Kerberos должны были использоваться, а не NTLM в этом обстоятельстве, существует ряд возможностей, почему произошло понижение уровня:

• Целевое имя, даже если оно могло быть в правильном формате, не существовало в домене (или лесу).

o Следует проверка, что вы создаете правильное целевое имя в клиентском приложении. Правильно ли класс службы? Правильно ли имя узла?

o Серверный процесс, выполняемый в контексте компьютера или другой учетной записи домена. В предыдущем случае имена субъектов-служб регистрируются автоматически, в последнем случае может потребоваться зарегистрировать имя участника-службы или использовать альтернативную форму, например неявное имя участника-пользователя или неструктурированное имя.

Может возникнуть проблема с сетевым подключением, предотвращающим связь с контроллером домена или DNS-сервером?

o Зарегистрировано ли целевое имя субъекта-службы в нескольких учетных записях? Это приведет к отклонению попыток проверки подлинности контроллера домена.

Печать

Средство проверки печати помогает найти и устранить неполадки, которые могут привести к вызову подсистемы печати приложения. Средство проверки печати предназначено для двух слоев подсистемы печати, слоя PrintAPI и слоя PrintDriver.

Печать уровня API

Средство проверки печати проверяет интерфейс между программой и Winspool.drv и prntvpt.dll и проверяет интерфейсы этих библиотек DLL. Правила вызова функций в этом интерфейсе можно просмотреть в разделе справки MSDN для API, экспортированных winspool.drv и prntvpt.dll.

Уровень драйвера печати

Средство проверки печати также проверяет интерфейс между основным драйвером печати, например UNIDRV.DLL, UNIDRUI.DLL, PSCRIPT5.DLL, PS5UI.DLL или MXDWDRV.DLL, а также подключаемыми модулями драйвера печати. Сведения об этом интерфейсе можно найти в MSDN и WDK.

Как правило, только отладочные версии запускают средство проверки приложений, поэтому производительность обычно не является проблемой. Если проблемы с производительностью возникают из-за использования этого или любого другого проверка проверки приложений, запустите один проверка за раз, пока не выполнили все необходимые проверка.

Веб-службы

Уровень проверки API веб-служб Windows (WWSAPI)

Подключаемый модуль WWSAPI позволяет разработчикам перехватывать экземпляры:

  • Вызывается WWSAPI, который ссылается на недопустимый встроенный объект WWSAPI.

  • Вызывается WWSAPI, который ссылается на один потоковый объект, который уже используется.

  • Встроенный объект, освобожденный с асинхронным вызовом.

  • Вызов api-интерфейсов блокировки из коротких потоков.

Кроме того, этот подключаемый модуль:

  • Отслеживает использование объектов из экземпляра для удаления.

  • Принудительное выполнение вызовов, которые можно выполнить асинхронно для выполнения синхронно. Это позволяет запретить приложениям в зависимости от конкретного поведения вызова WS_ASYNC_CONTEXT.

  • Предоставляет удобочитаемое описание api при передаче плохого объекта или объект используется с помощью расширения отладчика !avrf –ws –obj отладчик (показан ниже).

  • Для канала, прокси-сервера службы и узла службы каждый вызов, отслеживаемый, будет отображать текущее состояние объекта.

По умолчанию включены следующие проверка серы:

Свойство NameDescriptionValidateObjectValidates, что встроенный объект является допустимымTrackObjectTracks, используемым объектом через его время существования

Другие проверка пользователи, которые можно включить в этом поставщике с помощью пользовательского интерфейса свойств:

Свойство NameDescriptionCheckTimeoutValidates, которое асинхронные функции выполняются в течение времени ожидания, указанного как TimeoutValForceSyncForce, путь синхронизации, который необходимо выполнить, когда контекст WS_ASYNC_CONTEXT предоставляется API.

Предоставляется расширение отладчика (!avrf –ws –obj), отображающее открытые и закрытые встроенные объекты WWSAPI. Если это расширение суффиксировано объектом, оно будет отображать подробные сведения об использовании этого объекта.

!avrf -ws –obj

Эта команда отображает встроенные объекты WWSAPI, отслеживаемые как созданные, так и закрытые. Обратите внимание, что закрытые объекты хранятся в циклической очереди, поэтому существует потолок общего количества отслеживаемых объектов.

Объекты добавляются, когда следующие API успешно завершены: WsCreateChannel(), WsCreateChannelForListener(), WsCreateServiceHost(), WsCreateServiceProxy(), WsCreateServiceProxyFromTemplate(), WsCreateError(), WsCreateHeap(), WsCreateHeap(), WsCreateListListener(), WsCreateMetadata(), WsCreateMessage(), WsCreateMessageForChannel(), WsCreateReader(), WsCreateWriter(), WsCreateXmlBuffer(), WsReadXmlBuffer(), WsReadXmlBufferFromBytes()

Объекты перемещаются из созданного в освобожденный список при вызове и завершении соответствующей функции WsFree*().

!avrf –ws –obj [OBJECT]

Эта команда отображает использование встроенного объекта WWSAPI. Сведения об использовании включают стек при создании, использовании и освобождении объекта. Если объект является каналом, узлом службы или прокси-сервером службы, он отобразит состояние объекта до API, используя объект.

Ниже приведен пример параметров использования !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>

Службы

Тесты служб проверка для правильного использования служб Windows. Например, запущены и остановлены службы должным образом. Сведения об исключениях кода остановки, созданных этими тестами, см. в разделе "Проверка приложений" — "Коды остановки — службы".

Производительность

Тесты Perf проверка для эффективного использования API, влияющих на производительность системы и потребление энергии, например вызов функции Windows, использующую неправильный период ожидания. Сведения об исключениях кода остановки, созданных этими тестами, см. в разделе "Проверка приложений" — "Стоп-коды" — Perf.

Зависает

Тесты Зависания для использования API, которые приводят к тому, что система не отвечает, например, когда поток DllMain ожидает другого потока, который был заблокирован. Сведения об исключениях кода остановки, созданных этими тестами, см. в разделе "Проверка приложений" — "Остановочные коды" — зависания.

поддержка ARM64EC

Следующие поставщики не поддерживают ARM64EC и поэтому завершатся сбоем программы, работающей в ARM64EC:

См. также

Средство проверки приложений — обзор

Средство проверки приложений — функции

Средство проверки приложений — тестирование приложений

Средство проверки приложений — остановки кодов и определений

Средство проверки приложений— останавливается средство проверки приложений отладки

Средство проверки приложений — часто задаваемые вопросы