web analytics

Cross-compile Wireshark for Android

Wireshark (originally named Ethereal) is a free and open source packet analyzer. It is used for network troubleshooting, analysis, software and communications protocol development, and education. [1] It functions similar to pcap in terms of packet capturing, yet its major feature is the network protocol analysis which pcap cannot offer. According to the official site, “Wireshark is the world’s foremost network protocol analyzer.” [2] Though Wireshark has distribution on all major platforms: GNU/Linux, OS X, BSD, Solaris, some other Unix-like operating systems, and Microsoft Windows, there is no official distribution for Android or common embedded Linux platform. Some reader may know that for Android, there is an app called ``Shark for Root’’ on Google Play Store [3], but it is only an encapsulation of the tcpdump binary for Android.

I will discuss the major steps to cross-compile Wireshark libraries for the Android platform. This post is based on my experience compiling the Wireshark 2.0.x libraries for Android on Ubuntu 14.04/16.04.

To my best knowledge, this post is the first comprehensive guide on how to cross-compile the latest Wireshark for Android. But still, this is NOT an easy task, at all. You should anticipate to encounter new errors in your attempts, but be able to fix them with reasonable knowlege of compiling and programming. Only for tech-savvy people. (Don’t be intimidated, I am joking! :P)

DISCLAIMER: Though I believe that this post should work on most of the Linux distributions and subsequent Wireshark 2.0.x releases, and should be easily extended to other embedded Linux platforms, I cannot guarantee that it will work.

Prerequisites

Install required packages

In this post, I assume the building system is Ubuntu 16.04 64-bit. The following packages needs to be installed.

$ sudo apt-get update
$ sudo apt-get install build-essential
$ sudo apt-get install pkg-config automake autoconf libtool
$ sudo apt-get install zlib1g-dev byacc flex

Compile and install dependency libraries

If you directly starting to compile Wireshark using the cross compiler, most probably you will be stopped here:

...
checking for GLIB - version >= 2.16.0... no
*** Could not run GLIB test program, checking why...
*** The test program failed to compile or link. See the file config.log for the
*** exact error that occured. This usually means GLIB is incorrectly installed.
configure: error: GLib 2.16.0 or later distribution not found.

You can see, like many other open-source softwares, Wireshark depends on GLib. So you need to have GLib (>= 2.16.0) cross-compiled and installed in order to cross-compile Wireshark. The GLib cross-compilation process was discussed in detail in my previous blog (Cross-compile GLib for Android). Also make sure that GLib’s install location is included in the PATH, otherwise ld will complain that it cannot find -lglib-2.0.so and so on.

Download Wireshark sources

Download Wireshark sources from its official website. The latest stable version is 2.0.4. For example, the download link from North America CDN is: https://2.na.dl.wireshark.org/src/wireshark-2.0.4.tar.bz2.

Patch the Wireshark source codes

Because Android does not fully support some of the standard Unix functions, (such as endgrent()), we need to make several patches.

You will then be prompted that some function signatures do not match.

The first one is that some function signatures do not match their implementations. We need to change the function signature of void *DtdParseAlloc() at line 64 in epan/dfilter/dfilter-int.h. Change the input type from void *(*)(gsize) to void* (*mallocProc)(size_t). Same patch is needed for another occurance of it in file epan/dtd_parse.h, line 25.

The second patch we need to apply is in tools/lemon/Makefile.in at line 775. The lemon is one of Wireshark’s essential internal building tool. We need to change $(CC_FOR_BUILD) to its absolute path /usr/bin/cc assuming we are using the standard GCC install location. This is actually a bug in lemon’s environment configuration. The $(CC_FOR_BUILD) is supposed to be interpreted as the build system’s CC which is /usr/bin/cc, but in fact it will be wrongly taken as the host system’s CC which is the arm-eabi version when we cross-compile. That would be an error because lemon has to be built as the executable for the build system (x86_64 binary) to do the real work. Our patch will fix this issue.

The last one we need to patch is in wsutil/privileges.c at line 324. Here the wsutil library called endgrent() in privilege management. However, as of Android NDK r10e API level 19, there is no declaration of endgrent() in <sys/types.h> and grp.h. Thus we have to comment out this function call to fix it. It seems safe to do so, but I have not investigate this issue throughly. Interestingly, the Android NDK r12b API level 23 have better support of privileges in <sys/types.h> and grp.h and implemented this function. Unfortunately, however, as my previous post has pointed out, the attempt of cross-compiling GLib is not successful using Android NDK r12b. One possible way to keep endgrent() is that you get the GLib cross-compiled using NDK r10e, and then cross-compile wireshark using NDK r12b. This way, this patch can be probably skipped, but any complication raise from the inconsistent NDK versions is unknown.

