windows内核_1
@[TOC]
环境搭建
1.需要:vs2019+wdk
选择对应得wdk版本,成功安装后可以在vs上看到此模块
2.接下来找到windbg位置,在桌面创建一个快捷方式,在目标后加上
1 | -b -k com:pipe,port=\\.\pipe\com_2,resets=0 |
3.虚拟机打开xp,添加一个串行端口,填上
1 | \\.\pipe\com_2 |
4.打开系统环境变量设置,添加如下环境变量
1 | _NT_SYMBOL_PATH SRV*D:\Myself_Software\Windows_soft\symbols* http://msdl.microsoft.com/download/symbols |
5.打开设置好的xp虚拟机,首先在文件夹选项里把隐藏受保护得文件这个选项关闭,你就可以在c盘得跟目录下看到boot.ini文件
在boot.ini文件最后添加代码
1 | multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /debug /debugport=com_2 /baudrate=115200 |
之后用win+r,输入msconfig 打开启动项 修改如下:
一般>有选择的启动
boot.ini>时间改为3秒
对于xp虚拟机的配置选择单核单处理器,内存大小为256mb
这下在主机打开windbg,虚拟机重起xp,就会发现xp在重起阶段会弹出选项,选择调试模式,虚拟机就会在此断下,在windbg里按g即可正常开机
至此双击调试和vs的环境就已经配好
中断提权
在配好上述环境后,这里在虚拟机里做第一个实验,中断提权。Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3。Windows只使用其中的两个级别RING0和RING3,RING0只给操作系统用,RING3谁都能用。正常我们运行的程序都是在ring3层,这里通过中断的方法让我们的程序读取到0层的数据,从而完成提权。
1.先补充一些基础知识
IDT表就是中断描述符表,用来记录各种不同的中断,及对应的中断处理函数的地址,可以用pc_hunter这个软件进行查看,内核钩子>系统中断表
比如常见的除0异常序号就是00
如果能把我们的函数加入到这个表里,当系统遇到对应的异常时,就可以跳到我们自己的函数去实现功能,而因为异常属于内核层面,所以当进入我们的函数时,就已经完成了从3层到0层的转换,从而可以读取任意的内存数据。在图表里可以看见从0x20开始就是空白的,所以等下我们填入的时候可以从0x20开始。
2.先用vs写一个简单的代码
1 |
|
IdtEntry这个函数里我们用来写一些内敛汇编,__declspec(naked)是用来告诉编译器函数代码的汇编语言为自己的所写,不需要编译器添加任何汇编代码,尝试运行后发现会打印一个随机的地址
但我们修改代码后,这个地址会改变,为了实验方便,我们设置属性release,在属性>链接器>高级> 随即地址改成否 固定地址改成是
修改后就会发现地址变成固定的,即0x401040,记住这个地址
3 修改idt表
首先用双机调试环境打开,这里先补充一些常用的windbg命令
1 | g // Go(F5) |
用windbg查看idt表
继续查看表的数据,可以观察到
结合上面的图片,可以发现一个表项由8字节组成,地址就是前两字节和后两字节的拼接,对应到0x20项,即地址为0x803f500 也可以观察到大部分由0填充,那么我们可以在这里填充我们的函数
编辑数据,至于中间的四字节如何写,可以直接int3上面的,至于中间的四字节是什么意思,可以查看inter的白皮书idt的格式,大致意思是区分0环和3环,
假如你填写的是00408e00`00081040 代表这个是0环的,但是你在代码里写的是int 0x20 这是一个3环的代码,当他要跳到0x401040时会先匹配是不是0环的,因为是3环的,所以实际上不会运行0x401040的代码,而直接报错。而我们平常遇见的除0异常是真正的除0异常,它是由硬件所产生的,属于0环的,就可以跳到其处理函数,因此这里的格式应该和int 3的格式一样,因为int 3本身就是一个3环的断点。
1 | eq 8003f500 0040ee00`00081040 |
4.完善实验代码
在主函数里加入了一个判断地址的检测函数,新加入了一个go函数用来触发断点,随后会进入到IdEntry函数,并且切换到0环,尝试读取内存数据,如果读取成功,代表成功。
1 |
|
小端序,成功读入内核的数据
5 问题
如果在xp上运行发现不是有效的win32程序,需要配置vs环境
在vs里添加单个组件 支持xp的v141工具,修改我们的平台集环境,把“C/C++ - 语言 - 符合模式”改成否,在 Release配置 属性页下,把运行库改成“/MT”
可参考VS2019怎样编译出可以在WinXP上运行的exe?
多核复杂性
1 读取if标志位
继续利用上面的环境 编写代码 通过pushfd就可以把eflags读取出来
1 | #include<stdio.h> |
IF——中断允许标志若IF=1则cpu可以响应外部可屏蔽中断请求;若IF=0,则cpu不允许响应中断请求。可以发现if为0 关中断。这样就可以在0环的时候防止中断嵌套。
2 死循环
0环关中断 这样写一个死循环后,虚拟机和windbg都会卡死
1 | #include<stdio.h> |
但加入了汇编指令sti(开中断),那么就不会死循环,强制虚拟机蓝屏
1 | #include<stdio.h> |
3 多核
编辑虚拟机,设置为双核
windbg输入命令,可在0核和1核之间相互切换
1 | ~1 |
因为多核有两个idt表,表的内容不同,行为就有可能发生变化
在这里还是和之前的环境一样,把0核的idt表作修改,而1核的idt表变成函数2的地址
1 | #include<stdio.h> |
1 | ~1 |
多次运行后,就会发现结果不一样
4 cpu写保护
先设置单核环境
寻找一个内核模块,打开pchunter>驱动模块 第一个驱动即可 右键>定位到驱动模块 复制出来,用ida打开
把ida的基质调整和pchunter里显示的一样,然后找到地址0x8054520,这里是3环进入0环的入口
尝试在这里写入数据,会发现无法成功写入,这是因为此页的也属性不能写
1 | #include<stdio.h> |
可以通过windbg命令来查看页属性
1 | !pte xxxxxx |
有两种方法可以进行写,一种直接加入可写的属性,另一种是把cpu的写保护关闭
关闭cpu写保护的汇编代码
1 | mov eax,cr0 |
5 多核写内存稳定性
整合上面的汇编代码,在单核的条件下,会成功的写入数据,并陷入循环卡死中
1 | mov eax,cr0 |
而在切换到双核的条件下,会发现产生了蓝屏(在windbg调试的情况下,报错返回到调试器)
这是因为,0核会和上面一样成功写入数据,并且陷入死循环,而当1核想要进入0环时,发现入口代码已经被修改成无效代码,无法正常进入,而原本0核想要处理1核的异常却被陷入死循环,这样就会发生蓝屏