获取SSTD函数调用索引号
Windows在调用系统API时,通过ntdll.dll文件中的函数进入内核,每个函数在进入内核时都会有一个调用编号,这个调用编号被存放在eax中,windows通过这个编号在SSTD中查找对应的函数地址。
注意:ntdll.dll 导出表的函数编号并不是SSTD的函数编号,两者并不对应。并且已经公开的函数大多数是以NT开头的,还有一些为公开的是ZW。
x64:
mov r10, rcx ; NtSetEventBoostPriority
mov eax, 2Dh ; //其中2Dh就是调用编号
x32:
mov eax, 2Dh ; //其中2Dh就是调用编号
程序:
GetSSDTFunctionIndexAndAddress函数:
第一个参数接受一个PE文件路径
第二个参数接受一个指定函数名
第三个参数:当为TRUE时,返回SSTD函数编号,此时必须为ntdll.dll模块。当为FALST时,返回指定模块中的函数地址。
#include <ntddk.h>
#include <WinDef.h>
#include <aux_klib.h>
#pragma comment(lib,"aux_klib.lib")
//查找函数
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE* phFile, HANDLE* phSection, PVOID* ppBaseAddress)
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
PVOID pBaseAddress = NULL;
SIZE_T viewSize = 0;
// 打开 DLL 文件, 并获取文件句柄
InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status))
{
KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
return status;
}
// 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
return status;
}
// 映射到内存
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
if (!NT_SUCCESS(status))
{
ZwClose(hSection);
ZwClose(hFile);
KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
return status;
}
// 返回数据
*phFile = hFile;
*phSection = hSection;
*ppBaseAddress = pBaseAddress;
return status;
}
//映射文件
ULONGLONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName, BOOL bNumberAndAdd)
{
ULONGLONG ulFunctionIndexAndAdd = 0; // Dos Header
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; // NT Header
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew); // Export Table
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); // 有名称的导出函数个数
ULONG ulNumberOfNames = pExportTable->NumberOfNames;
// 导出函数名称地址表
PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
PCHAR lpName = NULL;
// 开始遍历导出表
for (ULONG i = 0; i < ulNumberOfNames; i++)
{
lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
// 判断是否查找的函数
if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
{
// 获取导出函数地址
USHORT uHint = *(USHORT*)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
if (bNumberAndAdd) //TRUE返回序号、FALSE返回地址
{
// 获取 SSDT 函数 Index
#ifdef _WIN64
ulFunctionIndexAndAdd = *(ULONG*)((PUCHAR)lpFuncAddr + 4);
#else
ulFunctionIndexAndAdd = *(ULONG*)((PUCHAR)lpFuncAddr + 1);
#endif
}
else
{
//返回函数地址
ulFunctionIndexAndAdd = (ULONGLONG)lpFuncAddr;
}
DbgPrint("Function = %s, %d, %p\n", lpName, ulFunctionIndex, lpFuncAddr);
break;
}
}
return ulFunctionIndexAndAdd;
}
//获取函数名对应编号或地址
ULONGLONG GetSSDTFunctionIndexAndAddress(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName, BOOL bNumberAndAdd)
{
ULONGLONG ulFunctionIndexAndAdd = 0;
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
PVOID pBaseAddress = NULL;
// 内存映射文件
status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
if (!NT_SUCCESS(status))
{
KdPrint(("DllFileMap Error!\n"));
return ulFunctionIndexAndAdd;
}
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ulFunctionIndexAndAdd = GetIndexFromExportTable(pBaseAddress, pszFunctionName, bNumberAndAdd);
// 释放
ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
ZwClose(hSection);
ZwClose(hFile);
return ulFunctionIndexAndAdd;
}
//卸载
VOID DriverUpLoad(PDRIVER_OBJECT pdriver)
{
DbgPrint("卸载了\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver, PUNICODE_STRING pReg) //返回一个地址、返回驱动被注册到注册表的某个地方
{
DbgPrint("pdriver = %wZ, , %x\n", pReg, pdriver);
pdriver->DriverUnload = DriverUpLoad;
//获取SSDT 函数编号
UNICODE_STRING ustrDllFileName;
RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
ULONGLONG ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, "NtTerminateProcess", TRUE);
//获取ntoskrnl.exe指定 函数地址
UNICODE_STRING ustrDllFileNameNtoskrnl;
RtlInitUnicodeString(&ustrDllFileNameNtoskrnl, L"\\??\\C:\\Windows\\System32\\ntoskrnl.exe");
ULONGLONG ulSSDTFunctionIndex1Ntoskrnl = GetSSDTFunctionIndexAndAddress(ustrDllFileNameNtoskrnl, "_strnicmp", FALSE);
return STATUS_SUCCESS;
}