Ну эта та которая лежит в win32k.sys. Так вот как востановить KeServiceDescriptorTable описано тут: http://www.security.org.sg/code/sdtrestore.html А как востановить KeServiceDescriptorTableShadow что-то я не нашел еще. Подскажите плиз...
а нетути там что-то такой вещи как "KeServiceDescriptorTableShadow"! В выше указанном примере поиск "KeServiceDescriptorTable" осуществляется так: Код (Text): DWORD procAPIExportAddr(DWORD hModule, char *apiName) { if(!hModule || !apiName) return 0; char *ptr = (char *)hModule; ptr += 0x3c; // offset 0x3c contains offset to PE header // offset 78h into PE header contains addr of export table ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // ptr now points to export directory table ptr = (char *)(*(DWORD *)ptr) + hModule; // offset 24 into the export directory table == number of entries // in the Export Name Pointer Table // table DWORD numEntries = *(DWORD *)(ptr + 24); //printf("NumEntries = %d\n", numEntries); // offset 32 into export directory contains offset to Export Name Pointer Table DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); DWORD ordinalBase = *((DWORD *)(ptr + 16)); //printf("OrdinalBase is %d\n", ordinalBase); // offset 36 into export directory contains offset to Ordinal Table WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // offset 28 into export directory contains offset to Export Addr Table DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); FILE *f = fopen("_ntoskrnl_exe.txt", "w+b"); for(DWORD i = 0; i < numEntries; i++) { char *exportName = (char *)(ExportNamePointerTable[i] + hModule); if (f) fprintf(f, "%s\r\n", exportName); if(myStrcmpA(exportName, apiName) == TRUE) { WORD ordinal = ExportOrdinalTable[i]; //printf("%s (i = %d) Ordinal = %d at %X\n", exportName, i, ordinal, ExportAddrTable[ordinal]); return (DWORD)(ExportAddrTable[ordinal]); } } if (f) fclose(f); return 0; } где apiName == "KeServiceDescriptorTable"! А в win32k.sys нет "KeServiceDescriptorTableShadow" в таблице экспорта. Так как и где ее искать?
SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - GetModuleHandle("win32k.sys"); pTrueSdt = LoadPeFile("win32k.sys") + SdtRVA; GetModuleHandle и LoadPeFile в ядре естественно нет, но я думаю у каждого есть свои их реализации. Суть такова: находим Shadow SDT в памяти, вычисляем разницу с базой загрйзки win32k, грузим свою копию win32k, прибавляем смещение и получаем чистую Shadow SDT. Единственно надо учесть, что перед восстановлением оригинальной SDT надо обработать релоки в win32k согласно базе загрузки основной копии win32k.sys. Все это может выглядеть примерно так: pWin32k = GetModuleHandle("win32k.sys"); SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ; w32kCopy = LoadPeFile("win32k.sys"); ProcessRelocs(w32kCopy, pWin32k); memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize); Сорцы кусков моего пелоадера (там LoadPeFile, GetModuleHandle, ProcessRelocs и прочая фигня) както проскакивали на форуме, так что поищи как следует.
СУПЕР! Ответ по существу и все понятно, но вот я не нашел в форуме сорцы GetModuleHandle и ProcessRelocs (LoadPeFile у меня есть свой)... Может искал плохо, но всеже если тебе не трудно то выложи их тут, или кинь мне на мыло: str1@tut.by
В принципе без GetModuleHandle можно обойтись перебрав все загруженные модули (NtQueryInformation или что-то в этом духе) и получить ImageBase win32k.sys
GetModuleHandle у меня собственно и перебирает модули через ZwQuerySystemInformation (только идет дополнительная обработка для ntoskrnl и hal, так как они называться могут по другому). А код ProcessRelocs приведу тут: Код (Text): void ProcessRelocs( IN PVOID Image, IN PVOID NewImageBase ) { PIMAGE_DOS_HEADER dHeader = Image; PIMAGE_NT_HEADERS ntHeaders = RVATOVA(Image, dHeader->e_lfanew); ULONG RelRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELO C].VirtualAddress; ULONG RelSize = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELO C].Size; ULONG Delta = (ULONG)NewImageBase - ntHeaders->OptionalHeader.ImageBase; if (RelRVA && RelSize && !(ntHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) && RelRVA + RelSize <= ntHeaders->OptionalHeader.SizeOfImage) { PIMAGE_BASE_RELOCATION Reloc = RVATOVA(Image, RelRVA); BOOLEAN bFirstChunk = TRUE; while (bFirstChunk || Reloc->VirtualAddress) { PIMAGE_FIXUP_ENTRY Fixup = (PVOID)((ULONG)Reloc + sizeof(IMAGE_BASE_RELOCATION)); ULONG r, dwPointerRva; bFirstChunk = FALSE; for (r = 0; r < (Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; r++) { if (Fixup->Type == IMAGE_REL_BASED_HIGHLOW) { dwPointerRva = Reloc->VirtualAddress + Fixup->Offset; if (dwPointerRva > ntHeaders->OptionalHeader.SizeOfImage) return; *(PULONG)((ULONG)dHeader + dwPointerRva) += Delta; } Fixup++; } Reloc = (PVOID)((ULONG)Reloc + Reloc->SizeOfBlock); } } }
вот только RVATOVA и PIMAGE_FIXUP_ENTRY у меня не определены... Подскажи где брал, или мот это чисто твои фичи -- тогда выложи.
RVATOVA и PIMAGE_FIXUP_ENTRY я уже в инете нашел: Код (Text): #define RVATOVA(base,offset) ((PVOID)((DWORD)(base)+(DWORD)(offset))) typedef struct _IMAGE_FIXUP_ENTRY { WORD Offset:12; WORD Type:4; } IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY; Вопросс у меня делетантский: А зачем надо делать ProcessRelocs? Почему нельзя просто скопировать эту таблицу?
Нет почему-же, скопировать можно, да только кроме бсода не удасться ничего получить В таблице находятся адреса функций в win32k, и эти адреса там идут относительно ее ImageBase. Так как драйвера грузятся всегда не по ImageBase, то адреса в загруженом win32k естественно будут отличаться от адресов в файле на величину разницы базы загрузки с ImageBase. В принципе, вместо обработки релоков можно просто прибавлять эту разницу.