上篇文章分析得到:
1.3环进0环的两种方式,分别是中断门和快速调用,CPU支持快速调用,那么_KUSER_SHARED_DATA 结构体的 SystemCall 属性指向的函数是 KiFastSystemCall,执行 KiFastSystemCall,使用快速调用的方式进0环;如果不支持,那么SystemCall 指向的函数是KiIntSystemCall,执行 KiIntSystemCall,使用中断门的方式进0环。
2.快速调用不需要访问内存,而中断门需要读TSS和IDT表
3.int 0x2e 和 sysenter 指令进0环后,分别调用了两个函数 KiSystemService 和 KiFastCallEntry。
4.原来的寄存器存储到了_KTRAP_FRAME 结构体里,3环API参数指针通过EDX传给0环。
上篇文章分析结果,两个函数最后执行同一段代码,如图
图中标记的是407781函数,之后是执行的相同代码部分,7781函数在_KiFastCallEntry函数内部。图片太大没法截图全部。
这两个函数虽然入口不同,但是填充完 _KTRAP_FRAME 后,就会执行相同的代码。
eax中存储的系统服务号 0BAh
edx存储的三环的参数指针
_KTHREAD+0xE0= +0x0e0 ServiceTable : Ptr32 Void
有两张系统服务表,第一张是用来找内核函数的,第二张是找Win32k.sys驱动函数的
结构:0x10大小
全称:System Services Descriptor Table(系统服务描述符表)
SSDT的每个成员叫做系统服务表
查看SSDT表
第二张表为0,使用KeServiceDescriptorTable这个公开的导出函数,我们无法看到win32k.sys这张表结构
win32k.sys系统服务表已经可见
系统服务号:低12位就是函数参数表和函数地址表的下标,而第13位(下标12)如果是0,表示找第一张系统服务表Ntoskrl.exe,如果是1,那么找第二张表win32k.sys.后12位是函数地址表和函数参数表的索引。
查看函数地址:
[函数地址表 + 系统服务号*4] = 内核函数地址 805aa712
查看参数地址
[参数表 + 系统服务号] = 内核函数参数个数(单位:字节)14
查看内核函数反汇编:
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PULONG ServiceTableBase;
/
/
指针,指向函数地址,每个成员占
4
字节
PULONG ServiceCounterTableBase;
/
/
当前系统服务表被调用的次数
ULONG NumberOfService;
/
/
服务函数的总数
PUCHAR ParamTableBase;
/
/
服务函数的参数总长度,以字节为单位,每个成员占一个字节
/
/
如:服务函数有两个参数,每个参数占四字节,那么对应参数总长度为
8
/
/
函数地址成员 与 参数总长度成员 一一对应
} SSDTEntry,
*
PSSDTEntry;
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PULONG ServiceTableBase;
/
/
指针,指向函数地址,每个成员占
4
字节
PULONG ServiceCounterTableBase;
/
/
当前系统服务表被调用的次数
ULONG NumberOfService;
/
/
服务函数的总数
PUCHAR ParamTableBase;
/
/
服务函数的参数总长度,以字节为单位,每个成员占一个字节
/
/
如:服务函数有两个参数,每个参数占四字节,那么对应参数总长度为
8
/
/
函数地址成员 与 参数总长度成员 一一对应
} SSDTEntry,
*
PSSDTEntry;
kd> dd nt!KeServiceDescriptorTable
kd> dd nt!KeServiceDescriptorTable
.text:
00407781
.text:
00407781
loc_407781: ; CODE XREF: _KiBBTUnexpectedRange
+
18
↑j
.text:
00407781
; _KiSystemService
+
6E
↑j
.text:
00407781
mov edi, eax ;eax中是系统服务号
.text:
00407783
shr edi,
8
;edi右移
8
位
.text:
00407786
and
edi,
30h
;判断系统服务号
12
位,
0
:edi
=
=
0x00
;
1
:edi
=
=
0x10
.text:
00407789
mov ecx, edi
.text:
0040778B
add edi, [esi
+
0E0h
]; [esi
+
0E0h
]:_KTHREAD
+
0xE0
=
ServiceTable,edi指向系统服务表,这里将系统服务表所在地址直接加上edi的运算结果,巧妙地得到要查哪张表(两张表是连续的),每张表占
16
字节
.text:
00407791
mov ebx, eax
.text:
00407793
and
eax,
0FFFh
;与运算后,只保留系统服务号低
12
位
.text:
00407798
cmp
eax, [edi
+
8
] ;edi指向系统服务表,[edi
+
8
]:NumberOfService,判断要找的函数是否超出范围
.text:
0040779B
jnb _KiBBTUnexpectedRange ;若大于系统调用号的个数则跳转,即系统调用号越界
.text:
004077A1
cmp
ecx,
10h
;ecx 保存的是 edi 与
0x30
与运算后的结果,只能是
0x00
或
0x10
.text:
004077A4
jnz short loc_4077C0 ;若系统调用号小于
0x1000
,则跳转
.text:
004077A6
mov ecx, ds:
0FFDFF018h
;只有当ecx
=
=
0x10
才会向下执行,作用是动态加载GUI等图形相关函数
.text:
004077AC
xor ebx, ebx
.text:
004077AE
.text:
004077AE
loc_4077AE: ; DATA XREF: _KiTrap0E
+
110
↓o
.text:
004077AE
or
ebx, [ecx
+
0F70h
]
.text:
004077B4
jz short loc_4077C0
.text:
004077B6
push edx
.text:
004077B7
push eax
.text:
004077B8
call ds:_KeGdiFlushUserBatch
.text:
004077BE
pop eax
.text:
004077BF
pop edx
.text:
004077C0
.text:
004077C0
loc_4077C0: ; CODE XREF: _KiFastCallEntry
+
B4↑j
.text:
004077C0
; _KiFastCallEntry
+
C4↑j
.text:
004077C0
inc dword ptr ds:
0FFDFF638h
;
.text:
004077C6
mov esi, edx ;edx:三环参数指针
.text:
004077C8
mov ebx, [edi
+
0Ch
] ; [edi
+
0Ch
]:ParamTableBase(参数表指针)
.text:
004077CB
xor ecx, ecx ;eax保存的是
3
环传入的系统调用号
.text:
004077CD
mov cl, [eax
+
ebx] ;eax保存的是
3
环传入的系统调用号,ebx保存的是是参数表指针,这条指令的目的是得到内核函数的参数总长度,存入cl
.text:
004077D0
mov edi, [edi] ;取出系统调用表的第一个成员(函数地址指针)
.text:
004077D2
mov ebx, [edi
+
eax
*
4
] ;函数地址指针
+
系统调用号
*
4
(乘
4
是因为每个成员占
4
字节),ebx中存入函数地址
.text:
004077D5
sub esp, ecx ;提升堆栈,提升高度为cl,目的是要把三环堆栈中的参数存进来
.text:
004077D7
shr ecx,
2
;参数总长度
/
4
=
参数个数
.text:
004077DA
mov edi, esp ;设置参数的
0
环堆栈地址
.text:
004077DC
cmp
esi, ds:_MmUserProbeAddress ;判断esi与用户程序能访问的最大地址范围,是否越界
.text:
004077E2
jnb loc_407990 ;如果越界了 进行跳转,处理异常
.text:
004077E8
.text:
004077E8
loc_4077E8: ; CODE XREF: _KiFastCallEntry
+
2A4
↓j
.text:
004077E8
; DATA XREF: _KiTrap0E
+
106
↓o
.text:
004077E8
rep movsd ;复制参数(执行几次取决于参数个数<
-
004077D7
结果 )到
0
环的堆栈
.text:
004077EA
call ebx ;调用内核函数NtReadVirtualMemory
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-9-29 20:51
被pyikaaaa编辑
,原因: 改个标题