动态调用kernel任意函数(anycall)

有的时候只需要简单调用下别的kernel函数

或者别的模块函数没有export,而你又不想单独编译kernel重新下载的时候

或者动态去修改某个驱动的寄存器值。

首先看下效果及使用步骤:

加入kernel ,更多时候是驱动中有以下函数:

 ssize_t justfortest0()
{
    printk(KERN_ERR"[anycall] successful....justfortest  000\r\n");
    return 0;
}
 ssize_t justfortest1(int i)
{
    printk(KERN_ERR"[anycall] successful....justfortest  111 value is %d \r\n",i);
    return 0;
}
 ssize_t justfortest2(int i, int j)
{
    printk(KERN_ERR"[anycall] successful....justfortest  222 value is %d ,%d \r\n",i,j);
    return 0;
}

我只需要在shell 中输入:

echo "^justfortest2:1,7788,#"  >  /sys/kernel/debug/anycall

log 输入如下:

内核即会去执行函数:justfortest2 (参数是1 及7788)

输入字符串的协议如下:

         ^address:1,2,3,4,#           (objdump -S vmlinux 可以通过函数名得到函数地址,注意这里输入函数地址必须是: 0X......格式)

或     ^func_name:1,2,3,4,#     (func_name是你执行的函数名)

看下此内核模块:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/dma-mapping.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/time.h>
#include <linux/debugfs.h>

#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>

#include <linux/kallsyms.h>
#if 0
protocol:
echo "^justfortest1:1,#"  >  /sys/kernel/debug/anycall
echo "^justfortest1:1#"  >  /sys/kernel/debug/anycall
echo "^justfortest2:1,7788,#"  >  /sys/kernel/debug/anycall
step:
make TARGET_PRODUCT=jrdhz75_gb2  SUBDIRS=./samples/ifs  modules
 insmod ifs.ko
 rmmod ifs
 lsmod
#endif


typedef char (*my_f_0)();
typedef char (*my_f_1)(int);
typedef char (*my_f_2)(int,int);
typedef char (*my_f_3)(int,int,int);
typedef char (*my_f_4)(int,int,int,int);

#define PRINT_ADDR(index)  printk(KERN_ERR"func: %s address is :%p\r\n","hello"#index,hello_##index) 
#define define_func(index)   my_f_##index pfun_##index
#define select_func(index)   pfun_##index
#define select_func_define(index)  my_f_##index

define_func(0);
define_func(1);
define_func(2);
define_func(3);
define_func(4);

