老技术,新人还是要学,高手飘过
如何获得一个干净的ssdt(ShadowSSDT)是一个主要问题
参考了KsBinSword的在R3下获得干净的ssdt(ShadowSSDT),没能看明白,
作者写的太深奥了,有没有注释,看的痛苦。
逆了一下Sysnap的Yas antiRootkit,是在R0下获得。
顺便贴下代码,
void GetSSDTFromFile()
{
//传11号进程获得ntoskernel.exe的地址和大小
ULONG dwsize;
NTSTATUS status;
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&dwsize);
PVOID sysinfo = ::ExAllocatePool(NonPagedPool,dwsize);
status = ZwQuerySystemInformation(SystemModuleInformation,sysinfo,dwsize,&dwsize);
if(!NT_SUCCESS(status))
{
return;
}
PSYSTEM_MODULE_INFORMATION psmi = (PSYSTEM_MODULE_INFORMATION)((char*)sysinfo+4);
ULONG ntaddress = (ULONG)(psmi->Base);//获得Ntoskernel.exe在内存中的基址
char *name = psmi->ImageName + psmi->ModuleNameOffset;
//把文件映射到我们的内存地址
HANDLE fileHandle;
IO_STATUS_BLOCK IoStatusBlock;
ULONG i;
char ModuleName[255];
ANSI_STRING asModuleName;
UNICODE_STRING usModuleName;
HANDLE SectionHandle;
strcpy(ModuleName,"\\Device\\HarddiskVolume1\\Windows\\System32\\");
strcat(ModuleName,name);
::RtlInitAnsiString(&asModuleName,ModuleName);
::RtlAnsiStringToUnicodeString(&usModuleName,&asModuleName,TRUE);//得到ntosker.exe的文件名
OBJECT_ATTRIBUTES oa = {sizeof oa, 0, &usModuleName, OBJ_CASE_INSENSITIVE};
status = ZwOpenFile( &fileHandle,
FILE_EXECUTE | SYNCHRONIZE,
&oa,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
oa.ObjectName = NULL;
#define SEC_IMAGE 0x01000000
status = ZwCreateSection( &SectionHandle,
SECTION_MAP_EXECUTE,
&oa,
0,
PAGE_EXECUTE,
SEC_IMAGE,
fileHandle);
PVOID BaseAddress = NULL;
ULONG size = 0;
status = ZwMapViewOfSection( SectionHandle,
NtCurrentProcess(),
&BaseAddress,
0,
1000,
0,
&size,
(SECTION_INHERIT)1,
MEM_TOP_DOWN,
PAGE_READWRITE);
//算出SSDT的相对虚拟地址
ULONG RVAofSSDT = (ULONG)(KeServiceDescriptorTable.ServiceTableBase) - ntaddress;
DWORD PEhead;
WORD NumberOfSection;
DWORD SectionOfRVAOffset;
DWORD SectionOfRVA;
DWORD ret;
__try
{
PEhead = (DWORD)((CHAR*)BaseAddress + (*(PDWORD)((CHAR*)BaseAddress+0x3C)));
NumberOfSection = *(PWORD)(PEhead + 6);
//第一个节的VirtualAddress的地址
SectionOfRVAOffset = PEhead + 0x104;
SectionOfRVA = *(PDWORD)(SectionOfRVAOffset);
for(int i = 0; i < NumberOfSection; i++)
{
if( RVAofSSDT > SectionOfRVA )
{
DWORD SizeofDrawData = *(PDWORD)(SectionOfRVAOffset + 4);//得到这个节在文件中大小
if( RVAofSSDT< (SectionOfRVA + SizeofDrawData))
{
DWORD PointerToDrawData = *(PDWORD)(SectionOfRVAOffset + 8);//这个节在文件的偏移
//RVAofSSDT - 它所在的节的RVA + 它所在的节的文件偏移
//这样就得到了它在文件中的地址偏移
ret = RVAofSSDT - SectionOfRVA + PointerToDrawData;
break;
}
}
SectionOfRVAOffset = SectionOfRVAOffset + 0x28;//下一个节的地址
SectionOfRVA = *(PDWORD)(SectionOfRVAOffset);//下一个节的相对虚拟地址
}
}
__except(1)
{
KdPrint(("INVALID ADDRESS is Access!!!"));
return;
}
//分配一块内存给读取文件上的SSDT
PULONG FileofSSDT = (PULONG)ExAllocatePool(NonPagedPool,4*KeServiceDescriptorTable.NumberOfServices);
LARGE_INTEGER ByteOffset;
ByteOffset.u.HighPart = 0;
ByteOffset.u.LowPart = ret;
IO_STATUS_BLOCK IostatusBlock;
//从文件中读取的数据
ZwReadFile( fileHandle,
NULL,
NULL,
NULL,
&IostatusBlock,
FileofSSDT,
KeServiceDescriptorTable.NumberOfServices * 4,
&ByteOffset,
NULL);
//分配一块内存作为原始的干净的SSDT
PULONG OrignalofSSDT = (PULONG)ExAllocatePool(NonPagedPool,4*KeServiceDescriptorTable.NumberOfServices);
ULONG ImageBase = *(PULONG)(PEhead + 0x34);
for(i = 0; i < KeServiceDescriptorTable.NumberOfServices; i++)
{
//得到干净的SSDT
OrignalofSSDT[i] = FileofSSDT[i] - ImageBase + ntaddress;
if(i%4==0 && i!=0)
{
KdPrint(("\n%x ",OrignalofSSDT[i]));
}
else
{
KdPrint(("%x ",OrignalofSSDT[i]));
}
}
ZwClose(fileHandle);
ZwClose(SectionHandle);
ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
ExFreePool(FileofSSDT);
}
ShadowSSDT也是这样,但它不是一个导出表,可以从KeAddSystemServiceTable获得
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!