Finally, if you are using NDK r10e, you can apply the following patch file without patch the source codes manually.

diff -Naur wireshark-2.0.4/epan/dfilter/dfilter-int.h wireshark-2.0.4-patched/epan/dfilter/dfilter-int.h
--- wireshark-2.0.4/epan/dfilter/dfilter-int.h  2016-06-07 14:27:44.000000000 -0400
+++ wireshark-2.0.4-patched/epan/dfilter/dfilter-int.h  2016-07-17 18:00:42.881276347 -0400
@@ -62,7 +62,9 @@
 extern dfwork_t *global_dfw;
 
 /* Constructor/Destructor prototypes for Lemon Parser */
-void *DfilterAlloc(void* (*)(gsize));
+// Change type to match function implementation
+// void *DtdParseAlloc(void *(*)(gsize));
+void *DfilterAlloc(void* (*mallocProc)(size_t));
 
 void DfilterFree(void*, void (*)(void *));
 void Dfilter(void*, int, stnode_t*, dfwork_t*);
diff -Naur wireshark-2.0.4/epan/dtd_parse.h wireshark-2.0.4-patched/epan/dtd_parse.h
--- wireshark-2.0.4/epan/dtd_parse.h    2016-06-07 14:27:46.000000000 -0400
+++ wireshark-2.0.4-patched/epan/dtd_parse.h    2016-07-17 18:01:40.185914348 -0400
@@ -25,7 +25,9 @@
 */
 
 extern void DtdParse(void*,int,dtd_token_data_t*,dtd_build_data_t*);
-extern void *DtdParseAlloc(void *(*)(gsize));
+// Change type to match function implementation
+// extern void *DtdParseAlloc(void *(*)(gsize));
+extern void *DfilterAlloc(void* (*mallocProc)(size_t));
 extern void DtdParseFree( void*, void(*)(void*) );
 extern void DtdParseTrace(FILE *TraceFILE, char *zTracePrompt);
 extern int Dtd_Parse_lex(void);
diff -Naur wireshark-2.0.4/tools/lemon/Makefile.in wireshark-2.0.4-patched/tools/lemon/Makefile.in
--- wireshark-2.0.4/tools/lemon/Makefile.in 2016-06-07 14:28:11.000000000 -0400
+++ wireshark-2.0.4-patched/tools/lemon/Makefile.in 2016-07-17 18:04:16.287926347 -0400
@@ -772,7 +772,7 @@
 
 
 lemon$(EXEEXT): lemon.c
-   $(CC_FOR_BUILD) -I$(top_builddir) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $?
+   /usr/bin/cc -I$(top_builddir) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $?
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff -Naur wireshark-2.0.4/wsutil/privileges.c wireshark-2.0.4-patched/wsutil/privileges.c
--- wireshark-2.0.4/wsutil/privileges.c 2016-06-07 14:27:47.000000000 -0400
+++ wireshark-2.0.4-patched/wsutil/privileges.c 2016-07-17 18:05:00.834188348 -0400
@@ -324,7 +324,8 @@
    } else {
        groupname = g_strdup("UNKNOWN");
    }
-   endgrent();
+   // As of Android NDK r10e API-19, endgrent() is not implemented
+   // endgrent();
    return groupname;
 }
 

Save it as wireshark-android.patch, and do

$ emacs wireshark-android.patch
$ patch -p0 < wireshark-android.patch

Cross-compile Wireshark

With all the prerequisite ready, we can begin cross-compiling wireshark.

First we need to set the environment variables to use Android cross-compilers, as the below script shows. The majority of the script is the same as the script we used for cross-compiling GLib. The only difference is the compiler flags part.

#!/bin/sh
# Android cross-compile environment setup script for Wireshark
# Author  : Zengwen Yuan
# Date    : 2016-07-16
# Version : 2.0

# All the sources and installed libs will be here
export DEV=${HOME}/dev

# This is just an empty directory where I want the built objects to be installed
export PREFIX=/opt/android

# Don't mix up .pc files from your host and build target
export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig

# GCC for Android version to use
# 4.9 is the only available version since NDK r11!
export GCC_VER=4.9

# The building system we are using -- Linux arch
export BUILD_SYS=x86_64-linux-gnu

# Set Android target API level
export ANDROID_API=19

# Set Android target arch
export ANDROID_ARCH=arm

# Set Android target name, according to Table 2 in
# https://developer.android.com/ndk/guides/standalone_toolchain.html
export ANDROID_TARGET=armv5te-none-linux-androideabi

# The cross-compile toolchain we use
export TOOLCHAIN=arm-linux-androideabi

# This is a symlink pointing to the latest Android NDK r12b
export NDK=${DEV}/android-ndk