int atoi(const char *s);
static int runAny( char * buf)
{
    int i=1;
    unsigned char * tempBuf;
    unsigned char * addr;
    
    unsigned char  addrLen;
    unsigned long sum=0;
    unsigned int temp=0;

    unsigned char * para;
    unsigned char * myPara[4]={0x00,0x00,0x00,0x00};
    unsigned int  myPara_i[4];
    unsigned char paraCount;
    // the input format like this :  ^address:1,2,3,4,#
    // 

    tempBuf=buf;
    if(*tempBuf!='^')
    {
        printk(KERN_ERR"[anycall]bad begin char is %02x and should be %02x \r\n",*tempBuf,'^');
        return -1;
    }
    printk(KERN_ERR"[anycall]  begin with ^ is right \r\n");
    addr=++tempBuf;
    printk(KERN_ERR"[anycall]addr is  %02x %02x %02x\r\n",addr[0],addr[1],addr[2]);

    char  name[256]={0x00};
     for(i=0;*tempBuf!=':';i++)
    {
                     name[i]=*tempBuf;
		       addrLen++;
		       tempBuf++;
    }
    //  判断输入的是函数名或者直接是函数的绝对地址     
    if(addr[0]=='0' && (addr[1]=='x' || addr[1]=='X') )
    {
	         //get func addr 

		  addr=addr+2;     //added for 0xaddress
		  printk(KERN_ERR"[anycall]addrLen is  %d \r\n",addrLen);
		  for(i=0;i<addrLen;i++)
		  {
		      unsigned int ii=addr[addrLen-1-i];   // this is key!!
		      if(ii>='0' && ii <='9')
		      {
		         ii=ii-'0';
		      }
		      else if(ii>='a' && ii <='f')
		      {
		         ii=ii-'a'+10;
		      }
		      ii=ii<<(4*i);
		      sum=ii+sum;
		   }
    }
    else
    {
        // get func name
        printk(KERN_ERR"[anycall]get func name  and name is %s\r\n",name);
        // 通过函数名,得到函数的地址
	sum=(unsigned long)kallsyms_lookup_name(name);
    }
   
    printk(KERN_ERR"[anycall] finaly func addr is :%08x\r\n",sum);

    //
    //get the func parameters
    //unsigned char * myPara[4];
    // 获取函数的参数
    para=++tempBuf;
    for(paraCount=0;*tempBuf!='#' && paraCount<4 ;)
    {
       if(*tempBuf==',')
       {
          *tempBuf=0X00;
          tempBuf++;
          myPara[paraCount]=para;
          para=tempBuf;
          paraCount++;
          continue;
       }
       tempBuf++;
    }
    // debug parameters
    for(i=0;i<(sizeof(myPara)/sizeof(myPara[0]));i++)
    {
       if(!myPara[i])
       {
          break;
       }
        printk(KERN_ERR"[anycall]para %d is %s \r\n",i,myPara[i]);
       myPara_i[i]=atoi(myPara[i]);
        printk(KERN_ERR"[anycall]para %d int is %d \r\n",i,myPara_i[i]);
    }
       
    // 调用不同参数个数,目前最多只支持4个参数,且都是INT类型
    switch(paraCount)
    {
        case 0:
	       printk(KERN_ERR"[anycall]pfun_0.....\r\n");
 	      pfun_0=(my_f_0)sum;
             pfun_0();    
	     
     		break;
	case 1:
	      printk(KERN_ERR"[anycall]pfun_1.....\r\n");
             pfun_1=(my_f_1)sum;
             pfun_1(myPara_i[0]);    
	      
            break;
        case 2:
	      printk(KERN_ERR"[anycall]pfun_2.....\r\n");
             pfun_2=(my_f_2)sum;
             pfun_2(myPara_i[0],myPara_i[1]); 
	      
            break;
        case 3:
	       printk(KERN_ERR"[anycall]pfun_3.....\r\n");
             pfun_3=(my_f_2)sum;
             pfun_3(myPara_i[0],myPara_i[1],myPara_i[2]);    
		
            break;
        case 4:
	      printk(KERN_ERR"[anycall]pfun_4.....\r\n");
             pfun_4=(my_f_4)sum;
             pfun_4(myPara_i[0],myPara_i[1],myPara_i[2],myPara_i[3]); 
	
            break;
    }
    
    return 0;
}
// copy from preloader 
int atoi(const char *s)
{
    unsigned val=0;         /* value we're accumulating */
    int neg=0;                 /* set to true if we see a minus sign */
    while (*s==' ' || *s=='\t') {
        s++;
    }
    if (*s=='-') {
        neg=1;
        s++;
    } else if (*s=='+') {
        s++;
    }
    while (*s) {
        unsigned digit;
        digit = (*s - '0');
        val = val*10 + digit;
        s++;
    }
    if (neg) {
        return -val;
    }
    return val;
}

static ssize_t anycall_write(struct file *file, const char __user *user_buf,
			      size_t size, loff_t *ppos)
{
	char buf[64];
	int buf_size;
	int ret=0;

	buf_size = min(size, (sizeof(buf) - 1));
        //user拷贝数据到kernel
	if (strncpy_from_user(buf, user_buf, buf_size) < 0)
		return -EFAULT;
	buf[buf_size] = 0;

	if (ret < 0)
		return ret;
	// 逻辑处理
        runAny(buf);
        return size;
}
static const struct file_operations anycall_fops = {
	.owner		= THIS_MODULE,
	.write		= anycall_write,
};

static int __init anycall_init(void)
{
     
	struct dentry *dentry;
        //创建debugfs文件节点
        //你可以在 /sys/kernel/debug/cancall 找到它
	dentry = debugfs_create_file("anycall", S_IRUGO, NULL, NULL,
			     &anycall_fops);
	printk(KERN_ERR "[anycall]install  anycall  !!!!\n");;
	return 0;
}
static void __exit anycall_exit(void)
{
	 printk(KERN_ERR "[anycall]remove anycall  !!!!\n");
}
module_init(anycall_init)
module_exit(anycall_exit)
MODULE_LICENSE("GPL");


在简单介绍下使用步骤:

1  编译上述模块

                加入上述模块名字为 : anycall.c

                放在  kernel/drivers/char/anycall

                          kernel/drivers/char/anycall/下的makefile   中添加   : obj-m +=anycall.c

2     kernel/drivers/char/ 下makefile 中添加 : obj-m += anycall/    (注意反斜杠的意思代表目录的意思,千万不能少)

3     insmod anycall.ko

 good luck !

 需要完整模块代码,可以给我留邮箱地址:) 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值