rootkit for linux 5.啥是skb

今天是光棍节。不知道我现在算不算光棍,呵呵。还是算吧,毕竟还是过着光棍的生活。典型地程序员的生活。

程序员不会觉得与电脑相处很无聊。如果无聊,也会做点rootkit来找找乐子。所以,鲁迅说过:世界上本是没有rootkit的,无聊的程序员多了,也就有了rootkit。

 

给个建议:调试还是用虚拟机吧,装个lfs。今天我的硬盘差点就坏了。所以换了个环境,改在win下了。现在的环境是LFS 6.3 linux 2.6.22.2。所以代码在 inline hook 那里有一点变。

 

玩过dota的都知道mkb是啥,但skb是个啥东西呢?

skb就是socket buffer。socket你总听过吧,就是网络编程要用到的那东西。skb在内核中就是代表一个数据包。简单地说法就是这样。它在linux 2.6.22.2的定义如下:

 

  1. struct sk_buff {
  2.     /* These two members must be first. */
  3.     struct sk_buff      *next;
  4.     struct sk_buff      *prev;
  5.     struct sock     *sk;
  6.     ktime_t         tstamp;
  7.     struct net_device   *dev;
  8.     int         iif;
  9.     /* 4 byte hole on 64 bit*/
  10.     struct  dst_entry   *dst;
  11.     struct  sec_path    *sp;
  12.     /*
  13.      * This is the control buffer. It is free to use for every
  14.      * layer. Please put your private variables there. If you
  15.      * want to keep them across layers you have to do a skb_clone()
  16.      * first. This is owned by whoever has the skb queued ATM.
  17.      */
  18.     char            cb[48];
  19.     unsigned int        len,
  20.                 data_len,
  21.                 mac_len;
  22.     union {
  23.         __wsum      csum;
  24.         struct {
  25.             __u16   csum_start;
  26.             __u16   csum_offset;
  27.         };
  28.     };
  29.     __u32           priority;
  30.     __u8            local_df:1,
  31.                 cloned:1,
  32.                 ip_summed:2,
  33.                 nohdr:1,
  34.                 nfctinfo:3;
  35.     __u8            pkt_type:3,
  36.                 fclone:2,
  37.                 ipvs_property:1;
  38.     __be16          protocol;
  39.     void            (*destructor)(struct sk_buff *skb);
  40. #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
  41.     struct nf_conntrack *nfct;
  42.     struct sk_buff      *nfct_reasm;
  43. #endif
  44. #ifdef CONFIG_BRIDGE_NETFILTER
  45.     struct nf_bridge_info   *nf_bridge;
  46. #endif
  47. #ifdef CONFIG_NET_SCHED
  48.     __u16           tc_index;   /* traffic control index */
  49. #ifdef CONFIG_NET_CLS_ACT
  50.     __u16           tc_verd;    /* traffic control verdict */
  51. #endif
  52. #endif
  53. #ifdef CONFIG_NET_DMA
  54.     dma_cookie_t        dma_cookie;
  55. #endif
  56. #ifdef CONFIG_NETWORK_SECMARK
  57.     __u32           secmark;
  58. #endif
  59.     __u32           mark;
  60.     sk_buff_data_t      transport_header;
  61.     sk_buff_data_t      network_header;
  62.     sk_buff_data_t      mac_header;
  63.     /* These elements must be at the end, see alloc_skb() for details.  */
  64.     sk_buff_data_t      tail;
  65.     sk_buff_data_t      end;
  66.     unsigned char       *head,
  67.                 *data;
  68.     unsigned int        truesize;
  69.     atomic_t        users;
  70. };

这数据结构相对task_struct来说还是好接受一点。不过也不是个省油的灯。你看那么多个#ifdef就知道怎么回事了。没错,我们遇上了老问题----怎么确定指定字段的偏移?哪怕在同一个版本的内核上,不同的编译的选项都有可能造成不同的偏移,更何况版本不同。

 

先抛开这个问题不管,看下我们到底需要什么字段先。我们要用到的sk_buff里的字段有三个 protocol,data,len。

为啥呢?

 

1.protocol字段

我们先来看一下网卡驱动封装skb的代码,skb就是从这里诞生的。

 

