{
NTSTATUS st;
/************************************************************************/
/* 读取文件镜像 */
/************************************************************************/
HANDLE hFile;
IO_STATUS_BLOCK iosb;
UNICODE_STRING usNtosPath;
RtlInitUnicodeString(&usNtosPath, szNtosFullPath);
OBJECT_ATTRIBUTES oa;
RtlZeroMemory(&oa, sizeof(OBJECT_ATTRIBUTES)) ;
InitializeObjectAttributes(&oa,
&usNtosPath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
st = ZwOpenFile(&hFile,
FILE_READ_DATA|FILE_EXECUTE|SYNCHRONIZE,
&oa,
&iosb,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
if(st != STATUS_SUCCESS)
{
DbgPrint("ReadNtosFile: ZwOpenFile() failed, NTSTATUS = %08X/n", st);
return false;
}
//设置名称为NULL
oa.ObjectName = 0;
FILE_STANDARD_INFORMATION fsi;
st = ZwQueryInformationFile(hFile,
&iosb,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if(st != STATUS_SUCCESS)
{
DbgPrint("ReadNtosFile: ZwQueryInformationFile() failed, NTSTATUS = %08X/n", st);
return false;
}
ULONG ulFileSize = fsi.AllocationSize.LowPart;
PVOID lpFileBase = ExAllocatePoolWithTag(NonPagedPool, ulFileSize, GGDRIVER_POOL_TAG);
if(lpFileBase == NULL)
{
DbgPrint("ReadNtosFile: ExAllocatePool() failed!");
return false;
}
st = ZwReadFile(hFile, NULL, NULL, NULL, &iosb, lpFileBase, ulFileSize, NULL, NULL);
if(st != STATUS_SUCCESS)
{
DbgPrint("ReadNtosFile: ZwReadFile() failed, NTSTATUS = %08X/n", st);
return false;
}
//关闭文件句柄
ZwClose(hFile);
DbgPrint("ReadNtosFile: read ntoskrnl file success base=0x%p, size=%d/n",
lpFileBase, ulFileSize);
*FileBase = lpFileBase;
*FileSize = ulFileSize;
return true;
}
/************************************************************************/
/* */
/************************************************************************/
ULONG PeFileGetImageBase(PVOID lpFileBase)
{
//MZ头
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER *)lpFileBase;
//PE头
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PUCHAR)lpDosHeader + lpDosHeader->e_lfanew);
return lpNtHeader->OptionalHeader.ImageBase;
}
/************************************************************************/
/* 在文件中查找ssdt的相关指针和变量
ReadNtosFile: read ntoskrnl file success base=0x81CE8000, size=2015232
81e9416f a1b0cd4200 mov eax,dword ptr ds:[0042CDB0h] //NumberOfService
81e94174 6a10 push 10h
81e94176 59 pop ecx
81e941cc c705e046480040c94200 mov dword ptr ds:[4846E0h],42C940h //ServiceTableBase
81e941d6 8935e4464800 mov dword ptr ds:[4846E4h],esi
81e941dc c705ec464800b4cd4200 mov dword ptr ds:[4846ECh],42CDB4h //ParamTableBase
81e941e6 8bc1 mov eax,ecx
81e941e8 89b0e8464800 mov dword ptr [eax+4846E8h],esi
81e941ee 03c1 add eax,ecx
81e941f0 83f840 cmp eax,40h
81e941f3 72f3 jb 81e941e8
81e941f5 bee0464800 mov esi,4846E0h //KeServiceDescriptorTable
81e941fa bfa0464800 mov edi,4846A0h //KeServiceDescriptorTableShadow
81e941ff f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
81e94201 5f pop edi
81e94202 5e pop esi
81e94203 c3 ret*/
/************************************************************************/
bool PeFileNtosGetSsdtParam(PVOID lpFileBase,
ULONG *ulNumberOfServiceVA,
ULONG *ulParamTableVA,
ULONG *ulServiceTableVA,
ULONG *ulKeServiceDescriptorTableShadowVA
)
{
PVOID lpSSDTAddr = NULL; //sdt地址
char *szSSDTName = "KeServiceDescriptorTable";
*ulNumberOfServiceVA = 0;
*ulParamTableVA = 0;
*ulServiceTableVA = 0;
*ulKeServiceDescriptorTableShadowVA = 0;
//MZ头
IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER *)lpFileBase;
//PE头
IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PUCHAR)lpDosHeader + lpDosHeader->e_lfanew);
/************************************************************************/
/* 先查找导出地址 */
/************************************************************************/
// 第0个目录是输出表
IMAGE_EXPORT_DIRECTORY *lpExport = (IMAGE_EXPORT_DIRECTORY *)PeRav2RawPtr(lpFileBase,
lpNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress);
ULONG *lpAddressOfFunctions = (ULONG *)PeRav2RawPtr(lpFileBase, lpExport->AddressOfFunctions);
ULONG *lpAddressOfNames = (ULONG *)PeRav2RawPtr(lpFileBase, lpExport->AddressOfNames);
USHORT *lpAddressOfNameOrdinals = (USHORT *)PeRav2RawPtr(lpFileBase, lpExport->AddressOfNameOrdinals);
for(ULONG i=0; i<lpExport->NumberOfNames; i++)
{
if(!_stricmp(szSSDTName, (char *)PeRav2RawPtr(lpFileBase, lpAddressOfNames[i])))
{
lpSSDTAddr = (PVOID)(lpNtHeader->OptionalHeader.ImageBase +
lpAddressOfFunctions[lpAddressOfNameOrdinals[i]]);
break;
}
}
//未找到ssdt导出地址则返回
if(lpSSDTAddr == NULL)
{
DbgPrint("PeFileNtosGetSsdtParam: %s not found!/n", szSSDTName);
return false;
}
/************************************************************************/
/* 在重定位中查找引用地址,并根据特征码判断是否符合要求 */
/************************************************************************/
// 第5个目录是重定位
IMAGE_BASE_RELOCATION *lpBaseReloc = (IMAGE_BASE_RELOCATION *)PeRav2RawPtr(lpFileBase,
lpNtHeader->OptionalHeader.DataDirectory[5].VirtualAddress);
while(lpBaseReloc->VirtualAddress != 0 || lpBaseReloc->SizeOfBlock != 0)
{
//word组成的偏移量数组
PUSHORT lpOffset = (PUSHORT)((PUCHAR)lpBaseReloc + sizeof(IMAGE_BASE_RELOCATION));
//本page中要处理的总项数
ULONG ulRelocSize = (lpBaseReloc->SizeOfBlock - 8)/sizeof(USHORT);
for(ULONG i=0; i<ulRelocSize; i++)
{
//不处理末尾项和非 IMAGE_REL_BASED_HIGHLOW 类型的重定位项
if(lpOffset[i] == 0 || (lpOffset[i] & 0xF000) != 0x3000)
continue;
//计算VA地址和引用地址
ULONG ulRelocVA = lpBaseReloc->VirtualAddress + (USHORT)(lpOffset[i] & 0x0FFF);
PVOID lpRelocRef = PeRav2RawPtr(lpFileBase, ulRelocVA);
if(lpSSDTAddr != (PVOID)*(PULONG)lpRelocRef)
continue;
//8608e1dc c705ec464800b4cd4200 mov dword ptr ds:[4846ECh],42CDB4h
if(*(PUSHORT)((PUCHAR)lpRelocRef - 2) != 0x05C7)
continue;
DbgPrint("PeFileNtosGetSsdtParam: SerivceTableBase reference addresss = %p/n", (PUCHAR)lpRelocRef - 2);
//ulServiceTableVA
ULONG ulServiceTableAddr = *(PULONG)((PUCHAR)lpRelocRef + 4);
*ulServiceTableVA = ulServiceTableAddr - lpNtHeader->OptionalHeader.ImageBase;
DbgPrint("PeFileNtosGetSsdtParam: ServiceTableVA = %08X/n", *ulServiceTableVA);
//ulParamTableVA
for(PUCHAR j=(PUCHAR)lpRelocRef; j-(PUCHAR)lpRelocRef < 0x20; j++)
{
if( *(PUSHORT)j == 0x05C7 && *(PULONG)(j+2) == *(PULONG)lpRelocRef + 0x0C )
{
*ulParamTableVA = *(PULONG)(j+6) - lpNtHeader->OptionalHeader.ImageBase;
break;
}
}
if(*ulParamTableVA == 0)
{
DbgPrint("PeFileNtosGetSsdtParam: ParamTableBase reference addresss not found!/n");
return false;
}
DbgPrint("PeFileNtosGetSsdtParam: ParamTableVA = %08X/n", *ulParamTableVA);
//ulNumberOfServiceVA
*ulNumberOfServiceVA = *ulParamTableVA - 4;
DbgPrint("PeFileNtosGetSsdtParam: NumberOfServiceVA = %08X/n", *ulNumberOfServiceVA);
//ulKeServiceDescriptorTableShadowVA
for(PUCHAR k=(PUCHAR)lpRelocRef; k-(PUCHAR)lpRelocRef < 0x80; k++)
{
if( *k == 0xBE && *(k+5) == 0xBF )
{
*ulKeServiceDescriptorTableShadowVA = *(PULONG)(k+6) - lpNtHeader->OptionalHeader.ImageBase;
break;
}
}
if(*ulKeServiceDescriptorTableShadowVA == 0)
{
DbgPrint("PeFileNtosGetSsdtParam: KeServiceDescriptorTableShadow reference addresss not found!/n");
return false;
}
DbgPrint("PeFileNtosGetSsdtParam: ulKeServiceDescriptorTableShadowVA = %08X/n", *ulKeServiceDescriptorTableShadowVA);
return true;
}
lpBaseReloc = (IMAGE_BASE_RELOCATION *)((PUCHAR)lpBaseReloc + lpBaseReloc->SizeOfBlock);
}
DbgPrint("PeFileNtosGetSsdtParam: SerivceTableBase reference addresss not found!/n");
return false;
}