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.
Contents
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://www.wireshark.org/download/src/all-versions/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 libwiretap.so
) 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¶
- [1] https://en.wikipedia.org/wiki/Wireshark
- [2] https://www.wireshark.org
- [3] https://play.google.com/store/apps/details?id=lv.n3o.shark&hl=en
- [4] https://gist.github.com/nddrylliog/4688209
- [5] http://linux.die.net/man/3/endgrent
- [6] http://lists.mindrot.org/pipermail/openssh-bugs/2013-April/012015.html
- [7] https://bugzilla.mindrot.org/attachment.cgi?id=2233&action=edit
- [8] https://www.google.com/search?q=cross+compile+wireshark