目录
- 64位内核映射DLL获取Zw函数调用功能号
- 一丶 简介
- 1.1 如何映射DLL
- 1.2 如何获取Zw功能调用号
- 二丶 代码示例
- 2.1 内存中映射文件 (模拟 Ring3 LoadLibrary)
- 2.2 Ring0下解析导出表 获取SystemCall功能号.
- 2.3 其它博客参考资料
- 一丶 简介
64位内核映射DLL获取Zw函数调用功能号
一丶 简介
1.1 如何映射DLL
映射DLL其实很简单 在内核中使用4个函数即可映射. 而这方面网上资料也很多.这里推荐几个 也不再重复叙述了. 转载链接: 内核映射文件 简而言之只需要熟悉四个API即可. 而核心API其实就三个 分别为如下:
ZwOpenFile(); 打开文件
ZwCreateSection() 创建映射 ---> 参考Ring3 Winapi CreateFileMapping
ZwMapViewOfSection(); 映射 ---> 参考Ring3 Winapi MapViewOfFile
ZwClose(); 关闭 文件句柄 关闭创建映射后的句柄
其实API很简单.只需要查下文档即可使用 而且在Ring3下也有与之对应的API. 只不过 这是换到Ring0中使用了.
1.2 如何获取Zw功能调用号
上面是映射了DLL. 那么映射的DLL相当于内存中已经有了DLL数据了. 我们只需要解析导出表即可. 我们映射的DLL是ntdll.dll 所以我们要寻找的函数也是 ntdll.dll下的Zw导出函数. 而我们的主题是获取Zw功能调用号. 我们获取Zw功能调用号其实就是想在SSDT(64位)表中查找对应的导出函数. 所以这一步 我们在Ring3做也可以. 原理就是加载ntdll.dll 直接解析它的导出表 从导出表中获取Zw功能函数. 至于如何获取调用号我们打开X64Dbg 随便调试一个64位程序. 然后去他的Ntdll.dll中随便找一个Zw函数. 比如我找的ZwReadFile. 那么观看其反汇编则如下:
可以看到我们想要获取的功能号位6 但是每个系统是不一样的. 所以我们必须先获取ZwReadFile的函数地址. 获取到它的地址后再按照 char *来解析这个地址. 在64位下
*((CHAR*)pfnAddress + 4)
则是要获取的功能号. 所以获取Zw功能号在Ring3下也可以做. 做了之后通信给Ring0 ring0直接拿着调用号去SSDT表找出对应的地址. 解析导出表也很简单。 1.首先获取内存导出表位置.virtualaddress + hmod 2.分别获取三个数组的地址 名字表 函数地址表 序号表 3.循环遍历导出表。判断名字是否落在范围内 4.从 序号表中拿到序号 然后从 函数地址表中拿到函数地址 order = 序号表[index] pfnaddr = 函数表[order]
解析的时候简单的导出表获取 可以直接 序号表[index] 但是导出序号是以导出表的base开始导出的。 而数组则是 0开始的。 所以有的时候 需要 order = 序号表[index] + export.base - 1; pfnaddr = 函数表[order] 这种情况需要注意。代码中有体现。我会注释掉。
我们主题是64位内核. 所以我们都在内核下做.
二丶 代码示例
2.1 内存中映射文件 (模拟 Ring3 LoadLibrary)
HANDLE CNtddkModule::DllLoadLibraryW(const PWCHAR pcwzfullDllPath)
{
/*
1.ZwOpenFile it
2.ZwCreateSection
3.ZwMapViewOfSection
4.ZwClose 1,2 Handle
*/
UNICODE_STRING uStrFullDllPath = {0};
OBJECT_ATTRIBUTES obAttriButeFullDllPth = {0};
HANDLE hBaseHandleAddr = NULL;
SIZE_T size = 0;
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
HANDLE hFileHandle = NULL;
HANDLE hSectionHandle = NULL;
IO_STATUS_BLOCK iosta = {0};
CONST ULONG SEC_IMAGE = 0x1000000;
if (pcwzfullDllPath == NULL)
{
goto RELEASE;
}
RtlInitUnicodeString(&uStrFullDllPath, pcwzfullDllPath);
InitializeObjectAttributes(
&obAttriButeFullDllPth,
&uStrFullDllPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
0,
0);
ntStatus = ZwOpenFile(&hFileHandle,
FILE_EXECUTE | SYNCHRONIZE,
&obAttriButeFullDllPth,
&iosta,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(ntStatus))
{
goto RELEASE;
}
//use ZwCreateSection
obAttriButeFullDllPth.ObjectName = 0;
ntStatus = ZwCreateSection(&hSectionHandle,
SECTION_ALL_ACCESS,
&obAttriButeFullDllPth,
NULL,
PAGE_EXECUTE,
SEC_IMAGE,
hFileHandle);
if (!NT_SUCCESS(ntStatus))
{
goto RELEASE;
}
//Map it
ntStatus = ZwMapViewOfSection(hSectionHandle,
NtCurrentProcess(),
&hBaseHandleAddr,
0,
0x1000,
0,
&size,
(SECTION_INHERIT)1,
MEM_TOP_DOWN,
PAGE_READWRITE);
if (!NT_SUCCESS(ntStatus))
{
hBaseHandleAddr = NULL;
goto RELEASE;
}
RELEASE:
if (hSectionHandle != NULL)
{
ZwClose(hSectionHandle);
hSectionHandle = NULL;
}
if (hFileHandle != NULL)
{
ZwClose(hFileHandle);
hFileHandle = NULL;
}
return hBaseHandleAddr;
}
HANDLE CNtddkModule::DllLoadLibraryA(const PCHAR pcwzfullDllPath)
{
ANSI_STRING ansiFullDllPath = {0};
UNICODE_STRING uStrFullDllPath = {0};
PWCHAR pwzFullDllPath = NULL;
HANDLE hBaseAddr = NULL;
if (pcwzfullDllPath == NULL)
{
return NULL;
}
RtlInitAnsiString(&ansiFullDllPath, pcwzfullDllPath);
RtlAnsiStringToUnicodeString(&uStrFullDllPath, &ansiFullDllPath, TRUE);
if (uStrFullDllPath.Buffer == NULL)
{
goto RELEASE;
}
pwzFullDllPath = (PWCHAR)ExAllocatePool(NonPagedPool, uStrFullDllPath.MaximumLength);
if (pwzFullDllPath == NULL)
{
goto RELEASE;
}
RtlZeroMemory(pwzFullDllPath, uStrFullDllPath.MaximumLength);
RtlCopyMemory(pwzFullDllPath, uStrFullDllPath.Buffer, uStrFullDllPath.Length);
hBaseAddr = DllLoadLibraryW(pwzFullDllPath);
RELEASE:
if (pwzFullDllPath != NULL)
{
ExFreePool(pwzFullDllPath);
pwzFullDllPath = NULL;
}
if (uStrFullDllPath.Buffer != NULL)
{
RtlFreeUnicodeString(&uStrFullDllPath);
}
return hBaseAddr;
}
调用示例: (DriverEntry中)
HANDLE ntDllBase = NULL;
#ifdef _WIN64
ntDllBase = ddkModule.DllLoadLibraryW(L"\\SystemRoot\\System32\\ntdll.dll");
#else
ntDllBase = ddkModule.DllLoadLibraryW(L"\\SystemRoot\\SysWOW64\\ntdll.dll");
#endif
2.2 Ring0下解析导出表 获取SystemCall功能号.
PVOID Cssdt::GetProcA(HANDLE hDll, CHAR *szSysProcName)
{
// /*
// Parse Pe Header Get Export DirEctory
// */
PIMAGE_DOS_HEADER pDosHeader = NULL;
#ifdef _AMD64_
PIMAGE_NT_HEADERS64 pNtHeader = NULL;
PIMAGE_OPTIONAL_HEADER64 pOptHeder = NULL;
#else
PIMAGE_NT_HEADERS32 pNtHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptHeder = NULL;
#endif // _AMD64_
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_EXPORT_DIRECTORY pExportTable = NULL;
#ifdef _AMD64_
PVOID pBaseAddr = NULL;
#else
PVOID pBaseAddr = NULL;
#endif // _AMD64_
// Export Info
PULONG plAddressOfFunctions = NULL;
PULONG plAddressOfNames = NULL;
PSHORT plAddressOfNameOrdinals = NULL;
ULONG_PTR plBase = NULL;
ULONG uIndex = 0;
ULONG_PTR pllFunctionOrider = NULL;
// SearchName
STRING saSearchName = {0};
STRING saCurName = {0};
PCHAR pCurFunctionName = NULL;
if (hDll == NULL)
{
return NULL;
}
if (szSysProcName == NULL)
{
return NULL;
}
pDosHeader = (PIMAGE_DOS_HEADER)hDll;
#ifdef _AMD64_
pNtHeader = (PIMAGE_NT_HEADERS64)((CHAR *)pDosHeader + pDosHeader->e_lfanew);
pOptHeder = (PIMAGE_OPTIONAL_HEADER64)&pNtHeader->OptionalHeader;
#else
pNtHeader = (PIMAGE_NT_HEADERS32)((CHAR *)pDosHeader + pDosHeader->e_lfanew);
pOptHeder = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;
#endif // _AMD64_
pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pOptHeder->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
// Get Export FunctioAddr FunctionNameRvaAddr Orider ..
plAddressOfFunctions = (PULONG)((PUCHAR)hDll + pExportTable->AddressOfFunctions);
plAddressOfNames = (PULONG)((PUCHAR)hDll + pExportTable->AddressOfNames);
plAddressOfNameOrdinals = (PSHORT)((PUCHAR)hDll + pExportTable->AddressOfNameOrdinals);
plBase = pExportTable->Base;
// Parse Export
RtlInitString(&saSearchName, szSysProcName);
for (uIndex = 0; uIndex < pExportTable->NumberOfNames; uIndex++)
{
// Search FunctionName
pCurFunctionName = (PCHAR)((PUCHAR)hDll + plAddressOfNames[uIndex]);
RtlInitString(&saCurName, pCurFunctionName);
if (RtlCompareString(&saSearchName, &saCurName, TRUE) == 0)
{
pllFunctionOrider = plAddressOfNameOrdinals[uIndex];
// pllFunctionOrider = arrayOfFunctionOrdinals[uIndex] + plBase - 1; // order = orderaddr[index] + base - 1 , pfn = nameaddr[order]
pBaseAddr = (PVOID)((PUCHAR)hDll + plAddressOfFunctions[pllFunctionOrider]);
return pBaseAddr;
}
}
return NULL;
}
ULONG Cssdt::ssdt_GetSystemProcIndexA(HANDLE hDll, CHAR *sysProcName)
{
ULONG uIndex = 0;
ULONG_PTR pfnFunctionAddress = NULL;
pfnFunctionAddress = (ULONG_PTR)this->GetProcA(hDll, sysProcName);
if (pfnFunctionAddress == NULL)
{
goto RELEASE;
}
#ifdef _AMD64_
uIndex = *(PULONG)((PUCHAR)pfnFunctionAddress + 4); //这里就是为什么要加4的意思
#else
uIndex = *(PULONG)((PUCHAR)pfnFunctionAddress + 1);
#endif
RELEASE:
return uIndex;
}
ULONG Cssdt::ssdt_GetSystemProcIndexA(HANDLE hDll, CHAR *sysProcName)
{
ULONG uIndex = 0;
ULONG_PTR pfnFunctionAddress = NULL;
pfnFunctionAddress = (ULONG_PTR)this->GetProcA(hDll, sysProcName);
if (pfnFunctionAddress == NULL)
{
goto RELEASE;
}
#ifdef _AMD64_
uIndex = *(PULONG)((PUCHAR)pfnFunctionAddress + 4);
#else
uIndex = *(PULONG)((PUCHAR)pfnFunctionAddress + 1);
#endif
RELEASE:
if (uIndex <= 0 || uIndex > 500)
{
return 0;
}
return uIndex;
}
DriverEntry下调用示例
id = ssdtopt.ssdt_GetSystemProcIndexA(ntDllBase, "ZwReadFile");