# The path of standalone NDK toolchain
# Refer to https://developer.android.com/ndk/guides/standalone_toolchain.html
export NDK_TOOLCHAIN=${DEV}/android-ndk-toolchain

# Set Android Sysroot according to API and arch
export SYSROOT=${NDK_TOOLCHAIN}/sysroot
# this one is the absolute, prebuilt path
# export SYSROOT=${NDK}/platforms/android-${ANDROID_API}/arch-${ANDROID_ARCH}

# Binutils path
export CROSS_PREFIX=${NDK_TOOLCHAIN}/bin/${TOOLCHAIN}
# this one is the absolute, prebuilt path
# export CROSS_PREFIX=${NDK}/toolchains/${TOOLCHAIN}-${GCC_VER}/prebuilt/linux-x86_64/bin/${TOOLCHAIN}

# Non-exhaustive lists of compiler + binutils
export AR=${CROSS_PREFIX}-ar
export AS=${CROSS_PREFIX}-as
export LD=${CROSS_PREFIX}-ld
export NM=${CROSS_PREFIX}-nm
export CC=${CROSS_PREFIX}-gcc
export CXX=${CROSS_PREFIX}-g++
export CPP=${CROSS_PREFIX}-cpp
export CXXCPP=${CROSS_PREFIX}-cpp
export STRIP=${CROSS_PREFIX}-strip
export RANLIB=${CROSS_PREFIX}-ranlib
export STRINGS=${CROSS_PREFIX}-strings

# Needed for Wireshark building
export CC_FOR_BUILD="/usr/bin/cc"

# Make sure GLib's installation path is included in $PATH
export PATH=$PATH:${PREFIX}/bin:${PREFIX}/lib

# Set build flags
export CFLAGS="--sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I${PREFIX}/include"
export CPPFLAGS="--sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I${NDK_TOOLCHAIN}/include/c++/"
export LDFLAGS="${LDFLAGS} -L${SYSROOT}/usr/lib -L${PREFIX}/lib -L${NDK_TOOLCHAIN}/lib"

Then, run autogen.sh, if it succeeds you should expect to see the similar output. Fix any error according to its output.

$ ./autogen.sh
aclocal -I ./aclocal-fallback
libtoolize --copy --force
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and
libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree.
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
autoheader
automake --add-missing --gnu
autoconf

Now type "./configure [options]" and "make" to compile Wireshark.

Next, configure the parameters using the following.

$ ./configure \
	--host=${TOOLCHAIN} \
	--target=${TOOLCHAIN} \
	--build=${BUILD_SYS} \
	--prefix=${PREFIX} \
	--with-sysroot=${SYSROOT} \
	--without-plugins \
	--without-pcap \
	--disable-wireshark \
	--disable-tshark \
	--disable-editcap \
	--disable-capinfos \
	--disable-captype \
	--disable-mergecap \
	--disable-reordercap \
	--disable-text2pcap \
	--disable-dftest \
	--disable-randpkt \
	--disable-airpcap \
	--disable-dumpcap \
	--disable-rawshark \
	--disable-androiddump \
	"$@"

We just want the basic Wireshark libraries (libwireshark.so, libwsutil.so and libws) working for Android, so I disabled most of its plugins, including pcap. You may want to keep pcap by using with-pcap to capture packets if you do not have packet capture program for Android. You can tailor the configure parameters to your own need, but probably you need to handle more dependencies. For example, if you want to use pcap, you need to cross-compile libpcap as well and add -lpcap in the LDFLAGS. That will not be too hard because there’s lots of tutorials and ready scripts to cross-compile libpcap for Android.

Finally, cross-compile Wireshark and install it to ${PREFIX}:

$ make
$ make install

To make the process easier, you can also run the script that I made.

$ chmod 755 ./wireshark-cross-compile-android.sh
$ ./wireshark-cross-compile-android.sh

Epilogue

When I write this post, it has been seven months since my first successful attempt in cross-compiling the Wireshark libraries for Android. Back then I cross-compiled the Wireshark libraries for Android using Wireshark 2.0.1 version on Ubuntu 14.04. But honestly, I spent nearly three days compiling, haunted by various strange errors here and there. So I know how it would be useful to help save someone efforts worthing at least 10+ hours. I should have posted the detailed steps then, but I was so busy to do so. If I do not write it down now, many of the obstacles that I met and solutions I found online would have be forgotten. To ensure the documented steps are still working, I took the newest stable version of Wireshark which is 2.0.4, and re-built it on a clean installed Ubuntu 16.04 virtual machine. Now, I finally have found some time to document the detailed steps in this post. Hope it will be useful. Sincerely thanks to many of the helpful discussion threads in Wirshark-dev mailing lists, as well as other blog post on cross-compiling for Android.

References

Creative Commons License
This work by Zengwen Yuan is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
comments powered by Disqus