убийство часового КРИС КАСПЕРСКИ, АКА МЫЩЪХ Спецвыпуск: Хакер, номер #072, стр. 072-072-7 Листинг 5. Код функции PgCreateBlockChecksumSubContext, рассчитывающий контрольную сумму заданного блока PPATCHGUARD_SUB_CONTEXT PgCreateBlockChecksumSubContext( IN PPATCHGUARD_CONTEXT Context, IN ULONG Unknown, IN PVOID BlockAddress, IN ULONG BlockSize, IN ULONG SubContextSize, OUT PBLOCK_CHECKSUM_STATE ChecksumState OPTIONAL) { ULONG64 Checksum = Context->RandomHashXorSeed; ULONG Checksum32; // Checksum 64-bit blocks while (BlockSize >= sizeof(ULONG64)) { Checksum ^= *(PULONG64)BaseAddress; Checksum = RotateLeft(Checksum, Context->RandomHashRotateBits); BlockSize -= sizeof(ULONG64); BaseAddress += sizeof(ULONG64); } // Checksum aligned blocks while (BlockSize-- > 0) { Checksum ^= *(PUCHAR)BaseAddress; Checksum = RotateLeft(Checksum, Context->RandomHashRotateBits); BaseAddress++; } Checksum32 = (ULONG)Checksum; Checksum >>= 31; do { Checksum32 ^= (ULONG)Checksum; Checksum >>= 31; } while (Checksum); } Как можно заметить, на выходе функции PgCreateBlockChecksumSubContext мы получаем 32-битный Checksum, записываемый в структуру BLOCK_CHECKSUM_STATE вместе с базовым адресом и размером контролируемого блока (кстати говоря, префикс «Pg» определенно означает Patch-Guard, позволяя нам легко и быстро отделять принадлежащие к Patch-Guard'у функции ото всех остальных функций ядра): Листинг 6. Структура, хранящая 32-битный CRC вместе с другими данными typedef struct BLOCK_CHECKSUM_STATE { ULONG Unknown; ULONG64 BaseAddress; ULONG BlockSize; ULONG Checksum; } BLOCK_CHECKSUM_STATE, *PBLOCK_CHECKSUM_STATE; Информационная емкость 32-битной контрольной суммы составляет всего 4 байта, которые элементарно рассчитываются даже без всякого перебора. Подробнее об этом можно прочитать в моей статье «Как подделывают CRC16/32» (валяющейся на ftp://nezumi.org,ru), а так же в замечательном хакерском руководстве, ориентированном на астматиков и доходчиво рассказывающим, как вычисляется и подделывается CRC32 путем дописывания 4-х корректирующих байт в конец контролируемого блока: http://foff.astalavista.ms/tutorialz/Crc.htm, добротный перевод которой на русский лежит на: www.pilorama.r2.ru/library/pdf/crcrevrs.pdf. Учитывая, что Microsoft в любой момент может пересмотреть свои позиции, расширив контрольную сумму до 8-байт (что на 64-разрядных процессорах очень легко сделать), нелишним будет заблаговременное ознакомление с базовыми принципами алгоритма CRC64, описание которого припрятано на: www.pdl.cmu.edu/mailinglists/ips/mail/msg02982.html. Аналогичным образом осуществляется и модификация GDT/IDT – в них полно незадействованных полей и выкроить четыре байта не будет проблемой. А вот с SSDT дела обстоят похуже, поскольку Patch-Guard сверяет «рабочую» копию с ее «оригиналом», хранящимся внутри образа NTOSKRNL.EXE по адресу nt!KeServiceDescriptorTable. Кажется, что ситуация - финиш, но нет! Ведь мы уже умеем безболезненно модифицировать образ ядра, следовательно, нам ничего не будет стоить синхронно произвести изменения в обеих таблицах, и Patch-Guard снова ничего не заметит. |