ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
阅读:5808回复:23

关于读文件恢复 SSDT 的问题

楼主#
更多 发布于:2007-04-04 17:25
  前段时间实现了 SSDT Shadow 的读文件恢复,在各个环境下测试了下都没有失败。
方法是: 表头地址与模块地址偏移 减去 RVA 加上 POINTTORAWDATA 等于表文件偏移。

这两天想试试用相同的方法,恢复 SSDT 试试,结果发现只在部分机器上生效。
在安装了卡巴的机器上,表头地址居然不在 ntoskrnl.exe 的范围内——;??

-------------下面是输出---------
DbgView_SSDT() g_pSST: 0x80562480
DbgView_SSDT() ServiceTable: 0x85583B58     **** 这地址不在模块内啊
DbgView_SSDT() TableSize: 0x00000129 (297)

DbgView_SSDT() gs_pSSTShadow: 0x80562450
DbgView_SSDT() ServiceTable: 0xBF998300
DbgView_SSDT() TableSize: 0x29B (667)

---------------------------
CTSSDTReserve::GetRealSSDT() pImageBase: 00400000
CTSSDTReserve::GetRealSSDT() pModuleBase: 804E0000   **** 模块起始地址
CTSSDT::GetRealSSDT() pModuleLen: 00213F80             **** 模块大小
CTSSDTReserve::GetRealSSDT() pSSTAddr: 85583B58       **** 表头(明显不在模块内)
CTSSDTReserve::GetRealSSDT() get image file: ntoskrnl.exe offset failed!

希望大虾们指点指点,感谢!

最新喜欢:

znsoftznsoft
Thinking
killvxk
论坛版主
论坛版主
  • 注册日期2005-10-03
  • 最后登录2014-04-14
  • 粉丝3
  • 关注1
  • 积分1082分
  • 威望2003点
  • 贡献值0点
  • 好评度1693点
  • 原创分2分
  • 专家分0分
沙发#
发布于:2007-04-04 18:08
翻翻我在CVC的帖子~
没有战争就没有进步 X3工作组 为您提供最好的军火
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-04-05 09:46
http://www.retcvc.com/
http://www.retcvc.com/cgi-bin/leobbs.cgi
貌似都打不开啊,是这两个地址么?
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-04-06 09:54
大虾们给点线索偶吧
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2007-04-09 09:26
看了两篇添加服务函数的资料,貌似添加过程会将 SSDT 表复制一份,这样表地址就改变了,卡巴的确添加了好几个服务函数!!
5,这样原来那张表貌似被遗弃了,怎么得到它的地址呢?
Thinking
baigan
驱动牛犊
驱动牛犊
  • 注册日期2006-07-04
  • 最后登录2011-10-21
  • 粉丝0
  • 关注0
  • 积分140分
  • 威望17点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2007-04-10 18:02
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2007-04-11 09:41
baigan 你是假设 NtReadFile 和 NtClose 没有被改变的情况搜索,是么?
貌似代码还有些小错误 ^^
不管怎么说,谢谢回复!
如果实在没办法也只好暴力了~~
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2007-04-11 09:59
在SDTrestore工具发布后,90210在rootkit.com提出了一种定位KiServiceTable更有效的办法。该技术主要基于KeServiceDescriptorTable是在KiInitSystem函数中通过下面的指令初始化:
mov ds:KeServiceDescriptorTable, offset KiServiceTable
可以通过搜索ntoskrnl.exe的重定位表找到这条指令。使用重定位表的搜索如上的指令比在整个ntoskrnl.exe的程序区中搜索,更加有效和可靠。一旦找到这条指令,KiServiceTable的偏移地址就找到了
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2007-04-11 10:03
90210 - A more stable way to locate real KiServiceTable

http://www.rootkit.com/newsread.php?newsid=176
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2007-04-11 11:48
I've found a way how to locate original KiServiceTable in the ntoskrnl file even if KeServiceDescriptorTable.Base has been changed. Method works both in the user mode and in the kmode.



This may be useful to bypass SDT-patching hooks, and not only to restore old SDT. For example, KAV uses SDT relocation ;)

KeServiceDescriptorTable is initialized by KiInitSystem():


    KeServiceDescriptorTable[0].Base = &KiServiceTable[0];
    KeServiceDescriptorTable[0].Count = NULL;
    KeServiceDescriptorTable[0].Limit = KiServiceLimit;
    KeServiceDescriptorTable[0].Number = &KiArgumentTable[0];
    for (Index = 1; Index < NUMBER_SERVICE_TABLES; Index += 1) {
        KeServiceDescriptorTable[Index].Limit = 0;
    }


