前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >64位内核映射DLL获取Zw函数调用功能号

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

作者头像
IBinary
发布2022-05-10 13:28:44
5280
发布2022-05-10 13:28:44
举报
文章被收录于专栏:逆向技术逆向技术

目录

  • 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其实就三个 分别为如下:

代码语言:javascript
复制
    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位下

代码语言:javascript
复制
*((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)

代码语言:javascript
复制
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功能号.

代码语言:javascript
复制
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");

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 64位内核映射DLL获取Zw函数调用功能号
    • 一丶 简介
      • 1.1 如何映射DLL
      • 1.2 如何获取Zw功能调用号
    • 二丶 代码示例
      • 2.1 内存中映射文件 (模拟 Ring3 LoadLibrary)
      • 2.2 Ring0下解析导出表 获取SystemCall功能号.
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档