"Найти таблицу системных вызовов в памяти очень просто. "Скармливаем" NTOSKRNL.EXE функции LoadLibrary и, используя возвращенный ей дескриптор, определяем адрес экспортируемой переменной KeServiceDescriptorTable через GetProcAddress (или разбираем таблицу экспорта вручную). Первое же двойное слово содержит указатель на SST, поэтому эффективный адрес требуемого системного сервиса по его "магическому" номеру определяется так: addr == *(DWORD *)(KeServiceDescriptorTable[0] + N*sizeof(DWORD)), где N - номер сервиса, а addr - его эффективный адрес." Это отсюда http://www.insidepro.com/kk/132/132r.shtml Но! Сие не пашет. По адресу, который выдает GetProcAddress все нули. В чем упущение автора, кто знает?
Дык там код-то проще некуда: Код (Text): typedef struct _SERVICE_DESCRIPTOR_TABLE { /* * Table containing cServices elements of pointers to service handler * functions, indexed by service ID. */ PVOID *ServiceTable; /* * Table that counts how many times each service is used. This table * is only updated in checked builds. */ PULONG CounterTable; /* * Number of services contained in this table. */ ULONG TableSize; /* * Table containing the number of bytes of parameters the handler * function takes. */ PUCHAR ArgumentTable; } SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE; HMODULE ntoskrnl = LoadLibrary("C:\\WINDOWS\\system32\\ntoskrnl.exe"); PSERVICE_DESCRIPTOR_TABLE SDT_ptr = (PSERVICE_DESCRIPTOR_TABLE)GetProcAddress(ntoskrnl, "KeServiceDescriptorTable"); и соотв. все поля у SDT_ptr равны 0!
Там массив описателей для каждой сст. Разумеется там нули, он же не инициализирован в KeAddSystemServiceTable()/KiInitSystem().
Ищут следующими способами: 1. Дизассемблировать KeAddSystemServiceTable(). 2. Поиск KiInitSystem() и дизассемблирование её. 3. Парсинг релоков ядра, отлично подходит для ядра на диске, ибо в загруженном ядре секция релоков выгружена. 4. Сигнатурный поиск в секции кода. Некоторые сервисы экспортируются, поиск нескольких указателей в таблице.
Этот метод хорошо работал, когда был доступ к PhysicalMemory из третьего кольца. Указанным в начале страницы способом искался RVA KeServiceDescriptorTable (тут это SDT_ptr - ntoskrnl), а потом уже непосредственно из "ядерной" памяти выдирались реальные таблицы. Автору советую глянуть исходники SDTrestore, там реализовано 2 метода поиска - через KiInitSystem и релоки.
AntiFreeze 4-й способ самый оптимальный, например часть сст на диске: Код (Text): 00456084 005EA597 ntoskrnl.NtOpenProcess 00456088 00620C89 ntoskrnl.NtOpenProcessToken 0045608C 0061BDD0 ntoskrnl.NtOpenProcessTokenEx Таблица выравнена на 4 байта в памяти в XP, Vista и Win7, тоесть находим адреса этих трёх функций, находим адрес секции кода и выполняем поиск указателя на NtOpenProcess посредством repne scasd. Прверяем следующий дворд, если он указывает на NtOpenProcessToken то сканим память вниз для поиска начала сст.
Clerk, в принципе у всех способов есть свои плюсы и минусы. nt!KeAddSystemServiceTable() хорош тем, что можно сразу выдрать и указатель на nt!KeServiceDescriptorTableShadow. Или например, когда я гружу модуль, я сразу фикшу релоки, мне не сложно ещё параллельно что-то найти. Но предложенный тобой способ, несомненно, интересен.