注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

SDTrestore  

2007-08-15 13:45:31|  分类: Delphi |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
//*********************************************************************************************
// SDTrestore (Proof-of-Concept)
// Version 0.2
// by SIG^2 G-TEC Lab
//
// Coded by Chew Keong TAN
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, provided that the above
// copyright notice(s) and this permission notice appear in all copies of
// the Software and that both the above copyright notice(s) and this
// permission notice appear in supporting documentation.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// This program needs to access \device\physicalmemory, so you must be
// running as Administrator when using this.
//
// CHANGES
// -------
// Version 0.2
// Thanks to 90210 for the suggestion of a more stable way to find the
// address of KiServiceTable from the disk image of ntoskrnl.exe
// http://www.rootkit.com/newsread.php?newsid=176
//
//*********************************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <aclapi.h>


#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define DEF_KERNEL_BASE 0x80400000L
#define SystemModuleInformation 11
#define PROT_MEMBASE 0x80000000

typedef LONG NTSTATUS;
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

DWORD gWinVersion;

typedef struct _STRING {
 USHORT  Length;
 USHORT  MaximumLength;
 PCHAR  Buffer;
} ANSI_STRING, *PANSI_STRING;

typedef struct _UNICODE_STRING {
 USHORT  Length;
 USHORT  MaximumLength;
 PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
   ULONG Length;
   HANDLE RootDirectory;
   PUNICODE_STRING ObjectName;
   ULONG Attributes;
   PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
   PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

typedef enum _SECTION_INHERIT {
   ViewShare = 1,
   ViewUnmap = 2
} SECTION_INHERIT;

typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION;

NTSTATUS (WINAPI * _RtlAnsiStringToUnicodeString)
(PUNICODE_STRING  DestinationString,
IN PANSI_STRING  SourceString,
IN BOOLEAN);

VOID (WINAPI *_RtlInitAnsiString)
(IN OUT PANSI_STRING  DestinationString,
IN PCHAR  SourceString);

VOID (WINAPI * _RtlFreeUnicodeString)
(IN PUNICODE_STRING  UnicodeString);

NTSTATUS (WINAPI *_NtOpenSection)
(OUT PHANDLE  SectionHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES  ObjectAttributes);

NTSTATUS (WINAPI *_NtMapViewOfSection)
(IN HANDLE  SectionHandle,
IN HANDLE  ProcessHandle,
IN OUT PVOID  *BaseAddress,
IN ULONG  ZeroBits,
IN ULONG  CommitSize,
IN OUT PLARGE_INTEGER  SectionOffset, /* optional */
IN OUT PULONG  ViewSize,
IN SECTION_INHERIT  InheritDisposition,
IN ULONG  AllocationType,
IN ULONG  Protect);

NTSTATUS (WINAPI *_NtUnmapViewOfSection)
(IN HANDLE ProcessHandle,
IN PVOID BaseAddress);

NTSTATUS (WINAPI * _NtQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);

//*******************************************************************************************************
// PE File structure declarations
//
//*******************************************************************************************************

struct PE_Header
{
unsigned long signature;
unsigned short machine;
unsigned short numSections;
unsigned long timeDateStamp;
unsigned long pointerToSymbolTable;
unsigned long numOfSymbols;
unsigned short sizeOfOptionHeader;
unsigned short characteristics;
};

struct PE_ExtHeader
{
unsigned short magic;
unsigned char majorLinkerVersion;
unsigned char minorLinkerVersion;
unsigned long sizeOfCode;
unsigned long sizeOfInitializedData;
unsigned long sizeOfUninitializedData;
unsigned long addressOfEntryPoint;
unsigned long baseOfCode;
unsigned long baseOfData;
unsigned long imageBase;
unsigned long sectionAlignment;
unsigned long fileAlignment;
unsigned short majorOSVersion;
unsigned short minorOSVersion;
unsigned short majorImageVersion;
unsigned short minorImageVersion;
unsigned short majorSubsystemVersion;
unsigned short minorSubsystemVersion;
unsigned long reserved1;
unsigned long sizeOfImage;
unsigned long sizeOfHeaders;
unsigned long checksum;
unsigned short subsystem;
unsigned short DLLCharacteristics;
unsigned long sizeOfStackReserve;
unsigned long sizeOfStackCommit;
unsigned long sizeOfHeapReserve;
unsigned long sizeOfHeapCommit;
unsigned long loaderFlags;
unsigned long numberOfRVAAndSizes;
unsigned long exportTableAddress;
unsigned long exportTableSize;
unsigned long importTableAddress;
unsigned long importTableSize;
unsigned long resourceTableAddress;
unsigned long resourceTableSize;
unsigned long exceptionTableAddress;
unsigned long exceptionTableSize;
unsigned long certFilePointer;
unsigned long certTableSize;
unsigned long relocationTableAddress;
unsigned long relocationTableSize;
unsigned long debugDataAddress;
unsigned long debugDataSize;
unsigned long archDataAddress;
unsigned long archDataSize;
unsigned long globalPtrAddress;
unsigned long globalPtrSize;
unsigned long TLSTableAddress;
unsigned long TLSTableSize;
unsigned long loadConfigTableAddress;
unsigned long loadConfigTableSize;
unsigned long boundImportTableAddress;
unsigned long boundImportTableSize;
unsigned long importAddressTableAddress;
unsigned long importAddressTableSize;
unsigned long delayImportDescAddress;
unsigned long delayImportDescSize;
unsigned long COMHeaderAddress;
unsigned long COMHeaderSize;
unsigned long reserved2;
unsigned long reserved3;
};


struct SectionHeader
{
unsigned char sectionName[8];
unsigned long virtualSize;
unsigned long virtualAddress;
unsigned long sizeOfRawData;
unsigned long pointerToRawData;
unsigned long pointerToRelocations;
unsigned long pointerToLineNumbers;
unsigned short numberOfRelocations;
unsigned short numberOfLineNumbers;
unsigned long characteristics;
};

struct MZHeader
{
unsigned short signature;
unsigned short partPag;
unsigned short pageCnt;
unsigned short reloCnt;
unsigned short hdrSize;
unsigned short minMem;
unsigned short maxMem;
unsigned short reloSS;
unsigned short exeSP;
unsigned short chksum;
unsigned short exeIP;
unsigned short reloCS;
unsigned short tablOff;
unsigned short overlay;
unsigned char reserved[32];
unsigned long offsetToPE;
};


struct ImportDirEntry
{
DWORD importLookupTable;
DWORD timeDateStamp;
DWORD fowarderChain;
DWORD nameRVA;
DWORD importAddressTable;
};


DWORD myStrlenA(char *ptr)
{
DWORD len = 0;
while(*ptr)
{
len++;
ptr++;
}

return len;
}


BOOL myStrcmpA(char *str1, char *str2)
{
while(*str1 && *str2)
{
if(*str1 == *str2)
{
str1++;
str2++;
}
else
{
return FALSE;
}
}

if(*str1 && !*str2)
{
return FALSE;
}
else if(*str2 && !*str1)
{
return FALSE;
}

return TRUE;
}

//*******************************************************************************************************
// Fills the various structures with info of a PE image.  The PE image is located at modulePos.
//
//*******************************************************************************************************

bool readPEInfo(char *modulePos, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
SectionHeader **outSecHdr)
{
// read MZ Header
MZHeader *mzH;
mzH = (MZHeader *)modulePos;

if(mzH->signature != 0x5a4d) // MZ
{
printf("File does not have MZ header\n");
return false;
}

// read PE Header
PE_Header *peH;
peH = (PE_Header *)(modulePos + mzH->offsetToPE);

if(peH->sizeOfOptionHeader != sizeof(PE_ExtHeader))
{
printf("Unexpected option header size.\n");

return false;
}

// read PE Ext Header
PE_ExtHeader *peXH;
peXH = (PE_ExtHeader *)((char *)peH + sizeof(PE_Header));

// read the sections
SectionHeader *secHdr = (SectionHeader *)((char *)peXH + sizeof(PE_ExtHeader));

*outMZ = *mzH;
*outPE = *peH;
*outpeXH = *peXH;
*outSecHdr = secHdr;

return true;
}


//*******************************************************************************************************
// Returns the total size required to load a PE image into memory
//
//*******************************************************************************************************

int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
      SectionHeader *inSecHdr)
{
int result = 0;
int alignment = inpeXH->sectionAlignment;

if(inpeXH->sizeOfHeaders % alignment == 0)
result += inpeXH->sizeOfHeaders;
else
{
int val = inpeXH->sizeOfHeaders / alignment;
val++;
result += (val * alignment);
}
for(int i = 0; i < inPE->numSections; i++)
{
if(inSecHdr[i].virtualSize)
{
if(inSecHdr[i].virtualSize % alignment == 0)
result += inSecHdr[i].virtualSize;
else
{
int val = inSecHdr[i].virtualSize / alignment;
val++;
result += (val * alignment);
}
}
}

return result;
}


