rootkit 的 getdents() 系统调用实现
getdents() syscall implementation for rootkit
我计划为我的 rootkit 挂钩我自己的 getdents() 版本。代码在这里:
asmlinkage int new_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count)
{
int nread;
int bpos;
struct linux_dirent *d;
int (*orig_func)(unsigned int fd, struct linux_dirent *dirp, unsigned int count);
t_syscall_hook *open_hook;
open_hook = find_syscall_hook(__NR_getdents);
orig_func = (void*) open_hook->orig_func;
nread = (*orig_func)(fd, dirp, count);
d = dirp;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) ((char*)dirp + bpos);
printk(KERN_INFO "%s\n", d->d_name);
bpos += d->d_reclen;
}
return nread;
}
我无法理解这一行中的类型转换:d = (struct linux_dirent *) ((char*)dirp + bpos);
d
和 dirp
都保存 linux_dirent 结构的内存地址。 d_reclen
包含条目的长度。如果我们收到 d_reclen
作为 3、5、7,则条目将出现在 dirp、dirp+3 /size(linux_dirent)、(dirp+3/size(linux_dirent)+ 5/尺寸(linux_dirent))...
所以那一行应该是这样的:d = (struct linux_dirent *) ((dirp + bpos)/size(linux_dirent));
为什么我们要转换成 (char *)?
typedef struct {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
} linux_dirent;
So the line should be something like this then: d = (struct linux_dirent *) ((dirp + bpos)/size(linux_dirent));
否 - dirp / sizeof(linux_dirent)
毫无意义,dirp
相对于 0
的偏移量与结构的大小无关。将内存地址除以结构的大小...它只是一些不相关的地址。
你的意思是,例如,从内存位置除掉 仅偏移量 ,然后将结果指针添加到指针。嗯,一起:
(char*)dirp + ((char*)(dirp + bpos) - (char*)dirp)/sizeof(linux_dirent)
^^^^^^^^^^^ = (char*)dirp + bpos * sizeof(linux_dirent)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = bpos * sizoef(linux_dirent)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = bpos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = (char*)dirp + bpos
但是...不是以 sizeof(linux_dirent)
步递增 dirp
指针,而是可以以 1 字节的步长递增它。这就是 char*
的演员正在做的事情。 sizeof(char)
总是 1
。以下是正确的值:
dirp + bpos == (char*)dirp + bpos * sizeof(linux_dirent)
Why are we converting into (char *)?
我们正在转换为 char *
以更改 +
运算符将递增的字节数。简短示例:
int *a = 20;
a + 5 == 20 + 5 * sizeof(int)
(char*)a + 5 == 20 + 5 * sizeof(char) // sizeof(char) = 1, so:
(char*)a + 5 == 25
指针运算是个很好的研究课题。
我计划为我的 rootkit 挂钩我自己的 getdents() 版本。代码在这里:
asmlinkage int new_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count)
{
int nread;
int bpos;
struct linux_dirent *d;
int (*orig_func)(unsigned int fd, struct linux_dirent *dirp, unsigned int count);
t_syscall_hook *open_hook;
open_hook = find_syscall_hook(__NR_getdents);
orig_func = (void*) open_hook->orig_func;
nread = (*orig_func)(fd, dirp, count);
d = dirp;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) ((char*)dirp + bpos);
printk(KERN_INFO "%s\n", d->d_name);
bpos += d->d_reclen;
}
return nread;
}
我无法理解这一行中的类型转换:d = (struct linux_dirent *) ((char*)dirp + bpos);
d
和 dirp
都保存 linux_dirent 结构的内存地址。 d_reclen
包含条目的长度。如果我们收到 d_reclen
作为 3、5、7,则条目将出现在 dirp、dirp+3 /size(linux_dirent)、(dirp+3/size(linux_dirent)+ 5/尺寸(linux_dirent))...
所以那一行应该是这样的:d = (struct linux_dirent *) ((dirp + bpos)/size(linux_dirent));
为什么我们要转换成 (char *)?
typedef struct {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
} linux_dirent;
So the line should be something like this then: d = (struct linux_dirent *) ((dirp + bpos)/size(linux_dirent));
否 - dirp / sizeof(linux_dirent)
毫无意义,dirp
相对于 0
的偏移量与结构的大小无关。将内存地址除以结构的大小...它只是一些不相关的地址。
你的意思是,例如,从内存位置除掉 仅偏移量 ,然后将结果指针添加到指针。嗯,一起:
(char*)dirp + ((char*)(dirp + bpos) - (char*)dirp)/sizeof(linux_dirent)
^^^^^^^^^^^ = (char*)dirp + bpos * sizeof(linux_dirent)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = bpos * sizoef(linux_dirent)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = bpos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = (char*)dirp + bpos
但是...不是以 sizeof(linux_dirent)
步递增 dirp
指针,而是可以以 1 字节的步长递增它。这就是 char*
的演员正在做的事情。 sizeof(char)
总是 1
。以下是正确的值:
dirp + bpos == (char*)dirp + bpos * sizeof(linux_dirent)
Why are we converting into (char *)?
我们正在转换为 char *
以更改 +
运算符将递增的字节数。简短示例:
int *a = 20;
a + 5 == 20 + 5 * sizeof(int)
(char*)a + 5 == 20 + 5 * sizeof(char) // sizeof(char) = 1, so:
(char*)a + 5 == 25
指针运算是个很好的研究课题。