linux怎么生成sct文件,[转载]linux系统的文件透明加解密的驱动程序(一)

这是一个在系统调用层劫持系统调用,实现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 %dn",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 : %cn",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 errorn");

}

}

//调用原来的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内核中试验成功

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值