Socket_Kernel_Module 06

3 利用proc实现内核和应用层交互

Linux中Proc被称为虚拟文件系统,位于/proc中,其实就是内存的内容。可以利用Proc实现内核和应用程序的数据交互。

对内核,要使用特殊的函数创建、删除proc文件, 参考下面代码: 

 

3.1内核myProc_test.c代码 

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/proc_fs.h>
#include <net/ip.h>

static struct proc_dir_entry* proc_mtd;
static char szProcBuffer[5000];
static char szTemp1[1000], szTemp2[1000];
extern int iAckCount;
static int iWritingLength;

//相当于每执行#cat /proc/myProc_test 一次,就执行profile_read一次, iAckCount就递增一次

static int procfile_read(char* buffer, char** buffer_location, off_t offset, int buffer_legnth, int zero)
{
 int iLen, iReturnLength;
 if( offset > 0 ) return 0;
 iWritingLength = 0;
 sprintk(szTemp1, "iAckCount = %d/n", iAckCount++);
 if( (iWritingLength + strlen(szTemp1)) < 5000)
 {
  strcat(szProcBuffer, szTemp1);
  iWritingLength = strlen(szProcBuffer);
 }

else

{
    szProcBuffer[0] = '/0';
    iWritingLength= 0;
}

   

 *buffer_location = szProcBuffer;
 iReturnLength = iWritingLength;
 iWritingLength = 0;
 return iReturnLength;
}

static int procfile_write(struct file* file, const char* buffer,  unsigned long count)
{
    iWritingLength = count;
    if(iWritingLength > 5000 ) iWritingLength = 5000;
    if( copy_from_user(szProcBuffer, buffer, iWritingLength))
    {
        return -EFAULT;
    }
    return iWritingLength;

}

int init_hook(void)
{
 //create dir /proc/myProc_test
 if((proc_mtd = create_proc_entry("myProc_test", 0, 0)))
 {

        proc_mtd->read_proc = procfile_read;
        proc_mtd->write_proc = procfile_write;
        printk("myProc: myProc installed/n");
 }
 return 0;
}

void remove_hook(void)
{
 iAckCount = 0;
 if( proc_mtd) remove_proc_entry("myProc_test", 0);
 printk("myProc: myProc removed/n");
}

MODULE_LICENSE("GPL");

module_init(init_hook);
module_exit(remove_hook);

 

编译后,insmod加载后,执行

#cat /proc/myProc_test

iAckCount = 0;

#cat /proc/myProc_test

iAckCount = 1;

可以看到,内核的变量在增长

 

3.2应用层test.c 

#include <unistd.h>

#include <pthread.h>

#include <signal.h>

#include <stdio.h>

#include <string.h>

#include <curses.h>

#include <stdlib.h>

 

int main( int argc, char* argv[])

{

     FILE* pf;

     if(( pf = fopen("/proc/myProc_test", "wb")) == 0)

     {

            return -1;

    }

 

     char buf[] = ("test --> /proc/myProc_test/n"); 

     int w = fprintf(pf, "%s/n",buf);

     fclose(pf);

    printf("write: %d/n", w);

     return 0;

}

编译后

#./test

#cat /myProc_test

test --> /proc/myProc_test

iAckCount = 2;

 

可以看到,应用程序的字符串内核中可以调用读取了

 

3.3内核写入/proc中

将myHook_TCPSYN修改为,写入/proc中,不用重编译内核,直接修改Module代码即可

 

#define __KERNEL__

#define MODULE

#include <linux/module.h>

#include <linux/skbuff.h>

#include <linux/tcp.h>

#include <linux/ip.h>

#include <linux/proc_fs.h>

#include <net/ip.h>

//big-endian和little-endian转换,big用在网络中,而linux中是little

