linux驅動編寫過程中遇到的幾個問題及解決辦法
1)抓取qq號一直不成功,直接上程式剖析問題
payload的資料型別是char指標,也就是每個元素都是char型別的,qq號的字元為(0-9),並且第一個字元不能為0. ‘0’-‘9’對應的ASCII碼的16進製為30-39
而且得知qq號的儲存方式為16進位制,故這樣比較:if(payload[15+qqlen]>=0x30&&payload[15+qqlen]<=0x39)
但是剛開始並不知道數字前面加0x就可以用16進位制的形式比較,所以就用10進位制的形式比較,
首先我定義變數
unsigned int tmp = 0;
tmp = payload[i] - '0';
if(tmp >=30&&tmp <=39)
可是這樣就失敗了,抓不到qq號。
後來改成0x30的形式就可以抓到qq號了。
if(iphdr->protocol==6)
{
//printk("iphdr->saddr = %8x");
//tcp 包長度 ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4
tcphdr = (void *)iphdr + iphdr->ihl*4;
unsigned int tcp_len = ntohs(iphdr->tot_len) - 40;
// payload = (void*)skb->data + 40;
// skb->data ethdr+iphdr+
// payload = (void*)skb->data + 40 + 14;
//payload = tcphdr + 20;
payload = (char *)tcphdr + (char)sizeof(struct tcphdr);
unsigned int flag = 0;
unsigned int qqlen = 0;
unsigned int tcphdr_len;
if(tcp_len>=25){
if(payload[14]>0x30&&payload[14]<=0x39){
for(qqlen=0;qqlen<9;qqlen++){
if(payload[15+qqlen]>=0x30&&payload[15+qqlen]<=0x39){
flag = 1;
}
else{
flag = 0;
break;
}
}
}
int tmp;
if(flag==1){
printk("qq: \n");
for(qqlen=0;qqlen<10;qqlen++){
tmp = payload[14+qqlen]-'0';
printk("%d\n",tmp);
}
send_by_skb(payload,tcp_len);
printk("find a datapacket of qq\n");
}
}
(2)使用者空間地址成功傳到核心空間,但是在hook的回撥函式裡面不能對該地址指向的使用者空間的記憶體進行賦值
使用者空間的地址傳到核心空間成功:
copy_to_user(data, test_buf, 20);
memcpy(data,test_buf,20);
這兩句在my_ioctl回撥函式裡面分別可以成功,但是在my_hook回撥函式裡面卻不能,而且會導致虛擬機器崩潰。有可能是hook裡面的程式碼才是核心級別的程式碼,memcpy和copytouser許可權不夠全域性變數:unsigned char *data = NULL;
unsigned char *test_buf = "test if ti is ok for user space to translate address to kernel";
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{ }
my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
case MEMDEV_IOCGETSET:
data = (unsigned char *)arg;
copy_to_user(data, test_buf, 20);
memcpy(data,test_buf,20);
printk("data address is: %08x\n",data);
break;
}
(3)程式除錯心得
我在驅動程式裡面寫了一個全域性變數:unsigned char *data; 然後在初始化函式裡面為其動態申請一塊4KB的記憶體,並對其初始化為全0;在hook回撥函式裡面把鉤到的資料包賦值給data。之後執行使用者程式,將data的內容copy給使用者空間的記憶體。
但是在拷貝過程中出現了以下錯誤:
1.使用者程式手動執行一次不會出錯,如果寫成死迴圈就會崩潰
2.首先找使用者程式崩潰的原因,發現從核心第一次讀資料不會出錯,第二次就會出錯,且日誌顯示出錯在資料包長度那裡。後來在老師的建議下把資料包長度寫死,結果程式不崩潰。故第一個出錯的地方是資料包的長度。接著去找跟長度相關的語句,發現在copytouser時,長度只copy了1024個位元組,但是有的資料包的長度超過了1024,就會導致使用者程式指標越界(例如:明明說有1500個位元組,我卻讀不到),那麼使用者程式肯定會崩潰
3. 長度問題解決後,發現使用者程式除了讀的第一個資料包的內容不為0,後面讀到的資料包都是0. 然後在驅動程式的hook裡面,把鉤到的資料包本來要copy的第一個欄位寫死,看之後使用者讀到的是不是0.但是發現還是為0.此時可以斷定,驅動寫資料沒問題,所以肯定是使用者讀資料有問題。那麼去檢查使用者程式,發現定義的start全域性變數在while死迴圈外邊初始化為0,故每次進迴圈的時候start的值都不從0開始。
所以在這得到的教訓是:在哪裡用到變數在哪裡 賦值
4.得到的另一個教訓是:在核心寫資料是一個欄位一個欄位的寫,在使用者空間是一個欄位一個欄位的讀,所以為了確保每個欄位的讀寫正確,要把每個欄位寫成死的,然後迴圈多次看是否讀寫一致。
執行一次成功,並不代表執行多次成功。一次成功的時候bug可能沒觸發,多次執行就會觸發