免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3060 | 回复: 2
打印 上一主题 下一主题

一个用kld替换内核函数指针的例子 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-05 19:35 |只看该作者 |倒序浏览
参照相关文档,写了(或者说是验证了)一个用kld修改函数指针,从而替换内核函数的例子,以icmp输入函数icmp_input()为例。这个简单的例子将内核中对icmp_input()的函数指针调用替换为对自己的new_icmp_input()的调用。我们可以在new_icmp_input()函数中对收到的报文进行自定义的解析处理。但是在本例中,我们不做任何处理,仅打印出一行调试信息,随后继续调用我们保存下来的系统原来的icmp_input()函数,从而完成正常的icmp输入处理。

工作目录下有两个文件,一个是Makefile,一个是我们的源文件icmphook.c。

Makefile文件的内容如下:

  1.       1    KMOD=   icmphook
  2.       2    SRCS=   icmphook.c
  3.       3
  4.       4    .include <bsd.kmod.mk>
复制代码


icmphook.c文件的内容如下:

  1.       1    #include <sys/types.h>
  2.       2    #include <sys/param.h>
  3.       3    #include <sys/module.h>
  4.       4    #include <sys/kernel.h>
  5.       5    #include <sys/conf.h>
  6.       6    #include <sys/protosw.h>
  7.       7    #include <sys/mbuf.h>
  8.       8    #include <netinet/in.h>
  9.       9   
  10.      10    extern struct protosw inetsw[];
  11.      11    extern u_char ip_protox[];
  12.      12    void new_icmp_input(struct mbuf *, int);
  13.      13    void *old_icmp_input;
  14.      14   
  15.      15    void new_icmp_input(struct mbuf * m, int off)
  16.      16    {
  17.      17        printf("new_icmp_input recv packet!\n");
  18.      18        ((void (*)(struct mbuf *, int))old_icmp_input)(m, off);
  19.      19    }
  20.      20   
  21.      21    static int
  22.      22    load(struct module *module, int cmd, void *arg)
  23.      23    {
  24.      24        int error = 0;
  25.      25   
  26.      26        switch(cmd) {
  27.      27        case MOD_LOAD:
  28.      28            uprintf("Replacing ICMP Input\n");
  29.      29            old_icmp_input = inetsw[ip_protox[IPPROTO_ICMP]].pr_input;
  30.      30            inetsw[ip_protox[IPPROTO_ICMP]].pr_input = new_icmp_input;
  31.      31            break;
  32.      32   
  33.      33        case MOD_UNLOAD:
  34.      34            uprintf("Restoring icmp_input\n");
  35.      35            inetsw[ip_protox[IPPROTO_ICMP]].pr_input = old_icmp_input;
  36.      36            break;
  37.      37   
  38.      38        default:
  39.      39            error = EINVAL;
  40.      40            break;
  41.      41        }
  42.      42        return(error);
  43.      43   
  44.      44    }
  45.      45   
  46.      46    DEV_MODULE(icmphook, load, NULL);
复制代码



在工作目录下make我们的模块:

  1. $make
  2. Warning: Object directory not changed from original /usr/home/xxx
  3. @ -> /usr/src/sys
  4. machine -> /usr/src/sys/i386/include
  5. cc -O2 -fno-strict-aliasing -pipe  -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I-   -I. -I@ -I@/contrib/altq -I@/../include -I/usr/include -finline-limit=8000 -fno-common  -mno-align-long-strings -mpreferred-stack-boundary=2  -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -ffreestanding -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual  -fformat-extensions -std=c99 -c icmphook.c
  6. ld  -d -warn-common -r -d -o icmphook.kld icmphook.o
  7. touch export_syms
  8. awk -f /sys/conf/kmod_syms.awk icmphook.kld  export_syms | xargs -J% objcopy % icmphook.kld
  9. ld -Bshareable  -d -warn-common -o icmphook.ko icmphook.kld
  10. objcopy --strip-debug icmphook.ko
  11. $
复制代码


此时,就会在工作目录中生成icmphook.ko文件,这就是我们的模块。以root权限加载它:

  1. #
  2. # kldload ./icmphook.ko
  3. Replacing ICMP Input
  4. #
复制代码


通过调试信息我们可以看到,这个模块已经成功加载了。现在我们就来测试它是否能正确工作。我做测试的FreeBSD是一台远程机器,现在我在本地ping它(用x.x.x.x隐去了真实的ip地址):

  1. C:\Documents and Settings\freebsd>ping x.x.x.x

  2. Pinging x.x.x.x with 32 bytes of data:

  3. Reply from x.x.x.x: bytes=32 time=14ms TTL=63
  4. Reply from x.x.x.x: bytes=32 time<10ms TTL=63
  5. Reply from x.x.x.x: bytes=32 time<10ms TTL=63
  6. Reply from x.x.x.x: bytes=32 time<10ms TTL=63

  7. Ping statistics for x.x.x.x:
  8.     Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
  9. Approximate round trip times in milli-seconds:
  10.     Minimum = 0ms, Maximum =  14ms, Average =  3ms

  11. C:\Documents and Settings\freebsd>
复制代码


我们可以看到,FreeBSD机器仍然可以ping通,这是因为我们在new_icmp_input()函数中调用了原来的icmp_input()函数,使得正常的icmp输入处理没有受到影响。由于我们测试的是远程机器,new_icmp_input()函数中的printf无法打印到本地屏幕上,我们可以使用dmesg来查看:

  1. #
  2. # dmesg
  3. ......
  4. new_icmp_input recv packet!
  5. new_icmp_input recv packet!
  6. new_icmp_input recv packet!
  7. new_icmp_input recv packet!
  8. #
复制代码


我们可以看到,dmesg正确的记录了我们在模块中添加的调试信息,说明我们的new_icmp_input()函数已经成功的“插入”了系统的icmp处理流程中。

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
2 [报告]
发表于 2006-06-05 21:14 |只看该作者
顶一个。最近比较忙,暂时没时间抽精力照顾BSD。

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
3 [报告]
发表于 2006-06-05 21:15 |只看该作者
看到这个"C:\Documents and Settings\freebsd"
友情再顶一个 娃哈哈哈
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP