这段代码我在Xp下测试很成功,
在Win7取出的地址是错误的。
第一个参数索引号,第二个参数是在内存中的SSDT表地址
ULONG GetReallySSDTFunctionAddress(ULONG index,ULONG _SSDT)
{
// 获取步骤
// 获取SSDT表基址
// 获取ntkrnlpa.exe载入基址
// SSDT表基址-ntkrnlpa.exe载入基址 = SSDT表RVA
// 计算RVA在ntkrnlpa.exe文件中的 FileOffet
// 读入保存在硬盘上的SSDT表
ULONG needlen;
ULONG i;
PVOID buf;
ULONG ntkrnlpaBase=0;
ULONG MemorySSDT; // 内存中SSDT表基址
ULONG SSDT_RVA=0;
PSYSTEM_MODULE_INFORMATION pModules;
HANDLE handle=NULL;
UNICODE_STRING FileName;
OBJECT_ATTRIBUTES fileInfo={0};
NTSTATUS status;
IO_STATUS_BLOCK ioStatus;
FILE_STANDARD_INFORMATION fsi={0};
unsigned char *pFileBuff=NULL;
ULONG NumberOfSection=0; //区块数目
PIMAGE_DOS_HEADER pDosHead=NULL;
PIMAGE_NT_HEADERS pNtHead=NULL;
PIMAGE_SECTION_HEADER pSection=NULL; //所有区段
ULONG addr2=0;
ULONG addr1=0;
ULONG ret_address;
ULONG ssa;
PWCHAR kernelName;
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&needlen);
buf=(PVOID)ExAllocatePoolWithTag(NonPagedPool,needlen,1448);
if (buf==NULL){ DbgPrint("分配内存失败!!\n");return STATUS_UNSUCCESSFUL;}
ZwQuerySystemInformation(SystemModuleInformation,(PVOID)buf,needlen,&needlen);
pModules=(PSYSTEM_MODULE_INFORMATION)buf;
ntkrnlpaBase=(ULONG)pModules->Module[0].Base;
if (ntkrnlpaBase==0)
{
DbgPrint("内核基址获取失败!\n");
return STATUS_UNSUCCESSFUL;
}
//DbgPrint("ntkrnlpaBase:%x",ntkrnlpaBase);
MemorySSDT=*(ULONG*)_SSDT;
if (MemorySSDT==0)
{
DbgPrint("获取SSDT表地址失败。\n");
return STATUS_UNSUCCESSFUL;
}else if (MemorySSDT<ntkrnlpaBase || MemorySSDT>(ntkrnlpaBase+pModules->Module[0].Size)) //SSDT表不再ntkrnlpa模块中
{
DbgPrint("SSDT表地址无效!\n");
return STATUS_UNSUCCESSFUL;
}
SSDT_RVA = MemorySSDT-ntkrnlpaBase;
if (SSDT_RVA==0)
{
DbgPrint("SSDT RVA未取到!\n");
return STATUS_UNSUCCESSFUL;
}
//DbgPrint("SSDT RVA:%x",SSDT_RVA);
__asm
{
pushad
_emit 0x0f
_emit 0x20
_emit 0xe0 //mov eax,cr4
shr eax,4
and eax,1
mov ssa,eax
popad
}
kernelName = ssa?L"\\SystemRoot\\system32\\ntkrnlpa.exe" : L"\\SystemRoot\\system32\\ntoskrnl.exe";
DbgPrint("内核文件 : %S",kernelName);
RtlInitUnicodeString(&FileName,kernelName);
InitializeObjectAttributes(&fileInfo,&FileName,OBJ_CASE_INSENSITIVE,NULL,NULL);
status=ZwCreateFile(&handle,GENERIC_READ,&fileInfo,&ioStatus,NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_OPEN,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0);
if (ioStatus.Information!=1)
{
DbgPrint("文件打开失败!\n");
return STATUS_UNSUCCESSFUL;
}
ZwQueryInformationFile(handle,&ioStatus,&fsi,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation);
if ((LONG)fsi.EndOfFile.QuadPart==0)
{
DbgPrint("获取文件大小失败!\n");
return STATUS_UNSUCCESSFUL;
}
pFileBuff=(unsigned char *)ExAllocatePoolWithTag(NonPagedPool,(size_t)fsi.EndOfFile.QuadPart,1449);
if (pFileBuff==NULL)
{
DbgPrint("为文件分配缓冲区失败!!\n");
return STATUS_UNSUCCESSFUL;
}
ZwReadFile(handle,NULL,NULL,NULL,&ioStatus,pFileBuff,(size_t)fsi.EndOfFile.QuadPart,0,NULL);
pDosHead=(PIMAGE_DOS_HEADER)pFileBuff;
pNtHead=(PIMAGE_NT_HEADERS)((ULONG)pDosHead+(ULONG)(pDosHead->e_lfanew));
NumberOfSection=pNtHead->FileHeader.NumberOfSections;
//DbgPrint("区块数目:%d",NumberOfSection);
pSection=(PIMAGE_SECTION_HEADER)((ULONG)pNtHead+sizeof(IMAGE_NT_HEADERS));
for(i=0;i<NumberOfSection;i++)
{
if ((SSDT_RVA>pSection[i].VirtualAddress) && (SSDT_RVA<(pSection[i].VirtualAddress+pSection[i].SizeOfRawData))) //判断是否位于某个区块之简
{
//数据的文件偏移=(数据RVA - 节RVA) + 节的文件偏移
//DbgPrint("RVA :%x %d ",SSDT_RVA,i);
//DbgPrint("RVA %d",pSection[i].VirtualAddress);
addr2=SSDT_RVA-pSection[i].VirtualAddress;
addr1=addr2+pSection[i].PointerToRawData;
break;
}
}
//DbgPrint("File Offset:%x",addr1);
ret_address=addr1+index*4;
_asm
{
pushad
mov ecx,pFileBuff
mov ebx,ret_address
mov eax,[ebx+ecx]
mov ret_address,eax
popad
}
// 重定位
ret_address-=pNtHead->OptionalHeader.ImageBase;
ret_address+=ntkrnlpaBase;
//释放资源
ExFreePool(pFileBuff);
ExFreePool(buf);
ZwClose(handle);
return ret_address;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!