阅读:5808回复:23
关于读文件恢复 SSDT 的问题
前段时间实现了 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! 希望大虾们指点指点,感谢! |
|
最新喜欢:![]()
|
沙发#
发布于:2007-04-04 18:08
翻翻我在CVC的帖子~
|
|
|
板凳#
发布于:2007-04-05 09:46
|
|
|
地板#
发布于:2007-04-06 09:54
大虾们给点线索偶吧
|
|
|
地下室#
发布于:2007-04-09 09:26
看了两篇添加服务函数的资料,貌似添加过程会将 SSDT 表复制一份,这样表地址就改变了,卡巴的确添加了好几个服务函数!!
5,这样原来那张表貌似被遗弃了,怎么得到它的地址呢? |
|
|
5楼#
发布于:2007-04-10 18:02
|
|
6楼#
发布于:2007-04-11 09:41
baigan 你是假设 NtReadFile 和 NtClose 没有被改变的情况搜索,是么?
貌似代码还有些小错误 ^^ 不管怎么说,谢谢回复! 如果实在没办法也只好暴力了~~ ![]() |
|
|
7楼#
发布于:2007-04-11 09:59
在SDTrestore工具发布后,90210在rootkit.com提出了一种定位KiServiceTable更有效的办法。该技术主要基于KeServiceDescriptorTable是在KiInitSystem函数中通过下面的指令初始化:
mov ds:KeServiceDescriptorTable, offset KiServiceTable 可以通过搜索ntoskrnl.exe的重定位表找到这条指令。使用重定位表的搜索如上的指令比在整个ntoskrnl.exe的程序区中搜索,更加有效和可靠。一旦找到这条指令,KiServiceTable的偏移地址就找到了 |
|
|
8楼#
发布于:2007-04-11 10:03
90210 - A more stable way to locate real KiServiceTable
http://www.rootkit.com/newsread.php?newsid=176 |
|
|
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 |
|
|
10楼#
发布于:2007-04-11 14:32
baigan 你是假设 NtReadFile 和 NtClose 没有被改变的情况搜索,是么?
___ NtReadFile 和 NtClose 从文件中得到的 , |
|
11楼#
发布于:2007-04-11 17:45
哦,是的
![]() |
|
|
12楼#
发布于:2007-04-12 18:42
我是没有好的Findaddr实现方法才没贴,,用的在导出表中查找地址(理论上这种方法没啥问题吧??),不过我在网吧的电脑上不能得到正确的地址(家里不能上网)就没贴,
ring3+mdl加载给驱动解决了, |
|
13楼#
发布于:2007-04-13 11:35
在导出表中查找地址?? 那得到的不是服务地址吧?
Nt××× 系列函数地址跟 SSDT 里面的服务地址不一样的不 这些函数调用中断转到服务函数里的 |
|
|
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); 貌似工作的蛮好,接下来全面测试中 :) |
|
|
15楼#
发布于:2007-04-16 15:11
![]() |
|
16楼#
发布于:2007-06-03 10:33
还是有错的,
static HMODULE hNtoskrnl = LoadLibrary("Ntdll.dll"); static PNtQuerySystemInformation pfnNtQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(hNtoskrnl, "NtQuerySystemInformation"); 应该放到main里面, |
|
|
17楼#
发布于:2007-07-03 00:00
SDTrestore0.2不是按90210的方法做了更新吗?
为什么两个程序找到的KiServiceTable值却不同? |
|
18楼#
发布于:2007-07-03 10:07
引用第16楼wingsoft于2007-06-03 10:33发表的 : 为什么要放里面呢? 我这样子运行貌似木有失败啊。。。 |
|
|
19楼#
发布于:2007-07-03 10:08
引用第17楼aliwy于2007-07-03 00:00发表的 : 有不同吗?不会吧? 我取到的地址貌似和 PJF 的 iceword 取到的一样... |
|
|
上一页
下一页