механизм реализации системных вызовов
Дескриптор, отвечающий за системные вызовы, указывает на System Service Table (Таблица Системных Вызовов), представляющую собой простой массив указателей на функции, которые _очень_ легко изменить (естественно, делать это нужно либо из режима ядра, либо с прикладного уровня, обратившись к псевдоустройству PhysicalMemory). Найти таблицу системных вызовов в памяти очень просто. "Скармливаем" NTOSKRNL.EXE функции LoadLibrary
и, используя возвращенный ей дескриптор, определяем адрес экспортируемой переменной KeServiceDescriptorTable через GetProcAddress (или разбираем таблицу экспорта вручную). Первое же двойное слово содержит указатель на SST, поэтому эффективный адрес требуемого системного сервиса по его "магическому" номеру определяется так: addr == *(DWORD *)(KeServiceDescriptorTable[0] + N*sizeof(DWORD)), где N – номер сервиса, а addr – его эффективный адрес.
Продемонстрируем эту технику на примере soft-ice:
:dd
:d KeServiceDescriptorTable
0008:8046AB80 804704D8 00000000 000000F8 804708BC ..G...........G.
:d 804704D8
0008:804704D8 804AB3BF 804AE86B 804BDEF3 8050B034 ..J.k.J...K.4.P.
0008:804704E8 804C11F4 80459214 8050C2FF 8050C33F ..L...E...P.?.P.
0008:804704F8 804B581C 80508874 8049860A 804FC7E2 .XK.t.P...I...O.
:u *(804704D8 + 97*4)
ntoskrnl!NtQuerySystemInformation
0023:804BF933 PUSH EBP
0023:804BF934 MOV EBP, ESP
0023:804BF936 PUSH FF
0023:804BF938 PUSH 804043A0
0023:804BF93D PUSH ntoskrnl!_except_handler3