//*******************************************************************************************************
// Returns the aligned size of a section
//
//*******************************************************************************************************

unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
{
if(curSize % alignment == 0)
return curSize;
else
{
int val = curSize / alignment;
val++;
return (val * alignment);
}
}

//*******************************************************************************************************
// Copy a PE image from exePtr to ptrLoc with proper memory alignment of all sections
//
//*******************************************************************************************************

bool loadPE(char *exePtr, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr, LPVOID ptrLoc)
{
char *outPtr = (char *)ptrLoc;

memcpy(outPtr, exePtr, inpeXH->sizeOfHeaders);
outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);

for(int i = 0; i < inPE->numSections; i++)
{
if(inSecHdr[i].sizeOfRawData > 0)
{
unsigned long toRead = inSecHdr[i].sizeOfRawData;
if(toRead > inSecHdr[i].virtualSize)
toRead = inSecHdr[i].virtualSize;

memcpy(outPtr, exePtr + inSecHdr[i].pointerToRawData, toRead);

outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
}
}

return true;
}


//*******************************************************************************************************
// Loads the DLL into memory and align it
//
//*******************************************************************************************************

LPVOID loadDLL(char *dllName)
{
char moduleFilename[MAX_PATH + 1];
LPVOID ptrLoc = NULL;
MZHeader mzH2;
PE_Header peH2;
PE_ExtHeader peXH2;
SectionHeader *secHdr2;

GetSystemDirectory(moduleFilename, MAX_PATH);
if((myStrlenA(moduleFilename) + myStrlenA(dllName)) >= MAX_PATH)
return NULL;

strcat(moduleFilename, dllName);

// load this EXE into memory because we need its original Import Hint Table

HANDLE fp;
fp = CreateFile(moduleFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

if(fp != INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION fileInfo;
GetFileInformationByHandle(fp, &fileInfo);

DWORD fileSize = fileInfo.nFileSizeLow;
//printf("Size = %d\n", fileSize);
if(fileSize)
{
LPVOID exePtr = HeapAlloc(GetProcessHeap(), 0, fileSize);
if(exePtr)
{
DWORD read;

if(ReadFile(fp, exePtr, fileSize, &read, NULL) && read == fileSize)
{
if(readPEInfo((char *)exePtr, &mzH2, &peH2, &peXH2, &secHdr2))
{
int imageSize = calcTotalImageSize(&mzH2, &peH2, &peXH2, secHdr2);

//ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ptrLoc = HeapAlloc(GetProcessHeap(), 0, imageSize);
if(ptrLoc)
{
loadPE((char *)exePtr, &mzH2, &peH2, &peXH2, secHdr2, ptrLoc);
}
}

}
HeapFree(GetProcessHeap(), 0, exePtr);
}
}
CloseHandle(fp);
}

return ptrLoc;
}


DWORD procAPIExportAddr(DWORD hModule, char *apiName)
{
if(!hModule || !apiName)
return 0;

char *ptr = (char *)hModule;
ptr += 0x3c; // offset 0x3c contains offset to PE header

ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // offset 78h into PE header contains addr of export table

ptr = (char *)(*(DWORD *)ptr) + hModule; // ptr now points to export directory table

// offset 24 into the export directory table == number of entries in the Export Name Pointer Table
// table
DWORD numEntries = *(DWORD *)(ptr + 24);
//printf("NumEntries = %d\n", numEntries);

DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule);  // offset 32 into export directory contains offset to Export Name Pointer Table

DWORD ordinalBase = *((DWORD *)(ptr + 16));
//printf("OrdinalBase is %d\n", ordinalBase);


WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // offset 36 into export directory contains offset to Ordinal Table
DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // offset 28 into export directory contains offset to Export Addr Table

for(DWORD i = 0; i < numEntries; i++)
{
char *exportName = (char *)(ExportNamePointerTable[i] + hModule);

if(myStrcmpA(exportName, apiName) == TRUE)
{
WORD ordinal = ExportOrdinalTable[i];
//printf("%s (i = %d) Ordinal = %d at %X\n", exportName, i, ordinal, ExportAddrTable[ordinal]);

return (DWORD)(ExportAddrTable[ordinal]);
}
}

return 0;
}

