我一直試圖攔截連接系統調用,試圖重寫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