我一直试图拦截连接系统调用,试图重写tcp请求的目标ip地址。我想我成功地从符号表中检索到连接系统调用的地址并拦截它。我的结论是基于我的函数被内核调用的事实。但是,我不太确定我的代码是否实际上拦截了连接系统调用。为了验证我试图打印出源或目的地的IP地址。但每当我尝试访问套接字缓冲区结构时,内核崩溃。您可以在hijackConnect函数中看到该代码段,并将它们注释掉。我想知道我在做什么错误,我如何确保我真的拦截了tcp请求。如果可能,我想知道如何重写目标IP地址,以便我可以将http请求重定向到特定的网站。即使你不知道如何去做,我仍然很欣赏良好的指针和学习资源。访问套接字缓冲区结构时内核崩溃
声明:我不想做任何险恶的事情。这是针对内核黑客学校项目的,它必须在内核空间中完成。我的内核是3.16版,下面的代码是根据我自己的需要调整在线教程的。
#define DISABLE_WRITE_PROTECTION (write_cr0(read_cr0() & (~ 0x10000)))
#define ENABLE_WRITE_PROTECTION (write_cr0(read_cr0() | 0x10000))
static unsigned long **find_sys_call_table(void);
asmlinkage int hijackConnect(struct sock *sk, struct sockaddr *uaddr,int addr_len);
asmlinkage int (*original_sys_connect)(struct sock *, struct sockaddr *, int);
asmlinkage unsigned long **sys_call_table;
/* Initialisation routine */
int init_module(void)
{
sys_call_table = find_sys_call_table();
if(!sys_call_table) {
printk(KERN_ERR "Couldn't find sys_call_table.\n");
return -EPERM; /* operation not permitted; couldn't find general error */
}
DISABLE_WRITE_PROTECTION;
original_sys_connect = (void *) sys_call_table[SYS_CONNECT];
sys_call_table[SYS_CONNECT] = (unsigned long *) hijackConnect;
ENABLE_WRITE_PROTECTION;
printk(KERN_INFO "Connect system call is hijacked!\n");
return 0;
}
/* Cleanup routine */
void cleanup_module(void)
{
printk(KERN_INFO "Unhook hijacking\n");
/* Restore the original sys_open in the table */
DISABLE_WRITE_PROTECTION;
sys_call_table[SYS_CONNECT] = (unsigned long *) original_sys_connect;
ENABLE_WRITE_PROTECTION;
}
static unsigned long **find_sys_call_table() {
unsigned long offset;
unsigned long **sct;
for(offset = PAGE_OFFSET; offset < ULLONG_MAX; offset += sizeof(void *)) {
sct = (unsigned long **) offset;
if(sct[__NR_close] == (unsigned long *) sys_close)
return sct;
}
/*
* Given the loop limit, it's somewhat unlikely we'll get here. I don't
* even know if we can attempt to fetch such high addresses from memory,
* and even if you can, it will take a while!
*/
return NULL;
}
asmlinkage int hijackConnect(struct sock *sk, struct sockaddr *uaddr,int addr_len)
{
printk(KERN_INFO "Connect is called!\n");
/* struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
__be16 orig_sport, orig_dport;
__be32 daddr, nexthop, test;
orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
test = inet->inet_saddr;
//daddr = usin->sin_addr.s_addr;
printk(KERN_INFO "ADDRESS - %d", ntohl(test));*/
return (*original_sys_connect)(sk,uaddr,addr_len);
}
syscall函数的正确定义是'SYSCALL_DEFINE3(connect,int,fd,struct sockaddr __user *,uservaddr,int,addrlen)'。请注意,它的第二个参数uservaddr具有其__user类型的修饰符。这意味着给定的指针指向*用户地址空间*,并且应该通过特殊函数(如'copy_from_user')来访问。顺便说一句,探索origin系统调用可能会发现,它使用'move_addr_to_kernel'来处理该指针。 – Tsyvarev