更新中
# hg 内核
# 环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 msconfig C:\Windows\system32>bcdedit /copy {current} /d debug 已将该项成功复制到 {9f1759e1-dbea-11ec-93bf-c2eeac6128aa}。 C:\Windows\system32>bcdedit.exe /displayorder {39ce96d1-40cb-11ee-adc5-e87c8ac93724} /addlast 操作成功完成。 C:\Windows\system32>bcdedit.exe /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200 操作成功完成。 C:\Windows\system32>bcdedit.exe /bootdebug {39ce96d0-40cb-11ee-adc5-e87c8ac93724} ON 操作成功完成。 C:\Windows\system32>bcdedit.exe/debug {39ce96d0-40cb-11ee-adc5-e87c8ac93724} ON 操作成功完成。 C:\Windows\system32>bcdedit.exe /timeout 30 操作成功完成。
重启需要使用系统重启,不能使用 vm 的重启
1 "E:\Windows Kits\10\Debuggers\x64\windbg.exe" -y SRV*E:\symbol*http://msdl.microsoft.com/download/symbols -b -k com:port=//./pipe/com_1,baud=115200,pipe
开启配置了 debug 引导的虚拟机,并且开启 windbg
lm
.reload 根据需要加载符号
ld * 加载全部符号
安装 wdm 后,创建 wdm driver
关闭 spectre
关闭警告
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <ntifs.h> VOID DriverUnload (PDRIVER_OBJECT pDriver) { DbgPrintEx (77 , 0 , "11111111111111" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgPrintEx (77 , 0 , "22222" ); pDriver->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
# 保护模式
# CPU
8086 实现了一半的保护模式,80386 完全实现保护模式
80486 奔腾 引入超线程 1 个 物理核虚拟出两个逻辑 cpu。寄存器,流水线,多了二级缓存
CPU 架构
RISC:移动端 ARM,定长硬编码,低耗电,一页 2kb,三级流水线
CISC:PC 端,变长硬编码,支持更多指令集,至少有五级流水线,一页是 4kb
CISC 架构指令执行过程
取指令,指令译码,访存取数,指令执行,结果写回
流水线
当大 jmp 到一个 eip 时,会清空局部缓存,局部缓存大约能存 9-32 条指令。执行预取,缓存指令
通过 JCC 跳转不会清空局部缓存,jmp 可以跳 2G,清空局部缓存
实模式下 ,段地址 * 0x10 + 逻辑地址 = 线性地址,导致可以跨进程修改内存
保护模式有 gdt 表,标识权限。多个进程共享一个内核
# 段寄存器
保护模式下一共有六个段寄存器,实模式只有四个
实模式:
CS (Code Segment):代码段寄存器;
DS (Data Segment):数据段寄存器;
SS (Stack Segment):堆栈段寄存器;
ES (Extra Segment):附加段寄存器;
保护模式:
32 位下没有 GS,GS 是 64 位下用的
段名称后面的数字是段选择子
全局变量是 ds 段描述的,局部变量是 ss 描述的
段是有权限的,读写执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 DWORD value = 100 ; int _tmain(int argc, _TCHAR* argv[]){ value = 1000 ; __asm{ mov ax,cs mov ds,ax mov eax,100 mov dword ptr ds:[value],eax mov ax,es mov ds,ax } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 kd> r // 看寄存器 rax=000000000000ea01 rbx=00000000002001d1 rcx=0000000000000001 rdx=0000000000000073 rsi=00000000000186a0 rdi=fffff80004005e80 rip=fffff80003e8b490 rsp=fffff800054c3888 rbp=fffff78000000320 r8=fffffa8018df2000 r9=0000000000000072 r10=00000000ffffffff r11=fffff800054c3770 r12=0000000000000000 r13=fffff800054c39c0 r14=0000000000000004 r15=0000000000000001 iopl=0 nv up ei pl nz na pe nc cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000202 nt!RtlpBreakWithStatusInstruction: fffff800`03e8b490 cc int 3 kd> r gdtr // windbg的寄存器 gdtr=fffff800054bc000 kd> dq fffff800054bc000 // 看内存 db dw dd dq fffff800`054bc000 00000000`00000000 00000000`00000000 fffff800`054bc010 00209b00`00000000 00cf9300`0000ffff fffff800`054bc020 00cffb00`0000ffff 00cff300`0000ffff fffff800`054bc030 0020fb00`00000000 00000000`00000000 fffff800`054bc040 05008b4b`d0800067 00000000`fffff800 fffff800`054bc050 ff40f3fd`a0003c00 00000000`00000000 fffff800`054bc060 00cf9a00`0000ffff 00000000`00000000 fffff800`054bc070 00000000`00000000 00000000`00000000 0: kd> r eax=00000001 ebx=00026160 ecx=863f8c78 edx=00000000 esi=83f36d20 edi=83f38654 eip=83e86110 esp=83f33b14 ebp=83f33b48 iopl=0 nv up ei pl nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202 0: kd> r gdtr gdtr=80b99000 0: kd> dq 80b99000 80b99000 00000000`00000000 00cf9b00`0000ffff 80b99010 00cf9300`0000ffff 00cffb00`0000ffff 80b99020 00cff300`0000ffff 80008b1e`400020ab 80b99030 834093f3`6c003748 0040f300`00000fff 80b99040 0000f200`0400ffff 00000000`00000000 80b99050 830089f3`40000068 830089f3`40680068 80b99060 00000000`00000000 00000000`00000000 80b99070 800092b9`900003ff 00000000`00000000
LDT: local Descriptor table
GDT: Global Descriptor table
DS == 23 == 0010 0011
RPL==11
TI == 0 // =0 查 GDT,=1 查 LDT
Index == 0010 0 == 0x04 // 查 GDT 第四项 00cff300 0000ffff`
00cff300 0000ffff`
Segment Limit: f ffff
Base Address: 0000 0000 基址
type: 3
s:1 系统段为 0 普通段为 1
DPL:3
P:1 段有效标识,=1 段有效
AVL: 0
D/B:1
G:1
type:3
A 是否被访问过。数据段至少是可读的
快速定位 gdtr 表中位置 1B (段选择子) & fff8 = x = 18
dq $(gdtr) + x == 00cffb00`0000ffff
CS:1B
base: 00000000
limit: fffff
type: b // 没有写权限
s:1
DPL: 3
P:1
AVL: 0
D/B:1
G:1
# 实验:
1 2 3 kd> eq 80b99000+0x48 00cff300`0001ffff // 修改内存 kd> dq 80b99000+0x48
1 2 3 4 5 6 7 8 9 10 DWORD value = 0x100; DWORD value2 = 0; __asm{ mov ax, 0x4b mov ds,ax mov eax,dword ptr ds:[value] // eax值错乱 mov value2, eax mov ax,es mov ds,ax // 还原后base值 变回0 }
[00277000] 逻辑地址
逻辑地址会和 base 相加
如果 base 不是 0
会变成 [00277000 + base] 导致值变了
但是最后会还原 ds 的值,只是中断在那行的时候值会变
gdt hook 改 base
hook int 3
base + idt.offset = 0x48
0x12345678 - idt.offset = value
gdt.48.base = value
# DB_G
64 位中没有 limit 和 base
1 页 = 4096 字节
G= 1 时,fffff 的单位是页 ,范围 (0xfffff+1) * 0x1000 == 0x100000000 - 1 = 0xffff ffff
G=0 按照字节为单位
# D/B
default/bit
D/B 描述 CS 时:
D/B = 1 寻址空间为 32 位
D/B = 0 16 位
更变 cs, jmp 0x4b:402344
此时 push 的时候压栈只压 2 字节
进入内核的时候会修复所有段选择子,退出的时候在恢复
D/B 描述数据段时 数据段 + 堆栈段
D/B = 0 此时寻址宽度变为 16 位,esp 变为 sp,此时 push 的时候程序会直接崩溃,因为系统可访问的最低地址是 0x10000。此时 limit 描述的范围不能访问
DB = 1 32 位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 eq gdtr+0x48 008ff300`0000ffff mov ax,0x4b mov ds,ax push 0 // 正常访问 eq gdtr+0x48 008ff600`0000ffff mov ax,0x4b mov ds,ax push 0 // 异常 eq gdtr+0x48 00c0f600`00000000 mov ax,0x4b mov ds,ax push 0 // 异常
type =2 的时候,如果访问过,会自动变成 3 (accessed)
DB=0 limit 描述的区域都不能访问,向下扩展
DB=1 描述的区域可以访问,向上扩展
DB=0,limit=0 全部可以访问
DB=0,type=6,limit=fffff ,全部都不能访问
向上扩展: 没有描述的区域可以访问。
向下扩展:描述的区域可以访问
保护模式分为
段页模式
纯段模式
纯段模式下:一致代码段:R3 直接调用 R0 非一致代码段:
# 权限检测
关闭增量连接,只有 debug 有
# 裸函数
64 位没有裸函数
1 2 3 4 5 6 7 void __declspec(naked) test2() { int x; // 有些编译器不能这么写,因为没提升堆栈 __asm{ ret } }
裸函数没有对堆栈做操作,如果在裸函数中没有保存现场用堆栈会出问题
DPL 段描述权限
RPL:request privilege level 看当前指令的段描述符 比如 mov dword ptr ds:[],0x12345678 ,DS 描述的这条,此时 RPL 为 DS 的 RPL
CPL:current privilege level 当前权限 值为 CS SS 的 RPL。两个 RPL 必须一致
ring0 - ring3
r0 权限最大
主流操作系统只有 R0 和 R3
VMware 特权级在 R1 早期,虚拟机操作系统在 R1
CS/SS 最后一位代表在几环 B 1011 3 0011 11 在 ring3
数据段取决于 CPL,CPL 数值上 <= DPL 就可以访问到
RPL = 0 ,CPL = 3 ,DPL = 3 可以请求到,RPL 在数据段意义不大
1 2 3 4 5 6 7 eq gdtr+48 008ff300`0000ffff mov ax,0x48 mov ds,ax mov edx,dword ptr ds:[eax] // dpl < cpl = rpl //
堆栈段 CPL=RPL=DPL
1 2 3 4 mov ax,0x48 mov ss,ax mov edx,dword ptr ss:[esp] // 不能改
代码段 CPL=RPL=DPL
1 2 jmp far 4b:410112 // 不会异常,但也不会提权
# jmp call ref
实验时关闭随机基址,链接器 -> 高级 -> 随机基址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 jmp far 0x48:0x401000 // 不能这样在编译器里面写代码 void __declspec(naked) test1() { __asm{ pop eax jmp eax } } char buf[] = {0,0,0,0,0x48,0} *(int *)&buf[0] = (ULONG)test1; __asm{ lea eax,[haha] push eax jmp fword ptr buf haha: }
jmp call 没法同时修改 cs 和 ss,所以不能提权
1 2 3 4 5 6 7 8 9 10 11 12 void __declspec(naked) test1() { __asm{ retf // 远返回,pop 8字节 } } char buf[] = {0,0,0,0,0x48,0} *(int *)&buf[0] = (ULONG)test1; __asm{ call fword ptr buf // 会压入返回地址和CS的段选择子,跨段不提权的call 会压8个字节 }
call 过去 jmp 回来
# 调用门
系统段在 GDT 中分成任务段和调用门
函数的逻辑地址:offset in segment
段选择子:segment selector 0 环默认 08
param count 调用门压入参数
type:1100 32-bit call gate
DPL:门权限,=3,同等权限才能进入
组装调用门描述符
00401000
0040ec00`00081000
call 0x48:0x0 如果是调用门,偏移是 offset in segment,后面的 0x 随便写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 typedef int (__CRTDECL *xxxxx)(_In_z_ _Printf_format_string_ char const* const _Format,...); xxxxx x1 = NULL; char* strings = "sssssss"; void __declspec(naked) test1() { __asm{ push fs int 3 // esp 959deca0 数据段不区分3和0 pop fs retf } } int main() { x1 = (xxxxx)0x83e5141f; // DbgPrint的地址 char buf[] = {0,0,0,0,0x48,0} system("pause"); __asm{ mov eax,esp // esp 12fe50 call fword ptr buf // 这里f10是单步不进去的 haha: } system("pause"); }
dds 959deca0
1 2 3 4 5 6 7 8 9 // 跨段提权 401088 // 返回地址 1b // cs 12fe50 // 保留3环esp 23 // SS // 跨段不提权 401088 // 返回地址 1b // cs
跨段提权会压入四个值,不提权两个值
int 3 会修改 fs 为 30 ,内核层不会还原原来的 fs
u nt!DbgPrint // 证明提权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 typedef int (__CRTDECL *xxxxx)(_In_z_ _Printf_format_string_ char const* const _Format,...); xxxxx x1 = NULL; char* strings = "sssssss"; void __declspec(naked) test1() { __asm{ push fs // 进入ring 0之前fs是0x3b mov ax, 0x30 mov fs,ax mov eax,[strings] push eax call x1 add esp,4 //int 3 pop fs retf } } int main() { x1 = (xxxxx)0x83e5141f; // DbgPrint的地址 char buf[] = {0,0,0,0,0x48,0} system("pause"); __asm{ mov eax,esp // esp 12fe50 call fword ptr buf // 这里f10是单步不进去的 haha: } system("pause"); }
参数个数 0-31
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 eq gdtr+0x48 0040ec01`00081000 typedef int (__CRTDECL *xxxxx)(_In_z_ _Printf_format_string_ char const* const _Format,...); xxxxx x1 = NULL; char* strings = "sssssss"; void __declspec(naked) test1() { __asm{ //int 3 push fs // 进入ring 0之前fs是0x3b int 3 pop fs retf // 跨段提权时 平衡自身esp和跨段之前的esp } } int main() { x1 = (xxxxx)0x83e5141f; // DbgPrint的地址 char buf[] = {0,0,0,0,0x48,0} system("pause"); __asm{ push 0x111111 call fword ptr buf // 这里f10是单步不进去的 haha: } system("pause"); }
retf 在跨段提权的时候平衡的 esp 有自身的和跨段之前的 retf 4
用 jmp
# 中断门
call jmp 只能在同等权限下,或者低权限往高权限跳转。jmp 不能提权调用门
retf iret 只能在同等权限下,或者高权限往低权限跳
D 默认是 1 default
1110 32bit interrupt gate
可屏蔽中断 / 不可屏蔽中断
ELF 中第十位 IF, =0 不接收可屏蔽中断信号
比如关机 是不可屏蔽中断
键盘 USB 可屏蔽中断
中断在 intel 中至少有 32 种中断
中断在 IDT 中存放,但是中断门的段选择子还是查 GDT
IDT:中断描述表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 0: kd> r idtr // interrupt descriptor table idtr=80b99400 0: kd> dq 80b99400 ReadVirtual: 80b99400 not properly sign extended 80b99400 83e48e00`00081fc0 83e48e00`00082150 80b99410 00008500`00580000 83e4ee00`000825c0 // 83e4ee00`000825c0 == int 3 80b99420 83e4ee00`00082748 83e48e00`000828a8 80b99430 83e48e00`00082a1c 83e48e00`00083018 80b99440 00008500`00500000 83e48e00`00083478 80b99450 83e48e00`0008359c 83e48e00`000836dc 80b99460 83e48e00`0008393c 83e48e00`00083c2c 80b99470 83e48e00`000842fc 83e48e00`000846b0 0: kd> !idt Dumping IDT: 80b99400 b7a341b100000037: 8422f104 b7a341b100000051: 871a6a58 0xffffffff88f02254 (KINTERRUPT 871a6a00) b7a341b100000052: 871b57d8 0xffffffff88f02254 (KINTERRUPT 871b5780) b7a341b100000053: 871c0558 0xffffffff88f02254 (KINTERRUPT 871c0500) b7a341b100000054: 871cb2d8 0xffffffff88f02254 (KINTERRUPT 871cb280) b7a341b100000055: 871db558 0xffffffff88fc4b72 (KINTERRUPT 871db500) b7a341b100000060: 871a6cd8 0xffffffff88f02254 (KINTERRUPT 871a6c80) b7a341b100000061: 8758b558 <Unloaded_serial.sys>+0x2cf9 (KINTERRUPT 8758b500) b7a341b100000062: 871b5a58 0xffffffff88f02254 (KINTERRUPT 871b5a00) b7a341b100000063: 871c07d8 0xffffffff88f02254 (KINTERRUPT 871c0780) b7a341b100000064: 871cb558 0xffffffff88f02254 (KINTERRUPT 871cb500) b7a341b100000065: 871db058 0xffffffff88da148a (KINTERRUPT 871db000) b7a341b100000066: 8758b7d8 0xffffffffa4f727ab (KINTERRUPT 8758b780) b7a341b100000070: 8735c058 0xffffffff88f02254 (KINTERRUPT 8735c000) b7a341b100000071: 8758ba58 <Unloaded_serial.sys>+0x749a (KINTERRUPT 8758ba00) b7a341b100000072: 871b5cd8 0xffffffff88f02254 (KINTERRUPT 871b5c80) b7a341b100000073: 871c0a58 0xffffffff88f02254 (KINTERRUPT 871c0a00) b7a341b100000074: 871cb7d8 0xffffffff88f02254 (KINTERRUPT 871cb780) b7a341b100000075: 871db2d8 0xffffffff88da148a (KINTERRUPT 871db280) b7a341b100000076: 87713cd8 0xffffffffa4fdbf00 (KINTERRUPT 87713c80) 0xffffffffa4e87d47 (KINTERRUPT 87713a00) b7a341b100000080: 8735c2d8 0xffffffff88f02254 (KINTERRUPT 8735c280) b7a341b100000082: 871a6058 0xffffffff88f02254 (KINTERRUPT 871a6000) b7a341b100000083: 871c0cd8 0xffffffff88f02254 (KINTERRUPT 871c0c80) b7a341b100000084: 871cba58 0xffffffff88f02254 (KINTERRUPT 871cba00) b7a341b100000085: 871db7d8 0xffffffff88f02254 (KINTERRUPT 871db780) b7a341b100000086: 8758b058 0xffffffffa4f727ab (KINTERRUPT 8758b000) b7a341b100000090: 8735c558 0xffffffff88f02254 (KINTERRUPT 8735c500) b7a341b100000092: 871a62d8 0xffffffff88f02254 (KINTERRUPT 871a6280) b7a341b100000093: 871b5058 0xffffffff88f02254 (KINTERRUPT 871b5000) b7a341b100000094: 871cbcd8 0xffffffff88f02254 (KINTERRUPT 871cbc80) b7a341b100000095: 871dba58 0xffffffff88f02254 (KINTERRUPT 871dba00) b7a341b100000096: 87235a58 0xffffffff88da148a (KINTERRUPT 87235a00) 0: kd> !idt 3 Dumping IDT: 80b99400 b7a341b100000003: 83e425c0 nt!KiTrap03 0: kd> u 83e425c0 L 30 83e425c0 6a00 push 0 83e425c2 66c74424020000 mov word ptr [esp+2],0 83e425c9 55 push ebp 83e425ca 53 push ebx 83e425cb 56 push esi 83e425cc 57 push edi 83e425cd 0fa0 push fs 83e425cf bb30000000 mov ebx,30h 83e425d4 668ee3 mov fs,bx 83e425d7 648b1d00000000 mov ebx,dword ptr fs:[0]
1 2 3 4 5 6 7 8 9 83e4ee00`000825c0 offset 83e425c0 80b99500 00000000`00080000 00000000`00080000 ( 500 - 400 ) / 8 = 0x20 = 32 可以自定义的第一个中断int 32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 dq idtr+0x100 0040 ee00`00081000 void __declspec(naked) test1 (){ __asm{ int 3 iretd } } int main () { char buf[] = {0 ,0 ,0 ,0 ,0x48 ,0 } system ("pause" ); __asm{ int 32 push 0x3b pop fs } system ("pause" ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void __declspec(naked) test1 (){ __asm{ int 3 retf 4 } } int main () { char buf[] = {0 ,0 ,0 ,0 ,0x48 ,0 } system ("pause" ); __asm{ int 32 push 1 push 0x3b pop fs } system ("pause" ); return 0 ; }
retf 同时修改 0 环和三环的堆栈平衡
iretd 返回五个值
1 2 3 4 5 6 dds esp eip cs eflag esp ss
# hook int3
ds.base + 逻辑地址 = 线性地址 (目标地址)
1 2 3 4 5 6 7 8 9 10 11 1: kd> dq 807d3020 ReadVirtual: 807d3020 not properly sign extended 807d3020 83e88e00`00081fc0 83e88e00`00082150 807d3030 00008500`00580000 83e8ee00`000825c0 807d3040 83e8ee00`00082748 83e88e00`000828a8 807d3050 83e88e00`00082a1c 83e88e00`00083018 807d3060 00008500`00500000 83e88e00`00083478 807d3070 83e88e00`0008359c 83e88e00`000836dc 807d3080 83e88e00`0008393c 83e88e00`00083c2c 807d3090 83e88e00`000842fc 83e88e00`000846b0
d.base = 目标地址 - 逻辑地址
= 0x12345678 - 0x83e825c0
因为局部缓存所以会缓存几条指令,需要在这几条指令内跨段跳转 jmp fword ptr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 0 : kd> r gdtr gdtr=80b 99000 0 : kd> dq 80b 9900080b 99000 00000000 `00000000 00 cf9b00`0000f fff80b 99010 00 cf9300`0000f fff 00 cffb00`0000f fff80b 99020 00 cff300`0000f fff 80008b 1e`400020 ab80b 99030 834093f 6`ec003748 0040f 300`00000f ff80b 99040 0000f 200`0400f fff 00000000 `00000000 80b 99050 830089f 6`c0000068 830089f 6`c068006880b 99060 00000000 `00000000 00000000 `00000000 80b 99070 800092b 9`900003f f 00000000 `00000000 1 : kd> r idtr idtr=807 d3020 1 : kd> dq 807 d3020807 d3020 83e88 e00`00081f c0 83e88 e00`00082150 807 d3030 00008500 `00580000 83e8 ee00`000825 c0807 d3040 83e8 ee00`00082748 83e88 e00`000828 a8807 d3050 83e88 e00`00082 a1c 83e88 e00`00083018 807 d3060 00008500 `00500000 83e88 e00`00083478 807 d3070 83e88 e00`0008359 c 83e88 e00`000836 dc807 d3080 83e88 e00`0008393 c 83e88 e00`00083 c2c807 d3090 83e88 e00`000842f c 83e88 e00`000846b 0401000 - 83e945 c0(int 3 ) = base (7 C56 CA40)eq 80b 99048 7 ccf9b56`ca40ffff eq 80b 99418 83e9 ee00`004845 c0 0 : kd> gBreak instruction exception - code 80000003 (first chance) 001b :004010 d4 cc int 3 #include "stdafx.h" #include <Windows.h> typedef int (__cdecl *DbgPrintf)(_In_z_ _Printf_format_string_ const char * _Format, ...);DbgPrintf dbgprintf = NULL ; char * shabi = NULL ;void __declspec(naked) test (){ __asm{ sub esp,8 lea eax,haha mov [esp],eax mov [esp+4 ],0x8 jmp fword ptr [esp] haha: add esp, 8 push fs push 0x30 pop fs mov eax,[shabi] push eax call dbgprintf add esp,4 pop fs mov eax, 0x83e945c0 jmp eax } } int _tmain(int argc, _TCHAR* argv[]){ printf ("%x\r\n" ,test); dbgprintf = (DbgPrintf)0x83e6441f ; shabi = (char *)malloc (30 ); memset (shabi,0 ,30 ); memcpy (shabi,"shabi!!!!!!!!" ,strlen ("shabi" )); system ("pause" ); __asm{ int 3 } system ("pause" ); return 0 ; }
# 陷阱门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 0040 ee00`00081000 eq 80b 99500 0040 ee00`00081000 #include "stdafx.h" #include <Windows.h> int eflags = 0 ;void __declspec(naked) test (){ __asm{ pushfd pop eax mov [eflags],eax push fs push 0x30 pop fs int 3 pop fs iretd } } int _tmain(int argc, _TCHAR* argv[]){ eflags = 0 ; printf ("%x\r\n" ,test); system ("pause" ); __asm{ int 32 } printf ("%X\r\n" ,eflags); system ("pause" ); return 0 ; }
中断门清空 VM TF IF NT ELF=0x46
陷阱门清空 VM TF NT ELF=0x246
VM 虚拟 8086 TF 调试位 IF 可屏蔽中断 NT 嵌套任务
# 任务段
B = busy 当然任务段是否运行,初始 = 0 ,此时 type=9 busy=1 时,type=b,用于判断是否运行过
previous task link :前一个任务的连接,上一个运行的任务段,类似于链表指向前一个节点的
esp0 ss0 0 环
esp2 2 环
esp 3 环
I/O map base 写死的值,用于 IOPL (ELF) ,=0 读写任意端口
1.22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 str # 获取段寄存器的值 ltr 寄存器/内存 # 设置 CPU没有线程,最小执行单元叫做任务。操作系统中最小执行单元是线程 0 : kd> r trtr=00000028 0 : kd> r gdtr gdtr=80b 99000 0 : kd> dq 80b 99000ReadVirtual: 80b 99000 not properly sign extended 80b 99000 00000000 `00000000 00 cf9b00`0000f fff80b 99010 00 cf9300`0000f fff 00 cffb00`0000f fff80b 99020 00 cff300`0000f fff 80008b 1e`400020 ab80b 99030 834093f 6`ec003748 0040f 300`00000f ff80b 99040 0000f 200`0400f fff 00000000 `00000000 80b 99050 830089f 6`c0000068 830089f 6`c068006880b 99060 00000000 `00000000 00000000 `00000000 80b 99070 800092b 9`900003f f 00000000 `00000000 0 : kd> dt nt!_*TSS* ntkrpamp!_KTSS 0 : kd> dt _KTSSnt!_KTSS +0x000 Backlink : Uint2B +0x002 Reserved0 : Uint2B +0x004 Esp0 : Uint4B +0x008 Ss0 : Uint2B +0x00a Reserved1 : Uint2B +0x00c NotUsed1 : [4 ] Uint4B +0x01c CR3 : Uint4B +0x020 Eip : Uint4B +0x024 EFlags : Uint4B +0x028 Eax : Uint4B +0x02c Ecx : Uint4B +0x030 Edx : Uint4B +0x034 Ebx : Uint4B +0x038 Esp : Uint4B +0x03c Ebp : Uint4B +0x040 Esi : Uint4B +0x044 Edi : Uint4B +0x048 Es : Uint2B +0x04a Reserved2 : Uint2B +0x04c Cs : Uint2B +0x04e Reserved3 : Uint2B +0x050 Ss : Uint2B +0x052 Reserved4 : Uint2B +0x054 Ds : Uint2B +0x056 Reserved5 : Uint2B +0x058 Fs : Uint2B +0x05a Reserved6 : Uint2B +0x05c Gs : Uint2B +0x05e Reserved7 : Uint2B +0x060 LDT : Uint2B +0x062 Reserved8 : Uint2B +0x064 Flags : Uint2B +0x066 IoMapBase : Uint2B +0x068 IoMaps : [1 ] _KiIoAccessMap +0x208c IntDirectionMap : [32 ] UChar 0 : kd> dg 28 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0028 801 ca000 000020 ab TSS32 Busy 0 Nb By P Nl 0000008b 0 : kd> dt _KTSS 801 ca000 ntdll!_KTSS +0x000 Backlink : 0 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x8415bcb0 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4 ] 0 +0x01c CR3 : 0 +0x020 Eip : 0 +0x024 EFlags : 0 +0x028 Eax : 0 +0x02c Ecx : 0 +0x030 Edx : 0 +0x034 Ebx : 0 +0x038 Esp : 0 +0x03c Ebp : 0 +0x040 Esi : 0 +0x044 Edi : 0 +0x048 Es : 0 +0x04a Reserved2 : 0 +0x04c Cs : 0 +0x04e Reserved3 : 0 +0x050 Ss : 0 +0x052 Reserved4 : 0 +0x054 Ds : 0 +0x056 Reserved5 : 0 +0x058 Fs : 0 +0x05a Reserved6 : 0 +0x05c Gs : 0 +0x05e Reserved7 : 0 +0x060 LDT : 0 +0x062 Reserved8 : 0 +0x064 Flags : 0 +0x066 IoMapBase : 0x20ac +0x068 IoMaps : [1 ] _KiIoAccessMap +0x208c IntDirectionMap : [32 ] "???" 1 : kd> r espesp=80 de6ae4 cr3 393b 6000403378 eq 80b 95048 0000e940 `50300100 0 : kd> r trtr=00000048 0 : kd> dg 28 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0028 801 ca000 000020 ab TSS32 Busy 0 Nb By P Nl 0000008b 0 : kd> dt _KTSS 801 ca000 ntdll!_KTSS +0x000 Backlink : 0 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x901e3cb0 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4 ] 0 +0x01c CR3 : 0 +0x020 Eip : 0x401111 +0x024 EFlags : 0x202 +0x028 Eax : 0 +0x02c Ecx : 0x3d5e38 +0x030 Edx : 0x3d0178 +0x034 Ebx : 0 +0x038 Esp : 0x12ff2c +0x03c Ebp : 0x12ff44 +0x040 Esi : 0x6e49cbe3 +0x044 Edi : 0x409430 +0x048 Es : 0x23 +0x04a Reserved2 : 0 +0x04c Cs : 0x1b +0x04e Reserved3 : 0 +0x050 Ss : 0x23 +0x052 Reserved4 : 0 +0x054 Ds : 0x23 +0x056 Reserved5 : 0 +0x058 Fs : 0x3b +0x05a Reserved6 : 0 +0x05c Gs : 0 +0x05e Reserved7 : 0 +0x060 LDT : 0 +0x062 Reserved8 : 0 +0x064 Flags : 0 +0x066 IoMapBase : 0x20ac +0x068 IoMaps : [1 ] _KiIoAccessMap +0x208c IntDirectionMap : [32 ] "???" 0 : kd> dg 48 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0048 00403378 00000100 TSS32 Busy 3 Nb By P Nl 000000 eb0 : kd> dt _KTSS 00403378 ntdll!_KTSS +0x000 Backlink : 0x28 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x407418 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4 ] 0 +0x01c CR3 : 0x1e033000 +0x020 Eip : 0x401000 +0x024 EFlags : 2 +0x028 Eax : 0 +0x02c Ecx : 0 +0x030 Edx : 0 +0x034 Ebx : 0 +0x038 Esp : 0x409418 +0x03c Ebp : 0 +0x040 Esi : 0 +0x044 Edi : 0 +0x048 Es : 0x23 +0x04a Reserved2 : 0 +0x04c Cs : 8 +0x04e Reserved3 : 0 +0x050 Ss : 0x10 +0x052 Reserved4 : 0 +0x054 Ds : 0x23 +0x056 Reserved5 : 0 +0x058 Fs : 0x30 +0x05a Reserved6 : 0 +0x05c Gs : 0 +0x05e Reserved7 : 0 +0x060 LDT : 0 +0x062 Reserved8 : 0 +0x064 Flags : 0 +0x066 IoMapBase : 0x20ac +0x068 IoMaps : [1 ] _KiIoAccessMap +0x208c IntDirectionMap : [32 ] "" 0 : kd> r esp esp=00409418 efl=00004002 任务嵌套 1 : kd> r tr tr=00000028 1 : kd> dg 28 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0028 807 cd750 000020 ab TSS32 Busy 0 Nb By P Nl 0000008b 1 : kd> dt _KTSS 807 cd750 ntdll!_KTSS +0x000 Backlink : 0 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x807e6cb0 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4 ] 0 +0x01c CR3 : 0 1 : kd> ed 807 cd750+1 c 3e876600
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 #include "stdafx.h" #include <Windows.h> struct _KiIoAccessMap { UCHAR DirectionMap[32 ]; UCHAR IoMap[8196 ]; }; typedef struct _KTSS { USHORT Backlink; USHORT Reserved0; ULONG Esp0; USHORT Ss0; USHORT Reserved1; ULONG NotUsed1[4 ]; ULONG CR3; ULONG Eip; ULONG EFlags; ULONG Eax; ULONG Ecx; ULONG Edx; ULONG Ebx; ULONG Esp; ULONG Ebp; ULONG Esi; ULONG Edi; USHORT Es; USHORT Reserved2; USHORT Cs; USHORT Reserved3; USHORT Ss; USHORT Reserved4; USHORT Ds; USHORT Reserved5; USHORT Fs; USHORT Reserved6; USHORT Gs; USHORT Reserved7; USHORT LDT; USHORT Reserved8; USHORT Flags; USHORT IoMapBase; struct _KiIoAccessMap IoMaps[1 ]; UCHAR IntDirectionMap[32 ]; }KTSS,*PKTSS;; KTSS tss = {0 }; char bufesp0[0x2000 ] = {0 };char bufesp3[0x2000 ] = {0 };void __declspec(naked) test (){ __asm{ int 3 pushfd pop eax or eax,0x4000 push eax popfd iretd } } int _tmain(int argc, _TCHAR* argv[]){ short trxx = 0 ; __asm{ str trxx ltr trxx } memset (bufesp0,0 ,0x02000 ); memset (bufesp3,0 ,0x02000 ); tss.Esp0 = (ULONG)bufesp0 + 0x1ff0 ; tss.Esp = (ULONG)bufesp3 + 0x1ff0 ; tss.Ss0 = 0x10 ; tss.Ss = 0x10 ; tss.Cs = 0x8 ; tss.Ds = 0x23 ; tss.Es = 0x23 ; tss.Fs = 0x30 ; tss.EFlags = 0x2 ; tss.Eip = (ULONG)test; tss.IoMapBase = 0x20ac ; printf ("cr3\r\n" ); DWORD dwcr3 = 0 ; scanf ("%x" ,&dwcr3); tss.CR3 = dwcr3; printf ("%X\r\n" ,&tss); system ("pause" ); char bufcode[] = {0 ,0 ,0 ,0 ,0x68 ,0 }; __asm{ call fword ptr bufcode } system ("pause" ); return 0 ; }
CPU 中最小执行单元叫做任务,操作系统中叫做线程
一个进程本质来说就是一个任务,在 CPU 看来
任务本质上就是切换寄存器
64 位任务段被废弃,作为别的用处
int 3 把 nt 清了,导致无法返回
iretd 首先检测 NT 为,如果等于 0 就按照堆栈返回
如果 NT=1,就按照 backlink 找到要回去的上下文环境
# 任务门
gdtr 中 10 和 40 都是任务门
type = 5
TSS S S = 任务段段选择子
int 8 双重异常!idt 8
task selector = 0x50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 0: kd> !idt 8 Dumping IDT: 80b99400 bfe94bd900000008: Task Selector = 0x0050 0: kd> dg 50 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0050 83f40000 00000068 TSS32 Avl 0 Nb By P Nl 00000089 0: kd> dt _KTSS 83f40000 nt!_KTSS +0x000 Backlink : 0 +0x002 Reserved0 : 0 +0x004 Esp0 : 0x83f3d000 +0x008 Ss0 : 0x10 +0x00a Reserved1 : 0 +0x00c NotUsed1 : [4] 0 +0x01c CR3 : 0x185000 +0x020 Eip : 0x83e57357 +0x024 EFlags : 0 +0x028 Eax : 0 +0x02c Ecx : 0 +0x030 Edx : 0 +0x034 Ebx : 0 +0x038 Esp : 0x83f3d000 +0x03c Ebp : 0 +0x040 Esi : 0 +0x044 Edi : 0 +0x048 Es : 0x23 +0x04a Reserved2 : 0 +0x04c Cs : 8 +0x04e Reserved3 : 0 +0x050 Ss : 0x10 +0x052 Reserved4 : 0 +0x054 Ds : 0x23 +0x056 Reserved5 : 0 +0x058 Fs : 0x30 +0x05a Reserved6 : 0 +0x05c Gs : 0 +0x05e Reserved7 : 0 +0x060 LDT : 0 +0x062 Reserved8 : 0 +0x064 Flags : 0 +0x066 IoMapBase : 0x20ac +0x068 IoMaps : [1] _KiIoAccessMap +0x208c IntDirectionMap : [32] "???" // 代码和上节课一样 eq 80b99048 0000e940`50300100 // 48 eq 807d3120 0000e500`00480000 // int 32 1: kd> ed 807cd750+1c 3e876580 // 修复dg 28的cr3 80b99040
# 配置 101012
CR4 中有 PAE,导致分页为 29912,29912 的 CR3 最后两位为 20 的倍数
1. 添加新条目
2. 高级设置
配置后 dirbase 都应该是 000 结尾,以 1k 为单位
32 位下有两种分页模式 29912 101012 64 位有 999912
ntoskrnl 101012 对应页表内核
ntkrnlpa 29912d 对应页表内核
虚拟内存
32 位 一个进程有自己的 4GB 空间,因为指针宽度是 32 位,寻址是 2^32
4GB 是虚拟内存,和真实物理内存没有联系
0018e0b0
10 (PDE) 10 (PTE) 12(页内偏移) page director element page table element
0000 0000 0000 0001 1000 1110 0000 1011 0000(页内偏移) 注意前面的两位 00 是需要补上去的,这样 10+2=12
0 18e 0b0
CR3 页表查询起始地址
1 2 3 4 5 6 !dd // 查看物理地址 !dd 50601000(CR3) !dd 50601000 + 0*4 // 拿到第一项,把最后三位清零 56457867 -> 56457000 !dd 56457000 + 18e*4 // 58073867 -> 58073000 !dd 58073000 + 0b0 // 0b0 是页内偏移 物理地址
CR3 中每一个元素都是 PDE
PTT 中可能没有挂物理页,此时 PTE 中为 NULL
1024*1024*4 = 4M 只需要 4m 就能管理 4G
一个进程实际只有 2G , 高地址的 2G 是所有进程共享的
intel 和 amd 最小页是 4k
Windows 64k
0-0x10000 和 0x7fff000 - 0x7fffffff 不能访问。前一个是 NULL 区,后一个是隔离区
从 0x8000000 到 0xfffffff 没有保留区域
CPU 中是通过 MMU 寻址。MMU 是一个寻址模块
MMU 寻址时
1. 把线性地址 右移 12 位
2.TLB 没有找到,找页表结构缓存,如果没有找到,就自己转化
3. 有 PTE + 页内偏移拿到数据
4. 所有的缓存中找不到,把物理地址转化为真正的物理地址 (内存条 板卡地址)
L1 L2 叫做局部缓存,是 CPU 内部缓存,每一个核都有自己的 L1 L2
L3 所有 CPU 共享缓存
虚拟的逻辑 CPU 对用一个 L1 L2 缓存
data 数据缓存 inst 指令缓存
从 L2 中拿到缓存,会把 L2 这页的缓存替换到 L1 中
L3 拿到会写到 L2 和 L1
# 幽灵地址
101012 中所有的地址都可以被当做代码执行
申请内存的时候如果没有初始化,只有线性地址,没有物理地址,没有物理页,!dd 中为 0
共享内存:多个线性地址共用一个或多个物理页
多核场景下,同时写一块物理内存会有问题。可以加锁,还可以互斥体,信号量,时间可以,临界区不行,因为他不能跨进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int _tmain(int argc, _TCHAR* argv[]) { int *x = NULL; PVOID mem = VirtualAlloc(0,0x100,MEM_COMMIT,PAGE_EXECUTE_READWRITE); memset(mem,1,4); printf("%x\r\n",mem); system("pause"); printf("%x\r\n",*x); system("pause"); return 0; }
通过修改 PDE 实现挂物理页,!ed
跨进程挂物理页
把 A 进程的物理页拿出来,挂到的 B 的 0 地址上
通过远程线程跑起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include "stdafx.h" #include <Windows.h> int _tmain(int argc, _TCHAR* argv[]){ int *x = NULL ; PVOID mem = VirtualAlloc (0 ,0x100 ,MEM_COMMIT,PAGE_EXECUTE_READWRITE); printf ("%x\r\n " ,mem); char bufcode[]= { 0x6A ,0 , 0x6A ,0 , 0x6A ,0 , 0x6A ,0 , 0xb8 ,0 ,0 ,0 ,0 , 0xff ,0xd0 , 0xc2 ,4 ,0 }; char user32[]={'u' ,'s' ,'e' ,'r' ,'3' ,'2' ,'.' ,'d' ,'l' ,'l' ,0 }; char MessageBoxAA[]={"MessageBoxA" }; HMODULE hmodule = LoadLibraryA (user32); ULONG messageBox = (ULONG)GetProcAddress (hmodule,MessageBoxAA); *(PULONG)&bufcode[9 ] = messageBox; memcpy (mem,bufcode,sizeof (bufcode)); system ("pause" ); HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE,1292 ); HANDLE hThread = CreateRemoteThread (hProcess,NULL ,NULL ,0 ,NULL ,NULL ,NULL ); CloseHandle (hThread); system ("pause" ); printf ("%x\r\n" ,*x); system ("pause" ); system ("pause" ); return 0 ; }
1. 没有多余的额内存,直接申请 64k
2. 有多余的没存,在多余的内存,在多余的内存,按照 4k 对齐
# 页属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 char *x = "1111111"; // 可读,包含初始化的数据 通过characteristic 判断是否可写 标志(属性块) 常用特征值对照表: [值:00000020h] [IMAGE_SCN_CNT_CODE // Section contains code.(包含可执行代码)] [值:00000040h] [IMAGE_SCN_CNT_INITIALIZED_DATA // Section contains initialized data.(该块包含已初始化的数据)] [值:00000080h] [IMAGE_SCN_CNT_UNINITIALIZED_DATA // Section contains uninitialized data.(该块包含未初始化的数据)] [值:00000200h] [IMAGE_SCN_LNK_INFO // Section contains comments or some other type of information.] [值:00000800h] [IMAGE_SCN_LNK_REMOVE // Section contents will not become part of image.] [值:00001000h] [IMAGE_SCN_LNK_COMDAT // Section contents comdat.] [值:00004000h] [IMAGE_SCN_NO_DEFER_SPEC_EXC // Reset speculative exceptions handling bits in the TLB entries for this section.] [值:00008000h] [IMAGE_SCN_GPREL // Section content can be accessed relative to GP.] [值:00500000h] [IMAGE_SCN_ALIGN_16BYTES // Default alignment if no others are specified.] [值:01000000h] [IMAGE_SCN_LNK_NRELOC_OVFL // Section contains extended relocations.] [值:02000000h] [IMAGE_SCN_MEM_DISCARDABLE // Section can be discarded.] [值:04000000h] [IMAGE_SCN_MEM_NOT_CACHED // Section is not cachable.] [值:08000000h] [IMAGE_SCN_MEM_NOT_PAGED // Section is not pageable.] [值:10000000h] [IMAGE_SCN_MEM_SHARED // Section is shareable(该块为共享块).] [值:20000000h] [IMAGE_SCN_MEM_EXECUTE // Section is executable.(该块可执行)] [值:40000000h] [IMAGE_SCN_MEM_READ // Section is readable.(该块可读)] [值:80000000h] [IMAGE_SCN_MEM_WRITE // Section is writeable.(该块可写)] // x 在 rdata中,40000040 可读,包含已初始化数据,但是不可写 // 查询 sgdt 内存,6字节 sidt // 特权指令 1gdt lidt char sgdtbuf[6] = {0}; __asm{ sgdt sgdtbuf } ULONG gdtTable = *(PULONG)&sgdtbuf[2]; ULONG gdtlimit = *(PSHORT)&sgdtbuf[0]; printf("%x\r\n %x\r\n",gdtTable,gdtlimit) r gdtr r gdtl
P:当前页是否有效,即真实物理页
R/W: 0 当前页只读页 = PTE & PDE=1 时,可以修改
U/S: 页特权位,=0 只有 3 环能访问 User/Super
G:全局页,切换 CR3 不刷新,只有内核中有,不手动刷新会一直缓存
A 、 D 和段一样,access 被访问过 A=1,被写过 D=1
PS:PDE.PS=1, 此时没有 PTE 大页,此时是 10 22 ,10 是索引,22 是偏移,一个 PDE 有 4M
avail:操作系统用到
3 环要是写高地址需要 P=1 R/W=1 U/S=1 P=0
# 页基址
无法直接操作物理地址,只能通过线性地址
第一次进入保护模式 的时候 线性地址与物理地址有一对一的等价映射
高地址中页管理的空间不是共享的
每个进程在高地址中有 4M 空间不共享
system 在低地址中没有内存
内核中没有附加进程,属于 system 进程
挂物理页,且 P=1,那么有效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 .text:00489B98 mov eax, ecx .text:00489B9A shr eax, 14h 右移20位 .text:00489B9D and eax, 0FFCh .text:00489BA2 sub eax, 3FD00000h .text:00489BA7 mov eax, [eax] .text:00489BA9 test al, 1 .text:00489BAB jnz short loc_489BB0 ;判断PDE p位 .text:00489BAD .text:00489BAD loc_489BAD: ; CODE XREF: sub_489B98+32j .text:00489BAD xor al, al .text:00489BAF retn .text:00489BB0 ; --------------------------------------------------------------------------- .text:00489BB0 .text:00489BB0 loc_489BB0: ; CODE XREF: sub_489B98+13j .text:00489BB0 test al, al .text:00489BB2 jns short loc_489BB7; 判断是否是大页 .text:00489BB4 mov al, 1 .text:00489BB6 retn .text:00489BB7 ; --------------------------------------------------------------------------- .text:00489BB7 .text:00489BB7 loc_489BB7: ; CODE XREF: sub_489B98+1Aj .text:00489BB7 shr ecx, 0Ah .text:00489BBA and ecx, 3FFFFCh .text:00489BC0 sub ecx, 40000000h .text:00489BC6 mov eax, [ecx] .text:00489BC8 test al, 1 .text:00489BCA jz short loc_489BAD .text:00489BCC and al, 80h .text:00489BCE cmp al, 80h .text:00489BD0 setnz al .text:00489BD3 retn .text:00489BD3 sub_489B98 endp
PDE,P=1,PS=1,有效
PDE P=1,ps=0,PTE P=1 PAT=0 有效
C0300000 + PDI*4 = PDE
C0000000 + PDI * 0x1000 + PTI*4 = PTE
# 29912
ARM 分页 2048
PC 4096
1 2 3 4 5 6 7 8 9 10 0x80b99000 10 - 2 00 0000 101 5 1 1001 1001 199 !dq cr3 + 2 * 8 + 5 * 8 + 199 * 8
29912 虚拟地址还是 32 位,支持 36 根地址总线,所以物理地址是 36 位
PDPTE -> PDE -> PTE
2^2* 8 = 0x20
29912 中基址只有 PDE 和 PTE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 .text:00411717 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress) .text:00411717 public MmIsAddressValid .text:00411717 MmIsAddressValid proc near ; CODE XREF: sub_40471B+31p .text:00411717 ; sub_4C9A84+13p ... .text:00411717 .text:00411717 VirtualAddress = dword ptr 8 .text:00411717 .text:00411717 mov edi, edi .text:00411719 push ebp .text:0041171A mov ebp, esp .text:0041171C mov edx, [ebp+VirtualAddress] .text:0041171F call sub_4B4AA8 .text:00411724 pop ebp .text:00411725 retn 4 .text:00411725 MmIsAddressValid endp .text:004B4AA8 mov edi, edi .text:004B4AAA push ebp .text:004B4AAB mov ebp, esp .text:004B4AAD push ecx ;保存易变寄存器 .text:004B4AAE push ecx ; esi-sbp是非易变寄存器 .text:004B4AAF mov eax, edx ;edx是外部传来的线性地址 .text:004B4AB1 shr eax, 12h ;右移18位, .text:004B4AB4 and eax, 3FF8h .text:004B4AB9 sub eax, 3FA00000h ; PDE 基址 .text:004B4ABE mov ecx, [eax] ; 低4字节存 .text:004B4AC0 mov eax, [eax+4] .text:004B4AC3 mov [ebp+var_4], eax .text:004B4AC6 mov eax, ecx ;低位给eax .text:004B4AC8 and eax, 1 ;判断p位 .text:004B4ACB push 0 .text:004B4ACD mov [ebp+var_8], eax .text:004B4AD0 pop eax .text:004B4AD1 jz short loc_4B4AD7 ; 根据p位是否 =0 跳 , =0 跳 .text:004B4AD3 test eax, eax .text:004B4AD5 jz short loc_4B4ADB ;效果和jmp一样 .text:004B4AD7 .text:004B4AD7 loc_4B4AD7: ; CODE XREF: sub_4B4AA8+29j .text:004B4AD7 xor al, al ; 返回0 .text:004B4AD9 leave .text:004B4ADA retn .text:004B4ADB ; --------------------------------------------------------------------------- .text:004B4ADB .text:004B4ADB loc_4B4ADB: ; CODE XREF: sub_4B4AA8+2Dj .text:004B4ADB push esi ; 保存非易变寄存器 .text:004B4ADC mov esi, 80h ; 判断大页 ,80是大页 .text:004B4AE1 and ecx, esi .text:004B4AE3 push 0 .text:004B4AE5 mov [ebp+var_8], ecx .text:004B4AE8 pop eax .text:004B4AE9 jz short loc_4B4AEF =0 是小页 .text:004B4AEB test eax, eax .text:004B4AED jz short loc_4B4B2B ;如果是大页,返回1 .text:004B4AEF .text:004B4AEF loc_4B4AEF: ; CODE XREF: sub_4B4AA8+41j .text:004B4AEF shr edx, 9 .text:004B4AF2 and edx, 7FFFF8h .text:004B4AF8 mov ecx, [edx-3FFFFFFCh] ; 获取pte高位4字节,c0000000 是PTE基址,29912下c0600000是PDE基址 .text:004B4AFE sub edx, 40000000h (edx >> 9) & 0x7fff8 ,ecx=*(edx+c00000004) .text:004B4B04 mov eax, [edx] eax = *(edx+c0000000) .text:004B4B06 mov [ebp+var_4], ecx .text:004B4B09 mov ecx, eax .text:004B4B0B and ecx, 1 PTE.P .text:004B4B0E push 0 .text:004B4B10 mov [ebp+var_8], ecx .text:004B4B13 pop ecx .text:004B4B14 jz short loc_4B4B27 .text:004B4B16 test ecx, ecx .text:004B4B18 jnz short loc_4B4B27 pte.pat .text:004B4B1A and eax, esi .text:004B4B1C push ecx .text:004B4B1D mov [ebp+var_8], eax .text:004B4B20 pop eax .text:004B4B21 jz short loc_4B4B2B .text:004B4B23 test eax, eax .text:004B4B25 jnz short loc_4B4B2B .text:004B4B27 .text:004B4B27 loc_4B4B27: ; CODE XREF: sub_4B4AA8+6Cj .text:004B4B27 ; sub_4B4AA8+70j .text:004B4B27 xor al, al .text:004B4B29 jmp short loc_4B4B2D .text:004B4B2B ; --------------------------------------------------------------------------- .text:004B4B2B .text:004B4B2B loc_4B4B2B: ; CODE XREF: sub_4B4AA8+45j .text:004B4B2B ; sub_4B4AA8+79j ... .text:004B4B2B mov al, 1 .text:004B4B2D .text:004B4B2D loc_4B4B2D: ; CODE XREF: sub_4B4AA8+81j .text:004B4B2D pop esi .text:004B4B2E leave .text:004B4B2F retn 80b99000 右移18位 == 202e 202e & 3ff8 == 2028 2028- 3fa00000 = c0602028
内核编译器和 ring3 编译器不一样
XD = 0 当前页可以执行
// PDE 与 PTE 最高位进行与, = 0 可执行 (小页看 PTE 高位,大页看 PDE 高位)
1 2 00000000`62cc1867 // PDE 80000000`636ec867 // PTE
如果 XD 描述 PDE,那么代表这个 PDE 管理了所有的 PTE
PDPTE 没有属性,只有 PCD 和 PWT
4 个 PDPTE * 512 = 2048 PDE
2048*512*8 = 8M
# 缓存
缓存类型
UC 没有缓存,直接从板卡地址拿数据。强制无缓存
UC- 有读缓存,无写缓存。弱无缓存
WC 写组合 \ 写合并,尝试从 L1 缓存行拿地址, 一次写 4 个地址,小于等于 4 都是按照组合写在同一时刻。每次刷新一个缓存行 (64 字节)
WB 回写,到时间才刷到内存中去。延时性低。只需要写到缓存,定时一次性刷新
WT 直写 直接写到缓存中,并且写到内存条中 。通常是做多媒体。全部写完才会返回
主存不是完全的内存,是显卡 + 设备内存
WP 写保护,只读
系统的 dll 是写拷贝。当无法写入的时候产生异常,拷贝一份
DLL 代码段一般是运行 只读 R/W=0 ,VAD 虚拟地址管理器,描述当前线性地址属性。线性地址和物理地址属性不一样
write copy 写时拷贝:多个 exe 加载一个路径下同一个名字的 dll,或者任意的 PE 文件的时候,此 dll 的物理地址只有一份
2.exe 如果强行去写 dll,不触发页异常的情况下 (修改 r/w=1),会导致所有引用这个 dll 的 exe 全部被修改
通过 VirtualProtected 修改之后,此时的 dll 已经不是一个物理页了,会挂新的物理页,再把 dll 复制过来
PAT
PWT = 0 回写 = 1 直写
# TLB
每个核有四个 TLB,两个数据 TLB- DTLB,两个指令 TLB-ITLB
小的 TLB 存 PTE,大的 TLB 存 PDE
PDE 大页一般都是 G=1,基本上在内核模块中 G=1 全局页
!pte gdtr // 当前进程下
!vtop cr3 gdtr
1. 申请 2 个地址分别赋值
2. 把第一个地址挂在 0 地址上,然后访问,取出结果保存变量
3. 又把第二个地址挂在 o 地址上,然后访问,取出结果也保存变量
4. 观察变量 1, 变量 2 的结果有什么不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 #include "stdafx.h" #include <Windows.h> PUCHAR addr1 = NULL ; PUCHAR addr2 = NULL ; ULONG temp1=0 ,temp2 = 0 ; void __declspec(naked) test1 (){ __asm { pushad; pushfd; push 0x30 ; pop fs; mov eax,[addr1]; shr eax,0x9 ; and eax,0x7ffff8 ; add eax,0xc0000000 ; mov ecx,[eax]; mov edx,[eax+4 ]; mov dword ptr ds:[0xc0000000 ],ecx; mov dword ptr ds:[0xc0000004 ],edx; mov eax,dword ptr ds:[0 ]; mov [temp1],eax; mov eax,[addr2]; shr eax,0x9 ; and eax,0x7ffff8 ; add eax,0xc0000000 ; mov ecx,[eax]; mov edx,[eax+4 ]; mov dword ptr ds:[0xc0000000 ],ecx; mov dword ptr ds:[0xc0000004 ],edx; mov eax,dword ptr ds:[0 ]; mov [temp2],eax; push 0x3b ; pop fs; popfd; popad; retf; } } int _tmain(int argc, _TCHAR* argv[]){ addr1 = (PUCHAR)VirtualAlloc (NULL ,0x1000 ,MEM_COMMIT,PAGE_EXECUTE_READWRITE); addr2 = (PUCHAR)VirtualAlloc (NULL ,0x1000 ,MEM_COMMIT,PAGE_EXECUTE_READWRITE); *(PULONG)addr1 = 0x1000 ; *(PULONG)addr2 = 0x2000 ; temp1 = 0 ; temp2 = 0 ; printf ("addr1 = %x,addr2 = %x,test1=%x\r\n" ,addr1,addr2,test1); system ("pause" ); char bufcode[]={0 ,0 ,0 ,0 ,0x4b ,0 }; __asm { call fword ptr bufcode; } system ("pause" ); printf ("temp1 = %x,temp2 = %x\r\n" ,temp1,temp2); system ("pause" ); return 0 ; }
切换 CR3 的时候回认为切换页表,导致 TLB 刷新,TLB 中 G=0 的全部刷掉
mov eax,cr3
mov cr3,eax
invlpg dowrd ptr ds:[]
刷新方式: 切页表刷新 (刷新除 G=1 的情况) / invlpg 把地址变成无效缓存 (刷新一条) / CR4 控制寄存器中有一个 PGE,控制所有的 G 位是否有效 (刷新所有)
切换线程的时候,判断当前被切换与切换是否是一个进程,如果不是会切换页表 CR3
本质上切换进程就是切换 CR3
# 控制寄存器
x86 有五个,x64 还有一个 CR8
CR2 保存了出异常的线性地址。针对于缺页和内存有问题的异常
CR0 PE:开启保护模式,但是没有分页保护,只有段保护
实模式通过写入字,打开 A20 端口,设置 CR0 进入保护模式
PG:开启分页模式 PG+PE = 段页保护模式
PE = 0,PG=1 无效 PE=0,PG=0 实模式 PE=1 PG = 0 段保护
Windows 无法使用实模式,除非是裸机,但是有虚拟 8086 模式,叫做虚拟实模式
TS:切换任务段,call 进去 =1 ,任务段切换标识
CD = 1 关闭缓存
AM 对齐位。对应 eflag 中 ac 的对齐检查。=1 32 位下堆栈必须 4 字节对齐,64 8 字节对齐
WP = 0 关闭写保护,不可写地址也可以写入。是 0 环写 3 环
CR4 辅助功能
VEM 开启虚拟中断,允许开启虚拟 8086 模式
PVI 是否支持虚拟 8086 虚拟化中断,=1 允许
TSD 只有特权级可以执行, = 1 3 环可以调用指令计算时间
DE =1 调试寄存器 DR4 和 DR5 可使用。DR6,DR7 的别名
PSE 大页开关 =0 强制小页
PAE =1 29912, =0 10102 ,只在 32 位下有用,64 下面只有 999912
MCE 机器检查
PGE =1 代表 G=1 =0 G=1 无效即没有全局页
PCE 性能监控器是否开启
VMXE VT 开启位 , =1 进入 VT
SMXE SMM 上帝模式 super mode manage
SMEP SMAP super mode execute protect super mode access protect =1 0 环不能执行 / 访问 US=1 的地址 。AM=0 这两个位无效
PKE 页表密钥 =1 保护 key 保护用户地址
IA-32e 兼容 cpu 支持 32 和 64,允许 64 位下运行 32 位程序
IA-64 纯 64 位 cpu
# 驱动
加载驱动类似于用户区加载 dll,驱动是所有进程共享的。驱动本质是模块
驱动有 NT 驱动,WDM,WDF (KWDF,UWDF
NT 虚拟驱动,如果出现绑定设备,不能卸载,只能重启
WDM 驱动,是一个热插拔方式,不需要重启
WDF 简化开发的,封装了一部分驱动,相当于事件驱动机制 。KWDF 内核驱动框架 UWDF 用户驱动框架,基于 com 开发
com 是 Windows 的一套组件,定义了一系列接口。对于 C#,js 等语言效果明显
# hello world
1 2 3 4 5 6 7 创建 empty wdm 文件 #include <ntifs.h> NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { return STATUS_SUCCESS; }
sys 入口是 GsDriverEntry
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 INIT:00405000 ; int __stdcall GsDriverEntry(_DRIVER_OBJECT *DriverObject, _UNICODE_STRING *RegistryPath) INIT:00405000 public _GsDriverEntry@8 INIT:00405000 _GsDriverEntry@8 proc near ; DATA XREF: .rdata:00402004↑o INIT:00405000 INIT:00405000 DriverObject = dword ptr 8 INIT:00405000 RegistryPath = dword ptr 0Ch INIT:00405000 INIT:00405000 mov edi, edi INIT:00405002 push ebp INIT:00405003 mov ebp, esp INIT:00405005 call ___security_init_cookie INIT:0040500A pop ebp INIT:0040500B jmp _DriverEntry@8 ; DriverEntry(x,x) INIT:0040500B _GsDriverEntry@8 endp INIT:0040500B
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 0: kd> dt pDriver Local var @ 0x8c72c9e0 Type _DRIVER_OBJECT* 0x865c9f08 +0x000 Type : 0n4 +0x002 Size : 0n168 +0x004 DeviceObject : (null) +0x008 Flags : 2 +0x00c DriverStart : 0x96dcb000 Void +0x010 DriverSize : 0x6000 +0x014 DriverSection : 0x864ef0d8 Void +0x018 DriverExtension : 0x865c9fb0 _DRIVER_EXTENSION +0x01c DriverName : _UNICODE_STRING "\Driver\3" +0x024 HardwareDatabase : 0x84177250 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM" +0x028 FastIoDispatch : (null) +0x02c DriverInit : 0x96dcf000 long 3!GsDriverEntry+0 +0x030 DriverStartIo : (null) +0x034 DriverUnload : (null) +0x038 MajorFunction : [28] 0x83ec0da3 long nt!IopInvalidDeviceRequest+0 0: kd> dt _DRIVER_EXTENSION 0x865c9fb0 nt!_DRIVER_EXTENSION +0x000 DriverObject : 0x865c9f08 _DRIVER_OBJECT +0x004 AddDevice : (null) +0x008 Count : 0 +0x00c ServiceKeyName : _UNICODE_STRING "3" +0x014 ClientDriverExtension : (null) +0x018 FsFilterCallbacks : (null)
start 2 开启自启 3 手工启动 4 禁用
ImagePath ?? 是内核路径
type 驱动 = 1
加载驱动
1. 服务加载。调用 Windows 所提供的服务,并不是本进程加载。通过 csrss 写注册表
opensrcmanage
CreateService
StartService
StopService
DeleteService
2. 本地加载
调用 zw/ntloadDriver
卸载调用 Zw/NtUnloadDriver
杀软链接模块加载时候,方式一拦截不到进程,只能通过其他方式获取进程是谁
方式二直接拦截,知道是谁加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; #ifdef MIDL_PASS [size_is(MaximumLength / 2 ), length_is((Length) / 2 ) ] USHORT * Buffer; #else _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer; #endif } UNICODE_STRING; net start 3 net stop 3 #include <ntifs.h> void DRIVERUNLOAD (PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgBreakPoint(); pDriver->DriverUnload = DRIVERUNLOAD; DbgPrint("===================%wZ=========\r\n" ,pReg); return STATUS_SUCCESS; }
# 类型
1 2 3 4 5 6 7 8 INT - int UCHAR - unsigned char typedef _Return_type_success_(return >= 0) LONG NTSTATUS; NTSTATUS status = xxx; if (NT_SUCCESS(status)) {}
# 字符串函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 __kernel_entry NTSYSCALLAPI NTSTATUS NTAPI NtOpenProcess ( _Out_ PHANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PCLIENT_ID ClientId ) ; UNICODE_STRING unName = {0 }; RtlInitUnicodeString(&unName, L"www" ); OBJECT_ATTRIBUTES obj = {0 }; obj.ObjectName = &unName; HANDLE hProcess = NULL ; NtOpenProcess(&hProcess,PROCESS_ALL_ACCESS,&obj,NULL );
1 2 3 4 UNICODE_STRING unName = {0}; PWCH x = L"xxxx"; RtlInitUnicodeString(&unName, x); DbgPrintEx(77,0,"%x %x",x,unName.Buffer);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 char* xxx = "1111"; UNICODE_STRING unName = { 0 }; STRING str = { 0 }; RtlInitString(&str, xxx); NTSTATUS status = RtlAnsiStringToUnicodeString(&unName, &str, TRUE); DbgPrintEx(77, 0, "%x", status); if (NT_SUCCESS(status)) { DbgPrintEx(77, 0, "%x %x", str.Buffer, unName.Buffer); RtlFreeUnicodeString(&unName); }
1 2 3 4 5 6 7 8 #include <ntstrsafe.h> char bb[1000] = { 0 }; RtlStringCbPrintfA(bb, 1000, "%d %s", 10, "ssss"); DbgPrintEx(77, 0, "%s", bb); RtlStringCbPrintfW
1 2 3 4 5 RtiInitString 初始化多字节ascii RtlInitUnicodeString 初始化宽字符 RtlFreeUnicodeString释放uncode学符串 RtlStringCbPrintfA格式化输出――记得引用#include <ntstrsafe.h> RtlCompareUnicodeString(a, b, TRUE); 字符串比较
1 2 3 4 5 6 7 8 # 申请内存 ExAllocatePool() ExAllocatePool(NonPagedPool, size); // 可执行 ExAllocatePoolWithTag(NonPagedPool, size,'111'); !pte Address ExFreePool(mem);
# 创建线程
1 2 3 4 5 6 7 8 9 10 void work(PVOID StartContext) { } HANDLE hThread = NULL; NTSTATUS status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, work, NULL); if (NT_SUCCESS(status)) { ZwClose(hThread); }
# 驱动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 0: kd> dt _LIST_ENTRY ntdll!_LIST_ENTRY +0x000 Flink : Ptr32 _LIST_ENTRY +0x004 Blink : Ptr32 _LIST_ENTRY 0: kd> dt _SINGLE_LIST_ENTRY ntdll!_SINGLE_LIST_ENTRY +0x000 Next : Ptr32 _SINGLE_LIST_ENTRY InitializeListHead(); // 链表定义在局部变量的时候需要初始化,防止垃圾数据,全局变量默认初始化都是0 IsListEmpty(); InsertHeadList(); InsertTailList(); RemoveHeadList(); RemoveTailList(); RemoveEntryList(); CONTAINING_RECORD(); #include <ntifs.h> RTL_GENERIC_TABLE gTABLE = { 0 }; typedef struct _AAA { int id; int y; int x; }AAA, * PAAA; void DRIVERUNLOAD(PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n"); } RTL_GENERIC_COMPARE_RESULTS NTAPI GenericCmp( _In_ struct _RTL_GENERIC_TABLE* Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct ) { PAAA a1 = (PAAA)FirstStruct; PAAA a2 = (PAAA)SecondStruct; if (a1->id == a2->id) { return GenericEqual; } if (a1->id > a2->id) return GenericGreaterThan; return GenericLessThan; } PVOID NTAPI GenericAllocate( _In_ struct _RTL_GENERIC_TABLE* Table, _In_ CLONG ByteSize ) { return ExAllocatePool(NonPagedPool, ByteSize); } VOID NTAPI GenericFree( _In_ struct _RTL_GENERIC_TABLE* Table, _In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer ) { ExFreePool(Buffer); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { AAA aaa = { 0 }; //DbgBreakPoint(); //InitializeListHead(); // 链表定义在局部变量的时候需要初始化,防止垃圾数据,全局变量默认初始化都是0 //IsListEmpty(); //InsertHeadList(); //InsertTailList(); //RemoveHeadList(); //RemoveTailList(); //RemoveEntryList(); //CONTAINING_RECORD(); aaa.id = 1; aaa.x = 2; aaa.y = 3; AAA node = { 3,2,1 }; BOOLEAN newE = FALSE; RtlInitializeGenericTable(&gTABLE, GenericCmp, GenericAllocate, GenericFree, NULL); //RtlInitializeGenericTableAvl(); 二叉搜索树 RtlInsertElementGenericTable(&gTABLE, &aaa, sizeof(AAA), &newE); // 用栈插入的数据会申请内存,把栈上的变成堆上的,保证数据不会被释放 AAA * xxx = RtlLookupElementGenericTable(&gTABLE, &aaa); int num = RtlNumberGenericTableElements(&gTABLE); RtlDeleteElementGenericTable(&gTABLE, &node); RtlIsGenericTableEmpty(&gTABLE); AAA* RestartKey = NULL; AAA* xx = 0; if (!RtlIsGenericTableEmpty(&gTABLE)) { //遍历 for (xx = RtlEnumerateGenericTableWithoutSplaying(&gTABLE, &RestartKey); xx != NULL; xx = RtlEnumerateGenericTableWithoutSplaying(&gTABLE, &RestartKey)) { DbgPrintEx(77, 0, "%x\r\n", xx->id); } } pDriver->DriverUnload = DRIVERUNLOAD; return STATUS_SUCCESS; }
# 驱动断链
pc hunter 会遍历 driver 和 filesystem 组成内核模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 0: kd> dt _DRIVER_OBJECT nt!_DRIVER_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x004 DeviceObject : Ptr32 _DEVICE_OBJECT +0x008 Flags : Uint4B +0x00c DriverStart : Ptr32 Void +0x010 DriverSize : Uint4B +0x014 DriverSection : Ptr32 Void +0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION +0x01c DriverName : _UNICODE_STRING +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING +0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH +0x02c DriverInit : Ptr32 long +0x030 DriverStartIo : Ptr32 void +0x034 DriverUnload : Ptr32 void +0x038 MajorFunction : [28] Ptr32 long
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 #include <ntifs.h> typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY exp ; ULONG un; ULONG NonPagedDebugInfo; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG __Undefined6; ULONG CheckSum; ULONG TimeDateStamp; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; void DRIVERUNLOAD (PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgBreakPoint(); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink; while (next != pre) { DbgPrintEx(77 , 0 , "%wZ\r\n" , &next->FullDllName); next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink; } pDriver->DriverUnload = DRIVERUNLOAD; return STATUS_SUCCESS; } 0 : kd> dt ldrLocal var @ 0x8cb309cc Type _KLDR_DATA_TABLE_ENTRY* 0x887d8e50 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x83f53850 - 0x880ac730 ] +0x008 exp : _LIST_ENTRY [ 0xffffffff - 0xffffffff ] +0x010 un : 0x887d8e68 +0x014 NonPagedDebugInfo : 0 +0x018 DllBase : 0x9609a000 +0x01c EntryPoint : 0x9609e000 +0x020 SizeOfImage : 0x6000 +0x024 FullDllName : _UNICODE_STRING "\??\C:\Users\shinya\Desktop\MyDriver2.sys" +0x02c BaseDllName : _UNICODE_STRING "MyDriver2.sys" +0x034 Flags : 0x49104000 +0x038 LoadCount : 1 +0x03a __Undefined5 : 0x86f8 +0x03c __Undefined6 : 0 +0x040 CheckSum : 0x1d5e +0x044 TimeDateStamp : 0x2010002 0 : kd> dt pDriverLocal var @ 0x8cb309e0 Type _DRIVER_OBJECT* 0x887dcae8 +0x000 Type : 0 n4 +0x002 Size : 0 n168 +0x004 DeviceObject : (null) +0x008 Flags : 2 +0x00c DriverStart : 0x9609a000 Void +0x010 DriverSize : 0x6000 +0x014 DriverSection : 0x887d8e50 Void +0x018 DriverExtension : 0x887dcb90 _DRIVER_EXTENSION +0x01c DriverName : _UNICODE_STRING "\Driver\MyDriver2" +0x024 HardwareDatabase : 0x84175250 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM" +0x028 FastIoDispatch : (null) +0x02c DriverInit : 0x9609e000 long MyDriver2!GsDriverEntry+0 +0x030 DriverStartIo : (null) +0x034 DriverUnload : (null) +0x038 MajorFunction : [28 ] 0x83ebeda3 long nt!IopInvalidDeviceRequest+0 0 : kd> dt PKLDR_DATA_TABLE_ENTRY 0x83f53850 MyDriver2!PKLDR_DATA_TABLE_ENTRY 0x86541c98 +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x86541c20 - 0x83f53850 ] +0x008 exp : _LIST_ENTRY [ 0x83e81544 - 0x12 ] +0x010 un : 0 +0x014 NonPagedDebugInfo : 0 +0x018 DllBase : 0x83e09000 +0x01c EntryPoint : 0x83f284d8 +0x020 SizeOfImage : 0x412000 +0x024 FullDllName : _UNICODE_STRING "\SystemRoot\system32\ntkrnlpa.exe" +0x02c BaseDllName : _UNICODE_STRING "ntoskrnl.exe" +0x034 Flags : 0x8004000 +0x038 LoadCount : 0x6c +0x03a __Undefined5 : 0 +0x03c __Undefined6 : 0 +0x040 CheckSum : 0x3c88ac +0x044 TimeDateStamp : 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY exp ; ULONG un; ULONG NonPagedDebugInfo; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG __Undefined6; ULONG CheckSum; ULONG TimeDateStamp; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; extern POBJECT_TYPE* IoDriverObjectType;void DRIVERUNLOAD (PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgBreakPoint(); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink; UNICODE_STRING driverName = { 0 }; RtlInitUnicodeString(&driverName, L"http.sys" ); while (next != pre) { if (next->BaseDllName.Length != 0 && RtlCompareUnicodeString(&driverName, &next->BaseDllName, TRUE)==0 ) { DbgPrintEx(77 , 0 , "%wZ\r\n" , &next->FullDllName); RemoveEntryList(&next->InLoadOrderLinks); break ; } next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink; } pDriver->DriverUnload = DRIVERUNLOAD; return STATUS_SUCCESS; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY exp ; ULONG un; ULONG NonPagedDebugInfo; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG __Undefined6; ULONG CheckSum; ULONG TimeDateStamp; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; NTKERNELAPI NTSTATUS ObReferenceObjectByName ( __in PUNICODE_STRING ObjectName, __in ULONG Attributes, __in_opt PACCESS_STATE AccessState, __in_opt ACCESS_MASK DesiredAccess, __in POBJECT_TYPE ObjectType, __in KPROCESSOR_MODE AccessMode, __inout_opt PVOID ParseContext, __out PVOID* Object ) ;extern POBJECT_TYPE* IoDriverObjectType;void DRIVERUNLOAD (PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgBreakPoint(); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; PKLDR_DATA_TABLE_ENTRY pre = (PKLDR_DATA_TABLE_ENTRY)ldr->InLoadOrderLinks.Flink; PKLDR_DATA_TABLE_ENTRY next = (PKLDR_DATA_TABLE_ENTRY)pre->InLoadOrderLinks.Flink; UNICODE_STRING driverName1 = { 0 }; RtlInitUnicodeString(&driverName1, L"\\driver\\http" ); UNICODE_STRING driverName = { 0 }; RtlInitUnicodeString(&driverName, L"http.sys" ); while (next != pre) { if (next->BaseDllName.Length != 0 && RtlCompareUnicodeString(&driverName, &next->BaseDllName, TRUE)==0 ) { PDRIVER_OBJECT httpDriver = NULL ; NTSTATUS status = ObReferenceObjectByName(&driverName1, FILE_ALL_ACCESS, 0 , 0 , *IoDriverObjectType, KernelMode, NULL , &httpDriver); if (NT_SUCCESS(status)) { RemoveEntryList(&next->InLoadOrderLinks); httpDriver->DriverInit = NULL ; httpDriver->DriverSection = NULL ; httpDriver->Type = 0 ; } DbgPrintEx(77 , 0 , "%wZ\r\n" , &next->FullDllName); break ; } next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink; } pDriver->DriverUnload = DRIVERUNLOAD; return STATUS_SUCCESS; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 # 隐藏当前驱动 # 调用完入口点在隐藏 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY exp ; ULONG un; ULONG NonPagedDebugInfo; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG __Undefined6; ULONG CheckSum; ULONG TimeDateStamp; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; NTKERNELAPI NTSTATUS ObReferenceObjectByName ( __in PUNICODE_STRING ObjectName, __in ULONG Attributes, __in_opt PACCESS_STATE AccessState, __in_opt ACCESS_MASK DesiredAccess, __in POBJECT_TYPE ObjectType, __in KPROCESSOR_MODE AccessMode, __inout_opt PVOID ParseContext, __out PVOID* Object ) ;extern POBJECT_TYPE* IoDriverObjectType;void DriverHide (PWCH ObjName) { LARGE_INTEGER in = { 0 }; in.QuadPart = -10000 * 5000 ; KeDelayExecutionThread(KernelMode, FALSE, in.QuadPart); UNICODE_STRING driverName1 = { 0 }; RtlInitUnicodeString(&ObjName, L"\\driver\\http" ); PDRIVER_OBJECT httpDriver = NULL ; NTSTATUS status = ObReferenceObjectByName(&driverName1, FILE_ALL_ACCESS, 0 , 0 , *IoDriverObjectType, KernelMode, NULL , &httpDriver); PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)httpDriver->DriverSection; if (NT_SUCCESS(status)) { httpDriver->DriverSection = ldr->InLoadOrderLinks.Flink; RemoveEntryList(&ldr->InLoadOrderLinks); DbgPrintEx(77 , 0 , "%wZ\r\n" , &ldr->FullDllName); httpDriver->DriverInit = NULL ; ObDereferenceObject(httpDriver); } return ; } void DRIVERUNLOAD (PDRIVER_OBJECT DriverObject) { DbgPrint("unload\r\n" ); } NTSTATUS DriverEntry (PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgBreakPoint(); HANDLE hThread = NULL ; NTSTATUS status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL , NULL , NULL , DriverHide, L"\\driver\\http" ); if (NT_SUCCESS(status)) { NtClose(hThread); } pDriver->DriverUnload = DRIVERUNLOAD; return STATUS_SUCCESS; }
dll 驱动必须通过主驱动调用加载
# 蓝屏分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 analyze -v kv // 查看堆栈调用 For analysis of this file, run !analyze -v nt!RtlpBreakWithStatusInstruction: 83e85110 cc int 3 0: kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e) This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Arguments: Arg1: c0000005, The exception code that was not handled Arg2: 952fe02f, The address that the exception occurred at Arg3: 8cb3490c, Exception Record Address Arg4: 8cb34370, Context Record Address Debugging Details: ------------------ Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. KEY_VALUES_STRING: 1 Key : AV.Dereference Value: NullPtr Key : AV.Fault Value: Write Key : Analysis.CPU.Sec Value: 0 Key : Analysis.DebugAnalysisProvider.CPP Value: Create: 8007007e on DESKTOP-BEKKQKM Key : Analysis.DebugData Value: CreateObject Key : Analysis.DebugModel Value: CreateObject Key : Analysis.Elapsed.Sec Value: 17 Key : Analysis.Memory.CommitPeak.Mb Value: 77 Key : Analysis.System Value: CreateObject BUGCHECK_CODE: 7e BUGCHECK_P1: ffffffffc0000005 BUGCHECK_P2: ffffffff952fe02f BUGCHECK_P3: ffffffff8cb3490c BUGCHECK_P4: ffffffff8cb34370 EXCEPTION_RECORD: 8cb3490c -- (.exr 0xffffffff8cb3490c) ExceptionAddress: 952fe02f (MyDriver3!DriverEntry+0x0000000f) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000001 Parameter[1]: 00000000 Attempt to write to address 00000000 CONTEXT: 8cb34370 -- (.cxr 0xffffffff8cb34370) eax=00000000 ebx=00000000 ecx=bb40e64e edx=00000651 esi=868ac9a8 edi=866c2000 eip=952fe02f esp=8cb349d4 ebp=8cb349d8 iopl=0 nv up ei pl nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010206 MyDriver3!DriverEntry+0xf: 952fe02f c70050000000 mov dword ptr [eax],50h ds:0023:00000000=???????? Resetting default scope PROCESS_NAME: System WRITE_ADDRESS: 00000000 ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p 0x%p %s EXCEPTION_CODE_STR: c0000005 EXCEPTION_PARAMETER1: 00000001 EXCEPTION_PARAMETER2: 00000000 EXCEPTION_STR: 0xc0000005 STACK_TEXT: 8cb349d8 83fce2e6 868ac9a8 866c2000 00000000 MyDriver3!DriverEntry+0xf [C:\Users\Administrator\source\repos\MyDriver3\MyDriver3\main.c @ 16] 8cb34bbc 83fd1d98 00000001 00000000 8cb34be4 nt!IopLoadDriver+0x7ed 8cb34c00 83e87aab 961f6bd0 00000000 86601020 nt!IopLoadUnloadDriver+0x70 8cb34c50 84013f5e 00000001 c9778f12 00000000 nt!ExpWorkerThread+0x10d 8cb34c90 83ebb219 83e8799e 00000001 00000000 nt!PspSystemThreadStartup+0x9e 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19 FAULTING_SOURCE_LINE: C:\Users\Administrator\source\repos\MyDriver3\MyDriver3\main.c FAULTING_SOURCE_FILE: C:\Users\Administrator\source\repos\MyDriver3\MyDriver3\main.c FAULTING_SOURCE_LINE_NUMBER: 16 FAULTING_SOURCE_CODE: 12: { 13: DbgBreakPoint(); 14: 15: int* x = 0; > 16: *x = 80; 17: 18: pDriver->DriverUnload = DRIVERUNLOAD; 19: return STATUS_SUCCESS; 20: } SYMBOL_NAME: MyDriver3!DriverEntry+f IMAGE_NAME: MyDriver3.sys MODULE_NAME: MyDriver3 STACK_COMMAND: .cxr 0xffffffff8cb34370 ; kb FAILURE_BUCKET_ID: 0x7E_MyDriver3!DriverEntry+f OS_VERSION: 7.1.7601.17514 BUILDLAB_STR: win7sp1_rtm OSPLATFORM_TYPE: x86 OSNAME: Windows 7 FAILURE_ID_HASH: {82a16a6f-d5b4-0708-1c67-c393a5a8a872} Followup: MachineOwner --------- 0: kd> kv # ChildEBP RetAddr Args to Child 00 83f32b10 83e8510b 00000001 83e850dd 00000002 nt!RtlpBreakWithStatusInstruction (FPO: [1,0,0]) 01 83f32b18 83e850dd 00000002 00000000 fffffffd nt!KdCheckForDebugBreak+0x22 (FPO: [0,0,0]) 02 83f32b48 83e84f6b 83e81e1a bc788c41 00000000 nt!KeUpdateRunTime+0x164 03 83f32ba0 83e89c17 01da2802 01da2802 000000d1 nt!KeUpdateSystemTime+0x613 04 83f32ba0 83e81e1a 01da2802 01da2802 000000d1 nt!KeUpdateSystemTimeAssist+0x13 (FPO: [0,2] TrapFrame @ 83f32bb4) 05 83f32c24 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x1a (FPO: [0,0,0]) dump 文件在 配置路径下
将 memory 拖到 windbg 分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 0: kd> dds esp 8cb34218 0000007e 8cb3421c c0000005 8cb34220 952fe02f MyDriver3+0x102f 8cb34224 8cb3490c 8cb34228 8cb34370 8cb3422c 00000000 8cb34230 8cb34c90 8cb34234 84013f9e nt!RtlAnsiStringToUnicodeString+0x1dd 8cb34238 0000007e 8cb3423c c0000005 8cb34240 952fe02f MyDriver3+0x102f 8cb34244 8cb3490c 8cb34248 8cb34370 8cb3424c 83e84494 nt!alloca_probe+0x130 8cb34250 00000000 8cb34254 8cb34c90 8cb34258 83e60d48 nt!NtBuildGUID+0xbcc4 8cb3425c 8cb34284 8cb34260 83ec9d5a nt!PsGetCurrentProcessSessionId+0x1a8 8cb34264 00000000 8cb34268 00000000 8cb3426c 00000000 8cb34270 8cb3490c 8cb34274 8cb34370 8cb34278 83e60d58 nt!NtBuildGUID+0xbcd4 8cb3427c 00000001 8cb34280 00e0a000 8cb34284 8cb342a8 8cb34288 83e82622 nt!KeReleaseInStackQueuedSpinLockFromDpcLevel+0x1e6 8cb3428c fffffffe 8cb34290 8cb34c80 8cb34294 8cb34370 BUGCHECK_CODE: 7e Bug Check 0x7E: SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Arguments: Arg1: c0000005, The exception code that was not handled Arg2: 952fe02f, The address that the exception occurred at Arg3: 8cb3490c, Exception Record Address Arg4: 8cb34370, Context Record Address // 代码蓝屏位置 MyDriver3+0x102f: 952fe02f c70050000000 mov dword ptr [eax],50h ds:0023:00000000=???????? 0: kd> .trap TrapFrame ESP EDITED! New esp=00000001 ErrCode = fffffffe eax=00000001 ebx=badb0d00 ecx=83e4b3d8 edx=8cb34960 esi=952fe02f edi=8cb349d8 eip=83ead744 esp=8cb34980 ebp=00000651 iopl=0 nv up di pl nz na po nc cs=0000 ss=0010 ds=0000 es=0095 fs=8d8a gs=0000 efl=00000000 nt!RtlInitEnumerationHashTable+0xb17: 83ead744 c23400 ret 34h
内核线程栈 12k
# 驱动通信
一个 DRIVER_OBJECT 可以管理多个设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 0: kd> dt _DRIVER_OBJECT nt!_DRIVER_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x004 DeviceObject : Ptr32 _DEVICE_OBJECT +0x008 Flags : Uint4B +0x00c DriverStart : Ptr32 Void +0x010 DriverSize : Uint4B +0x014 DriverSection : Ptr32 Void +0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION +0x01c DriverName : _UNICODE_STRING +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING +0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH +0x02c DriverInit : Ptr32 long +0x030 DriverStartIo : Ptr32 void +0x034 DriverUnload : Ptr32 void +0x038 MajorFunction : [28] Ptr32 long 0: kd> dt _DEVICE_OBJECT nt!_DEVICE_OBJECT +0x000 Type : Int2B +0x002 Size : Uint2B +0x004 ReferenceCount : Int4B +0x008 DriverObject : Ptr32 _DRIVER_OBJECT +0x00c NextDevice : Ptr32 _DEVICE_OBJECT +0x010 AttachedDevice : Ptr32 _DEVICE_OBJECT +0x014 CurrentIrp : Ptr32 _IRP +0x018 Timer : Ptr32 _IO_TIMER +0x01c Flags : Uint4B +0x020 Characteristics : Uint4B +0x024 Vpb : Ptr32 _VPB +0x028 DeviceExtension : Ptr32 Void +0x02c DeviceType : Uint4B +0x030 StackSize : Char +0x034 Queue : <unnamed-tag> +0x05c AlignmentRequirement : Uint4B +0x060 DeviceQueue : _KDEVICE_QUEUE +0x074 Dpc : _KDPC +0x094 ActiveThreadCount : Uint4B +0x098 SecurityDescriptor : Ptr32 Void +0x09c DeviceLock : _KEVENT +0x0ac SectorSize : Uint2B +0x0ae Spare1 : Uint2B +0x0b0 DeviceObjectExtension : Ptr32 _DEVOBJ_EXTENSION +0x0b4 Reserved : Ptr32 Void PDO 物理设备 FDO filter device io 附加设备:FDO 附加到 PDO 三环首先访问到FDO,经过多个FDO,访问到PDO 。PDO返回逐FDO返回 0: kd> dt _IRP nt!_IRP +0x000 Type : Int2B +0x002 Size : Uint2B +0x004 MdlAddress : Ptr32 _MDL +0x008 Flags : Uint4B +0x00c AssociatedIrp : <unnamed-tag> +0x010 ThreadListEntry : _LIST_ENTRY +0x018 IoStatus : _IO_STATUS_BLOCK +0x020 RequestorMode : Char +0x021 PendingReturned : UChar +0x022 StackCount : Char // 设备栈层数 +0x023 CurrentLocation : Char // 设备栈索引 +0x024 Cancel : UChar +0x025 CancelIrql : UChar +0x026 ApcEnvironment : Char +0x027 AllocationFlags : UChar +0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK +0x02c UserEvent : Ptr32 _KEVENT +0x030 Overlay : <unnamed-tag> +0x038 CancelRoutine : Ptr32 void +0x03c UserBuffer : Ptr32 Void +0x040 Tail : <unnamed-tag>