标题: kernel shellcode之寻找ntoskrnl.exe基址

http://scz.617.cn:8/windows/201704171416.txt

以64-bits为例,这是Eternalblue所用函数:

--------------------------------------------------------------------------
0000000000000961 Private_find_MZ proc near
0000000000000961 53 push rbx
/*
* 起始位置
*/
0000000000000962 65 48 8B 04 25 38 00 00+ mov rax, gs:qword_38 ; KPCR.IdtBase
000000000000096B 48 8B 40 04 mov rax, [rax+4]
000000000000096F 48 C1 E8 0C shr rax, 0Ch ; 右移左移目的是对齐在页边界上(0x1000)
0000000000000973 48 C1 E0 0C shl rax, 0Ch
0000000000000977
0000000000000977 loop_977:
0000000000000977 48 8B 18 mov rbx, [rax]
/*
* 寻找"MZ"
*/
000000000000097A 66 81 FB 4D 5A cmp bx, 5A4Dh
000000000000097F 74 08 jz short ok_989
0000000000000981 48 2D 00 10 00 00 sub rax, 1000h ; 以页为单位递减
0000000000000987 EB EE jmp short loop_977
0000000000000989
0000000000000989 ok_989:
0000000000000989 5B pop rbx
000000000000098A C3 retn
000000000000098A Private_find_MZ endp
--------------------------------------------------------------------------

x64内核态GS:0指向nt!_KPCR。对于x64,必须从相应的MSR中读取GS段基址:

kd> rdmsr 0xC0000101
msr[c0000101] = fffff800`019f9d00

在kd中有个办法变相获取GS段基址:

kd> !cpuinfo
CP F/M/S Manufacturer MHz PRCB Signature MSR 8B Signature Features
0 6,42,7 GenuineIntel 3392 0000002300000000 0000002300000000 21193ffe
Cached Update Signature 0000002300000000
Initial Update Signature 0000002300000000
kd> !pcr 0
KPCR for Processor 0 at fffff800019f9d00:
... kd> dt -v nt!_KPCR fffff800`019f9d00
struct _KPCR, 27 elements, 0x4e80 bytes
+0x000 NtTib : struct _NT_TIB, 8 elements, 0x38 bytes
+0x000 GdtBase : 0xfffff800`02cae000 union _KGDTENTRY64, 7 elements, 0x10 bytes
+0x008 TssBase : 0xfffff800`02caf080 struct _KTSS64, 8 elements, 0x68 bytes
+0x010 UserRsp : 0x2ef398
+0x018 Self : 0xfffff800`019f9d00 struct _KPCR, 27 elements, 0x4e80 bytes
+0x020 CurrentPrcb : 0xfffff800`019f9e80 struct _KPRCB, 242 elements, 0x4d00 bytes
+0x028 LockArray : 0xfffff800`019fa4f0 struct _KSPIN_LOCK_QUEUE, 2 elements, 0x10 bytes
+0x030 Used_Self : 0x000007ff`fffdd000 Void
+0x038 IdtBase : 0xfffff800`02cae080 union _KIDTENTRY64, 11 elements, 0x10 bytes
+0x040 Unused : [2] 0
+0x050 Irql : 0 ''
+0x051 SecondLevelCacheAssociativity : 0x10 ''
+0x052 ObsoleteNumber : 0 ''
+0x053 Fill0 : 0 ''
+0x054 Unused0 : [3] 0
+0x060 MajorVersion : 1
+0x062 MinorVersion : 1
+0x064 StallScaleFactor : 0xd40
+0x068 Unused1 : [3] (null)
+0x080 KernelReserved : [15] 0
+0x0bc SecondLevelCacheSize : 0x800000
+0x0c0 HalReserved : [16] 0xca337550
+0x100 Unused2 : 0
+0x108 KdVersionBlock : (null)
+0x110 Unused3 : (null)
+0x118 PcrAlign1 : [24] 0
+0x180 Prcb : struct _KPRCB, 242 elements, 0x4d00 bytes

GS:[0x38]是IdtBase,等于0xfffff800`02cae080,指向nt!_KIDTENTRY64:

