2

用忽略configure的方式 交叉编译 静态链接 的 tcpdump

 2 years ago
source link: https://xuanxuanblingbling.github.io/ctf/tools/2021/08/16/tcpdump/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

用忽略configure的方式 交叉编译 静态链接 的 tcpdump

发表于 2021-08-16

| 分类于 CTF/tools

在开源软件的编译过程中,一般都是先使用configure检查编译环境并生成makefile,然后使用make进行编译。但是对于IoT安全研究来说,经常要遇到两个坎,一个是交叉编译,一个是静态链接。如果是单个c代码文件,类似shellcode或者后门,使用相应的交叉编译工具,在加上 -static 参数直接编译就好了,可是对于一个有configure以及makefile的软件,我们该怎么跨过这两个坎呢?一般的交叉编译都是在configure处做一系列的配置,这个配置虽然方便,但却令人困惑,我们配置的那些变量到底在哪生效的呢?如:交叉编译+静态编译。不过,最终编译还是makefile的事,所以其实可以在某些比较简单的情景下,直接忽略configure。由于make的命令行参数优先于makefile文件中的变量,所以可直接在make命令后加相应的参数,进而完成交叉编译和静态链接。本篇采用这种奇怪的方法,编译出5种架构(x86_64,arm,aarch64,mips,mipsel)下的静态链接的tcpdump程序。

纯净的ubuntu20.04,使用tuna换源,并安装好一些基础的工具,编译tcpdump需要的依赖软件,以及交叉编译工具链:

$ sudo apt install -y vim 
$ sudo vim /etc/apt/sources.list
$ sudo apt update
$ sudo apt install -y  gcc flex bison make
$ sudo apt install -y  gcc-aarch64-linux-gnu gcc-arm-linux-gnueabi gcc-mipsel-linux-gnu gcc-mips-linux-gnu

交叉编译工具链可以按照如下方法搜索:

$ sudo apt search arm | grep gcc 
$ sudo apt search mip | grep gcc 

tcpdump官网:https://www.tcpdump.org/

$ wget https://www.tcpdump.org/release/tcpdump-4.99.1.tar.gz
$ wget https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz
$ tar -xvzf ./tcpdump-4.99.1.tar.gz
$ tar -xvzf ./libpcap-1.10.1.tar.gz

首先本地编译出x86_64版本的,一个是为了生成正常的makefile,另外也是最开始的排错,如果本地编译都错了,就也先别交叉编译了。

编译libpcap

$ cd libpcap-1.10.1/
$ ./configure 
$ make
$ sudo make install
$ ls /usr/local/lib
libpcap.a  libpcap.so  libpcap.so.1  libpcap.so.1.10.1  pkgconfig  python3.8

最后的路径/usr/local/lib可以在makefile中看到:

prefix = /usr/local

如果我们在./configure时指明参数--prefix,最终就会落实到makefile这个变量中,所以也可以在make时直接使用参数prefix=/XXX完成最终install路径的更换:

$ make prefix=./test install
$ ls -al ./test/
total 32
drwxrwxr-x  6 xuanxuan xuanxuan  4096 Aug 15 12:03 .
drwxr-xr-x 14 xuanxuan xuanxuan 12288 Aug 15 12:03 ..
drwxr-xr-x  2 xuanxuan xuanxuan  4096 Aug 15 12:03 bin
drwxr-xr-x  3 xuanxuan xuanxuan  4096 Aug 15 12:03 include
drwxr-xr-x  3 xuanxuan xuanxuan  4096 Aug 15 12:03 lib
drwxrwxr-x  3 xuanxuan xuanxuan  4096 Aug 15 12:03 share

编译tcpdump

正常install完libpcap/usr/local后,tcpdump的./configure即可顺利生成makefile,然后直接make完成编译:

$ cd tcpdump-4.99.1/
$ ./configure 
$ make
$ file ./tcpdump
./tcpdump: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked

如果想编译一个静态链接的tcpdump可以在make时直接加入LDFLAGS='-static'参数:

$ make clean
$ make LDFLAGS='-static'
$ file ./tcpdump
./tcpdump: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked,

测试运行成功:

$ cp ./tcpdump ../tcpdump-x86_64
$ sudo ../tcpdump-x86_64
tcpdump-x86_64: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

这个LDFLAGS='-static'背后的道理必定在makefile中:

PROG = tcpdump

all: $(PROG)

$(PROG): $(OBJ) ../libpcap-1.10.1/libpcap.a $(LIBNETDISSECT)
        @rm -f $@
        $(CC) $(FULL_CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBNETDISSECT) $(LIBS)

所以其实不和其他编译代码冲突的话,改FULL_CFLAGS甚至CC也对可以,反正就是拼接:

$ make CC='gcc -static'
$ file ./tcpdump
./tcpdump: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked

因为我们之前本地编译以及成功了,所以makefile都已经生成好了,所以直接复用并修改参数即可

编译libpcap

在编译libpcap时要注意,这里make install的背后,并不是直接复制拷贝到目标目录,而是也存在着编译:

DYEXT = so

install: install-shared install-archive libpcap.pc pcap-config
        [ -d $(DESTDIR)$(libdir) ] || \
            (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir))
        [ -d $(DESTDIR)$(includedir) ] || \
            (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir))
        [ -d $(DESTDIR)$(includedir)/pcap ] || \


install-shared: install-shared-$(DYEXT)

install-shared-so: libpcap.so

libpcap.so: $(OBJ)
        @rm -f $@
        VER=`cat $(srcdir)/VERSION`; \
        MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \
        $(CC) $(LDFLAGS) -shared -Wl,-soname,$@.$$MAJOR_VER \
            -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS)

所以在make install时一样要替换CC变量:

