绿林科技 发表于 2015-7-25 19:38:07

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;
}

tangptr@126.com 发表于 2015-7-25 21:16:23

我发过动态取得SSDT函数的帖子的,地址:http://www.m5home.com/bbs/thread-8518-1-1.html
就是像ZwProtectVirtualMemory这样的未导出函数不好用。思路很简单,获取对应的ZwXXX函数的地址,从第二个字节开始读四个字节,该数据就是服务编号了

tangptr@126.com 发表于 2015-7-25 21:21:47

额。。。那是32位的,64位的也有办法,用反汇编引擎解析出每一条指令,并判断指令的机器码是不是0xB8。第一个0xB8(mov)指令后面的四个字节就是这个函数的服务号

Tesla.Angela 发表于 2015-7-25 23:15:19

KernelLoadLibary+KernelGetProcAddress。获得的地址虽然是“假的”(可以简单理解为一个随机BASE+RVA),但数据是“真的”。足以从中提取出INDEX。

loriYagami 发表于 2017-3-24 09:51:12

和baseaddress 相关的计算,不能直接使用ULONG强制转换,需要使用ULONG_PTR。
页: [1]
查看完整版本: BUG:SSDT函数名获取SSDT函数号