更新中

# 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
操作成功完成。

image-20230930200944405

重启需要使用系统重启,不能使用 vm 的重启

image-20230930201418886

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

image-20230930202041547

开启配置了 debug 引导的虚拟机,并且开启 windbg

image-20230930202225347

lm

image-20230930202654966

.reload 根据需要加载符号

ld * 加载全部符号

安装 wdm 后,创建 wdm driver

image-20231001204151853

关闭 spectre

image-20231001205417683

关闭警告

image-20231001205358986

image-20231001205508311

image-20231001205756116

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

image-20231001220009107

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):附加段寄存器;

保护模式:

image-20231002212824591

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{ // x86中插入内联汇编
mov ax,cs
mov ds,ax
mov eax,100
mov dword ptr ds:[value],eax // CS 没有写的属性
mov ax,es // DS 和 ES 段选择子此处相同,可以用ES还原被修改为CS的DS
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

image-20231003204330216

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`

image-20231003204845003

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

image-20231003205741643

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

# G

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 有

image-20231004203140286

# 裸函数

64 位没有裸函数

1
2
3
4
5
6
7
void __declspec(naked) test2()
{
int x; // 有些编译器不能这么写,因为没提升堆栈
__asm{
ret
}
}

裸函数没有对堆栈做操作,如果在裸函数中没有保存现场用堆栈会出问题

image-20231006202157199

image-20231006202220240

image-20231006202344305

DPL 段描述权限

RPL:request privilege level 看当前指令的段描述符 比如 mov dword ptr ds:[],0x12345678 ,DS 描述的这条,此时 RPL 为 DS 的 RPL

CPL:current privilege level 当前权限 值为 CS SS 的 RPL。两个 RPL 必须一致

image-20231006202616101

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 中分成任务段和调用门

image-20231006214637792

image-20231006214841959

函数的逻辑地址: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
返回地址
CS
参数1
参数2
ESP
SS
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 只能在同等权限下,或者高权限往低权限跳

image-20231009222709758

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 0040ee00`00081000

void __declspec(naked) test1()
{
__asm{
int 3
//retf
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=80b99000
0: kd> dq 80b99000
80b99000 00000000`00000000 00cf9b00`0000ffff
80b99010 00cf9300`0000ffff 00cffb00`0000ffff
80b99020 00cff300`0000ffff 80008b1e`400020ab
80b99030 834093f6`ec003748 0040f300`00000fff
80b99040 0000f200`0400ffff 00000000`00000000
80b99050 830089f6`c0000068 830089f6`c0680068
80b99060 00000000`00000000 00000000`00000000
80b99070 800092b9`900003ff 00000000`00000000


1: kd> r idtr
idtr=807d3020
1: kd> dq 807d3020
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



401000 - 83e945c0(int 3) = base(7C56 CA40)
eq 80b99048 7ccf9b56`ca40ffff // 修改gdtr中的 48

eq 80b99418 83e9ee00`004845c0 // 修改idtr中int3 的段选择子


0: kd> g
Break instruction exception - code 80000003 (first chance)
001b:004010d4 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 // int 3
jmp eax
// 00401000 - 83e465c0= base(7C5B AA40)
}
}

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

// 运行的时候不能直接在调试器里运行,直接运行exe

image-20231014235313749

# 陷阱门

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

0040ee00`00081000
eq 80b99500 0040ee00`00081000


// xianjingmen.cpp : 定义控制台应用程序的入口点。
//

#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;
}// eflag = 46

中断门清空 VM TF IF NT ELF=0x46

陷阱门清空 VM TF NT ELF=0x246

VM 虚拟 8086 TF 调试位 IF 可屏蔽中断 NT 嵌套任务

image-20231014002754457

# 任务段

image-20231014195203261

image-20231014195304362

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 tr
tr=00000028

0: kd> r gdtr
gdtr=80b99000

0: kd> dq 80b99000
ReadVirtual: 80b99000 not properly sign extended
80b99000 00000000`00000000 00cf9b00`0000ffff
80b99010 00cf9300`0000ffff 00cffb00`0000ffff
80b99020 00cff300`0000ffff 80008b1e`400020ab
80b99030 834093f6`ec003748 0040f300`00000fff
80b99040 0000f200`0400ffff 00000000`00000000
80b99050 830089f6`c0000068 830089f6`c0680068
80b99060 00000000`00000000 00000000`00000000
80b99070 800092b9`900003ff 00000000`00000000