sky2_status_intr()

  1. /* Process status response ring */
  2. static int sky2_status_intr(struct sky2_hw *hw, int to_do)
  3. {
  4.     .... 
  5.    skb = sky2_receive(dev, length, status);
  6.    if (unlikely(!skb)) {
  7.     sky2->net_stats.rx_dropped++;
  8.     goto force_update;
  9.    }
  10.    skb->protocol = eth_type_trans(skb, dev);
  11.    sky2->net_stats.rx_packets++;
  12.    sky2->net_stats.rx_bytes += skb->len;
  13.    dev->last_rx = jiffies;
  14. #ifdef SKY2_VLAN_TAG_USED
  15.    if (sky2->vlgrp && (status & GMR_FS_VLAN)) {
  16.     vlan_hwaccel_receive_skb(skb,
  17.         sky2->vlgrp,
  18.         be16_to_cpu(sky2->rx_tag));
  19.    } else
  20. #endif
  21.     netif_receive_skb(skb);

sky2_receive里的内容大概就是从io网卡读取数据包,新alloc一个skb,然后把数据放进去。

怎样判断包是不是发给我们的rootkit的呢?我们要做读最少的数据,然后作出判断。

因为我们的hook的地方可是战略要地啊,相当于巴拿马海峡。所有skb在这里经过。如果你有8个cpu,那8个cpu的skb全部都是从我们的hook里经过的,我们的hook要是有一点拖拉,那管理员下载a片的速度就会减个几十kb/s。

如果管理员发现a片下载的速度慢了,那就坏了,肯定抄个底朝天也要把我们的hook抄出来。

所以这里判断速度一定要快。

 

sky2_status_intr() -> eth_type_trans()

  1. /**
  2.  * eth_type_trans - determine the packet's protocol ID.
  3.  * @skb: received socket data
  4.  * @dev: receiving network device
  5.  *
  6.  * The rule here is that we
  7.  * assume 802.3 if the type field is short enough to be a length.
  8.  * This is normal practice and works for any 'now in use' protocol.
  9.  */
  10. __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
  11. {
  12.  struct ethhdr *eth;
  13.  unsigned char *rawp;
  14.  skb->dev = dev;
  15.  skb_reset_mac_header(skb);
  16.  skb_pull(skb, ETH_HLEN);
  17.  eth = eth_hdr(skb);
  18.  if (is_multicast_ether_addr(eth->h_dest)) {
  19.   if (!compare_ether_addr(eth->h_dest, dev->broadcast))
  20.    skb->pkt_type = PACKET_BROADCAST;
  21.   else
  22.    skb->pkt_type = PACKET_MULTICAST;
  23.  }
  24.  /*
  25.   *      This ALLMULTI check should be redundant by 1.4
  26.   *      so don't forget to remove it.
  27.   *
  28.   *      Seems, you forgot to remove it. All silly devices
  29.   *      seems to set IFF_PROMISC.
  30.   */
  31.  else if (1 /*dev->flags&IFF_PROMISC */ ) {
  32.   if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))
  33.    skb->pkt_type = PACKET_OTHERHOST;
  34.  }
  35.  if (ntohs(eth->h_proto) >= 1536)
  36.   return eth->h_proto;
  37.  rawp = skb->data;
  38.  /*
  39.   *      This is a magic hack to spot IPX packets. Older Novell breaks
  40.   *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
  41.   *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
  42.   *      won't work for fault tolerant netware but does for the rest.
  43.   */
  44.  if (*(unsigned short *)rawp == 0xFFFF)
  45.   return htons(ETH_P_802_3);
  46.  /*
  47.   *      Real 802.2 LLC
  48.   */
  49.  return htons(ETH_P_802_2);
  50. }
  51. EXPORT_SYMBOL(eth_type_trans);

 

这个eth_type_trans 是判断数据链路层协议的。函数首先处理多播和广播和混杂模式的情况,这些情况我们没必要了解。这是通过以太网头的两个mac地址来判断的。

以太网头就是这东西

  1. struct ethhdr {
  2.  unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
  3.  unsigned char h_source[ETH_ALEN]; /* source ether addr */
  4.  __be16  h_proto;  /* packet type ID field */
  5. } __attribute__((packed));

你看,计算机网络的老师肯定讲过这东西吧,回忆起来没?

 

然后函数判断以太网头的协议字段是不是大于1536。我看了下,ETH_P_xxx有的是大于1536的,有的不是。如果是的话,就把skb->protocol设置为协议字段的内容。

然后函数判断是属于以太网的哪种类型。这也不用管。

 

我们要让内核在这里就把skb->protocol设为我们的协议号。这样,我们通过读skb->protocol就知道是不是我们的包了,就读16 bit而已。

 

 

2. len字段

 

这个字段没什么好说的了,首先要通过这个字段判断包的内容是否缺失。其次,我们处理完自己的包之后,要把它的len字段设置为0。这样,嗅探器就不会捡我们的垃圾了。

 

3. data字段

 

这个字段也没什么好说的了。指向数据的指针。

 

好了。知道了这些字段有什么用。我们咋得到它们的偏移呢?

 

有的人说“换成c语言就行了,直接取skb->protocol,多方便”

好,这idea真不错。。

 

下章讲解决这个问题

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值