//*******************************************************************************************************
// -- END PE File support functions --
//
//*******************************************************************************************************


//*********************************************************************************************
// Builds a table of native API names using the export table of ntdll.dll
//
//*********************************************************************************************

BOOL buildNativeAPITable(DWORD hModule, char *nativeAPINames[], DWORD numNames)
{
if(!hModule)
return FALSE;

char *ptr = (char *)hModule;
ptr += 0x3c; // offset 0x3c contains offset to PE header

ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // offset 78h into PE header contains addr of export table

ptr = (char *)(*(DWORD *)ptr) + hModule; // ptr now points to export directory table


// offset 24 into the export directory table == number of entries in the Name Pointer Table
// table
DWORD numEntries = *(DWORD *)(ptr + 24);

DWORD *ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule);  // offset 32 into export directory contains offset to Export Name Pointer Table

DWORD ordinalBase = *((DWORD *)(ptr + 16));

WORD *ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule); // offset 36 into export directory contains offset to Ordinal Table
DWORD *ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule); // offset 28 into export directory contains offset to Export Addr Table


for(DWORD i = 0; i < numEntries; i++)
{
// i now contains the index of the API in the Ordinal Table
// ptr points to Export directory table

WORD ordinalValue = ExportOrdinalTable[i];
DWORD apiAddr = (DWORD)ExportAddrTable[ordinalValue] + hModule;
char *exportName = (char *)(ExportNamePointerTable[i] + hModule);

// Win2K
if(gWinVersion == 0 &&
  *((unsigned char *)apiAddr) == 0xB8 &&
  *((unsigned char *)apiAddr + 9) == 0xCD &&
  *((unsigned char *)apiAddr + 10) == 0x2E)
{
DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);
if(serviceNum < numNames)
{
nativeAPINames[serviceNum] = exportName;
}
//printf("%X - %s\n", serviceNum, exportName);
}

