实现linux系统的文件透明加解密的驱动程序

来源:互联网 发布:胜科金仕达 待遇知乎 编辑:程序博客网 时间:2024/05/21 06:21
这是一个在系统调用层劫持系统调用,实现linux系统的文件透明加解密的驱动程序(一)。最后编写


Makefile文件(请看下一讲),生成.so文件,动态加载到内核中即可。
#include
······
#include


#define Encryption blowfish
#define Decryption blowfish
#define KERNEL_BUF_SIZE 1024*8


static char *key = "world";
static char *filename = "ttt.c";
//系统调用表sys_call_table存储了所有系统调用对应的服务例程的函数地址
static unsigned long *sys_call_table=NULL;//存放系统调用表的起始地址


//内核模块通过module_param来传递命令行参数
//module_param(name, type, perm);变量名、类型、权限掩码(用来作一个辅助的sysfs入口)
//charp一个字符指针值,内存为用户提供的字串分配
//S_IRUGO可以被所有人读取
module_param(key, charp, S_IRUGO);
module_param(filename, charp, S_IRUGO);


//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节


数进行对齐,是GCC特有的语法。
//__attribute__关键字主要是用来在函数或数据声明中设置其属性,给函数赋给属性的主要目的在于让


编译器进行优化
//packed可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位


对齐。
//中断向量表表项结构体
struct {
unsigned short limit;
unsigned int    base;
}__attribute__((packed)) idtr;


//中断向量描述符的结构体
struct _idt
{
unsigned short offset_low;
unsigned short segment_sel;
unsigned char reserved, flags;
unsigned short offset_high;
}__attribute__((packed));


//函数定义前加宏asmlinkage,表示这些函数通过堆栈而不是通过寄存器传递参数。
//告诉编译器仅从堆栈中获取该函数的参数
//定义一个函数指针,用于保存原系统调用read和write在系统调用表中的内容。
asmlinkage ssize_t (*orig_read)(int fd,void *buf, size_t count);
asmlinkage ssize_t (*orig_write)(int fd,void *buf, size_t count);


long enFile_fd;
unsigned int orig_cr0;//用于保存初始的CR0寄存器的值
static char *kernel_buf;
struct file *info_file = NULL;




unsigned int clear_and_ret_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret = 0;
//asm表示后面的代码为内嵌汇编,是__asm__的别名
//volatile表示编译器不要优化代码,后面的指令保持原样,是__volatile__的别名
//执行int 0x80后,系统调用的参数保存在寄存器中,eax传递的是系统调用号。
//汇编代码,用于取出CR0寄存器的值
//AT&T汇编代码使用小写字母,寄存器需要加前缀%
//AT&T语法第一个为源操作数,第二个为目的操作数,方向从左到右
//"movl %1, %0":"=r"(result):"m"(input) "=r"是表达式的说明和限制,(result)是每个操作数对应的C


表达式
//result前面的限制字符串是=r,=表示result是输出操作数
//冒号后第一项对应的是%0,第二项对应的是%1
//输入部分为空,也就是我们可以直接从CR0寄存器中取数;输出部分位cr0变量,a表示将cr0和eax相关


联,执行完后,cr0寄存器中的值就赋给了变量cr0.
asm volatile("movl %%cr0, %�x":"=a"(cr0));
ret = cr0;


//CR0的第16位是写保护位,0表示禁用写保护,1表示开启
cr0 &= 0xfffeffff;
//汇编代码,将修改后的CR0值写入CR0寄存器
//输出部分为空,我们直接将结果输出到cr0寄存器中;输入部分为变量cr0,它和eax寄存器相关联,执


行完后,变量cr0的值就赋给了寄存器cr0.
asm volatile("movl %�x, %%cr0"::"a"(cr0));
return ret;//返回初始CR0值
}


//改回原CR0寄存器的值
void setback_cr0(unsigned int val)
{
asm volatile("movl %�x, %%cr0"::"a"(val));
}


