4内核对象挂钩
4.1 字符设备挂钩
4.1.1 cdevp_list Tail Queue 和 cdev_priv
4.1.2 devmtx 互斥体
4.1.3 示例
4.2 小结
4
OBJECT HOOKING
对象挂钩
In the previous chapter we covered subverting the
kernel using simple data-state changes. The discussion centered around
modifying the data contained within the kernel queue data structures.
In addition to record keeping, many of these structures are also
directly involved in control flow, as they maintain a limited number
of entry points into the kernel. Consequently, these can be hooked,
too, just like the entry points discussed in Chapter 2. This technique
is referred to as Kernel Object Hooking (KOH). To demonstrate it, let’s
hook a character device.
在前面的章节里,我们讲解了通过对数据状态进行简单的修改来颠覆FreeBSD内核的
方法。这个讨论围绕的是如何修改内核队列数据结构内部的数据。除了用于记录报告,很多的这些结构体也直接与流程控制有关,因为它们维护着数量有限的进入内
核的入口点。因此,它们也可以被挂钩,就像在第2章讨论的入口点。这个技术称之为内核对象挂钩(KOH)。做个示范,我们挂钩一个字符设备。
4.1 Hooking a Character Device
4.1 字符设备挂钩
Recall
from Chapter 1 that a character device is defined by its entries in a
character device switch table.1 As such, by modifying these entries,
you can modify the behavior of a character device. Before demonstrating
this
记得在第1章中提到,字符设备是通过它在字符设备转换表中的入口点定义的。同样,通过修改这些入口点,你可以修改一个字符设备的行为。但是,在演示这种
----------------
1 For the definition of a character device switch table, see Section 1.6.1.
1 至于字符设备转换表的定义,可查看章节1.6.1.
“attack,” however, some background information on character device management is necessary.
“攻击”前,需要了解一些字符设备管理的背景信息。
4.1.1 The cdevp_list Tail Queue and cdev_priv Structures
4.1.1 cdevp_list Tail Queue 和 cdev_priv 结构体
In
FreeBSD all active character devices are maintained on a private,
doublylinked tail queue named cdevp_list, which is defined in the file
/sys/fs/devfs/ devfs_devs.c as follows:
在FreeBSD中,所有的字符设备都维护在一个私有的称为cdevp_list的双向tail queue中。cdevp_list在文件/sys/fs/devfs/ devfs_devs.c中定义如下:
--------------------------------------------------------------------------------
static TAILQ_HEAD(,/*1*/ cdev_priv) cdevp_list =
TAILQ_HEAD_INITIALIZER(cdevp_list);
--------------------------------------------------------------------------------
As
you can see, cdevp_list is composed of /*1*/ cdev_priv structures. The
definition for struct cdev_priv can be found in the
header. Here are the fields in struct
cdev_priv that you’ll need to understand in order to hook a character
device:
可以看到,cdevp_list 由cdev_priv 结构体组成。cdev_priv 的定义可在头文件 中找到。为了挂钩一个字符设备,你得理解cdev_priv 结构中的以下域:
TAILQ_ENTRY(cdev_priv) cdp_list;
This
field contains the linkage pointers that are associated with the
cdev_priv structure, which is stored on cdevp_list. This field is
referenced during insertion, removal, and traversal of cdevp_list.
这个域包含与cdev_priv 结构相关的链接。cdev_priv 保存在cdevp_list中。在cdevp_list的插入,删除和遍历过程中,这个域要被引用到。
struct cdev cdp_c;
This
structure maintains the context of the character device. The definition
for struct cdev can be found in the header. The
fields in struct cdev relevant to our discussion are as follows:
这个结构保存着字符设备的上下文。cdev 结构的定义可以在头文件 找到。在cdev 结构体中,与我们的讨论有关的域如下:
char *si_name; This field contains the name of the character device.
char *si_name; 这个域包含这个字符设备的名字
struct cdevsw *si_devsw; This field points to the character device’s switch table.
struct cdevsw *si_devsw; 这个域指向字符设备的转换表
4.1.2 The devmtx Mutex
4.1.2 devmtx 互斥体
The following excerpt from lists the resource access control associated with cdevp_list.
--------------------------------------------------------------------------------
extern struct mtx devmtx;
--------------------------------------------------------------------------------
4.1.3 Example
As
you might have guessed, in order to modify a character device’s switch
table, you simply have to go through cdevp_list. Listing 4-1 offers an
example. This code traverses cdevp_list, looking for cd_example;2 if it
finds it, cd_example’s read entry point is replaced with a simple call
hook.
你可能已经猜到了,为了修改一个字符设备的转换表,你只要遍历cdevp_list。清单4-1提供了一个例子。这个代码遍历cdevp_list, 寻找cd_example;2 如果找到它,cd_example 的读入口点就被一个简单的调用挂钩代替。
--------------------------------------------------------------------------------
#include
#include
#include
------------------
2 cd_example is the character device developed in Section 1.6.4.
#include
#include
#include
#include
#include
#include
#include
extern TAILQ_HEAD(,cdev_priv) cdevp_list;
d_read_t read_hook;
d_read_t *read;
/* read entry point hook. */
int
read_hook(struct cdev *dev, struct uio *uio, int ioflag)
{
uprintf("You ever dance with the devil in the pale moonlight?\n");
/*1*/ return((*read)(dev, uio, ioflag));
}
/* The function called at load/unload. */
/* 加载/卸载模块时调用此函数 */
static int
load(struct module *module, int cmd, *arg)
{
int error = 0;
struct cdev_priv *cdp;
switch (cmd) {
case MOD_LOAD:
mtx_lock(&devmtx);
/* Replace cd_example's read entry point with read_hook. */
/* 用read_hook 代替cd_example 的读入口点 */
TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
if (strcmp(cdp->cdp_c.si_name, "cd_example") == 0) {
/*2*/ read = cdp->cdp_c.si_devsw->d_read;
/*3*/ cdp->cdp_c.si_devsw->d_read = read_hook;
break;
}
}
mtx_unlock(&devmtx);
break;
case MOD_UNLOAD:
mtx_lock(&devmtx);
/* Change everything back to normal. */
/* 把一切还原如初 */
TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
if (strcmp(cdp->cdp_c.si_name, "cd_example") == 0) {
/*4*/ cdp->cdp_c.si_devsw->d_read = read;
break;
}
}
mtx_unlock(&devmtx);
break;
default:
error = EOPNOTSUPP;
break;
}
return(error);
}
static moduledata_t cd_example_hook_mod = {
"cd_example_hook", /* module name 模块的名称*/
load, /* event handler 时间处理程序*/
NULL /* extra data 额外数据*/
};
DECLARE_MODULE(cd_example_hook, cd_example_hook_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
--------------------------------------------------------------------------------
Listing 4-1: cd_example_hook.c
清单g 4-1: cd_example_hook.c
Notice
that prior to /*3*/ replacing cd_example’s read entry point, I /*2*/
saved the memory address of the original entry. This allows you to
/*1*/ call and /*4*/ restore the original function without having to
include its definition in your code.
注意到在替换cd_example 的读入口点前,我保存了原先入口的地址。这使得你可以调用和恢复原先的函数,而无须把它的定义包含在你的代码里面。
Here are the results of interacting with cd_example after loading the above module:
下面是加载上面的模块后与cd_example 交互的结果:
--------------------------------------------------------------------------------
$ sudo kldload ./cd_example_hook.ko
$ sudo ./interface Tell\ me\ something,\ my\ friend.
Wrote "Tell me something, my friend." to device /dev/cd_example
You ever dance with the devil in the pale moonlight?
Read "Tell me something, my friend." from device /dev/cd_example
--------------------------------------------------------------------------------
4.2 Concluding Remarks
5.2 小结
As
you can see, KOH is more or less like DKOM, except that it uses call
hooks instead of data-state changes. As such, there is really nothing “” presented in this chapter (which is why it’s so short).
可以看到,KOH除了它使用调用挂钩代替数据状态的改变之外,多多少少与DKOM类似。因此,本章实际上没有什么“新”的东西(这就是本章为什么这么短的原因)。
阅读(1033) | 评论(0) | 转发(0) |