티스토리 뷰
//*********************************************************************************************
// 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())
{
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;
}
'보안 > 분석' 카테고리의 다른 글
CreateMutex Function (2) | 2008.07.01 |
---|---|
[Note] KeyBoard 메시지 전달 순서 (1) | 2008.05.29 |
Defeating Kernel Native API Hookers by Direct Service Dispatch Table Restoration (by SIG^2) (1) | 2008.04.12 |
SDT Hooking 무력화에 대한 연구 (By Dual5651, dualpage.muz.ro) (0) | 2008.04.11 |
Using Files In A Driver [펌 MSDN] (0) | 2008.04.08 |
- Total
- Today
- Yesterday
- 지루박멸연구센타
- 열정의 힘을 믿는다
- Le4rN TO Cr4cK
- 디버깅에관한모든것(DebugLab)
- sysinternals
- FoundStone
- hashtab
- 보안-coderant
- 디바이스드라이버 개발자 포럼
- dualpage.muz.ro
- osronline.com - 드라이버 관련 정보 사이트
- NtInternals - NativeAPI Refere…
- pcthreat - spyware 정보 제공
- rootkit.com - 루트킷 관련 정보
- www.ntinternals.net
- WINE CrossRef. - source.winehq…
- tuts4you
- hex-rays
- idapalace
- idefense
- immunityinc
- threatexpert
- hdp.null2root.org
- www.crackstore.com
- crackmes.de
- www.who.is
- www.cracklab.ru
- community.reverse-engineering.…
- video.reverse-engineering.net
- SnD
- 클레이 키위
- reversengineering.wordpress.co…
- www.openrce.org
- www.woodmann.com
- PEID.Plusins.BobSoft
- roxik.com/pictaps/
- regexlib.com
- spyware-browser.com
- www.usboffice.kr
- regulator
- www.txt2re.com
- ietab.mozdev.org
- zesrever.xstone.org
- www.heaventools.com/PE-file-he…
- www.heaventools.com
- www.innomp3.com
- 울지않는벌새
- exetools.com-forum
- exetools.com
- utf8 conv
- robtex - IP trace
- onsamehost - same IP sites
- JpopSuki
- jsunpack.jeek.org
- wepawet.iseclab.org
- www.jswiff.com
- www.hackeroo.com
- winesearcher.co.kr
- khpga.org
- malwareurl.com
- anubis.iseclab.org
- www.crummy.com-eautifulSoup
- malwarebytes.org/forums
- bbs.janmeng.com
- blackip.ustc.edu.cn
- eureka.cyber-ta.org
- exploit-db.com
- 주택구매력지수
- 시스템트래이딩
- ROA
- 주식트래이딩
- Pivot
- 매매가격지수
- 자동트래이딩
- 사회간접자본
- O365
- CriticalSection
- 맥쿼리인프라
- SBI저축은행
- ubuntu
- 군함도
- ElasticSearch
- 신한저축은행
- 전세매매지수
- 미국주식
- systemd
- hai
- 다올저축은행
- 레고랜드
- 실시간트래이딩
- INVOICE
- ChatGPT
- 피봇
- 공공인프라
- 주식
- logrotate
- PIR
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |