Это не новый механизм, опишу использование верификатора. Это второе из средств диагностики, наряду с логгером поддерживаемое нэйтивом. Первое средство это логгер, выполняющий логгирование событий и ошибок в загрузчике(переменные ShowSnaps и ShowErrors загружаемые из ключа "Image File Execution Options", "GlobalFlag"). Принцип прост - загружается провайдер в виде модуля, он определяет список апи и передаёт его менеджеру. Тот выполняет патч IAT, перенаправляя ссылки в провайдер. Далее он анализирует неполадки в этих апи и ведёт лог, обычно просто отладочный вывод. Также провайдер может устанавливать калбэки на загрузку и выгрузку модулей. У InitRoutine() модулей причин вызова 5, последняя DLL_PROCESS_VERIFIER и есть загрузка/инициализация провайдера. Она вызывается ранее чем DLL_PROCESS_ATTACH каких либо модулей, так как менеджер должен ранее всех выполнить патч и мониторить все функции. Пользовательский провайдер загружается вторым, первым подгружается системный verifier.dll Менеджер реализован в виде не экспортируемых функций имеющих префикс AVrf. Отладочный вывод имеет префикс "AVRF: ". Провайдер может быть загружен динамически приложением посредством вызова AVrfInitializeVerifier()(первый считывает список провайдеров и параметры, второй вызов загружает и инициализирует их). В начале следует разрешить использование верификации. Это определяет один из флагов в "GlobalFlag", FLG_APPLICATION_VERIFIER(0x00000100). Параметр "VerifierDlls" это список имён провайдеров, они должны распологаться в системном каталоге. "VerifierFlags"(RTL_VRF_FLG_*) и "VerifierDebug" это конфиг и является набором флагов(загружается в переменные AVrfpVerifierFlags и AVrfpDebug соответственно). Когда прилодение запускается, менеджер определяет зарегистрирован ли для него провайдер. Если он есть, выполняется его загрузка и вызов с причиной DLL_PROCESS_VERIFIER(4). При этом в InitRoutine() передаётся ссылка на переменную, в которую провайдер(тоесть наш модуль) должен вернуть ссылку на дескриптор, описывающий список перехватываемых функций. Дескриптор является структурой RTL_VERIFIER_PROVIDER_DESCRIPTOR: Код (Text): RTL_VERIFIER_PROVIDER_DESCRIPTOR struct ; Заполняет провайдер. _Length ULONG ? ProviderDlls PRTL_VERIFIER_DLL_DESCRIPTOR ? ProviderDllLoadCallback PVOID ? ProviderDllUnloadCallback PVOID ? ; Заполняет менеджер. VerifierImage PWSTR ? VerifierFlags ULONG ? ; <- AVrfpVerifierFlags VerifierDebug ULONG ? ; <- AVrfpDebug RTL_VERIFIER_PROVIDER_DESCRIPTOR ends где Length - размер этой структуры, в XP равен 0x1C. ProviderDllLoadCallback и ProviderDllUnloadCallback - опциональные нотификаторы, вызываемые при загрузке/выгрузке модулей: Код (Text): typedef VOID (NTAPI * RTL_VERIFIER_DLL_LOAD_CALLBACK) ( PWSTR DllName, PVOID DllBase, SIZE_T DllSize, PVOID Reserved ); typedef VOID (NTAPI * RTL_VERIFIER_DLL_UNLOAD_CALLBACK) ( PWSTR DllName, PVOID DllBase, SIZE_T DllSize, PVOID Reserved ); Они вызываются из LdrpWalkImportDescriptor()(AVrfDllLoadNotification() и AVrfDllUnloadNotification()). ProviderDlls - ссылка на массив(конец списка завершается нулём) структур RTL_VERIFIER_DLL_DESCRIPTOR, описывающих модуля подлежащие патчу: Код (Text): RTL_VERIFIER_DLL_DESCRIPTOR struct DllName PWCHAR ? DllFlags ULONG ? ; Должно быть 1. DllAddress PVOID ? DllThunks PRTL_VERIFIER_THUNK_DESCRIPTOR ? RTL_VERIFIER_DLL_DESCRIPTOR ends где DllName - ссылка на имя модуля в юникоде. DllThunks - ссылка на массив(нулём завершается) структур RTL_VERIFIER_THUNK_DESCRIPTOR, описывающую функции, подлежащие патчу: Код (Text): RTL_VERIFIER_THUNK_DESCRIPTOR struct ThunkName PSTR ? ThunkOldAddress PVOID ? ThunkNewAddress PVOID ? RTL_VERIFIER_THUNK_DESCRIPTOR ends где ThunkName - ссылка на имя экспорта. ThunkNewAddress - указатель на новый обработчик, ThunkOldAddress - соответственно предыдущий(загружается менеджером). Остальные поля RTL_VERIFIER_PROVIDER_DESCRIPTOR структуры заполняет менеджер, загружая туда имя экзешника и конфиг(AVrfpVerifierFlags и AVrfpDebug соответственно). Список провайдеров находится в переменной AVrfpVerifierProvidersList и является началом двусвязанного списка. Таким образом провайдер заполняет эти структуры и возвращает их, далее менеджер перечисляет модуля(RTL_VERIFIER_DLL_DESCRIPTOR) и функции(RTL_VERIFIER_THUNK_DESCRIPTOR), выполняя их патч. Флажки: Код (Text): RTL_VRF_FLG_FULL_PAGE_HEAP equ 00000001H RTL_VRF_FLG_RESERVED_DONOTUSE equ 00000002H ; old RTL_VRF_FLG_LOCK_CHECKS RTL_VRF_FLG_HANDLE_CHECKS equ 00000004H RTL_VRF_FLG_STACK_CHECKS equ 00000008H RTL_VRF_FLG_APPCOMPAT_CHECKS equ 00000010H RTL_VRF_FLG_TLS_CHECKS equ 00000020H RTL_VRF_FLG_DIRTY_STACKS equ 00000040H RTL_VRF_FLG_RPC_CHECKS equ 00000080H RTL_VRF_FLG_COM_CHECKS equ 00000100H RTL_VRF_FLG_DANGEROUS_APIS equ 00000200H RTL_VRF_FLG_RACE_CHECKS equ 00000400H RTL_VRF_FLG_DEADLOCK_CHECKS equ 00000800H RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS equ 00001000H RTL_VRF_FLG_VIRTUAL_MEM_CHECKS equ 00002000H RTL_VRF_FLG_ENABLE_LOGGING equ 00004000H RTL_VRF_FLG_FAST_FILL_HEAP equ 00008000H RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING equ 00010000H RTL_VRF_FLG_ENABLED_SYSTEM_WIDE equ 00020000H RTL_VRF_FLG_MISCELLANEOUS_CHECKS equ 00020000H RTL_VRF_FLG_LOCK_CHECKS equ 00040000H
green Ога, особенно для тех кто древние патчи в IAT использует для всяко перехватов. Жаль что некому больше не интересно ничего
копал такое когда-то. itw вообще мало кастомного как бы. всё стандартно. Когда кто-нибудь преподносит нетривиальное решения, это считается откровением. Та же загрузка dll'ки через провайдер принтера.
Зря так считаете, просто слишком много недокументированных вещей описываете, человеку с квалификацией ниже вашей в этом материале разобраться очень не просто.
Clerk Я иногда для мониторинга API использую WinDbg Logger extension. Тоже довольно мощная вещь, позволяет описывать свои прототипы API. Но logger что-то работал у меня нестабильно и пару раз здорово подвёл при отладке. Правда, 3-ю версию, что в последних тулзах, я ещё не пробовал.
Встречал мнение, что первый нашел "особенность" верифера он, http://kitrap08.blogspot.ru/2011/04/application-verifier.html
yashechka Им бессмысленно писать по описанной вами причине. Один не ответит, второй наматает лапши на мозг. Тоесть я же пробовал.
Апну тему. Таки да инде был первым, но как всегда теория. Про это кстати даже ионеску написал, почему вообще такой хайп непонятно... Пиар. Теперь к делу) У данной методиги есть пару ньюансов, перед тем как кто-то захочет заюзать it the wild так сказать, надо о них упомянуть. Во-первых, дллка (кастомный варифер) должен лежать в систем32 либо вов либо в путях (тут не проверял, но это былоб логично). Те можно вколотить в реестр путь до своей дллине например в темпах, но это не будет рабатать. Если глянуть под виндбг, то там стопнеться на int 3 c криком, что ZEROED_STACK что-то там. Предпалагаю, что длинна пути критична - тут не ресечил точно. Во-вторых, будут ВСЕ время остановы с бредовыми выводами. Если их скипать, то все воркает (это я про дебаг под windbg). Но этоможно разрулить и даже про это написано в бложике чувака из ссылок выше в треде. Там идея простая - есть переменная (не экспортируемая из verifier.dll), если её поменять, то все будет норм. Прикол в том, что до этой переменной можно дотянуться из VerifierStopMessage и она на разных ос чуть разная. Например 7_64 Код (ASM): _VerifierStopMessage@40 proc near ; CODE XREF: AVrfpDphEnterHeapPath(x,x)+5Cp .text:1124B860 ; AVrfpDphPointerFromHandle(x)+B7p ... .text:1124B860 .text:1124B860 var_1C = dword ptr -1Ch .text:1124B860 var_18 = dword ptr -18h .text:1124B860 var_14 = dword ptr -14h .text:1124B860 var_10 = dword ptr -10h .text:1124B860 var_C = dword ptr -0Ch .text:1124B860 var_8 = dword ptr -8 .text:1124B860 var_4 = dword ptr -4 .text:1124B860 arg_0 = dword ptr 8 .text:1124B860 arg_4 = dword ptr 0Ch .text:1124B860 arg_8 = dword ptr 10h .text:1124B860 arg_C = dword ptr 14h .text:1124B860 arg_10 = dword ptr 18h .text:1124B860 arg_14 = dword ptr 1Ch .text:1124B860 arg_18 = dword ptr 20h .text:1124B860 arg_1C = dword ptr 24h .text:1124B860 arg_20 = dword ptr 28h .text:1124B860 arg_24 = dword ptr 2Ch .text:1124B860 .text:1124B860 mov edi, edi .text:1124B862 push ebp .text:1124B863 mov ebp, esp .text:1124B865 sub esp, 1Ch .text:1124B868 mov [ebp+var_1C], 0 .text:1124B86F mov [ebp+var_18], 0 .text:1124B876 mov [ebp+var_14], 0 .text:1124B87D mov [ebp+var_8], 0 .text:1124B884 cmp _AVrfpProcessBeingTerminated, 0 // <-- Вот эту переменную На 10_64 Код (ASM): _VerifierStopMessage@40 proc near ; CODE XREF: AVrfpDphEnterHeapPath(x,x)+5Fp .text:1000CAF0 ; AVrfpDphPointerFromHandle(x)+B7p ... .text:1000CAF0 .text:1000CAF0 var_24 = dword ptr -24h .text:1000CAF0 var_20 = dword ptr -20h .text:1000CAF0 var_1C = dword ptr -1Ch .text:1000CAF0 var_18 = dword ptr -18h .text:1000CAF0 var_14 = dword ptr -14h .text:1000CAF0 var_10 = dword ptr -10h .text:1000CAF0 var_C = dword ptr -0Ch .text:1000CAF0 var_8 = dword ptr -8 .text:1000CAF0 var_4 = dword ptr -4 .text:1000CAF0 arg_0 = dword ptr 8 .text:1000CAF0 arg_4 = dword ptr 0Ch .text:1000CAF0 arg_8 = dword ptr 10h .text:1000CAF0 arg_C = dword ptr 14h .text:1000CAF0 arg_10 = dword ptr 18h .text:1000CAF0 arg_14 = dword ptr 1Ch .text:1000CAF0 arg_18 = dword ptr 20h .text:1000CAF0 arg_1C = dword ptr 24h .text:1000CAF0 arg_20 = dword ptr 28h .text:1000CAF0 arg_24 = dword ptr 2Ch .text:1000CAF0 .text:1000CAF0 mov edi, edi .text:1000CAF2 push ebp .text:1000CAF3 mov ebp, esp .text:1000CAF5 sub esp, 24h .text:1000CAF8 mov eax, ___security_cookie .text:1000CAFD xor eax, ebp .text:1000CAFF mov [ebp+var_4], eax .text:1000CB02 mov [ebp+var_10], 0 .text:1000CB09 mov [ebp+var_18], 0 .text:1000CB10 mov [ebp+var_20], 0 .text:1000CB17 mov [ebp+var_C], 0 .text:1000CB1E cmp _RedirectedVerifierStopFunction, 0 .text:1000CB25 jz short loc_1000CB69 .text:1000CB27 mov eax, [ebp+arg_24] .text:1000CB2A push eax .text:1000CB2B mov ecx, [ebp+arg_20] .text:1000CB2E push ecx .text:1000CB2F mov edx, [ebp+arg_1C] .text:1000CB32 push edx .text:1000CB33 mov eax, [ebp+arg_18] .text:1000CB36 push eax .text:1000CB37 mov ecx, [ebp+arg_14] .text:1000CB3A push ecx .text:1000CB3B mov edx, [ebp+arg_10] .text:1000CB3E push edx .text:1000CB3F mov eax, [ebp+arg_C] .text:1000CB42 push eax .text:1000CB43 mov ecx, [ebp+arg_8] .text:1000CB46 push ecx .text:1000CB47 mov edx, [ebp+arg_4] .text:1000CB4A push edx .text:1000CB4B mov eax, [ebp+arg_0] .text:1000CB4E push eax .text:1000CB4F mov ecx, _RedirectedVerifierStopFunction .text:1000CB55 mov [ebp+var_14], ecx .text:1000CB58 mov ecx, [ebp+var_14] ; _DWORD .text:1000CB5B call ds:___guard_check_icall_fptr ; _guard_check_icall_nop(x) .text:1000CB61 call [ebp+var_14] .text:1000CB64 jmp loc_1000CE16 .text:1000CB69 ; --------------------------------------------------------------------------- .text:1000CB69 .text:1000CB69 loc_1000CB69: ; CODE XREF: VerifierStopMessage(x,x,x,x,x,x,x,x,x,x)+35j .text:1000CB69 cmp _AVrfpProcessBeingTerminated, 0 // <--- Теперь уже сдесь .text:1000CB70 jnz short loc_1000CB7B .text:1000CB72 cmp _AVrfpStopInitialized, 0 .text:1000CB79 jnz short loc_1000CB80 На 10 еще один if в начале добавился соответсвенно, кода стало больше. Так что тут как минимум надо еще писать код который будет бегать по верифаеру искать переменную и патчить её, чтоб воркало норм, а не утопало в бесконечном int 3 Ну это в кратце... Возможно что-то упустил/накосячил).
superakira Ионеску это для нас никто. Тоесть у этого человека нет своих работ, он никто(есть какой то примитив у него на гитхабе). Это коллектор инфы. То что он какое то уг разбирает - это делает каждый, кому данная тема интересна. Но он сказал что он автор данной инфы, тем самым облажался(не первый раз). > утопало в бесконечном int 3 Я уже и не помню всех нюансов, можно поднять старые темы и архивы, что бы разобраться. Было много кода по данной теме. Какой рип будет следующим, предполагаю что софтверные анклавы - моя парадигма. Но это не ионеску сделает, он не разрабатывает, он только реверсит и рипает.
Indy_, >Какой рип будет следующим, предполагаю что софтверные анклавы - моя парадигма. Но это не ионеску сделает, он не разрабатывает, он только реверсит и рипает. Не распарсил