kd> dt -v nt!_KIDTENTRY64
union _KIDTENTRY64, 11 elements, 0x10 bytes
+0x000 OffsetLow : Uint2B
+0x002 Selector : Uint2B
+0x004 IstIndex : Bitfield Pos 0, 3 Bits
+0x004 Reserved0 : Bitfield Pos 3, 5 Bits
+0x004 Type : Bitfield Pos 8, 5 Bits
+0x004 Dpl : Bitfield Pos 13, 2 Bits
+0x004 Present : Bitfield Pos 15, 1 Bit
+0x006 OffsetMiddle : Uint2B
+0x008 OffsetHigh : Uint4B
+0x00c Reserved1 : Uint4B
+0x000 Alignment : Uint8B
kd> db 0xfffff800`02cae080 l 0x10
fffff800`02cae080 00 81 10 00 00 8e 87 01-00 f8 ff ff 00 00 00 00 ................
kd> dt -v nt!_KIDTENTRY64 0xfffff800`02cae080
union _KIDTENTRY64, 11 elements, 0x10 bytes
+0x000 OffsetLow : 0x8100
+0x002 Selector : 0x10
+0x004 IstIndex : Bitfield 0y000
+0x004 Reserved0 : Bitfield 0y00000 (0)
+0x004 Type : Bitfield 0y01110 (0xe)
+0x004 Dpl : Bitfield 0y00
+0x004 Present : Bitfield 0y1
+0x006 OffsetMiddle : 0x187
+0x008 OffsetHigh : 0xfffff800
+0x00c Reserved1 : 0
+0x000 Alignment : 0x1878e00`00108100

Offset是ISR的入口地址,在中断描述符中被分成三部分,上例中Offset实际值是:

( OffsetHigh << 32 ) | ( OffsetMiddle << 16 ) | OffsetLow = 0xfffff80001878100

对比下面的命令输出:

kd> !idt 0

Dumping IDT:

00:     fffff80001878100 nt!KiDivideErrorFault

Private_find_MZ()从IDT[0]的偏移0x4处取8字节指针:

