- 注册时间
- 2011-3-10
- 最后登录
- 1970-1-1
该用户从未签到
|
未导出SSDT函数的查找方法
今天,我想要写一篇关于从用户模式查找未导出的内核函数地址的文章, 这技术是我原创的, 我想到这个方法是在一个关于Windows x86 kernel exploitation的讨论中,
呵..先不管了, 我无法保证在我之前有人用过这方法, 切入正题吧...
系统内核的实际漏洞利用的主题或它的模块之一太广泛了要完全在这里讨论它, 这样的漏洞使用方面的技术在之前就被一些研究人员描述过,
* Kernel-mode Payloads on Windows
* Remote Windows Kernel Exploitation – Step into the Ring 0
* How to exploit Windows kernel memory pool
一个基本问题是...新手通常对内核漏洞逆向的的潜在遭遇,是在实际中如何走捷径,当这漏洞可以让你在内核执行一个你自己的代码时,
创建一个相对稳定的环境,实际上..我们想要实现的每一个功能,都需要一些扩展的内核函数,通常这些函数99%都在ntoskrnl.exe,
接下来的步骤是,我们先创建一个可以获取我们要使用函数的虚拟地址的全功能PayLoad,在一种很简单的情况,我们之需要对导出的函数进行操作,
我们需要的是解析内部PE结构的方法,几行代码就可实现,通用的方法是对函数进行HASH运算,把函数名转换成一个DWORD值,HASH算法我们可以用
简单的位移操作,
01.; ASSUMPTIONS: ESI = string to hash (input)
02.; EAX = return value (output)
03.;
04. GenerateNameHash:
05. xor eax, eax ; Zero out the EAX (hash) value</p>
06. @HashLoop:
07. rol eax, 13 ; Rotate left by one
08. xor al, byte [esi] ; Xor with the current char
09.
10. inc esi ; Increment pointer
11. cmp byte [esi], 0 ; Check if NULL
12. jnz @HashLoop ; If not, carry on
13. ret ; EAX is already set, we have nothing to do - return
我们可能不需要函数结果的多余的16位,可以节省下内存,我们通常想要把Payload的代码降低到绝对小的体积,总而言之我们现在只想
访问内核镜像公开的可用地址,这不是很困难,更有趣的是可以去搜索一个内核函数,没有被内核导出的,我们尽量使用比较拉风的方法,
这主要根据实际操作系统的版本,
函数在一个SSDT的数组里,包含一些通过用户CALL触发的不同种类的系统调用的指针,它们在创建一些高级R0 Payload时非常有用,
在驱动里获取SSDT函数的地址很简单,倘若我们知道一个Call's ID,那么我们唯一的问题是如何得到系统版本,为了区配相应的函数号,
我写了一个程序设计概述:
加载ntoskrnl.exe到我们的进程上下文,因为再以后我们会广泛使用它,然后我们要轻松的引用导出函数的本地地址,因此我们要计算所有
函数的偏移,以实际内核基址为基础,由于我们不需要把它当作一个典型的DLL库处理,我们必须确保没有不必要的操作被执行(比如调用它的
DllMain()),但又要加载它到内存,呵,感谢微软给了一个LoadLibraryEx()函数,我们用DONT_RESLOVE_DLL_REFERENCES标志去调用它,
就可以跳开侧面影响了,
第一种选择,可以在SSDT内轻松的查找指定函数,和内核导出列表,比如(i.e.NtCreateFile, NtCreateEvent, NtConnectPort, NtClose.)
这功能是很拉风的,因为我们知道了在内核里的内存的精确地址(基于实际的ntoskrnl.exe的镜像基址),我们还可以指定任何其他的SSDT函数地址,
倘若我们知道SyscallID号(可以动态获取).
|
|