您的位置:首页 > 运维架构 > Linux

rootkit for linux 5.啥是skb

2008-11-11 21:40 393 查看
今天是光棍节。不知道我现在算不算光棍,呵呵。还是算吧,毕竟还是过着光棍的生活。典型地程序员的生活。

程序员不会觉得与电脑相处很无聊。如果无聊,也会做点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的定义如下:

struct sk_buff {

/* These two members must be first. */

struct sk_buff *next;

struct sk_buff *prev;

struct sock *sk;

ktime_t tstamp;

struct net_device *dev;

int iif;

/* 4 byte hole on 64 bit*/

struct dst_entry *dst;

struct sec_path *sp;

/*

* This is the control buffer. It is free to use for every

* layer. Please put your private variables there. If you

* want to keep them across layers you have to do a skb_clone()

* first. This is owned by whoever has the skb queued ATM.

*/

char cb[48];

unsigned int len,

data_len,

mac_len;

union {

__wsum csum;

struct {

__u16 csum_start;

__u16 csum_offset;

};

};

__u32 priority;

__u8 local_df:1,

cloned:1,

ip_summed:2,

nohdr:1,

nfctinfo:3;

__u8 pkt_type:3,

fclone:2,

ipvs_property:1;

__be16 protocol;

void (*destructor)(struct sk_buff *skb);

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)

struct nf_conntrack *nfct;

struct sk_buff *nfct_reasm;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

struct nf_bridge_info *nf_bridge;

#endif

#ifdef CONFIG_NET_SCHED

__u16 tc_index; /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

__u16 tc_verd; /* traffic control verdict */

#endif

#endif

#ifdef CONFIG_NET_DMA

dma_cookie_t dma_cookie;

#endif

#ifdef CONFIG_NETWORK_SECMARK

__u32 secmark;

#endif

__u32 mark;

sk_buff_data_t transport_header;

sk_buff_data_t network_header;

sk_buff_data_t mac_header;

/* These elements must be at the end, see alloc_skb() for details. */

sk_buff_data_t tail;

sk_buff_data_t end;

unsigned char *head,

*data;

unsigned int truesize;

atomic_t users;

};

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

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

为啥呢?

1.protocol字段

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

sky2_status_intr()

/* Process status response ring */

static int sky2_status_intr(struct sky2_hw *hw, int to_do)

{

....

skb = sky2_receive(dev, length, status);

if (unlikely(!skb)) {

sky2->net_stats.rx_dropped++;

goto force_update;

}

skb->protocol = eth_type_trans(skb, dev);

sky2->net_stats.rx_packets++;

sky2->net_stats.rx_bytes += skb->len;

dev->last_rx = jiffies;

#ifdef SKY2_VLAN_TAG_USED

if (sky2->vlgrp && (status & GMR_FS_VLAN)) {

vlan_hwaccel_receive_skb(skb,

sky2->vlgrp,

be16_to_cpu(sky2->rx_tag));

} else

#endif

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()

/**

* eth_type_trans - determine the packet's protocol ID.

* @skb: received socket data

* @dev: receiving network device

*

* The rule here is that we

* assume 802.3 if the type field is short enough to be a length.

* This is normal practice and works for any 'now in use' protocol.

*/

__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)

{

struct ethhdr *eth;

unsigned char *rawp;

skb->dev = dev;

skb_reset_mac_header(skb);

skb_pull(skb, ETH_HLEN);

eth = eth_hdr(skb);

if (is_multicast_ether_addr(eth->h_dest)) {

if (!compare_ether_addr(eth->h_dest, dev->broadcast))

skb->pkt_type = PACKET_BROADCAST;

else

skb->pkt_type = PACKET_MULTICAST;

}

/*

* This ALLMULTI check should be redundant by 1.4

* so don't forget to remove it.

*

* Seems, you forgot to remove it. All silly devices

* seems to set IFF_PROMISC.

*/

else if (1 /*dev->flags&IFF_PROMISC */ ) {

if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr)))

skb->pkt_type = PACKET_OTHERHOST;

}

if (ntohs(eth->h_proto) >= 1536)

return eth->h_proto;

rawp = skb->data;

/*

* This is a magic hack to spot IPX packets. Older Novell breaks

* the protocol design and runs IPX over 802.3 without an 802.2 LLC

* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This

* won't work for fault tolerant netware but does for the rest.

*/

if (*(unsigned short *)rawp == 0xFFFF)

return htons(ETH_P_802_3);

/*

* Real 802.2 LLC

*/

return htons(ETH_P_802_2);

}

EXPORT_SYMBOL(eth_type_trans);

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

以太网头就是这东西

struct ethhdr {

unsigned char h_dest[ETH_ALEN]; /* destination eth addr */

unsigned char h_source[ETH_ALEN]; /* source ether addr */

__be16 h_proto; /* packet type ID field */

} __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真不错。。

下章讲解决这个问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: