TA的每日心情 | 开心 2023-10-11 21:31 |
|---|
签到天数: 104 天 [LV.6]常住居民II
|
今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IT定时器,内核定时器其就是在内核中现的时钟,该定时器的枚举非常简单,因为在IIT初始化部分就可以找到ITQH地址,该变量内存储的就是定时器的链表头部。枚举IO定时器的案例并不多见,即便有也是法使用过时的,此教程学到肯定就是赚到了。 游戏数据分析的相关资讯可以到我们网站了解一下,从专业角度出发为您解答相关问题,给您优质的服务!
枚举I定时器过程是这样的:
1找到IIT函数,该函数可以通过MGSRA得到。
2找到地址以后,我们向下增加0FF偏移量,并搜索特征定位到ITQH链表头。
3将链表头转换为IO_TIMER结构体,并循环链表头输出。
这里解释一下为什么要找IIT这个函数他是一个初始化函数,既然是初始化里面一定会涉及到链表的存储问题,找到他就能找到定时器链表基址,该函数的定义如下。
1
2
3
4
5
6
NTSTATUS
IIT(
INPDEVICE_OBJECTDO,
设备对象指针
INPIO_TIMER_ROUTINETR,
定时器例程
INPVOIDC
传给定时器例程的函数
);
接着我们需要得到IO定时器的结构定义,在DEVICE_OBJECT设备对象指针中存在一个T属性。
1
2
3
4
5
6
7
8
9
:_DEVICE_OBJECT
!_DEVICE_OBJECT
+
0000
T
:I2B
+
00
S:U2B
+
00
RC:I4B
+
00
DO:P64_DRIVER_OBJECT
+
00
ND:P64_DEVICE_OBJECT
+
AD:P64_DEVICE_OBJECT
+
00
CI:P64_IRP
+
T:P64_IO_TIMER
+
00
F:U4B
+
C:U4B
+
V:P64_VPB
+
00
DE:P64V
+
DT:U4B
+
0
SS:C
+
00
Q:
-
+
08
AR:U4B
+
000
DQ:_KDEVICE_QUEUE
+
0
D:_KDPC
+
ATC:U4B
+
SD:P64V
+
DL:_KEVENT
+
SS:U2B
+
32
S1:U2B
+
38
DOE:P64_DEVOBJ_EXTENSION
+
40
R:P64V
这里的这个+T定时器是一个结构体_IO_TIMER其就是IO定时器的所需结构体。
1
2
3
4
5
6
7
8
:_IO_TIMER
!_IO_TIMER
+
0000
T
:I2B
+
00
TF:I2B
+
00
TL:_LIST_ENTRY
+
TR:P64
+
00
C:P64V
+
DO:P64_DEVICE_OBJECT
如上方的基础知识有了也就够了,接着就是际开发部分,首先我们需要编写一个GIITA()函数,让该函数可以定位到IIT所在内核中的基地址上面,具体现调用代码如下所示。
1
2
3
4
5
6
7
8
9
32
33
34
#
得到IIT基址
B:LS内核开发系列教程
PVOIDGIITA()
{
PVOIDVA
=
0
;
UNICODE_STRINGT
=
{
0
};
RIUS(T,L
"IIT"
);
VA
=
(PVOID)MGSRA(T);
(VA!
=
0
)
{
VA;
}
0
;
}
VOIDUD(PDRIVER_OBJECT)
{
DP((
"UDIOK\"
));
}
NTSTATUSDE(INPDRIVER_OBJECTD,PUNICODE_STRINGRP)
{
DP((
"\"
));
得到基址
PUCHARIIT
=
GIITA();
DP(
"IITA=%\"
,IIT);
D
-
DU
=
UD;
STATUS_SUCCESS;
}
运行这个驱动程序,然后对比下是否一致:
接着我们在反汇编代码中寻找ITQH,此处在LS系统内这个偏移位置是!IIT+具体输出位置如下。
1
2
3
4
5
6
7
8
9
:IIT
!IIT
+
:
8`
7485
48850
,[
+
8
]
8`
74851
488978
[
+
],
8`
74855
4844750
8,[!ITL(8`
74980
)]
8`
7485
488978
[
+
],
8`
748500
488
,[!ITQH(8`
7486390
)]
8`
7485
88!EIITL(8`
745
)
8`
74850
3
,
在WDBG中标注出颜色,[!ITQH(87486390)]`更容易看到。
接着就是通过代码现对此处的定位,定位我们就采用特征码搜索的方式,如下代码是特征搜索部分。
SSA代表开始位置
ESA代表结束位置,粗略计算0就可以定位到了。
1
2
3
4
5
6
7
8
9
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
#
得到IIT基址
B:LS内核开发系列教程
PVOIDGIITA()
{
PVOIDVA
=
0
;
UNICODE_STRINGT
=
{
0
};
RIUS(T,L
"IIT"
);
VA
=
(PVOID)MGSRA(T);
(VA!
=
0
)
{
VA;
}
0
;
}
VOIDUD(PDRIVER_OBJECT)
{
DP((
"UDIOK\"
));
}
NTSTATUSDE(INPDRIVER_OBJECTD,PUNICODE_STRINGRP)
{
DP((
"\"
));
得到基址
PUCHARIIT
=
GIITA();
DP(
"IITA=%\"
,IIT);
INT32O
=
0
;
PLIST_ENTRYITQH
=
NULL;
PUCHARSSA
=
IIT;
PUCHARESA
=
IIT
+
0FF
;
UCHAR1
=
0
,2
=
0
,3
=
0
;
(PUCHAR
=
SSA;ESA;
+
+
)
{
(MIAV()MIAV(
+
1
)MIAV(
+
2
))
{
1
=
*
;
2
=
*
(
+
1
);
3
=
*
(
+
2
);
个特征码
(1
=
=
8
2
=
=
3
=
=
00
)
{
(O,
+
3
,
4
);
ITQH
=
(PLIST_ENTRY)(O
+
(ULONG64)
+
7
);
DP(
"ITQH=%\"
,ITQH);
;
}
}
}
D
-
DU
=
UD;
STATUS_SUCCESS;
}
搜索个特征码1==82==3==00从而得到内存位置,运行驱动对比下。
运行代码会取出指令后面的操作数,而不是取出指令的内存地址。
比较后一步就是枚举部分,我们需要前面提到的IO_TIMER结构体定义。
PIO_TIMERT=CONTAINING_RECORD(NE,IO_TIMER,TL)得到结构体,循环输出即可。
1
2
3
4
5
6
7
8
9
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
0
1
1
1
1
1
1
1
1
1
B:LS内核开发系列教程
:
LS
784393
#
#
_IO_TIMER
{
INT
T
;
INTTF;
LONG32U;
LIST_ENTRYTL;
PVOIDTR;
PVOIDC;
PVOIDDO;
}IO_TIMER,
*
PIO_TIMER;
得到IIT基址
PVOIDGIITA()
{
PVOIDVA
=
0
;
UNICODE_STRINGT
=
{
0
};
RIUS(T,L
"IIT"
);
VA
=
(PVOID)MGSRA(T);
(VA!
=
0
)
{
VA;
}
0
;
}
VOIDUD(PDRIVER_OBJECT)
{
DP(
"卸载完成\"
);
}
NTSTATUSDE(INPDRIVER_OBJECTD,PUNICODE_STRINGRP)
{
DP((
"\"
));
得到基址
PUCHARIIT
=
GIITA();
DP(
"IITA=%\"
,IIT);
搜索ITQH地址
*
!IIT
+
:
8`
349963
48850
,[
+
8
]
8`
34996
488978
[
+
],
8`
3499635
486480
8,[!ITL(8`
34790
)]
8`
349963
488978
[
+
],
8`
34996
48896
,[!ITQH(8`
3467580
)]
8`
3499637
843598!EIITL(8`
34390
)
8`
349963
3
,
*
INT32O
=
0
;
PLIST_ENTRYITQH
=
NULL;
PUCHARSSA
=
IIT;
PUCHARESA
=
IIT
+
0FF
;
UCHAR1
=
0
,2
=
0
,3
=
0
;
(PUCHAR
=
SSA;ESA;
+
+
)
{
(MIAV()MIAV(
+
1
)MIAV(
+
2
))
{
1
=
*
;
2
=
*
(
+
1
);
3
=
*
(
+
2
);
8`
34996
48
8
0
99
6,[!ITQH(8`
3467580
)]
(1
=
=
8
2
=
=
3
=
=
00
)
{
(O,
+
3
,
4
);
ITQH
=
(PLIST_ENTRY)(O
+
(ULONG64)
+
7
);
DP(
"ITQH=%\"
,ITQH);
;
}
}
}
枚举列表
KIRQLOI;
获得特权级
OI
=
KRITDL();
(ITQHMIAV((PVOID)ITQH))
{
PLIST_ENTRYNE
=
ITQH
-
F;
(MIAV(NE)NE!
=
(PLIST_ENTRY)ITQH)
{
PIO_TIMERT
=
CONTAINING_RECORD(NE,IO_TIMER,TL);
(TMIAV(T))
{
DP(
"IO对象地址:%\"
,T);
}
NE
=
NE
-
F;
}
}
恢复特权级
KLI(OI);
D
-
DU
=
UD;
STATUS_SUCCESS;
}
运行这段源代码,并可得到以下输出,由于没有IO定时器所以输出结果是空的:
至此IO定时器的枚举就介绍完了,在教程中你已经学会了使用特征码定位这门技术,相信你完全可以输出内核中想要得到的任何结构体。 |
|