偶找到的,恢复被Hook的中断的真实地址,全局Hook的克星,可以对付3721的Minkp.sys<br>等修改ssdt的驱动.(原作者很谨慎,其实修改一下原程序的版本检测可适用至win2003)<br><br>//*********************************************************************************************<br>// SDTrestore (Proof-of-Concept) <br>// Version 0.2<br>// by SIG^2 G-TEC Lab<br>//<br>// Coded by Chew Keong TAN<br>//<br>// Permission is hereby granted, free of charge, to any person obtaining a<br>// copy of this software and associated documentation files (the<br>// "Software"
, to deal in the Software without restriction, including<br>// without limitation the rights to use, copy, modify, merge, publish,<br>// distribute, and/or sell copies of the Software, and to permit persons<br>// to whom the Software is furnished to do so, provided that the above<br>// copyright notice(s) and this permission notice appear in all copies of<br>// the Software and that both the above copyright notice(s) and this<br>// permission notice appear in supporting documentation.<br>//<br>// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS<br>// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br>// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT<br>// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR<br>// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL<br>// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING<br>// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,<br>// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION<br>// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.<br>//<br>// This program needs to access /device/physicalmemory, so you must be <br>// running as Administrator when using this.<br>//<br>// CHANGES<br>// -------<br>// Version 0.2<br>// Thanks to 90210 for the suggestion of a more stable way to find the <br>// address of KiServiceTable from the disk image of ntoskrnl.exe<br>// http://www.rootkit.com/newsread.php?newsid=176<br>//<br>//*********************************************************************************************<br><br>#include <stdio.h><br>#include <stdlib.h><br>#include <windows.h><br>#include <aclapi.h><br><br><br>#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)<br>#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)<br>#define OBJ_CASE_INSENSITIVE 0x00000040L<br>#define PAGE_READONLY 0x02<br>#define PAGE_READWRITE 0x04<br>#define DEF_KERNEL_BASE 0x80400000L<br>#define SystemModuleInformation 11<br>#define PROT_MEMBASE 0x80000000<br><br>typedef LONG NTSTATUS;<br>typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;<br><br>DWORD gWinVersion;<br><br>typedef struct _STRING {<br> USHORT Length;<br> USHORT MaximumLength;<br> PCHAR Buffer;<br>} ANSI_STRING, *PANSI_STRING;<br><br>typedef struct _UNICODE_STRING {<br> USHORT Length;<br> USHORT MaximumLength;<br> PWSTR Buffer;<br>} UNICODE_STRING, *PUNICODE_STRING;<br><br>typedef struct _OBJECT_ATTRIBUTES {<br> ULONG Length;<br> HANDLE RootDirectory;<br> PUNICODE_STRING ObjectName;<br> ULONG Attributes;<br> PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR<br> PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE<br>} OBJECT_ATTRIBUTES;<br>typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;<br><br>typedef enum _SECTION_INHERIT {<br> ViewShare = 1,<br> ViewUnmap = 2<br>} SECTION_INHERIT;<br><br>typedef struct _SYSTEM_MODULE_INFORMATION<br>{<br> ULONG Reserved[2];<br> PVOID Base;<br> ULONG Size;<br> ULONG Flags;<br> USHORT Index;<br> USHORT Unknown;<br> USHORT LoadCount;<br> USHORT ModuleNameOffset;<br> CHAR ImageName[256];<br>} SYSTEM_MODULE_INFORMATION;<br><br>NTSTATUS (WINAPI * _RtlAnsiStringToUnicodeString)<br> (PUNICODE_STRING DestinationString,<br> IN PANSI_STRING SourceString,<br> IN BOOLEAN);<br><br>VOID (WINAPI *_RtlInitAnsiString)<br> (IN OUT PANSI_STRING DestinationString,<br> IN PCHAR SourceString);<br><br>VOID (WINAPI * _RtlFreeUnicodeString)<br> (IN PUNICODE_STRING UnicodeString);<br><br>NTSTATUS (WINAPI *_NtOpenSection)<br> (OUT PHANDLE SectionHandle,<br> IN ACCESS_MASK DesiredAccess,<br> IN POBJECT_ATTRIBUTES ObjectAttributes);<br><br>NTSTATUS (WINAPI *_NtMapViewOfSection)<br> (IN HANDLE SectionHandle,<br> IN HANDLE ProcessHandle,<br> IN OUT PVOID *BaseAddress,<br> IN ULONG ZeroBits,<br> IN ULONG CommitSize,<br> IN OUT PLARGE_INTEGER SectionOffset, /* optional */<br> IN OUT PULONG ViewSize,<br> IN SECTION_INHERIT InheritDisposition,<br> IN ULONG AllocationType,<br> IN ULONG Protect);<br><br>NTSTATUS (WINAPI *_NtUnmapViewOfSection)<br> (IN HANDLE ProcessHandle,<br> IN PVOID BaseAddress);<br><br>NTSTATUS (WINAPI * _NtQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);<br><br>//*******************************************************************************************************<br>// PE File structure declarations<br>//<br>//*******************************************************************************************************<br><br>struct PE_Header <br>{<br> unsigned long signature;<br> unsigned short machine;<br> unsigned short numSections;<br> unsigned long timeDateStamp;<br> unsigned long pointerToSymbolTable;<br> unsigned long numOfSymbols;<br> unsigned short sizeOfOptionHeader;<br> unsigned short characteristics;<br>};<br><br>struct PE_ExtHeader<br>{<br> unsigned short magic;<br> unsigned char majorLinkerVersion;<br> unsigned char minorLinkerVersion;<br> unsigned long sizeOfCode;<br> unsigned long sizeOfInitializedData;<br> unsigned long sizeOfUninitializedData;<br> unsigned long addressOfEntryPoint;<br> unsigned long baseOfCode;<br> unsigned long baseOfData;<br> unsigned long imageBase;<br> unsigned long sectionAlignment;<br> unsigned long fileAlignment;<br> unsigned short majorOSVersion;<br> unsigned short minorOSVersion;<br> unsigned short majorImageVersion;<br> unsigned short minorImageVersion;<br> unsigned short majorSubsystemVersion;<br> unsigned short minorSubsystemVersion;<br> unsigned long reserved1;<br> unsigned long sizeOfImage;<br> unsigned long sizeOfHeaders;<br> unsigned long checksum;<br> unsigned short subsystem;<br> unsigned short DLLCharacteristics;<br> unsigned long sizeOfStackReserve;<br> unsigned long sizeOfStackCommit;<br> unsigned long sizeOfHeapReserve;<br> unsigned long sizeOfHeapCommit;<br> unsigned long loaderFlags;<br> unsigned long numberOfRVAAndSizes;<br> unsigned long exportTableAddress;<br> unsigned long exportTableSize;<br> unsigned long importTableAddress;<br> unsigned long importTableSize;<br> unsigned long resourceTableAddress;<br> unsigned long resourceTableSize;<br> unsigned long exceptionTableAddress;<br> unsigned long exceptionTableSize;<br> unsigned long certFilePointer;<br> unsigned long certTableSize;<br> unsigned long relocationTableAddress;<br> unsigned long relocationTableSize;<br> unsigned long debugDataAddress;<br> unsigned long debugDataSize;<br> unsigned long archDataAddress;<br> unsigned long archDataSize;<br> unsigned long globalPtrAddress;<br> unsigned long globalPtrSize;<br> unsigned long TLSTableAddress;<br> unsigned long TLSTableSize;<br> unsigned long loadConfigTableAddress;<br> unsigned long loadConfigTableSize;<br> unsigned long boundImportTableAddress;<br> unsigned long boundImportTableSize;<br> unsigned long importAddressTableAddress;<br> unsigned long importAddressTableSize;<br> unsigned long delayImportDescAddress;<br> unsigned long delayImportDescSize;<br> unsigned long COMHeaderAddress;<br> unsigned long COMHeaderSize;<br> unsigned long reserved2;<br> unsigned long reserved3;<br>};<br><br><br>struct SectionHeader<br>{<br> unsigned char sectionName[8];<br> unsigned long virtualSize;<br> unsigned long virtualAddress;<br> unsigned long sizeOfRawData;<br> unsigned long pointerToRawData;<br> unsigned long pointerToRelocations;<br> unsigned long pointerToLineNumbers;<br> unsigned short numberOfRelocations;<br> unsigned short numberOfLineNumbers;<br> unsigned long characteristics;<br>};<br><br>struct MZHeader<br>{<br> unsigned short signature;<br> unsigned short partPag;<br> unsigned short pageCnt;<br> unsigned short reloCnt;<br> unsigned short hdrSize;<br> unsigned short minMem;<br> unsigned short maxMem;<br> unsigned short reloSS;<br> unsigned short exeSP;<br> unsigned short chksum;<br> unsigned short exeIP;<br> unsigned short reloCS;<br> unsigned short tablOff;<br> unsigned short overlay;<br> unsigned char reserved[32];<br> unsigned long offsetToPE;<br>};<br><br><br>struct ImportDirEntry<br>{<br> DWORD importLookupTable;<br> DWORD timeDateStamp;<br> DWORD fowarderChain;<br> DWORD nameRVA;<br> DWORD importAddressTable;<br>};<br><br><br>DWORD myStrlenA(char *ptr)<br>{<br> DWORD len = 0;<br> while(*ptr)<br> {<br> len++;<br> ptr++;<br> }<br><br> return len;<br>}<br><br><br>BOOL myStrcmpA(char *str1, char *str2)<br>{<br> while(*str1 && *str2)<br> {<br> if(*str1 == *str2)<br> {<br> str1++;<br> str2++;<br> }<br> else<br> {<br> return FALSE;<br> }<br> }<br><br> if(*str1 && !*str2)<br> {<br> return FALSE;<br> }<br> else if(*str2 && !*str1)<br> {<br> return FALSE;<br> }<br><br> return TRUE; <br>}<br><br>//*******************************************************************************************************<br>// Fills the various structures with info of a PE image. The PE image is located at modulePos.<br>//<br>//*******************************************************************************************************<br><br>bool readPEInfo(char *modulePos, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,<br> SectionHeader **outSecHdr)<br>{<br> // read MZ Header<br> MZHeader *mzH;<br> mzH = (MZHeader *)modulePos;<br><br> if(mzH->signature != 0x5a4d) // MZ<br> {<br> printf("File does not have MZ header/n"
;<br> return false;<br> }<br><br> // read PE Header<br> PE_Header *peH;<br> peH = (PE_Header *)(modulePos + mzH->offsetToPE);<br><br> if(peH->sizeOfOptionHeader != sizeof(PE_ExtHeader))<br> {<br> printf("Unexpected option header size./n"
;<br> <br> return false;<br> }<br><br> // read PE Ext Header<br> PE_ExtHeader *peXH;<br> peXH = (PE_ExtHeader *)((char *)peH + sizeof(PE_Header));<br><br> // read the sections<br> SectionHeader *secHdr = (SectionHeader *)((char *)peXH + sizeof(PE_ExtHeader));<br><br> *outMZ = *mzH;<br> *outPE = *peH;<br> *outpeXH = *peXH;<br> *outSecHdr = secHdr;<br><br> return true;<br>}<br><br><br>//*******************************************************************************************************<br>// Returns the total size required to load a PE image into memory<br>//<br>//*******************************************************************************************************<br><br>int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,<br> SectionHeader *inSecHdr)<br>{<br> int result = 0;<br> int alignment = inpeXH->sectionAlignment;<br><br> if(inpeXH->sizeOfHeaders % alignment == 0)<br> result += inpeXH->sizeOfHeaders;<br> else<br> {<br> int val = inpeXH->sizeOfHeaders / alignment;<br> val++;<br> result += (val * alignment);<br> }<br> for(int i = 0; i < inPE->numSections; i++)<br> {<br> if(inSecHdr
.virtualSize)<br> {<br> if(inSecHdr.virtualSize % alignment == 0)<br> result += inSecHdr.virtualSize;<br> else<br> {<br> int val = inSecHdr.virtualSize / alignment;<br> val++;<br> result += (val * alignment);<br> }<br> }<br> }<br><br> return result;<br>}<br><br><br>//*******************************************************************************************************<br>// Returns the aligned size of a section<br>//<br>//*******************************************************************************************************<br><br>unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)<br>{ <br> if(curSize % alignment == 0)<br> return curSize;<br> else<br> {<br> int val = curSize / alignment;<br> val++;<br> return (val * alignment);<br> }<br>}<br><br>//*******************************************************************************************************<br>// Copy a PE image from exePtr to ptrLoc with proper memory alignment of all sections<br>//<br>//*******************************************************************************************************<br><br>bool loadPE(char *exePtr, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,<br> SectionHeader *inSecHdr, LPVOID ptrLoc)<br>{<br> char *outPtr = (char *)ptrLoc;<br> <br> memcpy(outPtr, exePtr, inpeXH->sizeOfHeaders);<br> outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);<br><br> for(int i = 0; i < inPE->numSections; i++)<br> {<br> if(inSecHdr.sizeOfRawData > 0)<br> {<br> unsigned long toRead = inSecHdr.sizeOfRawData;<br> if(toRead > inSecHdr.virtualSize)<br> toRead = inSecHdr.virtualSize;<br><br> memcpy(outPtr, exePtr + inSecHdr.pointerToRawData, toRead);<br><br> outPtr += getAlignedSize(inSecHdr.virtualSize, inpeXH->sectionAlignment);<br> }<br> }<br><br> return true;<br>}<br><br><br>//*******************************************************************************************************<br>// Loads the DLL into memory and align it<br>//<br>//*******************************************************************************************************<br><br>LPVOID loadDLL(char *dllName)<br>{<br> char moduleFilename[MAX_PATH + 1];<br> LPVOID ptrLoc = NULL;<br> MZHeader mzH2;<br> PE_Header peH2;<br> PE_ExtHeader peXH2;<br> SectionHeader *secHdr2;<br><br> GetSystemDirectory(moduleFilename, MAX_PATH);<br> if((myStrlenA(moduleFilename) + myStrlenA(dllName)) >= MAX_PATH)<br> return NULL;<br><br> strcat(moduleFilename, dllName);<br><br> // load this EXE into memory because we need its original Import Hint Table<br><br> HANDLE fp;<br> fp = CreateFile(moduleFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);<br> <br> if(fp != INVALID_HANDLE_VALUE)<br> {<br> BY_HANDLE_FILE_INFORMATION fileInfo;<br> GetFileInformationByHandle(fp, &fileInfo);<br><br> DWORD fileSize = fileInfo.nFileSizeLow;<br> //printf("Size = %d/n", fileSize);<br> if(fileSize)<br> {<br> LPVOID exePtr = HeapAlloc(GetProcessHeap(), 0, fileSize);<br> if(exePtr)<br> {<br> DWORD read;<br><br> if(ReadFile(fp, exePtr, fileSize, &read, NULL) && read == fileSize)<br> { <br> if(readPEInfo((char *)exePtr, &mzH2, &peH2, &peXH2, &secHdr2))<br> {<br> int imageSize = calcTotalImageSize(&mzH2, &peH2, &peXH2, secHdr2); <br><br> //ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);<br> ptrLoc = HeapAlloc(GetProcessHeap(), 0, imageSize);<br> if(ptrLoc)<br> { <br> loadPE((char *)exePtr, &mzH2, &peH2, &peXH2, secHdr2, ptrLoc);<br> }<br> }<br><br> }<br> HeapFree(GetProcessHeap(), 0, exePtr);<br> }<br> }<br> CloseHandle(fp);<br> }<br><br> return ptrLoc;<br>}<br><br><br>DWORD procAPIExportAddr(DWORD hModule, char *apiName)<br>{ <br> if(!hModule || !apiName)<br> return 0;<br><br> char *ptr = (char *)hModule;<br> ptr += 0x3c; // offset 0x3c contains offset to PE header<br> <br> ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // offset 78h into PE header contains addr of export table<br><br> ptr = (char *)(*(DWORD *)ptr) + hModule; // ptr now points to export directory table<br><br> // offset 24 into the export directory table == number of entries in the Export Name Pointer Table<br> // table<br> DWORD numEntries = *(DWORD *)(ptr + 24);<br> //printf("NumEntries = %d/n", numEntries);<br><br> DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // offset 32 into export directory contains offset to Export Name Pointer Table <br> <br> DWORD ordinalBase = *((DWORD *)(ptr + 16));<br> //printf("OrdinalBase is %d/n", ordinalBase);<br><br><br> WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // offset 36 into export directory contains offset to Ordinal Table<br> DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // offset 28 into export directory contains offset to Export Addr Table<br><br> for(DWORD i = 0; i < numEntries; i++)<br> { <br> char *exportName = (char *)(ExportNamePointerTable + hModule);<br><br> if(myStrcmpA(exportName, apiName) == TRUE)<br> { <br> WORD ordinal = ExportOrdinalTable;<br> //printf("%s (i = %d) Ordinal = %d at %X/n", exportName, i, ordinal, ExportAddrTable[ordinal]);<br><br> return (DWORD)(ExportAddrTable[ordinal]);<br> } <br> }<br><br> return 0;<br>}<br><br>//*******************************************************************************************************<br>// -- END PE File support functions --<br>//<br>//*******************************************************************************************************<br><br><br>//*********************************************************************************************<br>// Builds a table of native API names using the export table of ntdll.dll<br>//<br>//*********************************************************************************************<br><br>BOOL buildNativeAPITable(DWORD hModule, char *nativeAPINames[], DWORD numNames)<br>{<br> if(!hModule)<br> return FALSE;<br><br> char *ptr = (char *)hModule;<br> ptr += 0x3c; // offset 0x3c contains offset to PE header<br> <br> ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // offset 78h into PE header contains addr of export table<br><br> ptr = (char *)(*(DWORD *)ptr) + hModule; // ptr now points to export directory table<br><br> <br> // offset 24 into the export directory table == number of entries in the Name Pointer Table<br> // table<br> DWORD numEntries = *(DWORD *)(ptr + 24); <br> <br> DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule); // offset 32 into export directory contains offset to Export Name Pointer Table <br><br> DWORD ordinalBase = *((DWORD *)(ptr + 16));<br><br> WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // offset 36 into export directory contains offset to Ordinal Table<br> DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // offset 28 into export directory contains offset to Export Addr Table<br><br><br> for(DWORD i = 0; i < numEntries; i++)<br> { <br> // i now contains the index of the API in the Ordinal Table<br> // ptr points to Export directory table<br><br> WORD ordinalValue = ExportOrdinalTable; <br> DWORD apiAddr = (DWORD)ExportAddrTable[ordinalValue] + hModule;<br> char *exportName = (char *)(ExportNamePointerTable + hModule);<br> <br> // Win2K<br> if(gWinVersion == 0 &&<br> *((unsigned char *)apiAddr) == 0xB8 && <br> *((unsigned char *)apiAddr + 9) == 0xCD && <br> *((unsigned char *)apiAddr + 10) == 0x2E)<br> {<br> DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);<br> if(serviceNum < numNames)<br> {<br> nativeAPINames[serviceNum] = exportName;<br> }<br> //printf("%X - %s/n", serviceNum, exportName);<br> }<br><br> // WinXP<br> else if(gWinVersion == 1 &&<br> *((unsigned char *)apiAddr) == 0xB8 && <br> *((unsigned char *)apiAddr + 5) == 0xBA && <br> *((unsigned char *)apiAddr + 6) == 0x00 &&<br> *((unsigned char *)apiAddr + 7) == 0x03 &&<br> *((unsigned char *)apiAddr + 8) == 0xFE &&<br> *((unsigned char *)apiAddr + 9) == 0x7F)<br> {<br> DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);<br> if(serviceNum < numNames)<br> {<br> nativeAPINames[serviceNum] = exportName;<br> }<br> //printf("%X - %s/n", serviceNum, exportName);<br> }<br> }<br><br> return TRUE;<br>}<br><br><br>//*******************************************************************************************************<br>// Gets address of native API's that we'll be using<br>//<br>//*******************************************************************************************************<br><br>BOOL getNativeAPIs(void)<br>{<br> HMODULE hntdll;<br><br> hntdll = GetModuleHandle("ntdll.dll"<br> <br> *(FARPROC *)&_RtlAnsiStringToUnicodeString = <br> GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString"<br><br> *(FARPROC *)&_RtlInitAnsiString = <br> GetProcAddress(hntdll, "RtlInitAnsiString"<br><br> *(FARPROC *)&_RtlFreeUnicodeString = <br> GetProcAddress(hntdll, "RtlFreeUnicodeString"<br><br> *(FARPROC *)&_NtOpenSection =<br> GetProcAddress(hntdll, "NtOpenSection"<br><br> *(FARPROC *)&_NtMapViewOfSection =<br> GetProcAddress(hntdll, "NtMapViewOfSection"<br><br> *(FARPROC *)&_NtUnmapViewOfSection =<br> GetProcAddress(hntdll, "NtUnmapViewOfSection"<br><br> *(FARPROC *)&_NtQuerySystemInformation =<br> GetProcAddress(hntdll, "ZwQuerySystemInformation"<br><br> if(_RtlAnsiStringToUnicodeString && _RtlInitAnsiString && _RtlFreeUnicodeString &&<br> _NtOpenSection && _NtMapViewOfSection && _NtUnmapViewOfSection && _NtQuerySystemInformation)<br> {<br> return TRUE;<br> }<br> return FALSE;<br>}<br><br><br>//*******************************************************************************************************<br>// Obtain a handle to /device/physicalmemory<br>//<br>//*******************************************************************************************************<br><br>HANDLE openPhyMem()<br>{<br> HANDLE hPhyMem;<br> OBJECT_ATTRIBUTES oAttr;<br><br> ANSI_STRING aStr;<br> <br> _RtlInitAnsiString(&aStr, "//device//physicalmemory"<br> <br> UNICODE_STRING uStr;<br><br> if(_RtlAnsiStringToUnicodeString(&uStr, &aStr, TRUE) != STATUS_SUCCESS)<br> { <br> return INVALID_HANDLE_VALUE; <br> }<br><br> oAttr.Length = sizeof(OBJECT_ATTRIBUTES);<br> oAttr.RootDirectory = NULL;<br> oAttr.Attributes = OBJ_CASE_INSENSITIVE;<br> oAttr.ObjectName = &uStr;<br> oAttr.SecurityDescriptor = NULL;<br> oAttr.SecurityQualityOfService = NULL;<br><br> if(_NtOpenSection(&hPhyMem, SECTION_MAP_READ | SECTION_MAP_WRITE, &oAttr ) != STATUS_SUCCESS)<br> { <br> return INVALID_HANDLE_VALUE;<br> }<br><br> return hPhyMem;<br>}<br><br><br>//*******************************************************************************************************<br>// Map in a section of physical memory into this process's virtual address space.<br>//<br>//*******************************************************************************************************<br><br>BOOL mapPhyMem(HANDLE hPhyMem, DWORD *phyAddr, DWORD *length, PVOID *virtualAddr)<br>{<br> NTSTATUS ntStatus;<br> PHYSICAL_ADDRESS viewBase;<br><br> *virtualAddr = 0;<br> viewBase.QuadPart = (ULONGLONG) (*phyAddr);<br><br> ntStatus = _NtMapViewOfSection(hPhyMem, (HANDLE)-1, virtualAddr, 0,<br> *length, &viewBase, length,<br> ViewShare, 0, PAGE_READWRITE );<br><br> if(ntStatus != STATUS_SUCCESS)<br> {<br> printf("Failed to map physical memory view of length %X at %X!", *length, *phyAddr);<br> return FALSE; <br> }<br><br> *phyAddr = viewBase.LowPart;<br> return TRUE;<br>}<br><br><br>//*******************************************************************************************************<br>// Unmap section of physical memory<br>//<br>//*******************************************************************************************************<br><br>void unmapPhyMem(DWORD virtualAddr)<br>{<br> NTSTATUS status;<br><br> status = _NtUnmapViewOfSection((HANDLE)-1, (PVOID)virtualAddr);<br> if(status != STATUS_SUCCESS)<br> {<br> printf("Unmapping view failed!/n"<br> }<br>}<br><br><br>//*******************************************************************************************************<br>// Assign SECTION_MAP_WRITE assess of /device/physicalmemory to current user.<br>//<br>//*******************************************************************************************************<br><br>BOOL assignACL(void)<br>{<br> HANDLE hPhyMem;<br> OBJECT_ATTRIBUTES oAttr;<br> BOOL result = FALSE;<br><br> ANSI_STRING aStr;<br> <br> _RtlInitAnsiString(&aStr, "//device//physicalmemory"<br> <br> UNICODE_STRING uStr;<br><br> if(_RtlAnsiStringToUnicodeString(&uStr, &aStr, TRUE) != STATUS_SUCCESS)<br> { <br> return FALSE;<br> }<br><br> oAttr.Length = sizeof(OBJECT_ATTRIBUTES);<br> oAttr.RootDirectory = NULL;<br> oAttr.Attributes = OBJ_CASE_INSENSITIVE;<br> oAttr.ObjectName = &uStr;<br> oAttr.SecurityDescriptor = NULL;<br> oAttr.SecurityQualityOfService = NULL;<br><br> if(_NtOpenSection(&hPhyMem, READ_CONTROL | WRITE_DAC, &oAttr ) != STATUS_SUCCESS)<br> { <br> return FALSE;<br> }<br> else<br> {<br> PACL dacl;<br> PSECURITY_DESCRIPTOR sd;<br> <br> if(GetSecurityInfo(hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,<br> &dacl, NULL, &sd) == ERROR_SUCCESS)<br> {<br> EXPLICIT_ACCESS ea;<br> char userName[MAX_PATH];<br> DWORD userNameSize = MAX_PATH-1;<br><br> GetUserName(userName, &userNameSize);<br> ea.grfAccessPermissions = SECTION_MAP_WRITE;<br> ea.grfAccessMode = GRANT_ACCESS;<br> ea.grfInheritance = NO_INHERITANCE;<br> ea.Trustee.pMultipleTrustee = NULL;<br> ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;<br> ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;<br> ea.Trustee.TrusteeType = TRUSTEE_IS_USER;<br> ea.Trustee.ptstrName = userName;<br><br> PACL newDacl;<br> if(SetEntriesInAcl(1, &ea, dacl, &newDacl) == ERROR_SUCCESS)<br> {<br> if(SetSecurityInfo(hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,<br> newDacl, NULL) == ERROR_SUCCESS)<br> { <br> result = TRUE;<br> }<br><br> LocalFree(newDacl);<br> }<br> }<br> }<br><br> return result; <br>}<br><br><br>//*******************************************************************************************************<br>// Gets the kernel base address<br>//<br>//*******************************************************************************************************<br><br>DWORD getKernelBase(void)<br>{<br> HANDLE hHeap = GetProcessHeap();<br> <br> NTSTATUS Status;<br> ULONG cbBuffer = 0x8000;<br> PVOID pBuffer = NULL;<br> DWORD retVal = DEF_KERNEL_BASE;<br><br> do<br> {<br> pBuffer = HeapAlloc(hHeap, 0, cbBuffer);<br> if (pBuffer == NULL)<br> return DEF_KERNEL_BASE;<br><br> Status = _NtQuerySystemInformation(SystemModuleInformation,<br> pBuffer, cbBuffer, NULL);<br><br> if(Status == STATUS_INFO_LENGTH_MISMATCH)<br> {<br> HeapFree(hHeap, 0, pBuffer);<br> cbBuffer *= 2;<br> }<br> else if(Status != STATUS_SUCCESS)<br> {<br> HeapFree(hHeap, 0, pBuffer);<br> return DEF_KERNEL_BASE;<br> }<br> }<br> while (Status == STATUS_INFO_LENGTH_MISMATCH);<br><br> DWORD numEntries = *((DWORD *)pBuffer);<br> SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)((char *)pBuffer + sizeof(DWORD));<br><br> for(DWORD i = 0; i < numEntries; i++)<br> {<br> if(strcmpi(smi->ImageName, "ntoskrnl.exe")<br> {<br> //printf("%.8X - %s/n", smi->Base, smi->ImageName);<br> retVal = (DWORD)(smi->Base);<br> break;<br> }<br> smi++;<br> }<br><br> HeapFree(hHeap, 0, pBuffer);<br><br> return retVal;<br>}<br><br><br>struct FixupBlock<br>{<br> unsigned long pageRVA;<br> unsigned long blockSize;<br>};<br><br><br><br>BOOL checkKiServiceTableAddr(PVOID exeAddr, DWORD chkAddr, PE_ExtHeader *peXH2)<br>{<br> if(peXH2->relocationTableAddress && peXH2->relocationTableSize)<br> {<br> FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress); <br><br> while(fixBlk->blockSize)<br> {<br> int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;<br> <br> unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);<br><br> for(int i = 0; i < numEntries; i++)<br> { <br> int relocType = (*offsetPtr & 0xF000) >> 12;<br> <br> if(relocType == 3)<br> {<br> DWORD *codeLoc = (DWORD *)((char *)exeAddr + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));<br> <br> if(fixBlk->pageRVA + (*offsetPtr & 0x0FFF) + peXH2->imageBase == chkAddr)<br> {<br> return TRUE;<br> }<br> }<br> offsetPtr++;<br> }<br> fixBlk = (FixupBlock *)offsetPtr;<br> }<br> }<br> return FALSE;<br>}<br><br><br>// Thanks to 90210 for this excellent way of getting the KiServiceTable address from the disk image of<br>// ntoskrnl.exe<br>// http://www.rootkit.com/newsread.php?newsid=176<br><br>DWORD getKiServiceTableAddr(PVOID exeAddr, DWORD sdtAddr, PE_ExtHeader *peXH2)<br>{<br> if(peXH2->relocationTableAddress && peXH2->relocationTableSize)<br> {<br> FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress); <br><br> while(fixBlk->blockSize)<br> {<br> //printf("Addr = %X/n", fixBlk->pageRVA);<br> //printf("Size = %X/n", fixBlk->blockSize);<br><br> int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;<br> //printf("Num Entries = %d/n", numEntries);<br><br> unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);<br><br> for(int i = 0; i < numEntries; i++)<br> { <br> int relocType = (*offsetPtr & 0xF000) >> 12;<br> <br> //printf("Val = %X/n", *offsetPtr);<br> //printf("Type = %X/n", relocType);<br><br> if(relocType == 3)<br> {<br> DWORD *codeLoc = (DWORD *)((char *)exeAddr + fixBlk->pageRVA + (*offsetPtr & 0x0FFF)); <br><br> if(*codeLoc == sdtAddr + peXH2->imageBase &&<br> *(WORD *)((DWORD)codeLoc - 2) == 0x05c7)<br> {<br> DWORD kiServiceTableAddr = *(DWORD *)((DWORD)codeLoc + 4);<br> <br> // checks for presence of found address in the relocation table<br> if(checkKiServiceTableAddr(exeAddr, kiServiceTableAddr, peXH2))<br> {<br> return kiServiceTableAddr - peXH2->imageBase;<br> }<br> } <br> }<br><br> offsetPtr++;<br> }<br><br> fixBlk = (FixupBlock *)offsetPtr;<br> }<br> }<br> return 0;<br>}<br><br>//*******************************************************************************************************<br>// Program entry point<br>// No commandline arguments required.<br>//<br>//*******************************************************************************************************<br><br>int main(int argc, char* argv[])<br>{<br> MZHeader mzH2;<br> PE_Header peH2;<br> PE_ExtHeader peXH2;<br> SectionHeader *secHdr2;<br><br> printf("SDTrestore Version 0.2 Proof-of-Concept by SIG^2 G-TEC (www.security.org.sg)/n/n"<br><br> OSVERSIONINFO ov;<br> ov.dwOSVersionInfoSize = sizeof(ov);<br> GetVersionEx(&ov);<br> if(ov.dwMajorVersion != 5) //主版本号<br> {<br> printf("Sorry, this version supports only Win2K and WinXP./n"<br> return 1;<br> }<br><br> if(ov.dwMinorVersion != 0 && ov.dwMinorVersion != 1) //副版本<br> {<br> printf("Sorry, this version supports only Win2K and WinXP./n"<br> return 1;<br> }<br> gWinVersion = ov.dwMinorVersion;<br><br> if(!getNativeAPIs()) //取得要用的NT类函数地址<br> {<br> printf("Failed to get addresses of Native APIs!/n"<br> return 1;<br> }<br><br> assignACL();<br> HANDLE hPhyMem = openPhyMem();<br> if(hPhyMem == INVALID_HANDLE_VALUE)<br> assignACL();<br><br> hPhyMem = openPhyMem();<br> if(hPhyMem == INVALID_HANDLE_VALUE)<br> {<br> printf("Could not open physical memory device!/nMake sure you are running as Administrator./n"<br> return 1;<br> }<br><br> PVOID exeAddr = loadDLL("//ntoskrnl.exe"<br> if(!exeAddr)<br> {<br> printf("Failed to load ntoskrnl.exe!/n"<br> return 1;<br> }<br><br> DWORD sdtAddr = procAPIExportAddr((DWORD)exeAddr, "KeServiceDescriptorTable"<br> if(!sdtAddr)<br> {<br> printf("Failed to get address of KeServiceDescriptorTable!/n"<br> return 1;<br> }<br> <br> if(!readPEInfo((char *)exeAddr, &mzH2, &peH2, &peXH2, &secHdr2))<br> {<br> printf("Failed to get PE header of ntoskrnl.exe!/n"<br> return 1;<br> }<br><br> DWORD kernelPhyBase = getKernelBase() - PROT_MEMBASE;<br> DWORD kernelOffset = kernelPhyBase - peXH2.imageBase;<br><br> printf("KeServiceDescriptorTable/t/t%X/n", sdtAddr + kernelPhyBase + PROT_MEMBASE);<br><br> unsigned char *ptr = NULL;<br> DWORD pAddr = sdtAddr + kernelPhyBase;<br> DWORD wantedAddr = pAddr;<br> DWORD len = 0x2000;<br><br> // map in page containing KeServiceDecriptorTable<br> if(mapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr))<br> {<br> DWORD start = wantedAddr - pAddr;<br> DWORD serviceTableAddr, sdtCount; <br> DWORD wantedBytes = len - start;<br> if(wantedBytes >= 4)<br> {<br> serviceTableAddr = *((DWORD *)(&ptr[start]));<br> printf("KeServiceDecriptorTable.ServiceTable/t%X/n", serviceTableAddr);<br> if(wantedBytes >= 12)<br> {<br> sdtCount = *(((DWORD *)(&ptr[start])) + 2);<br> printf("KeServiceDescriptorTable.ServiceLimit/t%d/n", sdtCount);<br> }<br> }<br> else<br> {<br> printf("Sorry, an unexpected situation occurred!/n"<br> return 1;<br> }<br><br> unmapPhyMem((DWORD)ptr);<br> printf("/n"<br><br> if(sdtCount >= 300)<br> {<br> printf("Sorry, an unexpected error occurred! SDT Count > 300???/n"<br> return 1;<br> }<br><br> pAddr = serviceTableAddr - PROT_MEMBASE;<br> wantedAddr = pAddr;<br> ptr = NULL;<br> len = 0x2000;<br> if(mapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr))<br> {<br> start = wantedAddr - pAddr;<br> DWORD numEntries = (len - start) >> 2;<br> if(numEntries >= sdtCount)<br> {<br> char **nativeApiNames = NULL;<br> nativeApiNames = (char **)malloc(sizeof(char *) * sdtCount);<br> if(!nativeApiNames)<br> {<br> printf("Failed to allocate memory for Native API name table./n"<br> return 1;<br> }<br> memset(nativeApiNames, 0, sizeof(char *) * sdtCount);<br><br> PVOID ntdll = loadDLL("//ntdll.dll"<br> if(!ntdll)<br> {<br> printf("Failed to load ntdll.dll!/n"<br> return 1;<br> }<br><br> buildNativeAPITable((DWORD)ntdll, nativeApiNames, sdtCount);<br><br> DWORD *serviceTable = (DWORD *)(&ptr[start]);<br> DWORD *fileServiceTable = (DWORD *)((DWORD)exeAddr + wantedAddr - kernelOffset - peXH2.imageBase);<br> <br> // calculate address based on 90210's suggestion<br> DWORD fileAddr2 = (DWORD)exeAddr + getKiServiceTableAddr(exeAddr, sdtAddr, &peXH2); <br> <br> if(fileAddr2 && (DWORD)fileServiceTable != fileAddr2)<br> {<br> printf("Two possible addresses of KiServiceTable were found./n/n"<br> printf("1 - %.8X/n", fileServiceTable);<br> printf("2 - %.8X (using method suggested by 90210)/n/n", fileAddr2);<br> printf("Select One (1-2): "<br><br> char choice[10];<br> memset(choice, 0, sizeof(choice));<br> fgets(choice, sizeof(choice) - 1, stdin);<br> printf("/n" <br> int intChoice = atoi(choice);<br> if(intChoice < 1 || intChoice > 2)<br> {<br> printf("Invalid selection!/n"<br> unmapPhyMem((DWORD)ptr);<br> return 1;<br> }<br> else if(intChoice == 2)<br> fileServiceTable = (DWORD *)fileAddr2;<br> }<br> <br> if(!IsBadReadPtr(fileServiceTable, sizeof(DWORD)) && <br> !IsBadReadPtr(&fileServiceTable[sdtCount-1], sizeof(DWORD)))<br> {<br> DWORD hookCount = 0;<br> for(DWORD i = 0; i < sdtCount; i++)<br> { <br> if((serviceTable - PROT_MEMBASE - kernelOffset) != fileServiceTable)<br> {<br> printf("%-25s %3X --[hooked by unknown at %X]--/n", <br> (nativeApiNames ? nativeApiNames : "Unknown API", <br> i, serviceTable);<br> hookCount++;<br> }<br> <br> }<br> printf("/nNumber of Service Table entries hooked = %u/n", hookCount);<br> <br> if(hookCount)<br> {<br> printf("/nWARNING: THIS IS EXPERIMENTAL CODE. FIXING THE SDT MAY HAVE GRAVE/n"<br> "CONSEQUENCES, SUCH AS SYSTEM CRASH, DATA LOSS OR SYSTEM CORRUPTION./n"<br> "PROCEED AT YOUR OWN RISK. YOU HAVE BEEN WARNED./n"<br> printf("/nFix SDT Entries (Y/N)? : "<br> <br> char inputReply[10];<br> memset(inputReply, 0, sizeof(inputReply));<br> fgets(inputReply, sizeof(inputReply) - 1, stdin);<br> printf("/n"<br> <br> if(stricmp(inputReply, "y/n" == 0)<br> {<br> for(DWORD i = 0; i < sdtCount; i++)<br> {<br> if((serviceTable - PROT_MEMBASE - kernelOffset) != fileServiceTable)<br> {<br> serviceTable = fileServiceTable + PROT_MEMBASE + kernelOffset;<br> printf("[+] Patched SDT entry %.2X to %.8X/n", i, <br> fileServiceTable + PROT_MEMBASE + kernelOffset);<br> }<br> }<br> }<br> else<br> printf("[-] SDT Entries NOT fixed./n"<br> }<br> }<br> else<br> {<br> printf("It's likely that the SDT service table has been relocated./n"<br> "This POC code cannot support patching of relocated SDT service table./n"<br> }<br><br> }<br> unmapPhyMem((DWORD)ptr);<br> }<br> }<br><br> return 0;<br>}