Ага, ты и до NtGlobalFlag добрался А чего сам-то не проверишь ? Ежели там 70h стоит - флаги enable heap-checking в соответствии с учением Four-F, то ИМХО для приложения вроде бы ничего страшного быть не должно, а для отладчика - интересно, надо бы проверить ...
Можно смотреть по bp 7FFDF068 или bp RtlGetNtGlobalFlags, загрузчик этот флаг насилует во всю, а приложению, например простому (Hello World) оно не сдалось, а так (в VB\Delphi ...) чуть ли не каждая ф-ция в NT приводит к вызову RtlGetNtGlobalFlags, я думаю что на результат этих ф-ций влиять флаг не должен, только на "окружение" и вот если его обнулить, то отладчик например перестанет получать LDR строки
Тут практического исследования вряд ли достаточно, нужна теория. Я так понял что он и сейчас, т.е. при 0x70 не получает, нужно устанавливать в 0x72
Да, второй бит для этого, а 0x70 это вроде по умолчанию, но у каждого могут быть свои настройки (см. Gflags.exe)
Ну, чего не договариваем ? bogrus, ты же наверняка знаешь, что несмотря на большое число обращений к NtGlobalFlags реально интересные флажки 70h используются в одном определенном месте, а именно в RtlCreateHeap и попадают они именно в дворд по адресу ProcessHeap+10h со всеми вытекающими отсюда последствиями типа BAADF00D, ABABA.. и FEEE Кстати в XP SP2 флаги 70h трансформируются в ProcessHeap[10h] = 40000060h, а как в NT и w2k ?
Asterix > "нужна теория" Из теории мне известны две вещи: 1) Cогласно Four-F флаги 0х70 разрешают дополнительный контроль валидности операций с блоками кучи. 2) Известен механизм контроля валидности операций с блоками кучи в режиме отладки в NT-системах (см.например Using SoftIce). В частности для контроля записи за пределы выделенного размера HeapAlloc выделяет больше памяти чем запрашивается и дописывает в конец выделенного блока данных 8 байт хвостового маркера ABAB..ABh. Соответственно при освобождении блока HeapFree проверяет целостность этого маркера и в случае несовпадения сигнализирует отладчику (если таковой есть), вызывая DbgPrint и DbgBreakPoint (=int3). Если отладчика нет или он игнорирует int3 HeapFree возвращает false, устанавливает LastError (или генерит исключение если установлен флаг HEAP_GENERATE_EXCEPTIONS) и не освобождает блок. Для контроля записи в свободный блок HeapFree заполняет освободившееся место сигнатурой FEEEFEEE. Соответсвенно HeapAlloc\Realloc в режиме отладки проверяют не только валидность заголовка блока, но и указанной сигнатуры и при ее разрушении также сигнализируют отладчику. Вот теперь вопрос - как HeapAlloc и HeapFree определяют, что включен отладочный режим. "Практическое исследование" для winXP (SP2) показывает: 1) Несмотря на большое число вызовов RtlGetNtGlobalFlags в ntdll (около 30) обращение к флагам 0х70 осуществляется только в RtlCreateHeap. (Кстати бОльшая часть других вызовов идет в Heap-функциях на предмет проверки флага 0х800 - что это за флаг интересно знать ???) 2) В RtlCreateHeap часть флагов NtGlobalFlag OR-ятся с частью флагов Flags (флагами создания кучи) и копируются в дворд заголовка кучи по адресу Base+10h (для главной кучи Base = ProcessHeap). Соответсвенно без отладчика этот дворд обычно = 0, а с отладчиком <> 0 ("очередной" IsDebuggerPresent от bogrus'а). Флаги NtGlobalFlag копируются со смещением: х10 -> x20, x20 -> x40, x40 -> x40000000, x80 -> x20000000, x200000 -> x80. Соответсвенно флаги х70 превращаются в х40000060. 3) RtlAllocateHeap и RtlFreeHeap уже не проверяют флаги x70 NtGlobalFlag и работают только с флагами заголовка кучи dword[HeapBase+10h]. Эти флаги OR-ятся с флагами Flags, передаваемыми в качестве параметров в эти функции (!). В зависимости от того = 0 результирующие флаги или нет обработка идет по разным веткам - debugged или нет. 4) Тут вырисовывается интересная картина - получается что "отладочный режим" контроля блоков кучи (запись и контроль сигнатур) может быть не только глобальным (флаги [ProcessHeap+10h]), но и локальным для каждого HeapAlloc\HeapFree и значит блоки кучи в принципе могут быть разными (с сигнатурами и без, если глобальные флаги не установлены). Значит эти флаги должны копироваться в поле Flags заголовка блока (и эти флаги действительно отличаются в отладочном режиме). Поэтому, возможно, что сброс флагов [ProcessHeap+10h] уже в процессе работы скучей не приведет к ошибкам. По крайней мере если тупо занулить эти флаги под отладчиком, то последующее выделение\освобождение блоков памяти идет без всяких сигнатур - также как и без отладчика и ничего явно "катастрофического" не происходит. 5) Если под отладчиком запортить хвостовой маркер выделенного блока, то тоже получается интересная картина. RtlFreeHeep обнаруживает "коррупцию" и начинает "бить тревогу" - вроде как готовит сообщение DbgPrint, но что интересно DbgBreakPoint выдает только при IsDebuggerPresent. Поэтому, если обнулить PEB.BeingDebugged, то никакого int3 не вырабатывается и функция просто возвращает false, не освобождая блок (ес-но если не установлен флаг HEAP_GENERATE_EXCEPTIONS). Выводы: По крайней мере в WinXP (SP2) обнулить флаги х70 NtGlobalFlag можно ИМХО безболезненно. Это приведет к тому, что вновь создаваемые RtlCreateHeap кучи будут работать в обычном (неотладочном) режиме без дописывания контрольных сигнатур. Но чтобы отладочный режим не успел "наследить" нужно сбрасывать эти флаги до создания первой кучи процесса. Иначе остаются другие возможности выявления отладки по [HeapBase+10h] или "прогулке" по куче в поисках сигнатур ABABABAB и FEEEFEE.
Я вот ещё шо нашел, кроме менеджера памяти есть весьма интересные флажки (FLG_APPLICATION_VERIFIER например), чуть попозже попробую тоже чёт поисследовать (только с моря приехал) Global Flags Table The following table lists the flags that Gflags changes, the hexadecimal value and abbreviation for each flag, and the destination (R for registry, K for kernel, I for image file) in which the flag is valid. For a detailed description of each flag, see the Gflags Flag Reference Код (Text): ;==================================================================== = Symbolic name Hexadecimal Value Destination ;===================================================================== FLG_DISABLE_DBGPRINT 0x08000000 R,K FLG_KERNEL_STACK_TRACE_DB 0x2000 R FLG_USER_STACK_TRACE_DB 0x1000 R,K,I FLG_DEBUG_INITIAL_COMMAND 0x4 R,K FLG_DEBUG_INITIAL_COMMAND_EX 0x04000000 R, K FLG_HEAP_DISABLE_COALESCING 0x00200000 R,K,I FLG_DISABLE_PAGE_KERNEL_STACKS 0x80000 R,K FLG_DISABLE_PROTDLLS 0x80000000 R,K,I FLG_DISABLE_STACK_EXTENSION 0x10000 I FLG_CRITSEC_EVENT_CREATION 0x10000000 R,K,I FLG_APPLICATION_VERIFIER 0x100 R,K,I FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000 R,K FLG_ENABLE_CLOSE_EXCEPTIONS 0x00400000 R,K FLG_ENABLE_CSRDEBUG 0x20000 R,K FLG_ENABLE_EXCEPTION_LOGGING 0x00800000 R,K FLG_HEAP_ENABLE_FREE_CHECK 0x20 R,K,I FLG_HEAP_VALIDATE_PARAMETERS 0x40 R,K,I FLG_HEAP_ENABLE_TAGGING 0x800 R,K,I FLG_HEAP_ENABLE_TAG_BY_DLL 0x8000 R,K,I FLG_HEAP_ENABLE_TAIL_CHECK 0x10 R,K,I FLG_HEAP_VALIDATE_ALL 0x80 R,K,I FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x40000 R,K FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000 R,K FLG_HEAP_PAGE_ALLOCS 0x02000000 R,K,I FLG_POOL_ENABLE_TAGGING 0x400 R FLG_ENABLE_SYSTEM_CRIT_BREAKS 0x100000 R, K, I FLG_LDR_TOP_DOWN 0x20000000 R, K, I FLG_MAINTAIN_OBJECT_TYPELIST 0x4000 R,K FLG_SHOW_LDR_SNAPS 0x2 R,K,I FLG_STOP_ON_EXCEPTION 0x1 R,K,I FLG_STOP_ON_HUNG_GUI 0x8 K ;=====================================================================
leo Спасибо за подробную информацию. Момент когда DBEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT подойдет? Вот только я еще не пробовал будет ли в этот момент уже установлен NtGlobalFlag, и кстати PEB.BeingDebugged тоже не мешало бы проверить в этот момент, займусь как появится время.
Вывод получается "неутешительный" До того как система выдает отладчику первый DebugBreakPoint она успевает создать 3 "кучки" - основную кучу процесса (PEB.ProcessHeap), кучу для LDR (база PEB.LDR - вниз на 10000h) и еще какую-то (Olly называет ее Map). Разумеется все эти кучи имеют отладочные флаги HeapFlags = x40000060 и все выделенные блоки обильно загажены хвостовыми маркерами ABAB'ами, а свободные FEEE. Вот кстати я и нашел для себя объяснение почему PEB.LDR отличается на 10h под отладчиком и без - потому, что перед этим блоком вставлены 8 байт хвостового маркера ABABA.. и 8 байт нулей для выравнивания. Сбылась мечта идиота - надеялся хоть какие следы в памяти найти, а тут как слоны на водопой прошли Десятки килобайт - бери любой блок памяти и разматывай клубочек по цепочке Как думаете бороться с этим мусором, господа ? Или ну его ? PS: Да, ведь еще DebugActiveProcess есть ...
Уже давно ясно, что способов определения отладчика мильён, если не использовать только один (IsDebuggerPresent, DebugActiveProcess, etc), а десятки размазанных по коду, то только так можно отшить лентяев или замедлить исследование, а боротся просто: если видишь выгоду во взломе, то тупо трассируешь\патчишь до победного
Еще один вывод - для кого "утешительный", для кого как Если отладчик аттачится к запущенной проге (через DebugActiveProcess), то ес-но во всех хипах все чисто, NtGlobalFlag = 0 и соответственно вызов HeapCreate создает новую кучу без всяких следов отладки. Все шито-крыто, если не считать убогого байтика BeingDebugged bogrus > "Можно смотреть по bp 7FFDF068" А почему ты считаешь, что PEB лежит по фиксированному адресу (и Four-F кстати на это тоже "намекает") ? А вот у меня под XP SP2 частенько "проскакивали" и другие значения (и без отладчика и с отладчиком), типа 7FFD?000. С чего бы это ?
leo Теперь не считаю на XP я не игрался, а вообще я могу часто выдавать то, в чем наверняка не уверен, специально чтобы от кого-то получить подтверждение\опровержение p.s. помню на reng.ru читал люди знают как легко уронить отладчики 3-го кольца ... но не скажут ) Если так, то более менее крыша пошита у сайса
Интересная вещь получается, если сбросить Peb.NtGlobalFlag очень рано то приложение не загружается в отладчик, в частности в OllyDbg
Asterix > "если сбросить Peb.NtGlobalFlag очень рано то приложение не загружается в отладчик" Странно, т.к. стандартные флаги 70h вроде как относятся только к контролю кучи и на отладчик не влияют (по кр.мере приаттачиться к активному процессу он может без всяких флагов) Ты перед тем как сбрасывать флаги, смотрел значение - может там при загрузке кроме 70h еще чего установлено ?
Нет, не смотрел, пробовал на DBEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT сбрасывать но там действительно в этот момент что-то не то, потом пробовал при получении первого сообщения о загрузке DLL(LOAD_DLL_DEBUG_EVENT) сбрасывать, прога(моя прога) вроде сразу выходит, но все-равно сбросил чуть позже, вроде нормально пашет, т.е. без последствий и [Peb.ProcessHeap+10h] тоже заодно обнулил
Это я к тому, что может на ранних стадиях нужно не сбрасывать в 0, а достаточно AND делать с (not 70h). А с ProcessHeap+10h я не совсем понял - оно само стало нулем или ты уже установленное значение сам занулил. Если принудительно занулил, то остается еще аналогичные флаги в куче LDR, ну и хвостовые маркеры уже понатыканы: Код (Text): IsDebuggerPresent_byLDR_1: mov eax,fs:[30h] mov eax,[eax+0Ch] ;PEB.LDR and eax,0FFFF0000h ;базовый адрес кучи LDR mov eax,[eax+10h] ;<> 0 - отладка (HeapFlags <> 0) ret IsDebuggerPresent_byLDR_2: mov eax,fs:[30h] mov eax,[eax+0Ch] movzx eax,byte[eax-3] ;флаги блока кучи and eax, 2+4 ;<> 0 отладка (установлены флаги tail_checking=2 и free_checking=4) ret Кроме флагов можно проверить хвостовой маркер - будет чуть посложнее: IsDebuggerPresent_byLDR_3: mov eax,fs:[30h] mov eax,[eax+0Ch] movzx eсx,byte[eax-2] ;число служебных байт в блоке movzx edx,word[eax-8] ;общий размер блока в единицах 8 байт sub eax,ecx mov eax,[eax+edx*8] ;хвост xor eax,0ABABABABh ;= 0 - отладка (хвостовой маркер) ;sub eax,1 ;sbb eax,eax ;<> 0 - отладка ret Также можно проверять предыдущие или последующие блоки PS: Поправил, т.к. в первоначальном варианте с ABAB-ой я явно поспешил
Asterix мыло нормально работает, письмо получил, я просто ящик проверяю 1-2 в день Если обнулять NtGlobalFlag (биты 0x70) после system DbgBreakPoint то уже не помогает, а вот если до запуска (через реестр) [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\test.exe] "GlobalFlag"="0x00000000" "Debugger"="d:\\masm32\\ollydbg\\ollydbg.exe" Или сразу после первой LDR строки - тогда isdebug.exe не срабатывает, LDR опять же видимо включается только через реестр, с CREATE_PROCESS_DEBUG_EVENT я не пробовал, но он раньше чем первый OUTPUT_DEBUG_STRING_EVENT, должно было у тебя работать, LOAD_DLL_DEBUG_EVENT в w2k тоже идет раньше (в других не уверен)
bogrus есть сомнение что нормально, мне пришло письмо "отбойник" о невозможности доставить письмо, ответа от тебя не получал, он был? Не стало, сам занулил Я что-то не понял у них строго определенное место или нужен какой-то поиск? А что если отловить загрузку ntdll.dll и там попробовать отловить первую LDR строку Я тупо по приходу первого сообщения LOAD_DLL_DEBUG_EVENT обнулял Peb.NtGlobalFlag и прога сразу выходила, т.е. не грузилась