BUG:SSDT函数名获取SSDT函数号
一个有BUG的SSDT函数名返回SSDT函数序列号。一运行就蓝屏。不知道是怎的。大神如果有空帮我看看。然后就是你的代码了,你可以拿去用,谢谢!
这样测试
__try
{
KdPrint(("ZwOpenProcess的函数服务号为:%d", GetFunctionId("NtOpenProcess")));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("GetFunctionId出错了!"));
}
ULONG GetFunctionId(char* FunctionName)
/*++
Routine Description:
[已删除,请勿再提任何无理要求。]
Arguments:
FunctionName - 导出的函数名.
Return Value:
函数的服务号的地址.
--*/
{
NTSTATUS ntstatus;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
OBJECT_ATTRIBUTES object_attributes;
IO_STATUS_BLOCK io_status = { 0 };
PVOID baseaddress = NULL;
SIZE_T size = 0;
//模块基址
// PVOID ModuleAddress = NULL;
//偏移量
ULONG dwOffset = 0;
PIMAGE_DOS_HEADER dos = NULL;
#ifdef _WIN64
PIMAGE_NT_HEADERS64 nt = NULL;
#else
PIMAGE_NT_HEADERS nt = NULL;
#endif
PIMAGE_DATA_DIRECTORY expdir = NULL;
PIMAGE_EXPORT_DIRECTORY exports = NULL;
ULONG addr;
ULONG Size;
PULONG functions;
PSHORT ordinals;
PULONG names;
ULONG max_name;
ULONG max_func;
ULONG i;
ULONG pFunctionAddress = 0;
ULONG ServiceId;
UNICODE_STRING DllName;
RtlInitUnicodeString(&DllName, L"\\SystemRoot\\system32\\ntdll.dll");
//初始化OBJECT_ATTRIBUTES结构
InitializeObjectAttributes(
&object_attributes,
&DllName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
//打开文件
ntstatus = ZwCreateFile(
&hFile,
FILE_EXECUTE | SYNCHRONIZE,
&object_attributes,
&io_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE |
FILE_RANDOM_ACCESS |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(ntstatus))
{
KdPrint((" error0\n"));
KdPrint((" ntstatus = 0x%x\n", ntstatus));
return 0;
}
//创建区段
InitializeObjectAttributes(
&object_attributes,
NULL,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
#ifndef SEC_IMAGE
#define SEC_IMAGE 0x1000000
#endif
ntstatus = ZwCreateSection(
&hSection,
SECTION_ALL_ACCESS,
&object_attributes,
0,
PAGE_EXECUTE,
SEC_IMAGE,
hFile);
if (!NT_SUCCESS(ntstatus))
{
KdPrint((" error1\n"));
KdPrint((" ntstatus = 0x%x\n", ntstatus));
return 0;
}
//映射区段到进程虚拟空间
ntstatus = ZwMapViewOfSection(
hSection,
NtCurrentProcess(), //ntddk.h定义的宏用来获取当前进程句柄
&baseaddress,
0,
1000,
0,
&size,
(SECTION_INHERIT)1,
MEM_TOP_DOWN,
PAGE_READWRITE);
if (!NT_SUCCESS(ntstatus))
{
KdPrint((" error2\n"));
KdPrint((" ntstatus = 0x%x\n", ntstatus));
return 0;
}
//得到模块基址
dwOffset = (ULONG)baseaddress;
//验证基址
//KdPrint((" BaseAddress:0x%x\n", dwOffset));
dos = (PIMAGE_DOS_HEADER)baseaddress;
#ifdef _WIN64
nt = (PIMAGE_NT_HEADERS64)((ULONG)baseaddress + dos->e_lfanew);
#else
nt = (PIMAGE_NT_HEADERS)((ULONG)baseaddress + dos->e_lfanew);
#endif
expdir = (PIMAGE_DATA_DIRECTORY)(nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT);
addr = expdir->VirtualAddress;//数据块起始RVA
Size = expdir->Size; //数据块长度
exports = (PIMAGE_EXPORT_DIRECTORY)((ULONG)baseaddress + addr);
functions = (PULONG)((ULONG)baseaddress + exports->AddressOfFunctions);
ordinals = (PSHORT)((ULONG)baseaddress + exports->AddressOfNameOrdinals);
names = (PULONG)((ULONG)baseaddress + exports->AddressOfNames);
max_name = exports->NumberOfNames;
max_func = exports->NumberOfFunctions;
for (i = 0; i < max_name; i++)
{
ULONG ord = ordinals;
if (i >= max_name || ord >= max_func)
{
return 0;
}
if (functions < addr || functions >= addr + Size)
{
if (strncmp((PCHAR)baseaddress + names, FunctionName, strlen(FunctionName)) == 0)
{
pFunctionAddress = (ULONG)((ULONG)baseaddress + functions);
break;
}
}
}
//KdPrint((" %s:0x%x\n",FunctionName, pFunctionAddress));
ServiceId = *(PSHORT)(pFunctionAddress + 1);
//打印导出函数服务号
//KdPrint((" ServiceId:0x%x\n",ServiceId));
//卸载区段,释放内存,关闭句柄
ZwUnmapViewOfSection(NtCurrentProcess(), baseaddress);
ZwClose(hSection);
ZwClose(hFile);
return ServiceId;
} 我发过动态取得SSDT函数的帖子的,地址:http://www.m5home.com/bbs/thread-8518-1-1.html
就是像ZwProtectVirtualMemory这样的未导出函数不好用。思路很简单,获取对应的ZwXXX函数的地址,从第二个字节开始读四个字节,该数据就是服务编号了 额。。。那是32位的,64位的也有办法,用反汇编引擎解析出每一条指令,并判断指令的机器码是不是0xB8。第一个0xB8(mov)指令后面的四个字节就是这个函数的服务号 KernelLoadLibary+KernelGetProcAddress。获得的地址虽然是“假的”(可以简单理解为一个随机BASE+RVA),但数据是“真的”。足以从中提取出INDEX。 和baseaddress 相关的计算,不能直接使用ULONG强制转换,需要使用ULONG_PTR。
页:
[1]