0: kd> dt nt!_*TSS*
ntkrpamp!_KTSS

0: kd> dt _KTSS
nt!_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 801ca000 000020ab TSS32 Busy 0 Nb By P Nl 0000008b

0: kd> dt _KTSS 801ca000
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 esp
esp=80de6ae4


cr3
393b6000
403378

eq 80b95048 0000e940`50300100


0: kd> r tr
tr=00000048

0: kd> dg 28
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0028 801ca000 000020ab TSS32 Busy 0 Nb By P Nl 0000008b

0: kd> dt _KTSS 801ca000
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 000000eb
0: 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 任务嵌套


// 手工修复CR3
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 807cd750 000020ab TSS32 Busy 0 Nb By P Nl 0000008b
1: kd> dt _KTSS 807cd750
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 807cd750+1c 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
// renwuduan.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

struct _KiIoAccessMap
{
UCHAR DirectionMap[32]; //0x0
UCHAR IoMap[8196]; //0x20
};

typedef struct _KTSS
{
USHORT Backlink; //0x0
USHORT Reserved0; //0x2
ULONG Esp0; //0x4
USHORT Ss0; //0x8
USHORT Reserved1; //0xa
ULONG NotUsed1[4]; //0xc
ULONG CR3; //0x1c
ULONG Eip; //0x20
ULONG EFlags; //0x24
ULONG Eax; //0x28
ULONG Ecx; //0x2c
ULONG Edx; //0x30
ULONG Ebx; //0x34
ULONG Esp; //0x38
ULONG Ebp; //0x3c
ULONG Esi; //0x40
ULONG Edi; //0x44
USHORT Es; //0x48
USHORT Reserved2; //0x4a
USHORT Cs; //0x4c
USHORT Reserved3; //0x4e
USHORT Ss; //0x50
USHORT Reserved4; //0x52
USHORT Ds; //0x54
USHORT Reserved5; //0x56
USHORT Fs; //0x58
USHORT Reserved6; //0x5a
USHORT Gs; //0x5c
USHORT Reserved7; //0x5e
USHORT LDT; //0x60
USHORT Reserved8; //0x62
USHORT Flags; //0x64
USHORT IoMapBase; //0x66
struct _KiIoAccessMap IoMaps[1]; //0x68
UCHAR IntDirectionMap[32]; //0x208c
}KTSS,*PKTSS;;

KTSS tss = {0};

char bufesp0[0x2000] = {0};
char bufesp3[0x2000] = {0};

void __declspec(naked) test()
{
__asm{

int 3
pushfd // repair eflag
pop eax
or eax,0x4000
push eax
popfd
iretd
}
}
int _tmain(int argc, _TCHAR* argv[])
{
short trxx = 0;
__asm{
str trxx // get segment descriptor = 0x28
ltr trxx // edit tr ,ring 3 no privilege
}


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 都是任务门

img

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. 添加新条目

image-20231015211644175

2. 高级设置

image-20231015211718524

image-20231015211727770

配置后 dirbase 都应该是 000 结尾,以 1k 为单位

image-20231015211843834

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

image-20231018174920595

PTT 中可能没有挂物理页,此时 PTE 中为 NULL

1024*1024*4 = 4M 只需要 4m 就能管理 4G

一个进程实际只有 2G , 高地址的 2G 是所有进程共享的

image-20231018180122932

intel 和 amd 最小页是 4k

Windows 64k

0-0x10000 和 0x7fff000 - 0x7fffffff 不能访问。前一个是 NULL 区,后一个是隔离区

从 0x8000000 到 0xfffffff 没有保留区域

CPU 中是通过 MMU 寻址。MMU 是一个寻址模块

MMU 寻址时

1. 把线性地址 右移 12 位

2.TLB 没有找到,找页表结构缓存,如果没有找到,就自己转化

3. 有 PTE + 页内偏移拿到数据

4. 所有的缓存中找不到,把物理地址转化为真正的物理地址 (内存条 板卡地址)

image-20231016234849139

L1 L2 叫做局部缓存,是 CPU 内部缓存,每一个核都有自己的 L1 L2

L3 所有 CPU 共享缓存

虚拟的逻辑 CPU 对用一个 L1 L2 缓存

data 数据缓存 inst 指令缓存

从 L2 中拿到缓存,会把 L2 这页的缓存替换到 L1 中

L3 拿到会写到 L2 和 L1

# 幽灵地址

101012 中所有的地址都可以被当做代码执行

申请内存的时候如果没有初始化,只有线性地址,没有物理地址,没有物理页,!dd 中为 0

共享内存:多个线性地址共用一个或多个物理页

image-20231020172843070

多核场景下,同时写一块物理内存会有问题。可以加锁,还可以互斥体,信号量,时间可以,临界区不行,因为他不能跨进程

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);
//memset(mem,1,4);

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");




//int error = GetLastError();
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

image-20231020233208888

image-20231020231326046

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

image-20231021194659993

# 页基址

无法直接操作物理地址,只能通过线性地址

第一次进入保护模式 的时候 线性地址与物理地址有一对一的等价映射

高地址中页管理的空间不是共享的

每个进程在高地址中有 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

image-20231210191417372

# 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

image-20231105211300962

image-20231108000856947

image-20231108180550851

image-20231108180847403

# 缓存

缓存类型

image-20231108220412054

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 复制过来

image-20231109193507076

PAT

PWT = 0 回写 = 1 直写

image-20231109193730790

# TLB

每个核有四个 TLB,两个数据 TLB- DTLB,两个指令 TLB-ITLB

小的 TLB 存 PTE,大的 TLB 存 PDE

PDE 大页一般都是 G=1,基本上在内核模块中 G=1 全局页

!pte gdtr // 当前进程下

!vtop cr3 gdtr

image-20231109233501934

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
// 12.TLB.cpp : 定义控制台应用程序的入口点。
//

#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];//线形地址1
shr eax,0x9;
and eax,0x7ffff8;
add eax,0xc0000000;
mov ecx,[eax]; //取低4字节
mov edx,[eax+4]; //取高4字节
// or ecx,0x100; // 设置G,G=1无法通过CR3导致刷新
mov dword ptr ds:[0xc0000000],ecx;
mov dword ptr ds:[0xc0000004],edx;
mov eax,dword ptr ds:[0];
mov [temp1],eax;

//mov eax,cr3;
//mov cr3,eax;

mov eax,[addr2];//线形地址2
shr eax,0x9;
and eax,0x7ffff8;
add eax,0xc0000000;
mov ecx,[eax]; //取低4字节
mov edx,[eax+4]; //取高4字节

// 挂物理页
mov dword ptr ds:[0xc0000000],ecx;
mov dword ptr ds:[0xc0000004],edx;

//刷单条TLB
//invlpg dword ptr ds:[0]

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

image-20231111195301493

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

image-20231118144931361

image-20231118145032673

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

image-20231118150152408

image-20231118151446842

image-20231118152630283

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)

image-20231118153307784

start 2 开启自启 3 手工启动 4 禁用

image-20231118153559163

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 // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;

// 命令行启动 3.sys
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); // printf wz打印Unicode字符串指针 ===================\REGISTRY\MACHINE\SYSTEM\ControlSet001\services\9=========
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
//@[comment("MVI_tracked")]
__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;
// InitializeObjectAttributes

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 ldr
Local 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 pDriver
Local var @ 0x8cb309e0 Type _DRIVER_OBJECT*
0x887dcae8
+0x000 Type : 0n4
+0x002 Size : 0n168
+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

image-20231202145017088

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"\\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(&driverName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, *httpDriver);


//if (NT_SUCCESS(status))
//{
DbgPrintEx(77, 0, "%wZ\r\n", &next->FullDllName);
RemoveEntryList(&next->InLoadOrderLinks);
//httpDriver->DriverInit = NULL;
//httpDriver->DriverSection = NULL;
break;
//}

//break;
}

next = (PKLDR_DATA_TABLE_ENTRY)next->InLoadOrderLinks.Flink;
}

pDriver->DriverUnload = DRIVERUNLOAD;
return STATUS_SUCCESS;
}

image-20231203225145824

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;

//httpDriver->Type = 0;
ObDereferenceObject(httpDriver);
}
return;
}

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;
}
*/
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 文件在 配置路径下

image-20231206223053930

image-20231206223751789

image-20231206224032245

将 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

image-20231209161413434

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>

Edited on

Give me a cup of [coffee]~( ̄▽ ̄)~*

John Doe WeChat Pay

WeChat Pay

John Doe Alipay

Alipay

John Doe PayPal

PayPal