// WinXP
else if(gWinVersion == 1 &&
*((unsigned char *)apiAddr) == 0xB8 &&
*((unsigned char *)apiAddr + 5) == 0xBA &&
*((unsigned char *)apiAddr + 6) == 0x00 &&
*((unsigned char *)apiAddr + 7) == 0x03 &&
*((unsigned char *)apiAddr + 8) == 0xFE &&
*((unsigned char *)apiAddr + 9) == 0x7F)
{
DWORD serviceNum = *(DWORD *)((char *)apiAddr + 1);
if(serviceNum < numNames)
{
nativeAPINames[serviceNum] = exportName;
}
//printf("%X - %s\n", serviceNum, exportName);
}
}

return TRUE;
}


//*******************************************************************************************************
// Gets address of native API's that we'll be using
//
//*******************************************************************************************************

BOOL getNativeAPIs(void)
{
HMODULE hntdll;

hntdll = GetModuleHandle("ntdll.dll");

*(FARPROC *)&_RtlAnsiStringToUnicodeString =
GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString");

*(FARPROC *)&_RtlInitAnsiString =
GetProcAddress(hntdll, "RtlInitAnsiString");

*(FARPROC *)&_RtlFreeUnicodeString =
GetProcAddress(hntdll, "RtlFreeUnicodeString");

*(FARPROC *)&_NtOpenSection =
GetProcAddress(hntdll, "NtOpenSection");

*(FARPROC *)&_NtMapViewOfSection =
GetProcAddress(hntdll, "NtMapViewOfSection");

*(FARPROC *)&_NtUnmapViewOfSection =
GetProcAddress(hntdll, "NtUnmapViewOfSection");

*(FARPROC *)&_NtQuerySystemInformation =
GetProcAddress(hntdll, "ZwQuerySystemInformation");

if(_RtlAnsiStringToUnicodeString && _RtlInitAnsiString && _RtlFreeUnicodeString &&
_NtOpenSection && _NtMapViewOfSection && _NtUnmapViewOfSection && _NtQuerySystemInformation)
{
return TRUE;
}
return FALSE;
}