这里我将编译出的libpcap库放在了:/home/xuanxuan/Desktop/tcpdump/libpcap/

$ cd libpcap-1.10.1/
$ make clean

$ make CC=arm-linux-gnueabi-gcc
$ make CC=arm-linux-gnueabi-gcc prefix=/home/xuanxuan/Desktop/tcpdump/libpcap/arm install
$ make clean

$ make CC=aarch64-linux-gnu-gcc
$ make CC=aarch64-linux-gnu-gcc prefix=/home/xuanxuan/Desktop/tcpdump/libpcap/aarch64 install
$ make clean

$ make CC=mips-linux-gnu-gcc
$ make CC=mips-linux-gnu-gcc prefix=/home/xuanxuan/Desktop/tcpdump/libpcap/mips install
$ make clean

$ make CC=mipsel-linux-gnu-gcc
$ make CC=mipsel-linux-gnu-gcc prefix=/home/xuanxuan/Desktop/tcpdump/libpcap/mipsel install
$ make clean

编译好后我们可以挨个看看指令集,均成功编译出对应架构的库:

$ cd ../libpcap

$ file ./arm/lib/libpcap.so.1.10.1 
./arm/lib/libpcap.so.1.10.1: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked,

$ file ./aarch64/lib/libpcap.so.1.10.1
./aarch64/lib/libpcap.so.1.10.1: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked

$ file ./mips/lib/libpcap.so.1.10.1
./mips/lib/libpcap.so.1.10.1: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked

$ file ./mipsel/lib/libpcap.so.1.10.1
./mipsel/lib/libpcap.so.1.10.1: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked

编译tcpdump

编译tcpdump时,需要libpcap库,具体来说就是:

  • 原理:编译时,静态链接需要.a的库,动态链接需要.so的库,二者都需要.h头文件。
  • 编译:在gcc中,额外的头文件使用-I参数,库代码使用-L参数。
  • 变量:在makefile的变量中,编译参数一般是CFLAGS,链接参数一般是LDFLAGS,编译器本身是CC

以arm为例,为完成交叉编译,make需要以下三个参数:

  • CC=arm-linux-gnueabi-gcc
  • CFLAGS='-I/home/xuanxuan/Desktop/tcpdump/libpcap/arm/include'
  • LDFLAGS='-L/home/xuanxuan/Desktop/tcpdump/libpcap/arm/lib/ -static'

最后编译:

$ cd tcpdump-4.99.1/
$ make clean

$ make CC=arm-linux-gnueabi-gcc CFLAGS='-I/home/xuanxuan/Desktop/tcpdump/libpcap/arm/include' LDFLAGS='-L/home/xuanxuan/Desktop/tcpdump/libpcap/arm/lib/ -static' 
$ file ./tcpdump
./tcpdump: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=2f4af2d4b19f3abff33868d363b4f51530245239, for GNU/Linux 3.2.0, with debug_info, not stripped
$ cp ./tcpdump ../tcpdump-arm
$ make clean

$ make CC=aarch64-linux-gnu-gcc CFLAGS='-I/home/xuanxuan/Desktop/tcpdump/libpcap/aarch64/include' LDFLAGS='-L/home/xuanxuan/Desktop/tcpdump/libpcap/aarch64/lib/ -static' 
$ file ./tcpdump
./tcpdump: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=5b833dabb3175ab4cc0578d0d1ee534924f1201b, for GNU/Linux 3.7.0, with debug_info, not stripped
$ cp ./tcpdump ../tcpdump-aarch64
$ make clean

$ make CC=mipsel-linux-gnu-gcc CFLAGS='-I/home/xuanxuan/Desktop/tcpdump/libpcap/mipsel/include' LDFLAGS='-L/home/xuanxuan/Desktop/tcpdump/libpcap/mipsel/lib/ -static' 
$ file ./tcpdump
./tcpdump: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, BuildID[sha1]=4f5688b096e43e24ef45f8f84590278ebc421c1d, for GNU/Linux 3.2.0, with debug_info, not stripped
$ cp ./tcpdump ../tcpdump-mipsel
$ make clean

$ make CC=mips-linux-gnu-gcc CFLAGS='-I/home/xuanxuan/Desktop/tcpdump/libpcap/mips/include' LDFLAGS='-L/home/xuanxuan/Desktop/tcpdump/libpcap/mips/lib/ -static' 
$ file ./tcpdump
./tcpdump: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, BuildID[sha1]=4f5688b096e43e24ef45f8f84590278ebc421c1d, for GNU/Linux 3.2.0, with debug_info, not stripped
$ cp ./tcpdump ../tcpdump-mips
$ make clean

使用qemu测试,均可运行:

$ cd ..
$ sudo apt install qemu-user
$ qemu-aarch64 ./tcpdump-aarch64 
Unknown host QEMU_IFLA type: 54
Unknown host QEMU_IFLA type: 32820
Unsupported ioctl: cmd=0x8946
tcpdump-aarch64: ens33: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Function not implemented
$ qemu-arm ./tcpdump-arm 
Unknown host QEMU_IFLA type: 54
Unknown host QEMU_IFLA type: 32820
Unsupported ioctl: cmd=0x8946
tcpdump-arm: ens33: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Function not implemented
$ qemu-mips ./tcpdump-mips
Unknown host QEMU_IFLA type: 54
Unknown host QEMU_IFLA type: 32820
Unsupported ioctl: cmd=0x8946
tcpdump-mips: ens33: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Function not implemented
$ qemu-mipsel  ./tcpdump-mipsel 
Unknown host QEMU_IFLA type: 54
Unknown host QEMU_IFLA type: 32820
Unsupported ioctl: cmd=0x8946
tcpdump-mipsel: ens33: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed: Function not implemented

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK