Hi all. Pomogite reshit problemu odnu. Neobhodimo opredelit, gde nahoditsya, gde conchaetsya paged pool. I cto skolko, po kakim addresam iz nego vugruzil... Budu rad lubomu sovety...
В Win support tools есть утилита poolmon. Перед ее использованием необходимо разрешить pool tagging с помощью утилиты gflags. После этого она покажет всю инфу о пулах. Программно тебе нужно копать в сторону ф-ций Mm* и ковырять структуру MDL (Memory Descriptor List) и сказать спасибо Four-F-у за его ntddk.inc.
Как-то давно занимался этим вопросом - многое не помню. Начет начала и конца пулов не знаю, но вопрос "как определить размер" много раз задавался в конфе на osronline.com. Там через одного MVP мелькают, но никто так и не дал вразумительного ответа. Тебе нужно получить значения этих неэкспортируемых переменных ядра: MmSizeOfNonPagedPoolInBytes MmNonPagedPoolEnd MmNonPagedPoolStart MmSizeOfPagedPoolInBytes MmPagedPoolStart MmPagedPoolEnd В аттаче дока, рассказывающая, как они вычисляются. Также кое-что есть в книге "Внутренне устройство Windows". Но это всё теоретические измышления, к тому же применимые только к одной определенной версии системы. Опираться на них нельзя. Porocess Explorer в диалоге "System Information" показывает "Paged Limit" и "Nonpaged Limit". Делает он это путем доставания адресов MmSizeOfPagedPoolInBytes и MmMaximumNonPagedPoolInBytes из образа ntoskrnl.exe. Деталей не помню, кажется с помощью dbghelp.dll. Затем просит драйвер прочитать, что находится по этим адресам. То же самое, наверное, можно проделать и для MmPagedPoolStart и MmPagedPoolEnd. Если нужно чисто из драйвера, то, наверное, никак. Ну а кто и сколько определить вообще невозможно, только если выделение помечается тегом, а это не каждый делает. _2139892499__PagedPoolSizeAndNonPagedPoolSizeValuesInWindowsNT.rar
to Broken Sword >В Win support tools есть утилита poolmon копал... тулза дает статистику, которую с легкостью можно получить с помощью NtQuerySystemInformation(). Можно получить сколько раз выделялись пулы(Paged,NonPeged),и каким размером. на ХР тулза глючит немного... >ковырять структуру MDL не поможет, это всего лишь описание для куска памяти... ( а как описать память, если я не знаю даже базовый аддресс, да и зная его не поможет, это ИМХО, буду рад разочароватся to Four-F пасиба за инфу. >Ну а кто и сколько определить вообще невозможно не согласен, чисто интуитивно... довод н1 - ExFreePool(). как-то ж работает... )
Как-то раз, хотел писАть тул для поиска руткитов. Идея состояла в поиске скрытых объектов ядра путем анализа содержимого всех выделенных блоков памяти. Я тоже взял за основу "чисто интуитивный... довод": "функции ExAlloc/ExFree как-то работают и должны помнить выделенные блоки". После анализа исходного кода я понял, что довод был ошибочен. Для малых блоков памяти (меньше страницы) системные пулы работают как ассоциативные списки (look-aside lists). Имеется несколько списков с блоками разного размера. Блоки связаны посредством двусвязного списка. Когда приходит запрос на выделение памяти, система ищет блок подходящего размера и "отстегивает" его от списка. При этом LIST_ENTRY, в "отстегнутом" блоке, замыкается сам на себя. В начале блока имеется небольшая управляющая структура, в которую записывается тип пула, размер блока и ещё какая-то ерунда. За управляющей структурой идет собственно память доступная для использования - именно этот адрес возвращает ExAlloc. Т.о. можно пройтись по всем невыделенным блокам, но пройтись по выделенным невозможно, т.к. они просто "болтаются" сами по себе. Найти их в памяти тоже невозможно, т.к. отсутствует критерий поиска. Я анализировал код w2k. Возможно в ХР+ что-то и поменялось, но это очень маловероятно. Меня все это интересовало только применительно к объектам ядра, т.е. для блоков памяти меньше страницы. Как работает страничное выделение я не знаю. Может быть система и записывает где-то что она выделяет, но кому - вряд ли.
Можно просто загрузить свой драйвер как можно раньше (желательно boot) и просплайсить все функции создания/освобождения обьектов, а потом по их вызовам строить списки обьектов ядра. Главный недостаток этого метода в падении производительности системы (хотя это зависит от реализации), поэтому для постоянного применения не годиться. Будет время, напишу подобную тулзу.
Любые активные методы противодействия плохи тем, что их можно обнаружить и обойти. "просплайсить все функции создания/освобождения обьектов" - грубый метод, к тому же обходится. У меня была задача сделать все очень культурно и незаметно. Даже если бы руткит убирал выделенные им блоки памяти из системных списков, то имея списки выделенных и свободных блоков, можно было бы составить карту памяти, найти в ней дыры и посмотреть что там. Сожно, но можно. И это всё чисто пассивно. Например, RootkitRevealer'у довольно трудно противостоять, хотя теоретически возможно, именно потому, что он пассивен. К тому же есть такое понятие как "гонка вооружений". Не хотелось бы её подстёгивать.
Есть еще один выход - создать тулзу на любом неизвестном ранее способе обнаружения (пусть даже легко обходимом), и сделать ее приватной. Пока разработчики руткитов ее не увидят, они не смогут ее обойти. А любая публичная тулза будет немедленно обойдена хотя-бы примитивным хуком на IOCTL ее драйвера и подтасовкой результата. Например так делает hxdef. Поэтому выход - приватная и малоизвестная тулза, ни в коем случае не opensource.
Four-F Вы писали: > В начале блока имеется небольшая управляющая структура, в которую записывается тип пула, размер блока и ещё какая-то ерунда. Оччень хотелось бы посмотреть на эту структуру. Судя по тому, что Вы написали, то сам собой напрашывается такое решение - 1. Выгружаемый и невыгружаемый пул имеет свои границы. 2. Если просмотреть списки, то ессесно там окажутся не все блоки -> отсутствующие блоки представляют интерес ) а критерием поиска может быть как раз та управляющая структура.
Код (Text): struct _POOL_HEADER { /*<thisrel this+0x0>*/ /*|0x1|*/ unsigned char PreviousSize; /*<thisrel this+0x1>*/ /*|0x1|*/ unsigned char PoolIndex; /*<thisrel this+0x2>*/ /*|0x1|*/ unsigned char PoolType; /*<thisrel this+0x3>*/ /*|0x1|*/ unsigned char BlockSize; /*<thisrel this+0x0>*/ /*|0x4|*/ unsigned long Ulong1; /*<thisrel this+0x4>*/ /*|0x4|*/ struct _EPROCESS* ProcessBilled; /*<thisrel this+0x4>*/ /*|0x4|*/ unsigned long PoolTag; /*<thisrel this+0x4>*/ /*|0x2|*/ unsigned short AllocatorBackTraceIndex; /*<thisrel this+0x6>*/ /*|0x2|*/ unsigned short PoolTagHash; }; Если есть доступ к исходному коду w2k, то там более правильное определение Не думаю, что имея эти 8 байт, можно что-то найти.
Структура выдрана с помощью pdbdump из официальных символов. Кто никогда с ней не работал, её определения могут показаться странными. Вот по-человечески: Код (Text): typedef struct _POOL_HEADER { union { struct { UCHAR PreviousSize; UCHAR PoolIndex; UCHAR PoolType; UCHAR BlockSize; }; ULONG Ulong1; }; union { PEPROCESS ProcessBilled; ULONG PoolTag; struct { USHORT AllocatorBackTraceIndex; USHORT PoolTagHash; }; }; } POOL_HEADER, *PPOOL_HEADER; Этот хидер используется для выделений меньше страницы, для страничных выделений никакого оверхеда нет. Кстати, кроме границ пулов есть ещё масса интересных переменных, естественно не экспортируемых. Например, MmNonPagedPoolFreeListHead. Или Код (Text): POOL_DESCRIPTOR NonPagedPoolDescriptor; POOL_DESCRIPTOR PagedPoolDescriptor; POOL_DESCRIPTOR NonPagedPoolDescriptorMS; POOL_DESCRIPTOR PagedPoolDescriptorMS; POOL_DESCRIPTOR ExpPagedPoolDescriptor; PPOOL_DESCRIPTOR PoolVector[MaxPoolType] = { &NonPagedPoolDescriptor, &PagedPoolDescriptor, &NonPagedPoolDescriptorMS, &PagedPoolDescriptorMS }; struct _POOL_DESCRIPTOR { /*<thisrel this+0x0>*/ /*|0x4|*/ int PoolType; /*<thisrel this+0x4>*/ /*|0x4|*/ unsigned long PoolIndex; /*<thisrel this+0x8>*/ /*|0x4|*/ unsigned long RunningAllocs; /*<thisrel this+0xc>*/ /*|0x4|*/ unsigned long RunningDeAllocs; /*<thisrel this+0x10>*/ /*|0x4|*/ unsigned long TotalPages; /*<thisrel this+0x14>*/ /*|0x4|*/ unsigned long TotalBigPages; /*<thisrel this+0x18>*/ /*|0x4|*/ unsigned long Threshold; /*<thisrel this+0x1c>*/ /*|0x4|*/ void* LockAddress; /*<thisrel this+0x20>*/ /*|0x400|*/ struct _LIST_ENTRY ListHeads[128]; }; Если есть исходники, то разобравшись с механизмом работы пулов, можно попытаться что-то замутить, хотя, будет очень сложно.
Пасиба за инфу, в исходниках наверно покопатся придется... Одно но: на ХР перед началом пула, меньше страницы размером, стоит тэг, если выделялось с тэгом (проверено массу раз). Наверно структуры различаются... (
Структуры запросто могут отличаться, но размер POOL_HEADER = 8 байт. Вторые 4 байта - это тэг. Дальше сразу идет собственно доступный для вызывателя блок памяти. Так что тэг как раз и будет сразу перед началом блока.