kd> ? poi(0xfffff800`02cae080+4)
Evaluate expression: -8796067361280 = fffff800`01878e00

0xfffff80001878e00本身没有意义,因为低16位跟Offset没关系。但是,该值对齐在

页边界(0x1000)上后将位于nt模块中。考虑两个事实,一是高48位对应OffsetHigh、

OffsetMiddle,二是bit-15是KIDTENTRY64.Present,一般等于1。

kd> u 0xfffff80001878000
nt!KiUnexpectedInterrupt+0x1e0:

Private_find_MZ()从0xfffff80001878000开始向低址方向寻找"MZ",以页为单位递

减,以此定位nt模块基址。其实际值是:

kd> lm m nt
start end module name
fffff800`0180b000 fffff800`01df2000 nt

显然,这个算法是经验性的。

kernel 获取ntoskrnl.exe基址的更多相关文章

  1. 驱动中遍历模块,以及获取ntoskrnl.exe基址

    方法是基于PsLoadModuleList方式 驱动中遍历模块 一丶简介 简介: 进入内核了.遍历内核中使用的模块该怎么办. 其实在驱动中.我们的DriverEntry入口位置. 提供了两个参数. 一 ...

  2. Windows Server 2008 R2 ntoskrnl.exe 引起蓝屏故障,重新启动

    前不久在HP ProLiant DL360 G6的服务器上面安装了Windows Server 2008 R2,系统一到晚上凌晨就出现蓝屏.重启现象,并且在 C:\Windows\Minidump 目 ...

  3. ntoskrnl.exe损坏或丢失的解决方式

    同事的电脑启动时出现下面提示:"因下面文件损坏或丢失Windows无法启动 %systemroot%\system32\ntoskrnl.exe,请又一次安装以上文件的拷贝"(Wi ...

  4. 内核文件ntoskrnl.exe,ntkrnlpa.exe的区别??

    除了标题中说到的两个exe文件之外,还有另外两个ntkrnlmp.exe和ntkrpamp.exe.因为我目前用到的只是标题中的两个. 其中,我在网上搜索到的关于SSDT HOOK 的资料,举的例子, ...

  5. WPF获取外部EXE图标最简单的方法

    原文:WPF获取外部EXE图标最简单的方法 首先在工程添加对System.Drawing的引用 创建以下方法: public static ImageSource GetIcon(string fil ...

  6. 使用 PDBDownloader 解决 IDA 加载 ntoskrnl.exe 时符号不完全问题

    解决 IDA 加载 ntoskrnl.exe 时符号不完全问题 1. 问题:IDA加载xp系统的 ntoskrnl.exe 加载不完全. 2. 尝试过但未成功的解决方案: 1)配置好的IDA的 pdb ...

  7. Win10 ntoskrnl.exe蓝屏解决

    主机一直用的是无线网卡,装Win10下载驱动.不管是Window10自己更新,还是通过驱动人生.驱动精灵等安装的Killer网卡驱动,均日常导致蓝屏. 状态是这样的:玩游戏蓝屏.检测系统蓝屏.清垃圾蓝 ...

  8. 旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法

    0x01 找kernel32基地址的方法一般有三种: 暴力搜索法.异常处理链表搜索法.PEB法. 0x02 基本原理 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理是几乎所有的win ...

  9. 获取当前exe的路径

    1.Assembly.GetExecutingAssembly().Location得到exe的全路径,Path.GetDirectoryName得到目录路径,不要用Directory.GetCurr ...

随机推荐

  1. CLR学习之初识CLR

    一.什么是CLR? CLR即公共语言运行时(Common Language Runtime,简称CRL),就是微软为.net产品构建的运行环境,与java的JVM类似,通俗的讲就是.net虚拟机.CL ...

  2. Elasticsearch DSL 常用语法介绍

    课程环境 CentOS 7.3 x64 JDK 版本:1.8(最低要求),主推:JDK 1.8.0_121 Elasticsearch 版本:5.2.0 相关软件包百度云下载地址(密码:0yzd):h ...

  3. 【JVM学习笔记一】Java内存区域

    1. 运行时数据区域 1) 程序计数器 | 线程私有,存储线程运行时所执行字节码的行号,实现分支.循环.跳转.异常处理.线程恢复等基础功能 | Java方法,记录正在执行的虚拟机字节码指令的行号:Na ...

  4. 爬虫requests库 之爬虫贴吧

    首先要观察爬虫的URL规律,爬取一个贴吧所有页的数据,观察点击下一页时URL是如何变化的. 思路: 定义一个类,初始化方法什么都不用管 定义一个run方法,用来实现主要逻辑 3 class Tieba ...

  5. Python 栈、队列的实现

    在python中,列表既可以作为栈使用,又可以作为队列使用. 把列表作为栈使用 栈:后进先出 stack=[1,2,3] stack.append(4) #入栈,以列表尾部为栈顶 print(stac ...

  6. C# 7可以在.NET Framework 4上运行吗?

    https://stackoverflow.com/questions/42482520/does-c-sharp-7-0-work-for-net-4-5 To sum up: All of C# ...

  7. redis-Jedis连接集群

    关闭防火墙或把端口加入防火墙 一.通过代码 @Test public void testJedisCluster() throws Exception { //创建一连接,JedisCluster对象 ...

  8. JAVA线程池的创建与使用

    为什么要用线程池? 我们都知道,每一次创建一个线程,JVM后面的工作包括:为线程建立虚拟机栈.本地方法栈.程序计数器的内存空间(下图可看出),所以线程过多容易导致内存空间溢出.同时,当频繁的创建和销毁 ...

  9. 转载: JavaScript中执行环境和栈

    在这篇文章中,我会深入理解JavaScript最根本的组成之一 : "执行环境(执行上下文)".文章结束后,你应该对解释器试图做什么,为什么一些函数/变量在未声明时就可以调用并且他 ...

  10. 性能测试基础---LR运行设置

    ·LR的运行时设置(Runtime settings): ·Run Logic:该选项是用来控制脚本的真正的运行逻辑. ·该选项会把脚本中的函数分别放入三个运行模块中:Init.Run.End ·默认 ...