#define u32toValue(x) ((__u32)( /

                                  (((__u32)(x) & (__u32)0x000000ffUL) << 24) | /

                                  (((__u32)(x) & (__u32)0x0000ff00UL) <<   8) | /

                                  (((__u32)(x) & (__u32)0x00ff0000UL) >>   8) | /

                                  (((__u32)(x) & (__u32)0xff000000UL) >> 24) ))

extern int myHook_TCPSYN_count;

extern int (*myHook_TCPSYN)(struct sk_buff*);

 

//转为可打印地址

static void IpAddressToString(unsigned long i, char* s)

{

     unsinged long j1, j2,j3,j4;

     j1 = (i & 0x000000FF);

     j2 = (i & 0x0000FF00)>>8;

     j3 = (i & 0x00FF0000)>>16;

     j4 = (i & 0xFF000000)>>24;

     sprintf(s, "%u.%u.%u.%u", j4,j3,j2,j1); //注意顺序

}

 

static struct proc_dir_entry* proc_mtd;
static char szProcBuffer[5000];

static char szTmp[1000];
//相当于每执行#cat /proc/myProc_test 一次,就执行profile_read一次, iAckCount就递增一次

static int profile_read(char* buffer, char** buffer_location, off_t offset, int buffer_legnth, int zero)
{
    int iLen, iReturnLength;
    if( offset > 0 ) return 0;
    *buffer_location = szProcBuffer;  //相当于接口参数从全局变量传入值
    iReturnLength = iWritingLength;
    iWritingLength = 0;
    return iReturnLength;
}

 

//hook函数的实现

int myHook_TCPSYN_impl(struct sk_buff* skb)

{

    strcut iphdr* iph;

    strcut tcphdr* th;

    char szSourceIP[50], szTargetIP[50];

 

    iph = skb->nh.iph;

    if( iph->protocol == IPPROTO_TCP)  //判断是否是TCP

    {

         th = skb->h.th;

         if( th->syn)            //判断是否是SYN包

         {

             IpAddressToString(u32toValue(skb->nh.iph->saddr), szSourceIP);

             IpAddressToString(u32toValue(skb->nh.iph->daddr), szTargetIP);

             if( strcmp(szSourceIP, "192.168.0.1") == 0 && //判断源地址是否是自己, 根据实践地址修改

                 strcmp(szTargetIP, "192.168.0.2") == 0) //判断目的地址, 根据实践地址修改

             {

                 myHook_TCPSYN_count++;

                 if( myHook_TCPSYN_count > 0x0fffff) myHook_TCPSYN_count = 0;

                 //原来是printk显示到/var/log/message中       

                 printk(%s --> %s ===> SYNcount=%d/n", szSourceIP, szTargetIP, myHook_TCPSYN_count);

                 sprintf(szTmp,"%s --> %s ===> SYNcount=%d/n", szSourceIP, szTargetIP, myHook_TCPSYN_count);

                 //不需要调用函数,只需要将字符串写入全局变量就可以,每次#cat时读取

                 memcpy(&szProcBuffer[iWritingLength], szTmp, strlen(szTmp));

                 iWritingLength += strlen(szTmp);

             }

         }

    }     

    return 0;

}

 

static int init_hook( void )
{
    myHook_TCPSYN = myHook_TCPSYN_impl;  //后门函数指向了真正的实现函数

    printk("myHook_TCPSYN installed");        //表示加载成功
    return 0;
}

 

static int exit_hook(void)

{

    myHook_TCPSYN= 0;                    //后门函数清0
    printk("myHook_TCPSYN removed/n"); //表示卸载成功

    return 0;
}

 

MODULE_LICENSE("GPL"); //表示采用的开放协议

module_init(init_hook);     //为当加载Module时,自动调用init_hook
module_exit(exit_hook);   //当卸载Module时,自动调用exit_hook;

 

编译后,

#ping 192.168.0.1

#cat /proc/myProc_test

192.168........................  //显示值,表示内核写入了/proc中,应用程序也完全可以正常读取

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值