首页
社区
课程
招聘
[讨论]SSDT(ShadowSSDT)恢复
发表于: 2009-7-2 03:29 6711

[讨论]SSDT(ShadowSSDT)恢复

2009-7-2 03:29
6711

老技术,新人还是要学,高手飘过
如何获得一个干净的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获得


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
2
ShadowSSDT能这样恢复就怪了。。。
2009-7-2 13:10
0
游客
登录 | 注册 方可回帖
返回
//