//查找系统调用表到sys_call_table的偏移量
char* findoffset(char *start)
{
char *ptr = start;
int i = 0;
for(; i < 100; i++){
if(*(ptr+i) == '\xff' && *(ptr+ i + 1) == '\x14' && *(ptr+ i + 2) == '\x85'){
printk("find offset %d\n",i);
return ptr + i;
}
}
return NULL;
}


//加解密程序
void blowfish(const char * bfKey,char * pData, long size)
{
int i;
for(i = 0; i < size; ++i){
pData[i]=pData[i]^bfKey[0];
//printk("en : %c\n",pData[i]);
}
}


//找到系统调用表并替换内容
//通过中断向量表,找到系统调用的中断向量
unsigned long *getscTable(void)
{
//中断向量表IDT的入口地址是通过IDTR寄存器来确定的
struct _idt *idt;
unsigned long system_call = 0, sct = 0;
unsigned short offset_low,offset_high;
char *p = NULL;
orig_cr0 = clear_and_ret_cr0();   //注意在这里设置一下cr0
// 从idtr中获得中断描述符(相当于中断号号表)的首地址
//idtr寄存器的内容可以通过汇编指令sidt取出
__asm__("sidt %0" : "=m" (idtr));
setback_cr0(orig_cr0);
//由于每个中端描述符为8个字节,而软中断为int 0x80,据此获取系统调用中断即0x80的中断描述符的


首地址
//idt是获取到系统调用中断向量地址(即每一向量是中断服务程序的入口地址),即0x80地址
idt = (void *)(idtr.base + 8 * 0x80);
offset_low = idt->offset_low;
offset_high = idt->offset_high;
//获取系统调用中断发生时的中断处理例程的地址
system_call = (offset_high<<16)|offset_low;
//找到系统调用表(即中断向量表,系统调用表的入口地址是system_call)中,系统调用项的首地址,即


中断服务程序的入口地址
p = findoffset((char*)system_call);
if(NULL != p) {
//3表示3个指令码
sct = *(unsigned long*)(p+3);
}
return (unsigned long*)sct;
}




//具有解密功能的读
//判断是否是需要解密的文件,如果是执行替换后的read函数将数据拷贝到内核空间解密数据,否则调用


原来的read函数输出数据。
asmlinkage ssize_t hacked_read(unsigned int fd,char * buf,size_t count)
{
int err = 0;
struct file *file;
ssize_t ret = -EBADF;


//根据文件描述符获得文件的file结构,从而获得其文件名
file = fget(fd);
//调用原来的read系统调用将数据输入
ret=orig_read(fd,buf,count);
//判断当前进行read系统调用的文件是否为加载模块时指定的文件
if(!strcmp(file->f_dentry->d_name.name,filename)){
//判断要操作的字符数目是否是操作预先的分配值
if(count > KERNEL_BUF_SIZE ){
kfree(kernel_buf);
kernel_buf=kmalloc(count+10, GFP_KERNEL);
memset(kernel_buf, 0,count+10 );
}
//将数据拷贝到内核空间中
err = copy_from_user(kernel_buf,buf,count);
if(err){
printk("copy_from_user error!\n");
}
//解密数据
Decryption(key,kernel_buf,count);
//将数据拷回到用户空间
err = copy_to_user(buf,kernel_buf,count);
if(err){
printk("copy_to_user error!\n");
}
}


return ret;
}


//具有加密功能的写
//判断是否是需要加密的文件,如果是执行替换后write函数将数据拷贝到内核空间加密数据,否则调用


