能力值:
( LV2,RANK:10 )
|
-
-
13 楼
#include <tchar.h>
#include <Windows.h>
#include <winioctl.h>
#include "RSSDT.h"
/*
// RSSDT.h
typedef struct _tagSST_ENTRY
{
ULONG cbSize;
ULONG Index;
ULONG OrgValue; // 类型 RVA, 传给驱动的时做 Set Value
ULONG NowValue; // 类型 RVA, 传给驱动做 get value
} SST_ENTRY, *PSST_ENTRY;
#define IOCTL_RSSDT_ENTRY_SET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
*/
ULONG Rav2Raw(PVOID pFileData, ULONG rav) // 重定位 RAV转raw:内存相对偏移转数据在文件中相对偏移 、第一个参数为文件指针
{
PIMAGE_DOS_HEADER pDosH;
PIMAGE_NT_HEADERS pNtH;
PIMAGE_SECTION_HEADER pSectH;
ULONG Index;
pDosH = (PIMAGE_DOS_HEADER)pFileData; //dos头地址
pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);//PE文件头地址
pSectH = IMAGE_FIRST_SECTION(pNtH); //节表第一个元素地址
if ( rav >= 0 && rav < pSectH->VirtualAddress ) // 如果该内存地址相对偏移落在节表第一个元素地址的相对偏移之前表示不是节表里的东西,地址不需要重定位
return rav;
for ( Index = 0; Index < pNtH->FileHeader.NumberOfSections; Index++ )
{
if ( rav >= pSectH->VirtualAddress && rav < pSectH->VirtualAddress + pSectH->Misc.VirtualSize ) // 地址落在该节表之内
return rav - pSectH->VirtualAddress + pSectH->PointerToRawData; // 节表头文件相对偏移+该内存地址相对偏移-节表头内存相对偏移
pSectH++;
}
return (ULONG)-1;
}
PVOID NTAPI
GetImageDirEntry(
IN ULONG ImageBase,
IN ULONG DirIndex,
OUT OPTIONAL PIMAGE_NT_HEADERS* ppNtH,
OUT OPTIONAL PIMAGE_DATA_DIRECTORY* ppDataDir
) // 根据数组索引找到PE文件可选头内的数据目录结构数组元素指针(ppDataDir)和指针所指数据块的文件地址(返回值)
{
PIMAGE_DOS_HEADER pDosH;
PIMAGE_NT_HEADERS pNtH;
PIMAGE_DATA_DIRECTORY pDataDir;
pDosH = (PIMAGE_DOS_HEADER)ImageBase;
if ( pDosH->e_magic != IMAGE_DOS_SIGNATURE )
{
return NULL;
}
pNtH = (PIMAGE_NT_HEADERS)(ImageBase + pDosH->e_lfanew);
if ( pNtH->Signature != IMAGE_NT_SIGNATURE )
{
return NULL;
}
if ( ppNtH != NULL )
{
*ppNtH = pNtH;
}
pDataDir = &pNtH->OptionalHeader.DataDirectory[DirIndex];
if ( pDataDir->VirtualAddress == 0 )
{
return NULL;
}
if ( ppDataDir != NULL )
{
*ppDataDir = pDataDir;
}
return (PVOID)(ImageBase + Rav2Raw((PVOID)ImageBase, pDataDir->VirtualAddress));
}
typedef BOOLEAN (NTAPI* LOOPUPXREF_CALLBACK)(PULONG RefAddr, PVOID Param);
ULONG NTAPI // 返回找到的引用个数
pLookupImageXRef(
IN ULONG ImageBase, // 参考地址
IN PIMAGE_DATA_DIRECTORY pBrDir,//数据目录结构数组元素内存指针
IN PIMAGE_BASE_RELOCATION pBr, //指针所指数据块的文件地址
IN ULONG SymAddr,//要查找的地址
IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
IN PVOID pParam
)
{
ULONG nRefCount = 0;
__try
{
ULONG Size = 0;
while ( pBr->SizeOfBlock != 0 && Size < pBrDir->Size )
//单重定位块的长度如果=0表示读到所有重定位块的最后 如果长度超过整个大块的总长度也结束
{
PWORD pRelItem = (PWORD)(pBr + 1);
//IMAGE_BASE_RELOCATION结构后的实际重定位项(十六位)、因为pBr本身是IMAGE_BASE_RELOCATION类型的、指针+1=指针地址+sizeof(IMAGE_BASE_RELOCATION)
PIMAGE_BASE_RELOCATION pNextBr = (PIMAGE_BASE_RELOCATION)((ULONG)pBr + pBr->SizeOfBlock); //下一个单重定位块
while ( (ULONG)pRelItem < (ULONG)pNextBr )
{
ULONG RefBlock = Rav2Raw((PVOID)ImageBase, pBr->VirtualAddress);根据单个重定位内存块的起始RVA得到重定位内存块的文件相对偏移地址
if ( (pRelItem[0] >> 12) == 3 ) //十六位偏移中的4位用于重定位种类、只有值0和3可用
{
PULONG RefAddr = (PULONG)(ImageBase + RefBlock + (pRelItem[0] & 0x0FFF));//将具体需要重定位的代码地址转为该代码所在实际文件地址
// 验证内存是否有效
if ( !IsBadReadPtr(RefAddr, 1) && RefAddr[0] == SymAddr )
{
nRefCount++;
if ( LookupXRefCallback(RefAddr, pParam) ) //在文件里找需要重定位Keservi**地址的语句,并把实际Ki***地址写进pParam并中断
break;
}
}
pRelItem++;
}
Size += pBr->SizeOfBlock;
pBr = pNextBr;
}
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
// DbgPrint("pLookupImageXRef: Found a Exception!\n");
}
return nRefCount;
}
ULONG NTAPI
LookupImageXRef(
IN ULONG ImageBase, // 有效地址
IN ULONG SymAddr,//要查找的地址keservicede***
IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
IN PVOID Param //最终ki***的地址写回这个参数
)
{
if ( LookupXRefCallback != NULL )
{
PIMAGE_DATA_DIRECTORY pBrDir;
PIMAGE_BASE_RELOCATION pBr;
pBr = GetImageDirEntry(ImageBase, IMAGE_DIRECTORY_ENTRY_BASERELOC, NULL, &pBrDir);
if ( pBr != NULL )
{
return pLookupImageXRef(ImageBase, pBrDir, pBr, SymAddr, LookupXRefCallback, Param);
}
}
return 0;
}
typedef struct tag_SYSTEM_SERVICE_TABLE {
PULONG ServiceTable; // array of entry points
PULONG CounterTable; // array of usage counters
ULONG ServiceLimit; // number of table entries
PCHAR ArgumentTable; // array of argument counts
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE, **PPSYSTEM_SERVICE_TABLE;
BOOLEAN WINAPI LookXRefCallback(PULONG pRefAddr, PVOID pParam)
{
USHORT OpCode = *((PUSHORT)pRefAddr - 1);
if ( OpCode == 0x05C7 ) // 0x05C7:mov指令 ds:_KeServiceDe script orTable, offset _KiServiceTable
{
if ( pParam != NULL )
{
*(PULONG)pParam = pRefAddr[1]; // KiServiceTable
}
return FALSE;
}
return TRUE;
}
BOOL GetSSTEntry(PCTSTR pszServiceName, PSST_ENTRY pSSTEntry) //根据函数名查找 函数在SSDT表入口地址
{
HANDLE hFile, hFileMap;
LPVOID pFileData;
HMODULE hNtdll;
FARPROC pfnService;
BOOL bResult;
TCHAR szNtoskrnlPath[MAX_PATH];
hNtdll = GetModuleHandle(_T("ntdll.dll"));
pfnService = GetProcAddress(hNtdll, pszServiceName); //得到NTDLL导出的相应函数内存地址
if ( pfnService == NULL || *(PBYTE)pfnService != 0xB8 ) //第一个字符必然是MOV
return FALSE;
// mov eax, ??
pSSTEntry->Index = *(PULONG)((PBYTE)pfnService + 1); //第2个必然是在SSDT表中的服务号、也就是说NTDLL下的导出函数NT***、开始第一句话类似mov eax,7Ah 函数服务号
GetSystemDirectory(szNtoskrnlPath, MAX_PATH);
_tcscat(szNtoskrnlPath, _T("\\ntoskrnl.exe")); // or ntkrnlpa.exe
hFile = CreateFile(szNtoskrnlPath, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
return FALSE;
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
CloseHandle(hFile);
if ( hFileMap == NULL )
return FALSE;
pFileData = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hFileMap); //ntoskrnl.exe建立内存映射文件
if ( NULL == pFileData )
return FALSE;
bResult = FALSE;
__try
{
PIMAGE_DOS_HEADER pDosH;
PIMAGE_NT_HEADERS pNtH;
PIMAGE_EXPORT_DIRECTORY pExpDir;
PULONG pFunName, pFunAddr;
PUSHORT pFunNameOrd;
ULONG Index;
pDosH = (PIMAGE_DOS_HEADER)pFileData;
pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);
pExpDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)pFileData + pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); //ntoskrnl.exe文件中导出函数的地址
pFunName = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNames)); //导出函数名表的地址
pFunNameOrd = (PUSHORT)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNameOrdinals)); //函数名序号表的地址
pFunAddr = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfFunctions)); //导出函数地址表的地址
for ( Index = 0; Index < pExpDir->NumberOfNames; Index++ )
{
PCSTR pName = (PCSTR)((ULONG)pFileData + Rav2Raw(pFileData, pFunName[Index]));
if ( strcmp(pName, "KeServiceDe script orTable") == 0 ) //如果符合记住在字符串地址表中的索引、然后在addressofnameordinals指向的数组中用同样的索引值取出数组项的值,再以这个值为索引找AddressOfFunctions,就是函数入口地址
{
ULONG _KiServiceTable, _KeServiceDe script orTable; // 类型都是 va
_KiServiceTable = 0;
_KeServiceDe script orTable = pNtH->OptionalHeader.ImageBase + pFunAddr[pFunNameOrd[Index]];
LookupImageXRef((ULONG)pFileData, _KeServiceDe script orTable, LookXRefCallback, &_KiServiceTable);//在文件中找KiServiceTable的地址,因为KiServiceTable没有导出
if ( _KiServiceTable != 0 )
{
PULONG ServiceTable;
_KiServiceTable -= pNtH->OptionalHeader.ImageBase;//RVA
ServiceTable = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, _KiServiceTable));//实际文件地址
pSSTEntry->OrgValue = ServiceTable[pSSTEntry->Index] - pNtH->OptionalHeader.ImageBase;// 实际处理函数地址RVA
}
bResult = TRUE;
break;
}
}
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
bResult = FALSE;
}
UnmapViewOfFile(pFileData);
return bResult;
}
HANDLE GetServiceByName(IN PCTSTR pszServiceName, OUT OPTIONAL SC_HANDLE* pScManager)
{
SC_HANDLE hScManager, hScService;
hScService = NULL;
hScManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if ( pScManager != NULL )
*pScManager = hScManager;
if ( hScManager != NULL )
{
hScService = OpenService(hScManager, pszServiceName, SERVICE_ALL_ACCESS);
if ( pScManager == NULL )
CloseServiceHandle(hScManager);
}
return hScService;
}
SC_HANDLE InstallDriver(IN PCTSTR pszServiceName, IN PCTSTR pszDriverFile)
{
SC_HANDLE hScManager, hScService;
hScManager = NULL;
hScService = GetServiceByName(pszServiceName, &hScManager);
if ( hScService == NULL && hScManager != NULL )
{
hScService = CreateService(hScManager, pszServiceName, pszServiceName, SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, pszDriverFile, NULL,
NULL, NULL, NULL, NULL
);
// GetLastError();
}
if ( hScManager != NULL )
CloseServiceHandle(hScManager);
return hScService;
}
BOOL UninstallDriver(SC_HANDLE hScService)
{
SERVICE_STATUS Status;
if ( ControlService(hScService, SERVICE_CONTROL_STOP, &Status) )
{
DeleteService(hScService);
CloseServiceHandle(hScService);
return TRUE;
}
// GetLastError();
return FALSE;
}
BOOL ResetSSTEntry(PCSTR lpServiceName)
{
SC_HANDLE hScService;
HANDLE hDevice;
SST_ENTRY SstEntry;
ULONG cbReturn;
TCHAR szDriverPath[MAX_PATH];
PTSTR pszDriverName;
BOOL bResult;
SstEntry.cbSize = sizeof (SST_ENTRY);
if ( !GetSSTEntry(lpServiceName, &SstEntry) )
return FALSE;
GetModuleFileName(NULL, szDriverPath, MAX_PATH);
pszDriverName = _tcsrchr(szDriverPath, _T('\\'));
_tcscpy(pszDriverName, _T("\\RSSDT.sys"));
hScService = GetServiceByName(_T("RSSDT"), NULL);
if ( hScService == NULL )
{
hScService = InstallDriver(_T("RSSDT"), szDriverPath);
if ( hScService == NULL )
return FALSE;
}
bResult = FALSE;
if ( StartService(hScService, 0, NULL) || GetLastError() == ERROR_ALREADY_EXISTS )
{
hDevice = CreateFile(_T("\\\\.\\RSSDT"),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
GetLastError();
if ( hDevice != INVALID_HANDLE_VALUE )
{
bResult = DeviceIoControl(hDevice, IOCTL_RSSDT_ENTRY_SET, &SstEntry, sizeof (SstEntry),
&SstEntry, sizeof (SstEntry), &cbReturn, NULL);
CloseHandle(hDevice);
}
}
UninstallDriver(hScService);
return bResult;
}
#if 1
int __cdecl main()
{
ResetSSTEntry("NtCreateKey");
ResetSSTEntry("NtCreatePagingFile");
ResetSSTEntry("NtEnumerateValueKey");
ResetSSTEntry("NtOpenKey");
ResetSSTEntry("NtQueryKey");
ResetSSTEntry("NtQueryValueKey");
ResetSSTEntry("NtSetSystemPowerState");
return 0;
}
#endif
|