网上其实有很多介绍ssdt还原的文章,看起来也确实是一个很简单,套用一句网友的话,就是菜B才用的技术。但我着实也费了一番工夫,也可能真是我自己的理解能力太差。一个人搞了两三天才弄出来,其实真的很简单,只是有些文章说得很含糊。
下面我说几个要点:
1. ssdt已存在于原始pe文件中。(具体是ntoskrnl.exe、ntkrnlpa.exe、ntkrnlmp.exe、ntkrpamp.exe 自已想法确定)
操作系统根据是否是多处理器平台和是否支持PAE(Physical Address Extension)来选择合适的系
Picasa Content统文件。
ntoskrnl.exe
单x86处理器,使用不超过4GB的物理内存。
ntkrnlpa.exe
单x86处理器,支持PAE。
ntkrnlmp.exe
多处理器,使用不超过4GB的物理内存。
ntkrpamp.exe
多处理器,支持PAE。
//如何确定系统的内核是ntoskrnl.exe还是ntkrnlpa.exe? 这里没有考虑多核 int nPaeOpen = 0; WCHAR* kernelName= NULL; __asm{ _emit 0x0f _emit 0x20 _emit 0xe0 mov edx, 0x1 shl edx, 5 and eax, edx shr eax, 5 mov nPaeOpen,eax } kernelName = nPaeOpen?L"ntoskrnl.exe":L"ntkrnlpa";
2. 位置的计算牵涉到几个地址:
a. ssdt现存地址,可以通过windbg演示一下. (0x80504960 中存放地址表)
b. 找出当前内核基址 (804d8000)
关于这里为什么是ntkrpamp.exe,我找了点资料:
c. 有了这两个地址之后就可以算出RVA = 0x80504960 – 0x804d8000 = 0x2C960
d.我们再去ntkrnlpa.exe中寻找对应的File offset (2BF60)
e. 拿UE找出实际值 (04 C1 4C 00 也就是 0x004CC104)
f. 搞定,最后验证一下, 0x004CC104 – ImageBase + 内核基址
0x004CC104 – 0x00400000 + 0x804d8000 = 805A4104
在windbg中看一下,地址符合,不符的话,肯定就是被 hook掉了。
帖点实现代码:
//根据RVA获取原始PE文件中的SSDT表 void GetSSDTFromPE(const SSDT_PARAM& ssdt_param ){ gvSSDTList.clear(); const DWORD rva = ssdt_param.ServiceTableBase-ssdt_param.nKernelImageBase; HANDLE hMapFile =NULL; HANDLE hFile =NULL; SIZE_T size = 0; int ECode = 0; PVOID pLoadBase =NULL; __try{ __try{ hFile = CreateFile(ssdt_param.kernelpath, FILE_ALL_ACCESS, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hFile == INVALID_HANDLE_VALUE){ DisplayError(_T("CreateFile"),GetLastError()); RaiseException(1, // 抛?出?异?常?码?为?的?SEH异?常? 0, 0, NULL); // 没?有?参?数? __leave; } DWORD dwBytesInBlock = GetFileSize(hFile,NULL); //文?件?长?度? hMapFile = CreateFileMapping( hFile, // use paging file NULL, // default security PAGE_READWRITE, 0, // max. object size dwBytesInBlock, // buffer size NULL); // name of mapping object CloseHandle(hFile); if( hMapFile == NULL){ RaiseException(2, 0, 0, NULL); __leave; } pLoadBase = MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,dwBytesInBlock); if(pLoadBase == NULL){ RaiseException(3, 0, 0, NULL); __leave; } //_tprintf(_T("ImageBase = 0x%x\n"),pLoadBase); PIMAGE_NT_HEADERS pImageNtHeader = ImageNtHeader(pLoadBase); if(pImageNtHeader == NULL){ RaiseException(3, 0, 0, NULL); __leave; } DWORD ImageBase = pImageNtHeader->OptionalHeader.ImageBase; DWORD* VaAddr = (DWORD*)ImageRvaToVa(pImageNtHeader,pLoadBase,rva,NULL); if(VaAddr == NULL){ RaiseException(4, 0, 0, NULL); __leave; } //_tprintf(_T("Index\tAddress\n")); for(DWORD i = 1; i <= ssdt_param.nCount; ++i,++VaAddr){ //_tprintf(TEXT("0x%x\t[0x%x]\n"),i,*VaAddr-ImageBase+ssdt_param.nKernelImageBase); gvSSDTList.push_back(*VaAddr-ImageBase+ssdt_param.nKernelImageBase); } } __except(ECode=GetExceptionCode()) { DisplayError(_T(" "),GetLastError()); } } __finally{ if(pLoadBase) UnmapViewOfFile(pLoadBase); if(hMapFile) CloseHandle(hMapFile); if(hFile) CloseHandle(hFile); } return ; }