Thus, we can find KiServiceTable by examining all xrefs to KeServiceDescriptorTable in the kernel. We will search for


C7 05 ..8 bytes..   mov     ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable


from which we will get _KiServiceTable rva.

It's easy to find KeServiceDescriptorTable xrefs by scanning the code, but this is dangerous and time-consuming. It's better to use ntoskrnl's relocation information - it is always present in all nt systems.
This "mov [mem32], imm32" instruction will have 2 relocs pointing in it, and the second is the one we're searching for. So, the usermode code will do these steps:

1. Load ntosknrl as a dll.
2. Locate KeServiceDescriptorTable - it is exported.
3. Enumerate all relocations to find xrefs to the KeServiceDescriptorTable.
4. Check these opcodes to be a "mov [mem32],imm32".
5. Get KiServiceTable - it's offset is +6 from the opcode beginning.

The example code dumps KiServiceTable data from file and does no comparings with the existing sdt.

So, it's a must to a SDT-patching rootkit to hook file system and show "patched" version of ntoskrnl to all readers. And of course, services hooks code must reside in the ntoskrnl region and have no codepaths outside it. Otherwise it may be tracked in seconds.


///////////////////////////////////////////////////////////
// main.cpp
//
//        这是整理之后可以直接编译运行的代码(win32 console application)
//
///////////////////////////////////////////////////////////
#include <windows.h>
#include <winnt.h>
#include <stdio.h>
#include <conio.h>

#define RVATOVA(base,offset)            ((PVOID)((DWORD)(base)+(DWORD)(offset)))

#define ibaseDD                            *(PDWORD)&ibase

#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

#define NT_SUCCESS(Status)                ((NTSTATUS)(Status) >= 0)


typedef struct {
    WORD    offset:12;
    WORD    type:4;
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;


typedef LONG    NTSTATUS;

typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11
    ULONG    Reserved[2];
    PVOID    Base;
    ULONG    Size;
    ULONG    Flags;
    USHORT    Index;
    USHORT    Unknown;
    USHORT    LoadCount;
    USHORT    ModuleNameOffset;
    CHAR    ImageName[256];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;


typedef struct {
    DWORD    dwNumberOfModules;
    SYSTEM_MODULE_INFORMATION    smi;
} MODULES, *PMODULES;


//*
//
// NtQuerySystemInformation
//

#define    SystemModuleInformation    11


#ifdef __cplusplus
extern "C" {
#endif
    
typedef NTSTATUS
        (WINAPI
        *PNtQuerySystemInformation)(    
        DWORD        SystemInformationClass,
        PVOID        SystemInformation,
        ULONG        SystemInformationLength,
        PULONG        ReturnLength
        );
    
#ifdef __cplusplus
}
#endif

static  HMODULE  hNtoskrnl = LoadLibrary("Ntdll.dll");
static  PNtQuerySystemInformation pfnNtQuerySystemInformation
     = (PNtQuerySystemInformation)GetProcAddress(hNtoskrnl, "NtQuerySystemInformation");
//*/



//
// GetHeaders
//
DWORD
GetHeaders(    
           PBYTE                        ibase,
           PIMAGE_FILE_HEADER*            pfh,
           PIMAGE_OPTIONAL_HEADER*        poh,
           PIMAGE_SECTION_HEADER*        psh
           )
          
{
    PIMAGE_DOS_HEADER mzhead = (PIMAGE_DOS_HEADER)ibase;
    
    if    ((mzhead->e_magic!=IMAGE_DOS_SIGNATURE) ||        
        (ibaseDD[mzhead->e_lfanew]!=IMAGE_NT_SIGNATURE))
        return FALSE;
    
    *pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
    if (((PIMAGE_NT_HEADERS)*pfh)->Signature!=IMAGE_NT_SIGNATURE)
        return FALSE;
    *pfh=(PIMAGE_FILE_HEADER)((PBYTE)*pfh+sizeof(IMAGE_NT_SIGNATURE));
    
    *poh=(PIMAGE_OPTIONAL_HEADER)((PBYTE)*pfh+sizeof(IMAGE_FILE_HEADER));
    if ((*poh)->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC)
        return FALSE;
    
    *psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER));
    return TRUE;
}