//*******************************************************************************************************
// Obtain a handle to \device\physicalmemory
//
//*******************************************************************************************************

HANDLE openPhyMem()
{
HANDLE hPhyMem;
OBJECT_ATTRIBUTES oAttr;

ANSI_STRING aStr;

_RtlInitAnsiString(&aStr, "\\device\\physicalmemory");

UNICODE_STRING uStr;

if(_RtlAnsiStringToUnicodeString(&uStr, &aStr, TRUE) != STATUS_SUCCESS)
{
return INVALID_HANDLE_VALUE;
}

   oAttr.Length = sizeof(OBJECT_ATTRIBUTES);
   oAttr.RootDirectory = NULL;
   oAttr.Attributes = OBJ_CASE_INSENSITIVE;
   oAttr.ObjectName = &uStr;
   oAttr.SecurityDescriptor = NULL;
   oAttr.SecurityQualityOfService = NULL;

if(_NtOpenSection(&hPhyMem, SECTION_MAP_READ | SECTION_MAP_WRITE, &oAttr ) != STATUS_SUCCESS)
{
return INVALID_HANDLE_VALUE;
}

return hPhyMem;
}


//*******************************************************************************************************
// Map in a section of physical memory into this process's virtual address space.
//
//*******************************************************************************************************

BOOL mapPhyMem(HANDLE hPhyMem, DWORD *phyAddr, DWORD *length, PVOID *virtualAddr)
{
NTSTATUS ntStatus;
PHYSICAL_ADDRESS viewBase;

*virtualAddr = 0;
viewBase.QuadPart = (ULONGLONG) (*phyAddr);

ntStatus = _NtMapViewOfSection(hPhyMem, (HANDLE)-1, virtualAddr, 0,
*length, &viewBase, length,
                               ViewShare, 0, PAGE_READWRITE );

if(ntStatus != STATUS_SUCCESS)
{
printf("Failed to map physical memory view of length %X at %X!", *length, *phyAddr);
return FALSE;
}

*phyAddr = viewBase.LowPart;
return TRUE;
}


//*******************************************************************************************************
// Unmap section of physical memory
//
//*******************************************************************************************************

void unmapPhyMem(DWORD virtualAddr)
{
NTSTATUS status;

status = _NtUnmapViewOfSection((HANDLE)-1, (PVOID)virtualAddr);
if(status != STATUS_SUCCESS)
{
printf("Unmapping view failed!\n");
}
}


//*******************************************************************************************************
// Assign SECTION_MAP_WRITE assess of \device\physicalmemory to current user.
//
//*******************************************************************************************************

BOOL assignACL(void)
{
HANDLE hPhyMem;
OBJECT_ATTRIBUTES oAttr;
BOOL result = FALSE;

ANSI_STRING aStr;

_RtlInitAnsiString(&aStr, "\\device\\physicalmemory");

UNICODE_STRING uStr;

if(_RtlAnsiStringToUnicodeString(&uStr, &aStr, TRUE) != STATUS_SUCCESS)
{
return FALSE;
}

   oAttr.Length = sizeof(OBJECT_ATTRIBUTES);
   oAttr.RootDirectory = NULL;
   oAttr.Attributes = OBJ_CASE_INSENSITIVE;
   oAttr.ObjectName = &uStr;
   oAttr.SecurityDescriptor = NULL;
   oAttr.SecurityQualityOfService = NULL;

if(_NtOpenSection(&hPhyMem, READ_CONTROL | WRITE_DAC, &oAttr ) != STATUS_SUCCESS)
{
return FALSE;
}
else
{
PACL dacl;
PSECURITY_DESCRIPTOR sd;

if(GetSecurityInfo(hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
&dacl, NULL, &sd) == ERROR_SUCCESS)
{
EXPLICIT_ACCESS ea;
char userName[MAX_PATH];
DWORD userNameSize = MAX_PATH-1;

GetUserName(userName, &userNameSize);
ea.grfAccessPermissions = SECTION_MAP_WRITE;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.pMultipleTrustee = NULL;
ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = userName;

PACL newDacl;
if(SetEntriesInAcl(1, &ea, dacl, &newDacl) == ERROR_SUCCESS)
{
if(SetSecurityInfo(hPhyMem, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,
newDacl, NULL) == ERROR_SUCCESS)
{
result = TRUE;
}

LocalFree(newDacl);
}
}
}

return result;
}


