#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <asm/unistd.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/fs_struct.h>
#include <linux/msdos_fs.h>
#ifdef CONFIG_SMP
#define __SMP__
#endif
/*
系统调用号的定义在 /usr/include/asm/unistd.h 文件中
printk结果通过dmesg查看。
可以用cat /boot/System.map-`uname -r` |grep sys_call_table 查看table的地址
*/
#define __NR_get_FAT_boot 39
#define __NR_get_FAT_dir 15 //替换chmod系统调用
unsigned long **sys_call_table;//调用表
unsigned long * savedcall; //存放被替换的调用指针
struct idt_tag
{
unsigned short offset_low,segment_select;
unsigned char reserved,flags;
unsigned short offset_high;
};
asmlinkage long testsyscall(char *buf)//测试系统调用
{
printk("hello world/n");
char* b="hello world/n";
int n=copy_to_user(buf,b,strlen(b));
printk("复制成功/n");
return n;
}
asmlinkage long get_files_info(char * filesystem_type)//取得当前目录的文件系统信息
{
struct fs_struct *fs ;
struct vfsmount *mnt ;
struct super_block *mnt_sb ;
struct file_system_type *s_type;
read_lock(¤t->fs->lock);
fs = current->fs;
mnt = fs->pwdmnt;
mnt_sb = mnt-> mnt_sb ;
s_type = mnt_sb -> s_type;
printk("PWD Filesystem Type is : %s/n",s_type->name);
copy_to_user(filesystem_type,s_type->name,strlen(s_type->name));
printk("PWD= %ld/n",mnt_sb->s_blocksize);
read_unlock(¤t->fs->lock);
return 0;
}
/*
http://linux.chinaunix.net/bbs/viewthread.php?tid=916894&rpid=6437642&ordertype=0&page=1#pid6437642
//fat_boot_sector是一个定义在include/linux/msdos_fs.h中的结构体。
//它的内容结构和磁盘中的super block完全一样。所有可用直接赋值,这样变量b
//就有了这个设备的SB信息。
b = (struct fat_boot_sector *) bh->b_data;
/home/god/linux-2.6.24/include/linux
*/
/*get_FAT_boot*/
asmlinkage long get_FAT_boot(char * filesystem_type)//取得fat文件系统的信息
{
struct fs_struct *fs ;
struct vfsmount *mnt ;
struct super_block *mnt_sb ;
struct buffer_head * bh=NULL;
struct fat_boot_sector *fat_sector;
char c[512];
int len;
read_lock(¤t->fs->lock);
fs = current->fs;
mnt = fs->pwdmnt;
mnt_sb = mnt-> mnt_sb ;
char *fsname=mnt_sb -> s_type->name;
char *sfs="vfat";
if(strcmp(fsname,sfs)==0)//此时文件系统是vfat
{
sb_min_blocksize(mnt_sb, 512);
bh = sb_bread(mnt_sb, 0);
if(bh!=NULL)
{
fat_sector=(struct fat_boot_sector *)bh->b_data;
len=sprintf(c,"FAT文件系统具体参数如下:/n");
len=sprintf(c,"%sbackup boot sector= %d/n",c,fat_sector->backup_boot);
len=sprintf(c,"%ssectors/cluster= %d/n",c,fat_sector->sec_per_clus);
len=sprintf(c,"%snumber of heads= %d/n",c,fat_sector->heads);
len=sprintf(c,"%shidden sectors (unused)= %d/n",c,fat_sector->hidden);
len=sprintf(c,"%smedia code= %d/n",c,fat_sector->media);
len=sprintf(c,"%sbytes per logical sector= %d/n",c,(fat_sector->sector_size[1]<<8)+fat_sector->sector_size[0]);
}
else
len=sprintf(c,"BH is wrong!!");
}
else//此时文件系统不是vfat
len=sprintf(c,"Wrong !! The filesystem is %s!!/n",fsname);
c[len]='/0';
len++;
copy_to_user(filesystem_type,c,len);
read_unlock(¤t->fs->lock);
return len;
}
/*http://linux.chinaunix.net/bbs/thread-916894-1-1.html*/
/*目录文件的目录项在内核中用struct msdos_dir_entry(定义在 include/linux/msdos_fs.h中)来表示*/
/*可见这个数据结构与磁盘中的目录项基本一致*/
/*http://blog.chinaunix.net/u2/87570/showart_2126000.html*/
static bool isEmpty(unsigned char c)
{
if(c==0x00||c==0xE5)
return true;
else
return false;
}
static void memswap(unsigned char *dest,unsigned char *src, int count){//交换两块内存
int i=0;
unsigned char t;
while(i<count)
{
t=dest[i];
dest[i]=src[i];
src[i]=t;
i++;
}
}
/*get_FAT_dir*/
asmlinkage long get_FAT_dir(char * filesystem_type)//取得fat文件系统的目录信息
{
struct fs_struct *fs ;
struct vfsmount *mnt ;//当前挂载点
struct file_system_type *s_type;
//struct dentry *pwdentry;//当前目录项
struct super_block *mnt_sb ;
// struct inode *inode;
//struct list_head d_subdirs;
struct dentry *cpwd;
struct inode *ci;
struct msdos_sb_info * dos_sb;
struct msdos_dir_entry *dos_de;
struct msdos_inode_info *dos_si;
struct fat_boot_sector *fbs;
struct buffer_head *bh=NULL;
struct msdos_dir_entry *dir0,*dir1;
int len;
len=0;
char c[2048];
len=sprintf(c,"当前目录信息如下:/n");
read_lock(¤t->fs->lock);
fs = current->fs;
mnt = fs->pwdmnt;
mnt_sb = mnt-> mnt_sb ;
s_type = mnt_sb -> s_type;
cpwd = fs->pwd;
ci = cpwd->d_inode;
mnt_sb = ci->i_sb;
char *fsname=s_type->name;
char *sfs="vfat";
if(strcmp(fsname,sfs)==0)//此时文件系统是vfat
{
/* len=sprintf(c,"当前目录下的信息为:/n");*/
/* struct dentry *p;*/
/* list_for_each(p,d_subdirs)*/
/* {*/
/* len=sprintf(c,"%s目录 %p/n",c,p);*/
/* }*/
dos_sb = (struct msdos_sb_info *)mnt_sb->s_fs_info;
len=sprintf(c,"%s每簇扇数=%d/n",c,dos_sb->sec_per_clus);
len=sprintf(c,"%s簇大小=%d/n",c,dos_sb->cluster_size);
len=sprintf(c,"%sFAT位数=%d/n",c,dos_sb->fat_bits);
len=sprintf(c,"%sFAT开始扇=%d/n",c,dos_sb->fat_start);
len=sprintf(c,"%sFAT长度=%ld/n",c,dos_sb->fat_length);
len=sprintf(c,"%s目录开始扇=%ld/n",c,dos_sb->dir_start);
len=sprintf(c,"%s目录入口=%d/n",c,dos_sb->dir_entries);
len=sprintf(c,"%s数据开始扇=%ld/n",c,dos_sb->data_start);
len=sprintf(c,"%s最大簇号=%ld/n",c,dos_sb->max_cluster);
len=sprintf(c,"%s根开始扇=%ld/n",c,dos_sb->root_cluster);
dos_si = container_of(ci, struct msdos_inode_info, vfs_inode);
bh = sb_bread(mnt_sb, 0);
if(bh == NULL) {
printk(KERN_ERR "Boot failed/n");
}
fbs = (struct fat_boot_sector *)(bh->b_data);
len=sprintf(c,"%s系统信息=%s/n/n",c,fbs->system_id);
bh = sb_bread(mnt_sb, dos_sb->dir_start);//根据目录开始扇地址读出目录项
if (bh == NULL) {
printk(KERN_ERR "FAT: Directory bread failed/n");
}
len=sprintf(c,"%s##整理前##/n",c);
dos_de = (struct msdos_dir_entry *)(bh->b_data);
int i=0;
for(i=0; i<16; i++)
{
len=sprintf(c,"%s %d=%s/n",c,i,dos_de->name+ i*sizeof(struct msdos_dir_entry));
printk("%d=%s/n",i,dos_de->name+ i*sizeof(struct msdos_dir_entry));
}
/*
重新排序整理过程
*/
unsigned char head,tail;//存放两头的结构的名字首字符
int j=15;
i=0;
dir0=NULL;
dir1=NULL;
while(i < j){
if(dir0==NULL)
dir0 =(struct msdos_dir_entry*)(bh->b_data + i*sizeof(struct msdos_dir_entry));
if(dir1==NULL)
dir1 =(struct msdos_dir_entry*)(bh->b_data + j*sizeof(struct msdos_dir_entry));
head = dir0->name[0];
tail = dir1->name[0];
if(isEmpty(head)&&!isEmpty(tail))//前空后满则直接跳过
{
i++;
j--;
dir0=NULL;
dir1=NULL;
printk("i++=%d,j--=%d/n",i,j);
}
else if(isEmpty(head)&&isEmpty(tail))//前空后空则跳过前
{
i++;
dir0=NULL;
printk("i++=%d,j=%d/n",i,j);
}
else if(!isEmpty(head)&&!isEmpty(tail))//前满后满则跳过后
{
j--;
dir1=NULL;
printk("i=%d,j--=%d/n",i,j);
}
else if(!isEmpty(head)&&isEmpty(tail))//前满后空则交换两块内存
{
memswap((unsigned char*)dir0,(unsigned char*)dir1,sizeof(struct msdos_dir_entry));//交换内存
i++;
j--;
dir0=NULL;
dir1=NULL;
printk("交换后 i++=%d,j--=%d/n",i,j);
}
}
len=sprintf(c,"%s##整理后##/n",c);
i=0;
while(i < 16){
len=sprintf(c,"%s %d :%s/t",c,i,dos_de->name+ i*sizeof(struct msdos_dir_entry));
head = (dos_de->name+ i*sizeof(struct msdos_dir_entry))[0];
if(head == 0xE5){
len+=sprintf(c+len,"E5已删除/n");
}else if(head == 0x00){
len+=sprintf(c+len,"00未用/n");
}else{
len+=sprintf(c+len,"已用/n");
}
i++;
}
}
else//此时文件系统是vfat
len=sprintf(c,"Wrong !! The filesystem is %s!!/n",fsname);
c[len]='/0';
len++;
printk("/nLen= %d/n/n",len);
copy_to_user(filesystem_type,c,len);
read_unlock(¤t->fs->lock);
return len;
}
static unsigned long getSyscallTable(void)
{
unsigned char idtr[6],*shell,*sort;
struct idt_tag *idt;
unsigned long system_call,sct;
unsigned short offset_low,offset_high;
char *p;
int i;
__asm__("sidt %0":"=m"(idtr));
idt = (struct idt_tag*)((*(unsigned long*)&idtr[2]) + 8 * 0x80);
offset_low = idt->offset_low;
offset_high = idt->offset_high;
system_call = (offset_high)<<16 | offset_low;
shell = (char*)system_call;
sort = "/xff/x14/x85";
for(i = 0;i < 100-2;i++)
if(shell [ i ] == sort[0] && shell[i+1] == sort[1] && shell[i+2] == sort[2])
break;
p = &shell [ i ] + 3;
sct = *(unsigned long*)p;
return sct;
}
int init_module(void)
{
sys_call_table = (unsigned long**)getSyscallTable();
printk("/n*********************************/n");
printk("系统调用表的首地址为%p/n",sys_call_table);
savedcall=sys_call_table[__NR_get_FAT_boot];//保存原来的调用
printk("原来的%d系统调用为: %p/n",__NR_get_FAT_boot,savedcall);
printk("目的系统调用为%p/n",(unsigned long*)get_FAT_dir);
sys_call_table[__NR_get_FAT_boot]=(unsigned long*)get_FAT_dir;
printk("更改后的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);
printk("loaded success /n");
return 0;
}
void cleanup_module(void)
{
printk("恢复前的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);
sys_call_table[__NR_get_FAT_boot]=savedcall;
printk("恢复后的%d系统调用为: %p/n",__NR_get_FAT_boot,sys_call_table[__NR_get_FAT_boot]);
printk("unloaded success/n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("QCH");