//
// FindKiServiceTable
//
DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT)
{
    PIMAGE_FILE_HEADER            pfh;
    PIMAGE_OPTIONAL_HEADER        poh;
    PIMAGE_SECTION_HEADER        psh;
    PIMAGE_BASE_RELOCATION        pbr;
    PIMAGE_FIXUP_ENTRY            pfe;    
    
    DWORD    dwFixups=0,i,dwPointerRva,dwPointsToRva,dwKiServiceTable;
    BOOL    bFirstChunk;
    
    GetHeaders((PBYTE)hModule,&pfh,&poh,&psh);
    
    // loop thru relocs to speed up the search
    if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) &&
        (!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED))) {
        
        pbr=(PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule);
        
        bFirstChunk=TRUE;
        // 1st IMAGE_BASE_RELOCATION.VirtualAddress of ntoskrnl is 0
        while (bFirstChunk || pbr->VirtualAddress) {
            bFirstChunk=FALSE;
            
            pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr + sizeof(IMAGE_BASE_RELOCATION));
            
            for (i = 0; i < (pbr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))>>1; i++,pfe++)
            {
                if (pfe->type==IMAGE_REL_BASED_HIGHLOW)
                {
                    dwFixups++;
                    dwPointerRva=pbr->VirtualAddress+pfe->offset;
                    // DONT_RESOLVE_DLL_REFERENCES flag means relocs aren't fixed
                    dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase;
                    
                    // does this reloc point to KeServiceDescriptorTable.Base?
                    if (dwPointsToRva==dwKSDT)
                    {
                        // check for mov [mem32],imm32. we are trying to find
                        // "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"
                        // from the KiInitSystem.
                        if (*(PWORD)((DWORD)hModule + dwPointerRva - 2)==0x05c7)
                        {
                            // should check for a reloc presence on KiServiceTable here
                            // but forget it
                            dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase;
                            return dwKiServiceTable;
                        }
                    }
                    
                } else
                    if (pfe->type!=IMAGE_REL_BASED_ABSOLUTE)
                        // should never get here
                        printf("\trelo type %d found at .%X\n",pfe->type,pbr->VirtualAddress+pfe->offset);
            }
            *(PDWORD)&pbr+=pbr->SizeOfBlock;
        }
    }    
    
    if (!dwFixups)
        // should never happen - nt, 2k, xp kernels have relocation data
        printf("No fixups!\n");
    return 0;
}

int main(int argc,char *argv[])
{    
    HMODULE        hKernel;
    DWORD        dwKSDT;                // rva of KeServiceDescriptorTable
    DWORD        dwKiServiceTable;    // rva of KiServiceTable
    PMODULES    pModules = NULL;
    DWORD        dwNeededSize;
    DWORD        rc;
    DWORD        dwKernelBase;
    DWORD        dwServices = 0;
    PCHAR        pKernelName;
    PDWORD        pService;
    PIMAGE_FILE_HEADER            pfh;
    PIMAGE_OPTIONAL_HEADER        poh;
    PIMAGE_SECTION_HEADER        psh;
    
    
    // get system modules - ntoskrnl is always first there
    rc = pfnNtQuerySystemInformation(
                                    SystemModuleInformation,    // 11
                                    NULL,
                                    0,
                                    &dwNeededSize
                                    );
    if (rc == STATUS_INFO_LENGTH_MISMATCH)
    {
        pModules = (PMODULES)GlobalAlloc (GPTR, dwNeededSize);
        rc = pfnNtQuerySystemInformation(
                                    SystemModuleInformation,
                                    pModules,
                                    dwNeededSize,
                                    NULL
                                    );
    }
    else
    {
strange:
        printf("strange NtQuerySystemInformation()!\n");
        return 0;
    }
    if (!NT_SUCCESS(rc)) goto strange;
    
    // imagebase
    dwKernelBase=(DWORD)pModules->smi.Base;
    // filename - it may be renamed in the boot.ini
    pKernelName=pModules->smi.ModuleNameOffset+pModules->smi.ImageName;
    
    // map ntoskrnl - hopefully it has relocs
    hKernel=LoadLibraryEx(pKernelName,0,DONT_RESOLVE_DLL_REFERENCES);
    if (!hKernel)
    {
        printf("Failed to load! LastError=%i\n",GetLastError());
        return 0;        
    }
    
    GlobalFree(pModules);
    
    // our own export walker is useless here - we have GetProcAddress :)    
    if (!(dwKSDT=(DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable"))) {
        printf("Can't find KeServiceDescriptorTable\n");
        return 0;
    }
    
    // get KeServiceDescriptorTable rva
    dwKSDT-=(DWORD)hKernel;    
    // find KiServiceTable
    if (!(dwKiServiceTable=FindKiServiceTable(hKernel,dwKSDT))) {
        printf("Can't find KiServiceTable...\n");
        return 0;
    }
    
    printf("&KiServiceTable==%08X\n\nDumping 'old' ServiceTable:\n\n",
        dwKiServiceTable+dwKernelBase);    
    
    // let's dump KiServiceTable contents        
    
    // MAY FAIL!!!
    // should get right ServiceLimit here, but this is trivial in the kernel mode
    GetHeaders((PBYTE)hKernel,&pfh,&poh,&psh);
    
    for (pService=(PDWORD)((DWORD)hKernel+dwKiServiceTable);
    *pService-poh->ImageBase<poh->SizeOfImage;
    pService++,dwServices++)
        printf("%08X\n",*pService-poh->ImageBase+dwKernelBase);    
    
    printf("\n\nPossibly KiServiceLimit==%08X\n",dwServices);
    
    FreeLibrary(hKernel);
    
    getch();
    return 0;
}





wbr, 90210
Thinking
baigan
驱动牛犊
驱动牛犊
  • 注册日期2006-07-04
  • 最后登录2011-10-21
  • 粉丝0
  • 关注0
  • 积分140分
  • 威望17点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2007-04-11 14:32
baigan 你是假设 NtReadFile 和 NtClose 没有被改变的情况搜索,是么?
___

NtReadFile 和 NtClose 从文件中得到的 ,
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2007-04-11 17:45
哦,是的 ,不过在你的代码里面没有看到 Findaddr 函数的实现。
Thinking
baigan
驱动牛犊
驱动牛犊
  • 注册日期2006-07-04
  • 最后登录2011-10-21
  • 粉丝0
  • 关注0
  • 积分140分
  • 威望17点
  • 贡献值0点
  • 好评度16点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2007-04-12 18:42
我是没有好的Findaddr实现方法才没贴,,用的在导出表中查找地址(理论上这种方法没啥问题吧??),不过我在网吧的电脑上不能得到正确的地址(家里不能上网)就没贴,

ring3+mdl加载给驱动解决了,
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2007-04-13 11:35
在导出表中查找地址?? 那得到的不是服务地址吧?
Nt××× 系列函数地址跟 SSDT 里面的服务地址不一样的不
这些函数调用中断转到服务函数里的
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2007-04-13 11:39
上面的代码只是稍微整理了下,现在我又改正了释放资源的分支和其他若干不合理的地方,再把它做成了一个函数
//
// FUNCTION:
//        get original ssdt table
// PARAMETER:
//        OUT        pTable        buffer point
//        IN        uSize        buffer size
//RETURN VALUE:
//        ULONG    table size    (0 indicate failed)
//
ULONG GetOriginalSSDT(PULONG pTable, const ULONG uSize);

貌似工作的蛮好,接下来全面测试中 :)
Thinking
cppdev
驱动牛犊
驱动牛犊
  • 注册日期2006-11-26
  • 最后登录2009-01-11
  • 粉丝0
  • 关注0
  • 积分300分
  • 威望43点
  • 贡献值0点
  • 好评度42点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2007-04-16 15:11
wingsoft
驱动小牛
驱动小牛
  • 注册日期2006-05-16
  • 最后登录2008-10-14
  • 粉丝0
  • 关注0
  • 积分1001分
  • 威望216点
  • 贡献值0点
  • 好评度214点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2007-06-03 10:33
还是有错的,
static HMODULE hNtoskrnl = LoadLibrary("Ntdll.dll");
static PNtQuerySystemInformation pfnNtQuerySystemInformation
  = (PNtQuerySystemInformation)GetProcAddress(hNtoskrnl, "NtQuerySystemInformation");

应该放到main里面,
[url] http://www.81915.com[/url]
aliwy
驱动牛犊
驱动牛犊
  • 注册日期2006-11-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分11分
  • 威望79点
  • 贡献值0点
  • 好评度32点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2007-07-03 00:00
SDTrestore0.2不是按90210的方法做了更新吗?
为什么两个程序找到的KiServiceTable值却不同?
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2007-07-03 10:07
引用第16楼wingsoft于2007-06-03 10:33发表的  :
还是有错的,
static HMODULE hNtoskrnl = LoadLibrary("Ntdll.dll");
static PNtQuerySystemInformation pfnNtQuerySystemInformation
  = (PNtQuerySystemInformation)GetProcAddress(hNtoskrnl, "NtQuerySystemInformation");

.......

为什么要放里面呢?
我这样子运行貌似木有失败啊。。。
Thinking
ks12345
驱动小牛
驱动小牛
  • 注册日期2006-09-21
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望223点
  • 贡献值0点
  • 好评度189点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2007-07-03 10:08
引用第17楼aliwy于2007-07-03 00:00发表的  :
SDTrestore0.2不是按90210的方法做了更新吗?
为什么两个程序找到的KiServiceTable值却不同?


有不同吗?不会吧?
我取到的地址貌似和 PJF 的 iceword 取到的一样...
Thinking
上一页
游客

返回顶部