十一假期做西电的信安比赛(内核关linux部分)
2012-10-15 10:17
429 查看
内核关分为linux和windows两个部分,每部分三道题,因为linux内核个人觉得比较简单所以就首先做了一下。
第一题是输出一条内核信息,使用printk就可以,但是这个printk有一个等级,大概是这样,等级越低越容易被输出到终端上
可以使用这条语句来,查看输出终端,和记录log的设置,使用dmesg来查看内核信息
最后好象是虚拟机,会出现使用emergency等级都无法输出到终端的情况,这个貌似是虚拟机自己的问题,不要强求~
然后说一下makefile,这个一般会由IDE负责完成,但编译内核的时候还是需要自己写一下,使用make -n可以显示所有执行过程,
这是编译内核所需要的Makefile,详细的分析在这里http://blog.chinaunix.net/space.php?uid=20678786&do=blog&id=111321
$加括号代表了参数的调用,shell是make的内部函数,可以调用命令行uname -r就是取得当前版本
其中/lib/modules/2.6.13-study/build是指向linux内核源文件的一个符号链接,类似快捷方式的东西,
所以在这里执行了两次Makefile,一个是hello文件下的Makefile一个是linux内核源文件中的Makefile
最后面的modules应该就是声明是一个内核模块的编译
如果觉得写Makefile麻烦用这一句也可以,-I 就是include某些源码,-D是预定义宏,内核模块需要,
在源文件中定义也可以。
最后的源码比较简单,就没什么好说的了。
第二题是进程间的通信使用到一个叫做netlink的东西,这个东西内核态和用户态的实现是不一样的,直接上代码
涉及到的东西在这两篇文章里
第一题是输出一条内核信息,使用printk就可以,但是这个printk有一个等级,大概是这样,等级越低越容易被输出到终端上
Loglevel Description KERN_EMERG An emergency condition; the system is probably dead KERN_ALERT A problem that requires immediate attention KERN_CRIT A critical condition KERN_ERR An error KERN_WARNING A warning KERN_NOTICE A normal, but perhaps noteworthy, condition KERN_INFO An informational message KERN_DEBUG A debug messagetypically superfluous
可以使用这条语句来,查看输出终端,和记录log的设置,使用dmesg来查看内核信息
cat /proc/kernel/printk
最后好象是虚拟机,会出现使用emergency等级都无法输出到终端的情况,这个貌似是虚拟机自己的问题,不要强求~
然后说一下makefile,这个一般会由IDE负责完成,但编译内核的时候还是需要自己写一下,使用make -n可以显示所有执行过程,
这是编译内核所需要的Makefile,详细的分析在这里http://blog.chinaunix.net/space.php?uid=20678786&do=blog&id=111321
ifneq ($(KERNELRELEASE),) obj-m:=hello.o else KERNELDIR:=/lib/modules/$(shell uname -r)/build PWD:=$(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o *.mod.c *.mod.o *.ko endif首先不带任何参数的make调用,会执行第一个选项也就是default:后面的这一句,
$加括号代表了参数的调用,shell是make的内部函数,可以调用命令行uname -r就是取得当前版本
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules把这句话还原就是这样
make -C /lib/modules/2.6.13-study/build M=/home/study/prog/mod/hello/ modules
其中/lib/modules/2.6.13-study/build是指向linux内核源文件的一个符号链接,类似快捷方式的东西,
所以在这里执行了两次Makefile,一个是hello文件下的Makefile一个是linux内核源文件中的Makefile
最后面的modules应该就是声明是一个内核模块的编译
如果觉得写Makefile麻烦用这一句也可以,-I 就是include某些源码,-D是预定义宏,内核模块需要,
在源文件中定义也可以。
gcc -c -o hello.o -I/usr/src/linux/include -D__KERNEL__ -DMODULE hello.c
最后的源码比较简单,就没什么好说的了。
// //hello.c // #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> static int hello_init(void) { printk(KERN_EMERG "Module init: Hello!\n"); return 0; } static void hello_exit(void) { printk(KERN_EMERG "Module exit: bye-bye!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("DUAL_BSD"); MODULE_AUTHOR("RANDOM");
第二题是进程间的通信使用到一个叫做netlink的东西,这个东西内核态和用户态的实现是不一样的,直接上代码
涉及到的东西在这两篇文章里
http://blog.csdn.net/unbutun/article/details/5181607 http://www.cnblogs.com/hoys/archive/2011/04/09/2010788.html[/code]netlink的DOChttp://www.gridmpi.org/pspacer-2.1/libnl-1.0-pre6/group__nl.html
user.c#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <asm/types.h> #include <linux/netlink.h> #define MAX_MSGSIZE 1024 struct sockaddr_nl src_addr, dest_addr; struct msghdr msg; struct nlmsghdr *nlhdr = NULL; struct iovec iov; int sockfd; char buffer[100] = ""; int main(int argc, char* argv[]) { printf("In User Mod\n"); sockfd = socket(AF_NETLINK, SOCK_RAW, 17); memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); //self pid src_addr.nl_groups = 0; if(bind(sockfd, (struct sockaddr*)&src_addr, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(sockfd); } memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; //for kernel set 0 dest_addr.nl_groups = 0; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&(dest_addr); msg.msg_namelen = sizeof(dest_addr); nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); /* Fill the netlink message datapart */ printf("What do you want to say to kernel? \n"); scanf("%s",buffer); strcpy(NLMSG_DATA(nlhdr), buffer); /* Fill the netlink message header */ nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer)); nlhdr->nlmsg_pid = getpid(); /* self pid */ nlhdr->nlmsg_flags = 0; iov.iov_base = (void *)nlhdr; iov.iov_len = nlhdr->nlmsg_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; sendmsg(sockfd, &msg, 0); close(sockfd); return 0; }
kernel.c
static int __init init( void ) __init是参数前的修饰,说明此函数是一个init函数
消息接收使用了回调函数的方法//kernel.c #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/sched.h> #include <net/sock.h> #include <linux/netlink.h> #define NL_MYTEST 17 static struct sock *nlfd = NULL; void nl_data_recv(struct sk_buff *__skb) { struct sk_buff *skb; struct nlmsghdr *nlhdr; u32 pid; int ret; int len = NLMSG_SPACE(1024); char str[100]; printk(KERN_EMERG "KNL: Get data from sk_buff . \n"); skb = skb_get(__skb); if(skb->len >= NLMSG_SPACE(0)) { nlhdr = nlmsg_hdr(skb); printk(KERN_EMERG "KNL: Recv %s \n", (char*)NLMSG_DATA(nlhdr)); memcpy(str, NLMSG_DATA(nlhdr), sizeof(str)); //printk(KERN_EMERG "KNL: Recv %s \n",str); pid = nlhdr->nlmsg_pid; /*send process pid*/ printk(KERN_EMERG "KNL: Pid is %d \n", pid); kfree_skb(skb); skb = alloc_skb(len, GFP_ATOMIC); //allocate buffer if(!skb) { printk(KERN_EMERG "KNL: Allocate failed ! \n"); return; } } return; } static int __init init(void) { nlfd = netlink_kernel_create(&init_net, NL_MYTEST, 0, nl_data_recv, NULL, THIS_MODULE); if(!nlfd) { printk(KERN_EMERG "KNL: Can not create a netlink socket!\n"); return -1; } printk(KERN_EMERG "KNL: Create netlink socket ok!\n"); return 0; } static void __exit fini(void) { if(nlfd != NULL) { sock_release(nlfd->sk_socket); } printk(KERN_EMERG "KNL: Remove ok!\n"); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("RANDOM"); module_init(init); module_exit(fini);
Makefile 这个Makefile吧kernel.c和user.c在一起编译,只要加入gcc -o user user.c就行了MODULE_NAME :=linux_kernel_2 obj-m := $(MODULE_NAME).o KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) gcc -o user user.c clean: rm -fr *.ko *.o *.cmd sender $(MODULE_NAME).mod.c
第三题是使用一个叫做netfilter的东西,来过滤指定IP的包,是linux内核态的防火墙,用户态的叫做iptables
功能还是很强大的,可以实现一个自定义的IDS之类的
只要看这篇文档就好http://www.wenkudaquan.com/doc/20120416/73167.html
代码如下
kernel.c
这里需要注意一点,不同的linux版本skb结构体有变化
只要这样修改就可以了在linux 2.4~linux 2.6.20下: struct iphdr *ip = skb->nh.iph; 到了linux 2.6.22下,就变成了: struct iphdr *ip = ip_hdr(skb);#include <linux/module.h> #include <linux/kernel.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/ip.h> #include <linux/init.h> #include <linux/types.h> #include <linux/sched.h> #include <net/sock.h> #include <linux/netlink.h> #define NL_MYTEST 17 static struct sock *nlfd = NULL; static struct nf_hook_ops nfho; unsigned char *drop_ip = "\x7f\x00\x00\x01"; //127.0.0.1 //--------------------------------------------------------------------------- void nl_data_recv(struct sk_buff *__skb) { struct sk_buff *skb; struct nlmsghdr *nlhdr; u32 pid; int ret; int len = NLMSG_SPACE(1024); char str[100]; printk(KERN_EMERG "KNL: Get data from sk_buff . \n"); skb = skb_get(__skb); if(skb->len >= NLMSG_SPACE(0)) { nlhdr = nlmsg_hdr(skb); printk(KERN_EMERG "KNL: Recv %s \n", (char*)NLMSG_DATA(nlhdr)); drop_ip = (char*)NLMSG_DATA(nlhdr); memcpy(str, NLMSG_DATA(nlhdr), sizeof(str)); //printk(KERN_EMERG "KNL: Recv %s \n",str); pid = nlhdr->nlmsg_pid; /*send process pid*/ printk(KERN_EMERG "KNL: Pid is %d \n", pid); kfree_skb(skb); skb = alloc_skb(len, GFP_ATOMIC); //allocate buffer if(!skb) { printk(KERN_EMERG "KNL: Allocate failed ! \n"); return; } } return; } //--------------------------------------------------------------------------- unsigned int hook_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct sk_buff *sb = *skb; struct iphdr* iph = ip_hdr(skb); if (iph->saddr == *(unsigned int *)drop_ip) { // if (sb->nh.iph->saddr == drop_ip) { printk("Dropped packet from... %d.%d.%d.%d\n",*drop_ip, *(drop_ip + 1),*(drop_ip + 2), *(drop_ip + 3)); return NF_DROP; } else { return NF_ACCEPT; } } //============================================================================================ int init_module() { nlfd = netlink_kernel_create(&init_net, NL_MYTEST, 0, nl_data_recv, NULL, THIS_MODULE); if(!nlfd) { printk(KERN_EMERG "KNL: Can not create a netlink socket!\n"); return -1; } printk(KERN_EMERG "KNL: Create netlink socket ok!\n"); //--------------------------------------------------------------------------------------------- nfho.hook = hook_func; nfho.hooknum = 0; //define NF_IP_PRE_ROUTING nfho.pf = PF_INET; nfho.priority = NF_IP_PRI_FIRST; nf_register_hook(&nfho); return 0; } void cleanup_module() { if(nlfd != NULL) { sock_release(nlfd->sk_socket); } printk(KERN_EMERG "KNL: Remove ok!\n"); //--------------------------------------------------------------------------------------------- nf_unregister_hook(&nfho); }
user.c
和第二题进程通信一样,使用netlink#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <asm/types.h> #include <linux/netlink.h> #define MAX_MSGSIZE 1024 struct sockaddr_nl src_addr, dest_addr; struct msghdr msg; struct nlmsghdr *nlhdr = NULL; struct iovec iov; int sockfd; char buffer[100] = ""; int main(int argc, char* argv[]) { printf("In User Mod\n"); sockfd = socket(AF_NETLINK, SOCK_RAW, 17); memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); //self pid src_addr.nl_groups = 0; if(bind(sockfd, (struct sockaddr*)&src_addr, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(sockfd); } memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; //for kernel set 0 dest_addr.nl_groups = 0; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&(dest_addr); msg.msg_namelen = sizeof(dest_addr); nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); /* Fill the netlink message datapart */ printf("What IP do you want to drop? \n"); scanf("%s",buffer); strcpy(NLMSG_DATA(nlhdr), buffer); /* Fill the netlink message header */ nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(buffer)); nlhdr->nlmsg_pid = getpid(); /* self pid */ nlhdr->nlmsg_flags = 0; iov.iov_base = (void *)nlhdr; iov.iov_len = nlhdr->nlmsg_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; sendmsg(sockfd, &msg, 0); close(sockfd); return 0; }Makefileifneq ($(KERNELRELEASE),) obj-m:=linux_kernel_3.o else KDIR := /lib/modules/$(shell uname -r)/build all: gcc -o user.c user make -C $(KDIR) M=$(PWD) modules clean:make -C $(KDIR) M=$(PWD) cleanendif
相关文章推荐
- 十一假期做西电的信安比赛(渗透关)
- 【转载】在 Linux 下用户空间与内核空间数据交换的方式,第 2 部分: procfs、seq_file、debugfs和relayfs
- 《linux 内核完全剖析》 keyboard.S 部分代码分析(key_map)
- 在 Linux 下用户空间与内核空间数据交换的方式,第 2 部分: procfs、seq_file、debugfs和relayfs
- 使用 ftrace 调试 Linux 内核,第 1 部分
- 浅析 Linux 中的时间编程和实现原理,第 3 部分: Linux 内核的工作
- Linux的4个主要部分:内核、Shell、文件结构和实用工具
- Linux 2.6 内核中的最新电源管理技术综述,第 1 部分
- 使用 ftrace 调试 Linux 内核 —— 第 2 部分
- 在 Linux 下用户空间与内核空间数据交换的方式,第 2 部分: procfs、seq_file、debugfs和relayfs
- linux 内核的启动部分
- Linux 内核的同步机制,第 2 部分
- Linux系统优化部分内核参数调优中文注释
- Linux-2.6.32.2内核在mini2440上的移植(十一)---移植SD卡驱动
- Linux的内存管理主要分为两部分:物理地址到虚拟地址的映射,内核内存分配管理(主要基于slab)。
- 在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysfs、sysctl、系统调用和netlink
- Linux 内核中大页的实现与分析,第 1 部分
- (原创)Linux内核网络设备操作部分阅读笔记
- Linux内核网络部分控制流
- linux内核选项部分翻译