看流星社区

 找回密码
 注册账号
查看: 2145|回复: 0

内核所有模块导出函数inlinehook检测-模仿XT检测

[复制链接]

该用户从未签到

发表于 2013-5-5 10:03:50 | 显示全部楼层 |阅读模式
要功能:检测内核已加载模块的所有导出函数是否被inlinehook。


实现方法:将内存中的模块与原始磁盘文件来做比对,若不同,则此函数被inlinehook。所以各种狡诈的inlinehook伎俩(mov eax ,xxxx add eax,xxxx,call eax)是逃不过检测的,除非它修改原始磁盘文件。不过可惜,在比较之前是可以进行md5验证的。若原始磁盘文件被修改,显然是昭然若揭了。
相对其他较复杂检测技术,这个法子最简单而且同样有效。


主体函数实现如下:
void HookCheckAllModuleExportRoutine (PVOID sysInfo)
{
int i,j,k,len,length;
PSYSMODULELIST List = NULL;
char image[256], Name[256],sysDir[256];
ANSI_STRING FullPath;
UNICODE_STRING uFullPath;
ANSI_STRING Temp1,Temp2,Temp3,Temp4,Temp5;


HANDLE hFile = NULL, hSection = NULL;
PVOID BaseAddress = NULL;
IO_STATUS_BLOCK IoStatusBlock;
CLIENT_ID ClientID;
PVOID SysInfo;




PIMAGE_DOS_HEADER DosHead = NULL;
PIMAGE_NT_HEADERS NtHeads = NULL;
PIMAGE_SECTION_HEADER Section = NULL;
PIMAGE_EXPORT_DIRECTORY ExportDir = NULL;
PIMAGE_BASE_RELOCATION RelocDir = NULL;
ULONG kBase = 0, mBase = 0, kNameBase = 0, kOrdinalBase = 0, kFunctionBase = 0;
ULONG ByteEqual, Address = 0, index, NameNumbers, FixAddr = 0, FixAddrBase = 0,RelocSize;
ULONG DataSecVA[24], DataSecSize[24], DataSec;




USHORT Temp = 0;
PUCHAR SystemFunName;
PKPROCESS Eprocess;
KAPC_STATE ApcState;
HANDLE ProcessHandle;
UNICODE_STRING ProcessName;
PSYSTEM_PROCESSES pSysinfo;


PKUSER_SHARED_DATA kShareData = USER_SHARED_DATA;


size_t size = 0;
NTSTATUS status;
OBJECT_ATTRIBUTES oa, ob = {sizeof (ob), NULL, NULL,NULL, NULL};




RtlInitAnsiString (&Temp2, "sys");
RtlInitAnsiString (&Temp3, "dll");
RtlInitAnsiString (&Temp4, "exe");
RtlInitAnsiString (&Temp5, "win32k.sys");
RtlInitUnicodeString (&ProcessName, L"winlogon.exe");


w2ascll (Name, kShareData->NtSystemRoot);


strcpy (sysDir, "\\??\\");
strcat (sysDir, Name);


List = (PSYSMODULELIST)sysInfo;


for (j = 0; j < List->ulCount; j++)
{






if (StringCompare ("\\??\\", List->smi[j].ImageName, 4))
{
DbgPrint ("Skip %s\n", List->smi[j].ImageName);
continue;
}


mBase = NULL;
hFile = NULL;
hSection = NULL;
BaseAddress = NULL;


memset (Name, 0, sizeof (Name));
memset (image,0, sizeof (image));


strcpy (Name, sysDir);
strcpy(image, List->smi[j].ImageName + List->smi[j].ModuleNameOffset);


len = strlen (image);
RtlInitAnsiString (&Temp1, image + len - 3);




if (!RtlCompareString (&Temp1, &Temp2, TRUE))
{
if (strstr (image, "watchdog"))
{
strcat (Name, "\\System32\\");
}else
{
strcat (Name, "\\System32\\Drivers\\");
}
strcat (Name, image);
}
else if (!RtlCompareString (&Temp1, &Temp3, TRUE) || !RtlCompareString (&Temp1, &Temp4, TRUE))
{
strcat (Name, "\\System32\\");
strcat (Name, image);
}
else
{
continue;
}


RtlInitAnsiString (&Temp1, image);
if (!RtlCompareString (&Temp5, &Temp1, TRUE))
{ //win32.sys模块的空间必须挂靠进程才能读取


status = ZwQuerySystemInformation(5,NULL,0,&length);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
SysInfo = ExAllocatePool(NonPagedPool,length);
if (NULL == SysInfo)
{
goto Error;
}
}
pSysinfo = (PSYSTEM_PROCESSES)SysInfo;
status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pSysinfo, length, &length);
if(!NT_SUCCESS(status))
{
goto Error;
}


//找到winlogon.exe进程,挂靠空间
do
{
if (!RtlCompareString (&(pSysinfo->ProcessName), &ProcessName, TRUE))
{
ClientID = pSysinfo->Threads[0].ClientId;
ZwOpenProcess (&ProcessHandle, PROCESS_ALL_ACCESS, &ob, &ClientID);
ObReferenceObjectByHandle (ProcessHandle, PROCESS_ALL_ACCESS, *PsProcessType, KernelMode, &Eprocess, NULL);
KeStackAttachProcess (Eprocess, &ApcState);
break;
}


if (pSysinfo->NextEntryDelta == 0) break;


pSysinfo = (ULONG)pSysinfo + pSysinfo->NextEntryDelta;
}while (1);


ExFreePool(SysInfo);
memset (Name, 0, sizeof(Name));
strcpy (Name, "\\Device\\HarddiskVolume1\\Windows\\System32\\");
strcat (Name, image);


}


