系统调用、进程、线程

系统调用

我只能说,windows真是等级森严啊

假如说我们要调用ControlDeviceIo这个API,那么会经过kernel32.dll->kernelbase.dll->ntdll.dll->ntoskrnl.exe->xxx->hal.dll

差不多就是层层审批,所以这也解释了为什么说有的函数出自kernel32.dll但是用ida看的时候却发现,里面的实现仅有一个call指令,原来是在向下蔓延

kernel32.dll.OpenProcess—>kernelBase.dll.OpenProcess–>ntdll.dll.ZwOpenProcess–>0x7ffe0300–>sysenter–>内核

SSDT和ShadowSSDT表

ntdll.dll和user32.dll gdt32.dll访问内核时,用到的函数表

里面存储了四个元素 函数表 服务调用次数统计 函数个数 参数表

SSDT表中基本存储无通信的内核函数,另一个存的就是有通信的了(不全是

这涉及到一个东西,服务号,比如pwn中最常见的system就是0x2b,这就是服务号,参数表查询和函数表查询都是通过服务号偏移拿到的(举例仅供参考,这个是linux系统的服务号)

自己定义

1
2
3
4
5
6
7
8
9
typedef struct __SSDTItem
{
PULONG funcTable;
ULONG count;
ULONG funcMax;
PUCHAR paremTable;
}SSDTItem,*PSSDTItem

EXTERN_C PSSDTItem KeServiceDescriptorTable;

syscall

嗯,这节课相当于分析了,sysentry实现细节,总结来说就是三个步骤

1.保存环境,搞新环境

2.复制参数

3.CALL

不过细细下来分析还是很复杂的,后面如果用到再说吧

这个里面分析好像就能跟着学很多比如

IRQL

代码等级,0 1 2,代码等级2号要大于1号大于0号,运行起来优先级也会高,比如说键盘和语雀,我输入一个'a',语雀会立马出现,是因为键盘的等级高,它可以让语雀中断先执行键盘,然后回去执行语雀,大致是这个意思

syscall返回部分

返回部分还有有一个R3esp设置回去,这里作用主要在R0调用R0然后返回R3要返回栈环境的

SSDT_HOOK

Cr0 MDL

Cr0这个词我都差点忘了

是系统内的控制寄存器之一。控制寄存器是一些特殊的寄存器,它们可以控制CPU的一些重要特性。

0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。

1 位是监控协处理位MP(Moniter coprocessor),它与第3位一起决定:当TS=1时操作码WAIT是否产生一个“协处理器不能使用”的出错信号。第3位是任务转换位(Task Switch),当一个任务转换完成之后,自动将它置1。随着TS=1,就不能使用协处理器。

CR0的第2位是模拟协处理器位 EM (Emulate coprocessor),如果EM=1,则不能使用协处理器,如果EM=0,则允许使用协处理器。

第4位是微处理器的扩展类型位 ET(Processor Extension Type),其内保存着处理器扩展类型的信息,如果ET=0,则标识系统使用的是287协处理器,如果 ET=1,则表示系统使用的是387浮点协处理器。

CR0的第31位是分页允许位(Paging Enable),它表示芯片上的分页部件是否允许工作。

CR0的第16位是写保护未即WP位(486系列之后),只要将这一位置0就可以禁用写保护,置1则可将其恢复。

在网上找了一个文章补了一下

简单来讲就是决定当前代码是否可写

但是在内核中没有Virtualprotect这样的函数,所以要用MDL,也是用来改保护的

源码

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>
#include<ntimage.h>
#include <ntddk.h>

typedef struct __SSDTItem
{
PULONG funcTable;
ULONG count;
ULONG funcMax;
PUCHAR paremTable;
}SSDTItem, * PSSDTItem;

typedef struct __SSDTservice
{
SSDTItem ssdt;
SSDTItem sssdt;
}SSDTservice,* PSSDTservice;

NTSTATUS NTAPI MyOpenProcess(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
)
{
DbgPrintEx(77, 0, "helloworld\t\n");
return NtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}

EXTERN_C PSSDTservice KeServiceDescriptorTable;

PVOID MDLmAPvIRTUAL(PVOID VirtualAddress, ULONG_PTR len, MODE mode, PMDL *Retpmdl)
{
PMDL pmdl = IoAllocateMdl(VirtualAddress, len, NULL, NULL, NULL);
BOOLEAN isLock = FALSE;
PULONG map = NULL;
__try
{
MmProbeAndLockPages(pmdl, mode, IoReadAccess); //锁页
isLock = TRUE;
map = MmMapLockedPagesSpecifyCache(pmdl, mode, MmNonCached, NULL, FALSE, NormalPagePriority);
}
__except (1)
{
map = NULL;
if (isLock)
{
MmUnlockPages(pmdl);
}
if (pmdl)
{
IoFreeMdl(pmdl);
}
return NULL;

}
if (!map)
{
return NULL;
}
*Retpmdl = pmdl;
return map;
}

PVOID MDUnLmAPvIRTUAL(PVOID mapAddress, PMDL pmdl)
{
MmUnmapLockedPages(mapAddress, pmdl);

MmUnlockPages(pmdl);

IoFreeMdl(pmdl);
}

VOID KernelSleep(ULONG ms, BOOLEAN isAlert)
{
LARGE_INTEGER inTime = { 0 };
inTime.QuadPart = -10000;
inTime.QuadPart *= ms;
KeDelayExecutionThread(KernelMode, isAlert, &inTime);
}

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
PUCHAR tempFuncTable = KeServiceDescriptorTable->ssdt.funcTable;
PMDL pmdl;
PULONG map = MDLmAPvIRTUAL(tempFuncTable, PAGE_SIZE, KernelMode, &pmdl);
if (map)
{
map[0xBE] = (ULONG)NtOpenProcess;
}
MDUnLmAPvIRTUAL(map, pmdl);
KernelSleep(300, FALSE);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPeg) {
PUCHAR tempFuncTable = KeServiceDescriptorTable->ssdt.funcTable;
PMDL pmdl;
PULONG map = MDLmAPvIRTUAL(tempFuncTable, PAGE_SIZE, KernelMode, &pmdl);
if (map)
{
map[0xBE] = (ULONG)MyOpenProcess;
}
MDUnLmAPvIRTUAL(map, pmdl);

pDriver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}

改进

`MmProbeAndLockPages`这个创建页的函数效率很低,可以用其他API代替如: `MmBuildForNonPagePool`

区别在于锁页

API

`IoAllocateMdl` 创建一个页描述符

MmProbeAndLockPages 锁页(挂页并且上梭)

MmMapLockedPagesSpecifyCache 访问页(解锁访问)

进程

结构

进程刚开始创建仅仅是有一个空间,和对进程的描述结构,实际上就是申请了一片地用于进程

相关windbg

`EPROCESS` 进程结构体(PEB?) 指令 `dt _EPROCESS Addrxxx`

KPROCESS EPROCESS的第一个成员 指令 dt _KPROCESS AAddrxxx

内核小知识

linux使用的是宏内核,线程调度,内存,进程管理,文件管理是一体的,紧密联系。模块无法抽出

win用的是微内核,线程调度,内存,进程管理,对象的管理,是可以抽出来的

K_系列封装 微内核层

E_封装 执行体层

样本分析

EPROCESS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
+0x000 Pcb              : _KPROCESS																		KPROCESS																		
+0x098 ProcessLock : _EX_PUSH_LOCK 锁-字段成员
+0x0a0 CreateTime : _LARGE_INTEGER 0x01dbb81f`fc377b28 开始时间
+0x0a8 ExitTime : _LARGE_INTEGER 0x0 结束时间
+0x0b0 RundownProtect : _EX_RUNDOWN_REF 锁-标志位
+0x0b4 UniqueProcessId : 0x00000c68 Void
+0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x83f4dd70 - 0x87698bb0 ]
+0x0c0 ProcessQuotaUsage : [2] 0xd5c
+0x0c8 ProcessQuotaPeak : [2] 0xdd4
+0x0d0 CommitCharge : 0x100
+0x0d4 QuotaBlock : 0x8733e940 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : (null)
+0x0dc PeakVirtualSize : 0x4480000
+0x0e0 VirtualSize : 0x447e000
+0x0e4 SessionProcessLinks : _LIST_ENTRY [ 0x8d44e010 - 0x87698bdc ]
+0x0ec DebugPort : (null)
+0x0f0 ExceptionPortData : 0x8719df00 Void
+0x0f0 ExceptionPortValue : 0x8719df00
+0x0f0 ExceptionPortState : 0y000
+0x0f4 ObjectTable : 0xb02d9828 _HANDLE_TABLE

KRPOCESS
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
+0x000 Header           : _DISPATCHER_HEADER							
+0x010 ProfileListHead : _LIST_ENTRY [ 0x85770580 - 0x85770580 ]
+0x018 DirectoryTableBase : 0x3ea6f680 //cr3
+0x01c LdtDescriptor : _KGDTENTRY
+0x024 Int21Descriptor : _KIDTENTRY
+0x02c ThreadListHead : _LIST_ENTRY [ 0x85720b10 - 0x85720b10 ] //线程链表
+0x034 ProcessLock : 0 //修改成员同步锁
+0x038 Affinity : _KAFFINITY_EX //亲核性 在哪个CPU核跑
+0x044 ReadyListHead : _LIST_ENTRY [ 0x857705b4 - 0x857705b4 ] //进程下的就绪线程链表
+0x04c SwapListEntry : _SINGLE_LIST_ENTRY //磁盘交换链表
+0x050 ActiveProcessors : _KAFFINITY_EX //当前进程下活动的核
+0x05c AutoAlignment : 0y0 //自动对齐
+0x05c DisableBoost : 0y0 //和线程优先级有关
+0x05c DisableQuantum : 0y0 //是否关闭进程下线程时间碎片机制
+0x05c ActiveGroupsMask : 0y1
+0x05c ReservedFlags : 0y0000000000000000000000000000 (0)
+0x05c ProcessFlags : 0n8
+0x060 BasePriority : 8 '' //线程继承进程的基本优先级
+0x061 QuantumReset : 18 '' //线程的时间碎片基础值
+0x062 Visited : 0 ''
+0x063 Unused3 : 0 ''
+0x064 ThreadSeed : [1] 0
+0x068 IdealNode : [1] 0
+0x06a IdealGlobalNode : 0
+0x06c Flags : _KEXECUTE_OPTIONS //关闭SEH机制
+0x06d AddressPolicy : 0 ''
+0x06e IopmOffset : 0x20ac
+0x070 Unused4 : 0
+0x074 StackCount : _KSTACK_COUNT
+0x078 ProcessListEntry : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x080 CycleTime : 0
+0x088 KernelTime : 0
+0x08c UserTime : 0
+0x090 VdmTrapcHandler : (null)