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真不错。。
下章讲解决这个问题
程序员不会觉得与电脑相处很无聊。如果无聊,也会做点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真不错。。
下章讲解决这个问题
相关文章推荐
- rootkit for linux 6.截获skb
- rootkit for linux 8.大大杀器---“模拟法”获得字段偏移
- rootkit for linux 17.ip、tcp数据报
- rootkit for linux 18.tcp原理概述
- [zz]rootkit for linux 2.寻找入口点
- rootkit for linux 16.获取tcp可用端口号
- rootkit for linux 12.枚举目录
- rootkit for linux 2.寻找入口点
- rootkit for linux 19.山寨tcpip协议栈--连接的建立和初始化.doc
- rootkit for linux 7.大杀器---反汇编引擎xde
- rookit for linux 9.发送skb---使用工作队列
- rootkit for linux 10.小结
- rootkit for linux 15.寻找eth设备
- rootkit for linux 在csdn开源项目注册了。可以查看代码。
- rootkit for linux 11.“寻找入口点”的改进方法
- rootkit for linux 1.ring0下的溢出
- rootkit for linux 3.小窥数据链路层
- rootkit for linux 13.指令查找代码的简化
- rootkit for linux 14.file handle
- oracle 10G for linux常用命令