RtlInitAnsiString (&FullPath, Name);
RtlAnsiStringToUnicodeString (&uFullPath, &FullPath, TRUE);


//获得模块在内核中的相关参数
kBase = List->smi[j].Base;
if (!MmIsAddressValid (kBase))
{
DbgPrint ("%s 'base is not valid!\n", image);
goto Error;
}


DosHead = (PIMAGE_DOS_HEADER)kBase;
NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew);
Section = (PIMAGE_SECTION_HEADER) ((ULONG)NtHeads + sizeof(IMAGE_NT_HEADERS));


if (NULL == NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress)
{
DbgPrint ("%s doesnt has valid export table!\n", image);
continue;
}


DataSec = 0;
for (i = 0; i < NtHeads->FileHeader.NumberOfSections; i++)
{
if (strstr (Section->Name, "text") ||strstr (Section->Name, "PAGE")||strstr (Section->Name, "INIT"))
{
DataSecVA = Section->Misc.VirtualSize;
DataSecSize = Section->VirtualAddress;
DataSec++;
}
Section ++;
}
if (i == NtHeads->FileHeader.NumberOfSections && DataSec == 0)
{
DbgPrint ("%wZ doesnt find the text section!\n", &FullPath);
}




ExportDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)kBase + NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress);
NameNumbers = ExportDir->NumberOfNames;


kNameBase = kBase + ExportDir->AddressOfNames;
kOrdinalBase = kBase + ExportDir->AddressOfNameOrdinals;
kFunctionBase = kBase + ExportDir->AddressOfFunctions;