//*******************************************************************************************************
// Gets the kernel base address
//
//*******************************************************************************************************

DWORD getKernelBase(void)
{
HANDLE hHeap = GetProcessHeap();

NTSTATUS Status;
   ULONG cbBuffer = 0x8000;
   PVOID pBuffer = NULL;
DWORD retVal = DEF_KERNEL_BASE;

   do
   {
pBuffer = HeapAlloc(hHeap, 0, cbBuffer);
if (pBuffer == NULL)
return DEF_KERNEL_BASE;

Status = _NtQuerySystemInformation(SystemModuleInformation,
pBuffer, cbBuffer, NULL);

if(Status == STATUS_INFO_LENGTH_MISMATCH)
{
HeapFree(hHeap, 0, pBuffer);
cbBuffer *= 2;
}
else if(Status != STATUS_SUCCESS)
{
HeapFree(hHeap, 0, pBuffer);
return DEF_KERNEL_BASE;
}
   }
   while (Status == STATUS_INFO_LENGTH_MISMATCH);

DWORD numEntries = *((DWORD *)pBuffer);
SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)((char *)pBuffer + sizeof(DWORD));

for(DWORD i = 0; i < numEntries; i++)
{
if(strcmpi(smi->ImageName, "ntoskrnl.exe"))
{
//printf("%.8X - %s\n", smi->Base, smi->ImageName);
retVal = (DWORD)(smi->Base);
break;
}
smi++;
}

HeapFree(hHeap, 0, pBuffer);

return retVal;
}


struct FixupBlock
{
unsigned long pageRVA;
unsigned long blockSize;
};



BOOL checkKiServiceTableAddr(PVOID exeAddr, DWORD chkAddr, PE_ExtHeader *peXH2)
{
if(peXH2->relocationTableAddress && peXH2->relocationTableSize)
{
FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress);

while(fixBlk->blockSize)
{
int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;

unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

for(int i = 0; i < numEntries; i++)
{
int relocType = (*offsetPtr & 0xF000) >> 12;

if(relocType == 3)
{
DWORD *codeLoc = (DWORD *)((char *)exeAddr + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));

if(fixBlk->pageRVA + (*offsetPtr & 0x0FFF) + peXH2->imageBase == chkAddr)
{
return TRUE;
}
}
offsetPtr++;
}
fixBlk = (FixupBlock *)offsetPtr;
}
}
return FALSE;
}


// Thanks to 90210 for this excellent way of getting the KiServiceTable address from the disk image of
// ntoskrnl.exe
// http://www.rootkit.com/newsread.php?newsid=176

DWORD getKiServiceTableAddr(PVOID exeAddr, DWORD sdtAddr, PE_ExtHeader *peXH2)
{
if(peXH2->relocationTableAddress && peXH2->relocationTableSize)
{
FixupBlock *fixBlk = (FixupBlock *)((char *)exeAddr + peXH2->relocationTableAddress);

while(fixBlk->blockSize)
{
//printf("Addr = %X\n", fixBlk->pageRVA);
//printf("Size = %X\n", fixBlk->blockSize);

int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
//printf("Num Entries = %d\n", numEntries);

unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

for(int i = 0; i < numEntries; i++)
{
int relocType = (*offsetPtr & 0xF000) >> 12;

//printf("Val = %X\n", *offsetPtr);
//printf("Type = %X\n", relocType);

if(relocType == 3)
{
DWORD *codeLoc = (DWORD *)((char *)exeAddr + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));

if(*codeLoc == sdtAddr + peXH2->imageBase &&
*(WORD *)((DWORD)codeLoc - 2) == 0x05c7)
{
DWORD kiServiceTableAddr = *(DWORD *)((DWORD)codeLoc + 4);

// checks for presence of found address in the relocation table
if(checkKiServiceTableAddr(exeAddr, kiServiceTableAddr, peXH2))
{
return kiServiceTableAddr - peXH2->imageBase;
}
}
}

offsetPtr++;
}

fixBlk = (FixupBlock *)offsetPtr;
}
}
return 0;
}

//*******************************************************************************************************
// Program entry point
// No commandline arguments required.
//
//*******************************************************************************************************

int main(int argc, char* argv[])
{
MZHeader mzH2;
PE_Header peH2;
PE_ExtHeader peXH2;
SectionHeader *secHdr2;

printf("SDTrestore Version 0.2 Proof-of-Concept by SIG^2 G-TEC (www.security.org.sg)\n\n");

OSVERSIONINFO ov;
ov.dwOSVersionInfoSize = sizeof(ov);
GetVersionEx(&ov);
if(ov.dwMajorVersion != 5)  //主版本号
{
printf("Sorry, this version supports only Win2K and WinXP.\n");
return 1;
}

if(ov.dwMinorVersion != 0 && ov.dwMinorVersion != 1) //副版本
{
printf("Sorry, this version supports only Win2K and WinXP.\n");
return 1;
}
gWinVersion = ov.dwMinorVersion;

if(!getNativeAPIs())  //取得要用的NT类函数地址
{
printf("Failed to get addresses of Native APIs!\n");
return 1;
}

assignACL();
HANDLE hPhyMem = openPhyMem();
if(hPhyMem == INVALID_HANDLE_VALUE)
assignACL();

hPhyMem = openPhyMem();
if(hPhyMem == INVALID_HANDLE_VALUE)
{
printf("Could not open physical memory device!\nMake sure you are running as Administrator.\n");
return 1;
}

PVOID exeAddr = loadDLL("\\ntoskrnl.exe");
if(!exeAddr)
{
printf("Failed to load ntoskrnl.exe!\n");
return 1;
}

DWORD sdtAddr = procAPIExportAddr((DWORD)exeAddr, "KeServiceDescriptorTable");
if(!sdtAddr)
{
printf("Failed to get address of KeServiceDescriptorTable!\n");
return 1;
}

if(!readPEInfo((char *)exeAddr, &mzH2, &peH2, &peXH2, &secHdr2))
{
printf("Failed to get PE header of ntoskrnl.exe!\n");
return 1;
}

DWORD kernelPhyBase = getKernelBase() - PROT_MEMBASE;
DWORD kernelOffset = kernelPhyBase - peXH2.imageBase;

printf("KeServiceDescriptorTable\t\t%X\n", sdtAddr + kernelPhyBase + PROT_MEMBASE);

unsigned char *ptr = NULL;
DWORD pAddr = sdtAddr + kernelPhyBase;
DWORD wantedAddr = pAddr;
DWORD len = 0x2000;

// map in page containing KeServiceDecriptorTable
if(mapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr))
{
DWORD start = wantedAddr - pAddr;
DWORD serviceTableAddr, sdtCount;
DWORD wantedBytes = len - start;
if(wantedBytes >= 4)
{
serviceTableAddr = *((DWORD *)(&ptr[start]));
printf("KeServiceDecriptorTable.ServiceTable\t%X\n", serviceTableAddr);
if(wantedBytes >= 12)
{
sdtCount = *(((DWORD *)(&ptr[start])) + 2);
printf("KeServiceDescriptorTable.ServiceLimit\t%d\n", sdtCount);
}
}
else
{
printf("Sorry, an unexpected situation occurred!\n");
return 1;
}

unmapPhyMem((DWORD)ptr);
printf("\n");

if(sdtCount >= 300)
{
printf("Sorry, an unexpected error occurred! SDT Count > 300???\n");
return 1;
}

pAddr = serviceTableAddr - PROT_MEMBASE;
wantedAddr = pAddr;
ptr = NULL;
len = 0x2000;
if(mapPhyMem(hPhyMem, &pAddr, &len, (LPVOID *)&ptr))
{
start = wantedAddr - pAddr;
DWORD numEntries = (len - start) >> 2;
if(numEntries >= sdtCount)
{
char **nativeApiNames = NULL;
nativeApiNames = (char **)malloc(sizeof(char *) * sdtCount);
if(!nativeApiNames)
{
printf("Failed to allocate memory for Native API name table.\n");
return 1;
}
memset(nativeApiNames, 0, sizeof(char *) * sdtCount);

PVOID ntdll = loadDLL("\\ntdll.dll");
if(!ntdll)
{
printf("Failed to load ntdll.dll!\n");
return 1;
}

buildNativeAPITable((DWORD)ntdll, nativeApiNames, sdtCount);

DWORD *serviceTable = (DWORD *)(&ptr[start]);
DWORD *fileServiceTable = (DWORD *)((DWORD)exeAddr + wantedAddr - kernelOffset - peXH2.imageBase);

// calculate address based on 90210's suggestion
DWORD fileAddr2 = (DWORD)exeAddr + getKiServiceTableAddr(exeAddr, sdtAddr, &peXH2);

if(fileAddr2 && (DWORD)fileServiceTable != fileAddr2)
{
printf("Two possible addresses of KiServiceTable were found.\n\n");
printf("1 - %.8X\n", fileServiceTable);
printf("2 - %.8X (using method suggested by 90210)\n\n", fileAddr2);
printf("Select One (1-2): ");

char choice[10];
memset(choice, 0, sizeof(choice));
fgets(choice, sizeof(choice) - 1, stdin);
printf("\n");
int intChoice = atoi(choice);
if(intChoice < 1 || intChoice > 2)
{
printf("Invalid selection!\n");
unmapPhyMem((DWORD)ptr);
return 1;
}
else if(intChoice == 2)
fileServiceTable = (DWORD *)fileAddr2;
}

if(!IsBadReadPtr(fileServiceTable, sizeof(DWORD)) &&
  !IsBadReadPtr(&fileServiceTable[sdtCount-1], sizeof(DWORD)))
{
DWORD hookCount = 0;
for(DWORD i = 0; i < sdtCount; i++)
{
if((serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i])
{
printf("%-25s %3X --[hooked by unknown at %X]--\n",
 (nativeApiNames[i] ? nativeApiNames[i] : "Unknown API"),
 i, serviceTable[i]);
hookCount++;
}

}
printf("\nNumber of Service Table entries hooked = %u\n", hookCount);

if(hookCount)
{
printf("\nWARNING:  THIS IS EXPERIMENTAL CODE.  FIXING THE SDT MAY HAVE GRAVE\n"
  "CONSEQUENCES, SUCH AS SYSTEM CRASH, DATA LOSS OR SYSTEM CORRUPTION.\n"
  "PROCEED AT YOUR OWN RISK.  YOU HAVE BEEN WARNED.\n");
printf("\nFix SDT Entries (Y/N)? : ");

char inputReply[10];
memset(inputReply, 0, sizeof(inputReply));
fgets(inputReply, sizeof(inputReply) - 1, stdin);
printf("\n");

if(stricmp(inputReply, "y\n") == 0)
{
for(DWORD i = 0; i < sdtCount; i++)
{
if((serviceTable[i] - PROT_MEMBASE - kernelOffset) != fileServiceTable[i])
{
serviceTable[i] = fileServiceTable[i] + PROT_MEMBASE + kernelOffset;
printf("[+] Patched SDT entry %.2X to %.8X\n", i,
fileServiceTable[i] + PROT_MEMBASE + kernelOffset);
}
}
}
else
printf("[-] SDT Entries NOT fixed.\n");
}
}
else
{
printf("It's likely that the SDT service table has been relocated.\n"
  "This POC code cannot support patching of relocated SDT service table.\n");
}

}
unmapPhyMem((DWORD)ptr);
}
}

return 0;
}
  评论这张
 
阅读(1438)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017