64位内核映射DLL获取Zw函数调用功能号

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");

2.3 其它博客参考资料

https://yhsnlkm.github.io/2021/03/08/%E6%94%BB%E9%98%B2%E4%BF%9D%E6%8A%A4/%E5%9C%A8%E5%86%85%E6%A0%B8%E4%B8%AD%E8%8E%B7%E5%8F%96%E8%BF%9B%E7%A8%8B%E7%9A%84DLL%E5%92%8C%E5%AF%BC%E5%87%BA%E5%87%BD%E6%95%B0-1/

posted @ 2022-01-03 21:20  iBinary  阅读(252)  评论(0编辑  收藏  举报