//获得模块加载后的相关参数
InitializeObjectAttributes (
&oa,
&uFullPath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = ZwOpenFile(
&hFile,
FILE_READ_ACCESS,
&oa,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (!NT_SUCCESS(status))
{
KdPrint (("OpenFile %wZ error\n", &uFullPath));
goto Error;


}
oa.ObjectName = NULL;
status = ZwCreateSection(
&hSection,
SECTION_MAP_EXECUTE,
&oa,
0,
PAGE_EXECUTE,
SEC_IMAGE,
hFile
);
if (!NT_SUCCESS(status))
{


KdPrint (("CreateSection for %wZ error", &uFullPath));
goto Error;


}
size = 0;
status = ZwMapViewOfSection(
hSection,
NtCurrentProcess(),
&BaseAddress,
0,
1000,
0,
&size,
(SECTION_INHERIT)1,
MEM_TOP_DOWN,
PAGE_READWRITE
);
if (!NT_SUCCESS(status))
{
KdPrint (("MapViewSection for %wZ error", &uFullPath));
goto Error;


}


mBase = ExAllocatePool (NonPagedPool, size);
if (NULL == mBase)
{
goto Error;
}


if (BaseAddress != NULL)
{
RtlCopyMemory (mBase, BaseAddress, size);
}


DosHead = (PIMAGE_DOS_HEADER)mBase;
NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew);
RelocDir = (PIMAGE_BASE_RELOCATION)((ULONG)mBase + NtHeads->OptionalHeader.DataDirectory[5].VirtualAddress);
if (RelocDir != NULL)
{
while (RelocDir->VirtualAddress != 0 || RelocDir->SizeOfBlock != 0)
{
FixAddrBase = RelocDir->VirtualAddress + (ULONG)mBase;
RelocSize = (RelocDir->SizeOfBlock - 8)/2;
for ( i = 0; i < RelocSize; i++)
{
Temp = *(PUSHORT)((ULONG)RelocDir + sizeof (IMAGE_BASE_RELOCATION) + i * 2);
if ( (Temp & 0xF000) == 0x3000)
{
Temp &= 0x0FFF;
FixAddr = FixAddrBase + (ULONG)Temp;
*(PULONG)FixAddr = *(PULONG)FixAddr + (ULONG)kBase - (ULONG)NtHeads->OptionalHeader.ImageBase;
}
}
RelocDir = (ULONG)RelocDir + RelocDir->SizeOfBlock;
}
}
/*
if (j == 0)
{
KernelCheck (kBase, mBase, sysInfo);
}
*/


for (i = 0; i < NameNumbers; i++)
{
SystemFunName = (PUCHAR)(*(PULONG)(kNameBase + i * 4) + (ULONG)kBase);
index = *((PUSHORT)(kOrdinalBase + i * 2));
Address = *(PULONG)(kFunctionBase + index * 4);


for (k = 0; k < DataSec; k++)
{
if ( (Address >= DataSecVA[k]) && (Address <= DataSecVA[k] + DataSecSize[k]))
{
length = GetFunctionLength(kBase + Address);
if (length)
{
ByteEqual = RtlCompareMemory (kBase + Address, mBase + Address, length);
if (ByteEqual != length)
{
KdPrint (("%s:%s:%x has been inline-hooked!\n", image, SystemFunName, kBase + Address));
}
}
break;
}
}


}






Error:
RtlFreeUnicodeString (&uFullPath);
if (!RtlCompareString (&Temp5, &Temp1, TRUE))
{
KeUnstackDetachProcess (&ApcState);
}
if (mBase != NULL)
{
ExFreePool (mBase);
mBase = NULL;
}
if (hFile != NULL)
{
ZwClose(hFile);
hFile = NULL;
}
if (hSection != NULL)
{
ZwClose(hSection);
hSection = NULL;
}
if (BaseAddress != NULL)
{
ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
BaseAddress = NULL;
}


}
return;
}


ULONG GetFunctionLength(ULONG FAddress)
{
ULONG i = 0, Flag = 0;
PUCHAR Temp = NULL;


Temp = FAddress;
while (!Flag && MmIsAddressValid(Temp) && MmIsAddressValid (Temp + 1)
&& MmIsAddressValid(Temp + 2) && MmIsAddressValid (Temp + 3)&& MmIsAddressValid (Temp + 4))
{


switch (*Temp)
{
case 0xc3:
case 0xcf:
case 0xcb:
if ( (*(Temp+1) == 0xcc) || (*(Temp+1) == 0x8b && *(Temp+1) == 0xFF))
{
Flag = 1;
}
break;


case 0xc2:
case 0xca:
if ( (*(Temp+3) == 0xcc) || (*(Temp+3) == 0x8b && *(Temp+4) == 0xFF))
{
Flag = 1;
}
break;


default:
break;
}


if (!Flag)
{
if (*((PULONG)Temp) == 0 && *(Temp + 4) == 0)
return 0;
}


Temp ++;
i++;
}


return i;
}
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-5-14 09:02

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表