原来的write函数输入数据。
asmlinkage ssize_t hacked_write(unsigned int fd,char * buf,size_t count)
{
int err = 0;
struct file *file;
ssize_t ret = -EBADF;
//根据文件描述符获得文件的file结构,从而获得其文件名
file = fget(fd);
//判断当前进行write系统调用的文件是否为加载模块时指定的文件
if(!strcmp(file->f_dentry->d_name.name,filename)){
//判断要操作的字符数目是否时操作预先的分配值
if(count > KERNEL_BUF_SIZE ){
kfree(kernel_buf);
kernel_buf=kmalloc(count+10, GFP_KERNEL);
memset(kernel_buf, 0,count+10 );
}
//将数据拷贝到内核空间中
err = copy_from_user(kernel_buf,buf,count);
if(err){
printk("copy_from_user error!\n");
}
//加密数据
Encryption(key,kernel_buf,count);
//将数据拷回到用户空间
err = copy_to_user(buf,kernel_buf,count);
if(err){
printk("copy_to_user error\n");
}
}
//调用原来的write系统调用将数据输入
ret = orig_write(fd,buf,count);


return ret;
}




static int hack_init(void)
{
sys_call_table = getscTable();
if(NULL != sys_call_table){
orig_read=(asmlinkage ssize_t (*)(int ,void *, size_t))sys_call_table[__NR_read];
orig_write=(asmlinkage ssize_t (*)(int ,void *, size_t))sys_call_table[__NR_write];
orig_cr0 = clear_and_ret_cr0(); 
sys_call_table[__NR_read]=(unsigned long)hacked_read;
sys_call_table[__NR_write]=(unsigned long)hacked_write;
setback_cr0(orig_cr0);
kernel_buf=kmalloc(KERNEL_BUF_SIZE, GFP_KERNEL);
memset(kernel_buf, 0,KERNEL_BUF_SIZE );
}
return 0;
}


void hack_cleanup(void)
{
orig_cr0 = clear_and_ret_cr0();
printk("UnHacked 3!");


//sys_call_table = getscTable();
if(sys_call_table){
sys_call_table[__NR_read]=(unsigned long)orig_read;
sys_call_table[__NR_write]=(unsigned long)orig_write;
}
setback_cr0(orig_cr0);
kfree(kernel_buf);
return;
}


MODULE_LICENSE("GPL");
module_init(hack_init);
module_exit(hack_cleanup);


·生成加解密模块:make
·装载模块,文件名为test.c 密码为zz: insmod encryption.ko key = "zz" filename = "test.c"
·对test.c进行编辑: vi test.c 
·卸载模块查看效果 : rmmod encryption
·查看加密后的文件: vi test.c
·加载模块,查看原文件: insmod encryption.ko key = "zz" filename = "test.c"
·查看源文件: vi test.c
·在Fedora 17,Linux 3.3内核中试验成功
关于上一讲中的Makefile的书写  (2013-09-10 23:59:52) 转载▼
标签:  pwd   make   moudles   it 分类: 个人日记
obj-m := encryption.o
##m:编译成模块,但不会编译进内核
KDIR :=  /lib/modules/`uname -r`(反逗点)/build
##指定内核路径
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
linux系统的文件透明加解密的驱动程序(二)  (2013-09-11 00:05:14) 转载▼
标签:  vfs   加解密   动态加载   file结构体   传递性 分类: 个人日记
这是一个在VFS层劫持系统调用,实现Linux系统的文件透明加解密的驱动程序(二)。最后编写Makefile


(请看上一讲),生成.so文件,动态加载到内核中即可。
#include
······
#include


#define Encryption blowfish
#define Decryption blowfish
#define FOP file->f_dentry->d_inode->i_fop


static char *key = "zz";
static char *filename = "ttt.c";


module_param(key, charp, S_IRUGO);
module_param(filename, charp, S_IRUGO);


char *root_fs = "/test.c";
unsigned int orig_cr0;
typedef ssize_t (*read_t)(struct file *, char __user *, size_t, loff_t *);
typedef ssize_t (*write_t)(struct file *, const char __user *, size_t, loff_t *);
read_t orig_read = NULL;
write_t orig_write = NULL;


unsigned int clear_and_ret_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret = 0;


asm volatile("movl %%cr0, %�x":"=a"(cr0));
ret = cr0;


cr0 &= 0xfffeffff;
asm volatile("movl %�x, %%cr0"::"a"(cr0));


return ret;
}


void setback_cr0(unsigned int val)
{
asm volatile("movl %�x, %%cr0"::"a"(val));
}


void blowfish(const char *bfkey, char *pData, size_t size)
{
int i = 0;
for(; i < size; ++i){
pData[i] = pData[i]^bfkey[0];
}
}


ssize_t hacked_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
ssize_t ret = -EBADF;


ret = orig_read(file, buf, count, offset);
if(!strcmp(file->f_dentry->d_name.name, filename))
Decryption(key, buf, count);


return ret;
}




ssize_t hacked_write(struct file *file, const char __user *buf, size_t count, loff_t 


*offset)
{
ssize_t ret = -EBADF;


if(!strcmp(file->f_dentry->d_name.name, filename))
Encryption(key, (char __user *)buf, count);


ret = orig_write(file, buf, count, offset);


return ret;
}




int patch_vfs(const char *p, read_t *orig_read, write_t *orig_write, read_t new_read, 


write_t new_write)
{
struct file *file;


file = filp_open(p, O_RDONLY, 0);
if(IS_ERR(file))
return -1;


orig_cr0 = clear_and_ret_cr0();


if(orig_read)
*orig_read = FOP->read;
if(orig_write)
*orig_write = FOP->write;


((struct file_operations *)(FOP))->read = new_read;
((struct file_operations *)(FOP))->write = new_write;


setback_cr0(orig_cr0);


filp_close(file, 0);
return 0;
}


int unpatch_vfs(const char *p, read_t orig_read, write_t orig_write)
{
struct file *file;


file = filp_open(p, O_RDONLY, 0);
if(IS_ERR(file))
return -1;


orig_cr0 = clear_and_ret_cr0();


((struct file_operations *)(FOP))->write = orig_write;
((struct file_operations *)(FOP))->read = orig_read;


setback_cr0(orig_cr0);


filp_close(file, 0);
return 0;
}




static __init int patch_init(void)
{
patch_vfs(root_fs, &orig_read, &orig_write, hacked_read, hacked_write);
return 0;
}


static __exit void patch_cleanup(void)
{
unpatch_vfs(root_fs, orig_read, orig_write);
}


MODULE_LICENSE("GPL");
module_init(patch_init);
module_exit(patch_cleanup);


·本驱动程序的缺点是必须在/目录下有test.c文件,才能实现加解密功能。
·生成加解密模块:make
·装载模块,文件名为test.c 密码为zz: insmod encryption.ko key = "zz" filename = "test.c"
·对test.c进行编辑: vim test.c 
·卸载模块查看效果 : rmmod encryption
·查看加密后的文件: vim test.c
·加载模块,查看原文件: insmod encryption.ko key = "zz" filename = "test.c"
·查看源文件: vim test.c

·在Fedora 17,Linux 3.3内核中试验成功

http://www.jm8848.com 有实验产品,大家可以交流

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 没麦芽糖怎么做江米条 用白面怎么做酥脆的江米条 江米粥 今夕何夕by梨籽 锦瑟txt梨籽popo 梨籽的功效与作用 佳人有约江柔全章节目录 江约诚 江组词 江的组词 江字组词 继女暖暖江诚全文阅读 江美仪 江美琪 路人 江美琪 至少还有你 江美琪 江美琪的歌 江耀城 江背镇 江烟柔顾邵霖笫十五章 沈烽霖江清柠 至霖情歌 江芷薇 江苏人 江苏69人感染丙肝 江苏人亊考试网 江苏省人医app网上预约 江苏中人工资 日本人为啥不杀江苏人 江苏英语高考卷 江苏卷高考作文 2019江苏卷语文 外省学生眼中的江苏卷 江苏携号转网 江苏人才网 江苏卫视吧 江苏自考吧 江苏大学考研吧 江苏科技大学吧 江苏海事职业技术学院吧 江苏师范大学吧