Sunday, November 11, 2012

What is Cross Compilation ? Cross Compilation Demystified For Embedded Linux System

What is Cross Compilation ? Cross Compilation Demystified

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 11/11/2012

Cross compilation is a very important topic in embedded linux system design. It is
about to use a host machine to build a software which is going to be run in embedded
system. Besides, it is also about to harness the power of open source technology for
embedded applications. The compiler that is going to be used in cross compilation is
known as cross compiler. So, the cross compiler will be run in a standard x86 PC as
host machine, and generate binary for embedded platform such as ARM, MIPS, or PPC.
Let's illustrate with example.

Host:# cat hello.c
#include

main()
{
  printf("hello world\n");
}
Host:# gcc -o hello-x86 hello.c
Host:# file hello-x86
hello-x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.15, dynamically linked (uses shared libs), not stripped
Host:# ./hello-x86
hello world
Host:#

Well, we have a hello.c and we compile it with default gcc to generate a x86
compliant elf executable which is able to run on x86 based platform, as shown.
Nothing special here. However, for cross compilation, we are going to use platform
dependent cross compiler instead of the default gcc. As demonstration here, we are
going to use a MIPS based cross compiler to generate a executable which is able to
run on MIPS platform. Let's start.

Host:# ./mips-linux-gnu-gcc -EL -o hello-mips hello.c
Host:# file hello-mips
hello-mips: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1, for GNU/Linux 2.6.12, dynamically linked (uses shared libs), not stripped
Host:# ./hello-mips
bash: ./hello-mips: cannot execute binary file
Host:#

In this case, the mips-linux-gnu-gcc is the MIPS based cross compiler. The -EL flag
is to tell cross compiler to generate code which is compliant to little endian MIPS
architecture. Without the -EL flag, the cross compiler will generate default big
endian MIPS binary. Of course, when we try to run it on our x86 based host machine,
it should fail. However, if we run the executable in a MIPS platform, it should work
as expected.

tango3[~]# ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: seq=0 ttl=64 time=1.942 ms
64 bytes from 192.168.1.1: seq=1 ttl=64 time=1.090 ms
64 bytes from 192.168.1.1: seq=2 ttl=64 time=1.049 ms

--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 1.049/1.360/1.942 ms

tango3[~]# mkdir ./cawan
tango3[~]# mount -o nolock 192.168.1.1:/home/smp383/mips-4.3/bin/ ./cawan
tango3[~]# cd cawan
tango3[cawan]# ls -l hello-mips
-rwxr-xr-x    1 root     root         5870 Nov 10  2012 hello-mips*
tango3[cawan]# ./hello-mips
hello world
tango3[cawan]#

The 192.168.1.1 is host machine, when ping it from embedded system, it is alive.
Then, we create a local directory in the embedded system and mount it onto a
development directory at remote host machine by using NFS. The -o nolock is normally
added in embedded environment for compatibility issues. From development directory
of host machine, we found our hello-mips, and once we run it in MIPS console, it
works well as expected. How about the hello-x86 ? Let's verify.

tango3[cawan]# ./hello-x86
-sh: ./hello-x86: cannot execute binary file
tango3[cawan]#

Yes, it should not able to run in MIPS platform. How about big endian MIPS binary ?

Host:# ./mips-linux-gnu-gcc -o hello-mips-be hello.c
Host:# ls -l hello-mips-be
-rwxr-xr-x 1 root root 5870 2012-11-11 14:06 hello-mips-be
Host:# file hello-mips-be
hello-mips-be: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, for GNU/Linux 2.6.12, dynamically linked (uses shared libs), not stripped
Host:#

tango3[cawan]# ./hello-mips-be
-sh: ./hello-mips-be: cannot execute binary file
tango3[cawan]#

Yes, the big endian MIPS binary should not able to run in little endian MIPS
platform. Well, that is simple. But, how to cross compile an open source project in
order to let it run in our MIPS platform ? For this issue, we need to know more about
make tool, and we need to instruct the make tool to invoke the appropriate cross
compiler instead of the default gcc. Let us demonstrate with an open source project
such as Lame MP3 Encoder.

Host:# pwd
/home/smp383/mips-4.3/bin/lame-3.99.5
Host:# make --help
Usage: make [options] [target] ...
Options:
  -b, -m                      Ignored for compatibility.
  -B, --always-make           Unconditionally make all targets.
  -C DIRECTORY, --directory=DIRECTORY
                              Change to DIRECTORY before doing anything.
  -d                          Print lots of debugging information.
  --debug[=FLAGS]             Print various types of debugging information.
  -e, --environment-overrides
                              Environment variables override makefiles.
  -f FILE, --file=FILE, --makefile=FILE
                              Read FILE as a makefile.
  -h, --help                  Print this message and exit.
  -i, --ignore-errors         Ignore errors from commands.
  -I DIRECTORY, --include-dir=DIRECTORY
                              Search DIRECTORY for included makefiles.
  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg.
  -k, --keep-going            Keep going when some targets can't be made.
  -l [N], --load-average[=N], --max-load[=N]
                              Don't start multiple jobs unless load is below N.
  -L, --check-symlink-times   Use the latest mtime between symlinks and target.
  -n, --just-print, --dry-run, --recon
                              Don't actually run any commands; just print them.
  -o FILE, --old-file=FILE, --assume-old=FILE
                              Consider FILE to be very old and don't remake it.
  -p, --print-data-base       Print make's internal database.
  -q, --question              Run no commands; exit status says if up to date.
  -r, --no-builtin-rules      Disable the built-in implicit rules.
  -R, --no-builtin-variables  Disable the built-in variable settings.
  -s, --silent, --quiet       Don't echo commands.
  -S, --no-keep-going, --stop
                              Turns off -k.
  -t, --touch                 Touch targets instead of remaking them.
  -v, --version               Print the version number of make and exit.
  -w, --print-directory       Print the current directory.
  --no-print-directory        Turn off -w, even if it was turned on implicitly.
  -W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
                              Consider FILE to be infinitely new.
  --warn-undefined-variables  Warn when an undefined variable is referenced.

This program built for i486-pc-linux-gnu
Report bugs to
Host:#

Nothing related to cross compilation in make tool. But, the definition of cross
compiler should be in Makefile, which is generated by configuration tool. Let's
check now.

Host:# ./configure --help
`configure' configures lame 3.99.5 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.

Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
  -V, --version           display version information and exit
  -q, --quiet, --silent   do not print `checking ...' messages
      --cache-file=FILE   cache test results in FILE [disabled]
  -C, --config-cache      alias for `--cache-file=config.cache'
  -n, --no-create         do not create output files
      --srcdir=DIR        find the sources in DIR [configure dir or `..']

Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [PREFIX]

By default, `make install' will install all the files in
`/usr/local/bin', `/usr/local/lib' etc.  You can specify
an installation prefix other than `/usr/local' using `--prefix',
for instance `--prefix=$HOME'.

For better control, use the options below.

Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
  --libdir=DIR            object code libraries [EPREFIX/lib]
  --includedir=DIR        C header files [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
  --infodir=DIR           info documentation [DATAROOTDIR/info]
  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
  --mandir=DIR            man documentation [DATAROOTDIR/man]
  --docdir=DIR            documentation root [DATAROOTDIR/doc/lame]
  --htmldir=DIR           html documentation [DOCDIR]
  --dvidir=DIR            dvi documentation [DOCDIR]
  --pdfdir=DIR            pdf documentation [DOCDIR]
  --psdir=DIR             ps documentation [DOCDIR]

Program names:
  --program-prefix=PREFIX            prepend PREFIX to installed program names
  --program-suffix=SUFFIX            append SUFFIX to installed program names
  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names

System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-maintainer-mode  enable make rules and dependencies not useful
              (and sometimes confusing) to the casual installer
  --disable-dependency-tracking  speeds up one-time build
  --enable-dependency-tracking   do not reject slow dependency extractors
  --enable-shared[=PKGS]  build shared libraries [default=yes]
  --enable-static[=PKGS]  build static libraries [default=yes]
  --enable-fast-install[=PKGS]
                          optimize for fast installation [default=yes]
  --disable-libtool-lock  avoid locking (might break parallel builds)
  --disable-largefile     omit support for large files
  --enable-nasm              Allow the use of nasm if available
  --disable-rpath         do not hardcode runtime library paths
  --disable-cpml              Do not use Compaq's fast Math Library
  --disable-gtktest       Do not try to compile and run a test GTK program
  --enable-efence            Use ElectricFence for malloc debugging
  --disable-analyzer-hooks   Exclude analyzer hooks
  --disable-decoder          Exclude mpg123 decoder
  --disable-frontend         Do not build the lame executable default=build
  --enable-mp3x              Build GTK frame analyzer default=no
  --enable-mp3rtp            Build mp3rtp default=no
  --enable-dynamic-frontends Link frontends against shared libraries default=no
  --enable-expopt=full,norm  Whether to enable experimental optimizations
                             default=no
  --enable-debug=alot,norm   Enable debugging (disables optimizations)
                             default=no

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-pic              try to use only PIC/non-PIC objects [default=use
                          both]
  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
  --with-dmalloc          use dmalloc, as in
              http://www.dmalloc.com/dmalloc.tar.gz
  --with-gnu-ld           assume the C compiler uses GNU ld default=no
  --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
  --without-libiconv-prefix     don't search for libiconv in includedir and libdir
  --with-gtk-prefix=PFX   Prefix where GTK is installed (optional)
  --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)
  --with-fileio=lame         Use lame's internal file io routines default
               =sndfile      Use Erik de Castro Lopo's libsndfile
                             (no stdin possible currently)

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L if you have libraries in a
              nonstandard directory
  LIBS        libraries to pass to the linker, e.g. -l
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I if
              you have headers in a nonstandard directory
  CPP         C preprocessor
  PKG_CONFIG  path to pkg-config utility
  PKG_CONFIG_PATH
              directories to add to pkg-config's search path
  PKG_CONFIG_LIBDIR
              path overriding pkg-config's built-in search path
  SNDFILE_CFLAGS
              C compiler flags for SNDFILE, overriding pkg-config
  SNDFILE_LIBS
              linker flags for SNDFILE, overriding pkg-config

Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.

Report bugs to .
Host:#

Well, there are several items related to cross compilation here.

1. --host=HOST       cross-compile to build programs to run on HOST [BUILD]
2. CFLAGS      C compiler flags
3. --prefix=PREFIX         install architecture-independent files in PREFIX

The --host is about to let us to specify the prefix of the cross compiler being
used. For our case here, we should specify it as "mips-linux-gnu". Regarding the
CFLAGS, of course we need to specify -EL for our little endian MIPS architecture.
For --prefix, it is about to redefine the installation directory which is other
than /usr/local. As personal experience, I really not recommend to use this option.
The reason is the binary being generated at the path that specified in --prefix is
not as "friendly" as the counterpart option in make install DESTDIR. Let us start
to cross compile this Lame MP3 Encoder now.

Host:# ./configure --host="mips-linux-gnu" CFLAGS="-EL"
configure: WARNING: if you wanted to set the --build type, don't use --host.
    If a cross compiler is detected then cross compile mode will be used
checking build system type... i686-pc-linux-gnu
checking host system type... mips-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for mips-linux-gnu-strip... mips-linux-gnu-strip
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether to enable maintainer-specific portions of Makefiles... no
checking for style of include used by make... GNU
checking for mips-linux-gnu-gcc... mips-linux-gnu-gcc
...
...
config.status: creating ACM/ddk/Makefile
config.status: creating ACM/tinyxml/Makefile
config.status: creating lame.spec
config.status: creating mac/Makefile
config.status: creating macosx/Makefile
config.status: creating macosx/English.lproj/Makefile
config.status: creating macosx/LAME.xcodeproj/Makefile
config.status: creating vc_solution/Makefile
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands
Host:# make
make  all-recursive
make[1]: Entering directory `/home/smp383/mips-4.3/bin/lame-3.99.5'
Making all in mpglib
...
...
collect2: ld returned 1 exit status
make[3]: *** [libmp3lame.la] Error 1
make[3]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5/libmp3lame'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5/libmp3lame'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5'
make: *** [all] Error 2
Host:#

Unfortunately, make error. It might because of some source files might be in .cpp
and since we don't specify the CPPFLAGS yet, error should be incurred. Let's check
for any .cpp file.

Host:# find . -iname "*.cpp"
./ACM/DecodeStream.cpp
./ACM/AEncodeProperties.cpp
./ACM/tinyxml/xmltest.cpp
./ACM/tinyxml/tinyxmlparser.cpp
./ACM/tinyxml/tinyxmlerror.cpp
./ACM/tinyxml/tinyxml.cpp
./ACM/main.cpp
./ACM/ACM.cpp
./ACM/ADbg/ADbg.cpp
./ACM/ACMStream.cpp
./Dll/Example.cpp
./dshow/REG.CPP
./dshow/Mpegac.cpp
./dshow/PropPage.cpp
./dshow/aboutprp.cpp
./dshow/PropPage_adv.cpp
./dshow/Encoder.cpp
Host:#

Yes, there are some .cpp files in certain subdirectories. Let's specify CPPFLAGS and
try again.

Host:# make distclean
Host:# ./configure --host="mips-linux-gnu" CFLAGS="-EL" CPPFLAGS="-EL"
Host:# make

However, the error still there. Now, we suspect we are missing LDFLAGS. Specify it
and try again.

Host:# make distclean
Host:# ./configure --host="mips-linux-gnu" CFLAGS="-EL" CPPFLAGS="-EL" LDFLAGS="-EL"
Host:# make

Unfortunately, the error is still. So, we doubt the Makefile being generated by
configure tool did not specify the options of cross compiler properly. In other
words, if we redefine the CFLAGS, CPPFLAGS, or LDFLAGS, the default options might
be overrode, and this might be the reason to cause the error. Let us ignore those
CFLAGS, CPPFLAGS, and LDFLAGS, and we specify the -EL option in CC now.

Host:# make distclean
Host:# ./configure --host="mips-linux-gnu" CC="mips-linux-gnu-gcc -EL"
Host:# make

Excellent, it is done. Now, let us make a comparison between the cross compilation
options being generated by those 2 configuration methods as aforementioned.

//////////////////////////////////////////////////////////////////////////////////

Host:# ./configure --host="mips-linux-gnu" CFLAGS="-EL" CPPFLAGS="-EL" LDFLAGS="-EL"

Makefile:
...
...
CC = mips-linux-gnu-gcc
CCDEPMODE = depmode=gcc3
CFLAGS =  -Wall -pipe -EL
CONFIG_DEFS =
CONFIG_MATH_LIB = -lm
CPP = mips-linux-gnu-gcc -E
CPPFLAGS = -EL
...
...

//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////

Host:# ./configure --host="mips-linux-gnu" CC="mips-linux-gnu-gcc -EL"

Makefile:
...
...
CC = mips-linux-gnu-gcc -EL
CCDEPMODE = depmode=gcc3
CFLAGS = -O3 -fomit-frame-pointer -ffast-math -Wall -pipe
CONFIG_DEFS =
CONFIG_MATH_LIB = -lm
CPP = mips-linux-gnu-gcc -EL -E
CPPFLAGS =
...
...

//////////////////////////////////////////////////////////////////////////////////

Apparently, some default options in CFLAGS have been overrode if we redefine the
CFLAGS ourself. So, it is important to note that we should avoid to redefine those
compilation and link flag in doing cross compilation. Now, the binaries are ready
for us, and we are not going to install it into /usr/local/. Because we are doing
cross compilation now, we expect the binaries will be concentrated in a special
directory in our development directory. Yes, for this purpose, we can make use of
DESTDIR option in doing make install. Let's check.

Host:# make install DESTDIR=$PWD/cawanlame
Making install in mpglib
make[1]: Entering directory `/home/smp383/mips-4.3/bin/lame-3.99.5/mpglib'
make[2]: Entering directory `/home/smp383/mips-4.3/bin/lame-3.99.5/mpglib'
make[2]: Nothing to be done for `install-exec-am'.
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5/mpglib'
make[1]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5/mpglib'
Making install in libmp3lame
...
...
make[2]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5'
make[1]: Leaving directory `/home/smp383/mips-4.3/bin/lame-3.99.5'
Host:# cd cawanlame
Host:# ls
usr
Host:# cd usr
Host:# ls
local
Host:# cd local
Host:# ls
bin  include  lib  share
Host:#

Well, the lame executable and shared library should be in bin and lib folders,
respectively. Let's verify.

Host:# cd bin
Host:# ls -l male
ls: cannot access male: No such file or directory
Host:# cd ..
Host:# cd bin
Host:# ls -l lame
-rwxr-xr-x 1 root root 409167 2012-11-11 16:10 lame
Host:# cd ..
Host:# cd lib
Host:# ls -l
total 768
-rw-r--r-- 1 root root 429192 2012-11-11 16:10 libmp3lame.a
-rwxr-xr-x 1 root root    943 2012-11-11 16:10 libmp3lame.la
lrwxrwxrwx 1 root root     19 2012-11-11 16:10 libmp3lame.so -> libmp3lame.so.0.0.0
lrwxrwxrwx 1 root root     19 2012-11-11 16:10 libmp3lame.so.0 -> libmp3lame.so.0.0.0
-rwxr-xr-x 1 root root 343465 2012-11-11 16:10 libmp3lame.so.0.0.0
Host:#

Nice, we are at the right point now. Let us make sure the binaries are really for
little endian MIPS platform.

Host:# cd bin
Host:# file lame
lame: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1, for GNU/Linux 2.6.12, dynamically linked (uses shared libs), not stripped
Host:# cd ..
Host:# cd lib
Host:# ls -l
total 768
-rw-r--r-- 1 root root 429192 2012-11-11 16:10 libmp3lame.a
-rwxr-xr-x 1 root root    943 2012-11-11 16:10 libmp3lame.la
lrwxrwxrwx 1 root root     19 2012-11-11 16:10 libmp3lame.so -> libmp3lame.so.0.0.0
lrwxrwxrwx 1 root root     19 2012-11-11 16:10 libmp3lame.so.0 -> libmp3lame.so.0.0.0
-rwxr-xr-x 1 root root 343465 2012-11-11 16:10 libmp3lame.so.0.0.0
Host:# file libmp3lame.so.0.0.0
libmp3lame.so.0.0.0: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, not stripped
Host:#

Yes, we got what we want. Let's run it in MIPS environment now.

tango3[cawan]# cd lame-3.99.5
tango3[lame-3.99.5]# cd cawanlame/
tango3[cawanlame]# cd usr/
tango3[usr]# cd local/
tango3[local]# cd bin
tango3[bin]# ./lame
LAME 32bits version 3.99.5 (http://lame.sf.net)

usage: ./lame [options] [outfile]

    and/or can be "-", which means stdin/stdout.

Try:
     "./lame --help"           for general usage information
 or:
     "./lame --preset help"    for information on suggested predefined settings
 or:
     "./lame --longhelp"
  or "./lame -?"              for a complete options list

tango3[bin]#

Good, the lame executable running well in our MIPS platform. In order to get better
experience in running executable in MIPS platform, let us use the lame executable to
compress an .wav file into .mp3 file now. Of course the process might take quite a
while because we are running the compression process in a resource constraint
embedded platform.

tango3[bin]# ./lame --help
LAME 32bits version 3.99.5 (http://lame.sf.net)

usage: ./lame [options] [outfile]

    and/or can be "-", which means stdin/stdout.

RECOMMENDED:
    lame -V2 input.wav output.mp3

OPTIONS:
    -b bitrate      set the bitrate, default 128 kbps
    -h              higher quality, but a little slower.  Recommended.
    -f              fast mode (lower quality)
    -V n            quality setting for VBR.  default n=4
                    0=high quality,bigger files. 9=smaller files
    --preset type   type must be "medium", "standard", "extreme", "insane",
                    or a value for an average desired bitrate and depending
                    on the value specified, appropriate quality settings will
                    be used.
                    "--preset help" gives more info on these

    --help id3      ID3 tagging related options

    --longhelp      full list of options

    --license       print License information

tango3[bin]# ./lame -V2 luohua.wav luohua.mp3
LAME 3.99.5 32bits (http://lame.sf.net)
Using polyphase lowpass filter, transition band: 18671 Hz - 19205 Hz
Encoding luohua.wav to luohua.mp3
Encoding as 44.1 kHz j-stereo MPEG-1 Layer III VBR(q=2)
    Frame          |  CPU time/estim | REAL time/estim | play/CPU |    ETA
  6253/6253  (100%)|    1:52/    1:52|    5:37/    5:37|   1.4538x|    0:00
 32 [  81] **                                                                 
 40 [   0]                                                                    
 48 [   0]                                                                    
 56 [   1] %                                                                  
 64 [   2] %                                                                  
 80 [   5] %                                                                  
 96 [   2] %                                                                  
112 [   1] *                                                                  
128 [  73] %*                                                                 
160 [2410] %%%%%************************************************              
192 [3126] %%%%%%%%%%%%%%%%%%%%%%%%********************************************
224 [ 295] %%*****                                                            
256 [ 197] %%***                                                              
320 [  60] %*                                                                 
-------------------------------------------------------------------------------
   kbps        LR    MS  %     long switch short %                            
  181.4       23.4  76.6        95.6   2.4   2.0                              
Writing LAME Tag...done
ReplayGain: -8.0dB
tango3[bin]# ls
lame*       luohua.mp3  luohua.wav

Well, the luohua.mp3 is generated. Let us play it with a player. Nice, it sounds
really good.


pdf version:

http://www.scribd.com/doc/112842652/What-is-Cross-Compilation-Cross-Compilation-Demystified


Friday, November 9, 2012

What is Ramdisk ? Ramdisk Demystified From The Perspective of Embedded System

What is Ramdisk ? Ramdisk Demystified From The Perspective of Embedded System

by cawan (cawan[at]ieee.org, chuiyewleong[at]hotmail.com)

on 10/11/2012

From embedded system point of view, ramdisk is an image file to be copied into a
specific logical address in a flash chip. So, when the system boot up, the bootloader
can duplicate the portion of flash space with the content of image file into RAM.
From that onwards, the kernel portion will be decompressed on the fly in RAM and
being executed once the decompression process completed. On the other hand, the file
system portion will stay in RAM as is where is basis. In most of the times, it is
represented in rootfs format, which is a special instance of ramfs or tmpfs. Refer to
the following link for further description about rootfs, ramfs, and tmpfs.

http://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt

Well, the file system is already in the RAM now, and it is in the format of rootfs.
So, what the kernel need to do now is to mount onto it and start to make use of it.
Let us verify it.

tango3[~]# mount
rootfs on / type rootfs (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw)
tmpfs on /tmp type tmpfs (rw)
/dev/sigmblockg on /app type squashfs (ro)
/dev/sigmblockh on /run type ext3 (rw,data=ordered)
tango3[~]#

Nice, the file system is mounted to root in the format of rootfs, with read and write
(rw) permission. However, any content being updated or altered is volatile. In other
words, any altered file in rootfs will be reverted to original state after reboot.
Yes, it should be, because the everything is in the RAM, which is volatile. Let verify.

tango3[~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:100:sync:/bin:/bin/sync
mail:x:8:8:mail:/var/spool/mail:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
operator:x:37:37:Operator:/var:/bin/sh
sshd:x:103:99:Operator:/var:/bin/sh
nobody:x:99:99:nobody:/home:/bin/sh
default:x:1000:1000:Default non-root user:/home/default:/bin/sh
tango3[~]# echo cawan > /etc/passwd
tango3[~]# cat /etc/passwd        
cawan
tango3[~]#

We reboot the system now. After reboot, we will check the content of /etc/passwd again.

tango3[~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:100:sync:/bin:/bin/sync
mail:x:8:8:mail:/var/spool/mail:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
operator:x:37:37:Operator:/var:/bin/sh
sshd:x:103:99:Operator:/var:/bin/sh
nobody:x:99:99:nobody:/home:/bin/sh
default:x:1000:1000:Default non-root user:/home/default:/bin/sh
tango3[~]#

Yes, it has been reverted.

In additional, as side topic, the partition /dev/sigmblockg of flash chip has been
mounted onto /app in the format of squashfs, with read only (ro) permission, where
the squashfs itself is a read only file system with high compression rate. Besides,
the partition /dev/sigmblockh is also in flash chip. However, it is mounted on /run
in the format of ext3, with read and write permission. As a file system format with
read and write support, the ext3 partition allows data to be altered or modified and
keep in intact after reboot. An important point to take note here, the so called read
only file system of squashfs on /app only means the file system itself is read only,
but not the case of partition /dev/sigmblockg. From the angle of device file, the
partition /dev/sigmblockg is still free to write by any appropriate shell command.
Let's verify.

tango3[~]# echo cawan > /app/cawan
-sh: /app/cawan: Read-only file system
tango3[~]#

Yes, /app is really a read on squashfs file system. How about /run ?

tango3[~]# echo cawan > /run/cawan
tango3[~]# cat /run/cawan
cawan
tango3[~]#

As expected, /run is writable. Let's reboot the system now, the /run/cawan should be
still there after reboot.

tango3[~]# cat /run/cawan
cawan
tango3[~]#

Nice, the /run/cawan is still there as expected. So, the concept of ramdisk should
be clear now.

pdf version:

http://www.scribd.com/doc/112759625/What-is-Ramdisk-Ramdisk-Demystified-From-the-Perspective-of-Embedded-System


Embedded Linux System Design From Software Perspective

Embedded Linux System Design From Software Perspective

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 9/11/2012

In embedded linux system design, the software concepts and issues are normally a
little bit confusing and hard to understand. However, it is actually simple if we
try to categorize it different abstraction layer. In general, there are only 3
pieces of image files to be generated in order to build an embedded linux system.

1. Bootloader
2. System (kernel + rootfs)
3. User Application

Bootloader has 2 functions.

1. Initialize Peripherals
2. Bring Up the Kernel

Besides, in most of the times, bootloader will come with a monitoring and
configuration interface to let users have certain level of control to the hardware,
such as,

1. Check Peripherals Status (NAND Flash exist ?)
2. Perform Operations to Peripherals
     - Erase / Format NAND Flash
     - Load Image File from TFTP or NFS
     - Burn Image File to NAND Flash
     - Verify Flash Checksum
     - Make Partition to Flash
3. Determine How to Bring Up the Kernel (TFTP / Flash ?)

Bootloader is normally processor architecture dependent, for example, ARM is normally
bind to u-boot.

System image is the combination of kernel image and rootfs image. Kernel image is
something to be loaded by bootloader into memory, and run in memory. On the other
hand, rootfs image is the archive of necessary files and directories to run the
system. For those system default applications with no requirement to be updated can
be stored in rootfs. Besides, it is important to note that rootfs is normally run as
ramdisk. For those who new to the concept of ramdisk, please refer my next paper
about ramdisk explaination.

User application is normally an executable to be run by the system to provide
services. It also has requirement to be updated frequently. The user application
package is used to be archived as a specific file system image file, for example
SquashFS, which is going to be copied onto the embedded system. So, it will be
mounted by the system and run accordingly.

Well, based on those 3 pieces of software image files, we suppose have no problem to
build a fully functional embedded system now, but how ? Yes, this is the main issue
to be discussed in this paper. Bootloader image is always put into block 0 of the
flash chip. In terms of address abstraction, the unit in block is the lowest level,
which is close to physical layer. Block 0 is defined as the first block of the flash
chip, which is almost similar to the first sector of hard disk. So, bootloader image
should be located at this area to ease the processor to start at the very initial
boot stage. For the case of hard disk, the first sector is usually for master boot
record (mbr). Fine, once the system has successfully initialized by the bootloader,
it should understand logical address, which has higher abstraction level than the
physical address in the unit of block. So, with logical address, the respective
associated physical block can be assigned at any location within the flash chip.
Thus, the system image should place at a specific logical address, which is making
sense to the bootloader. Hence, the bootloader can easily bring up the kernel and
mount to the rootfs as ramdisk. Well, once the system is up with kernel and rootfs,
it should understand the concept of file system right now. The user application image
is usually placed at certain partition of the flash chip, and as all of us knew,
partition is expressed as device file in /dev directory. So, the user application
image should map onto the partition and get ready to be mounted and run by the
system. As comparison to bootloader and system image, the user application image has
highest abstraction level which is represented as a device file in file system. So,
as summary, bootloader has lowest abstraction level (in the unit of block), following
by system image (in the unit of logical address), and finally the user application
image (in the unit of file system).

pdf version:

http://www.scribd.com/doc/112733417/Embedded-Linux-System-Design-From-Software-Perspective

Wednesday, November 7, 2012

How To Check For ASLR And NX Features Of Embedded Linux System

How To Check For ASLR And NX Features Of Embedded Linux System

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 7/11/2012

In exploiting embedded linux system, it is crucial to ensure ASLR and NX features are
enabled or not. If both of the features are enabled, then we need to apply ROP with
offset comparison technique in creating shellcode to work with the exploit. If any of
them is disabled, then it is much simpler to be compromised. Let's start from how to
check an embedded linux system has ASLR and NX features enabled or not first. For ASLR,
it is really simple by checking the user and kernel modules layout in memory before
and after the system reboot. Let's show with an example.

Before Reboot,

tango3[bin]# cat /proc/modules
em8xxx 935488 0 - Live 0xc01b8000 (PF)
llad 144800 1 em8xxx, Live 0xc00b0000 (P)
sigmablock 70976 3 - Live 0xc002c000 (P)
tango3[bin]# cat /proc/self/maps
00400000-004b0000 r-xp 00000000 00:01 387        /bin/busybox
004bc000-004c0000 rw-p 000ac000 00:01 387        /bin/busybox
004c0000-004c4000 rwxp 004c0000 00:00 0          [heap]
2aaa8000-2aac8000 r-xp 00000000 00:01 624        /lib/ld-2.8.so
2aac8000-2aacc000 rw-p 2aac8000 00:00 0
2aad4000-2aad8000 rw-p 0001c000 00:01 624        /lib/ld-2.8.so
2aad8000-2ab54000 r-xp 00000000 00:01 514        /lib/libm-2.8.so
2ab54000-2ab60000 ---p 0007c000 00:01 514        /lib/libm-2.8.so
2ab60000-2ab64000 rw-p 00078000 00:01 514        /lib/libm-2.8.so
2ab64000-2acac000 r-xp 00000000 00:01 630        /lib/libc-2.8.so
2acac000-2acb8000 ---p 00148000 00:01 630        /lib/libc-2.8.so
2acb8000-2acc0000 r--p 00144000 00:01 630        /lib/libc-2.8.so
2acc0000-2acc4000 rw-p 0014c000 00:01 630        /lib/libc-2.8.so
2acc4000-2acc8000 rw-p 2acc4000 00:00 0
7fb84000-7fbd8000 rwxp 7fb84000 00:00 0          [stack]

After Reboot,

tango3[bin]# cat /proc/modules
em8xxx 935488 0 - Live 0xc01b8000 (PF)
llad 144800 1 em8xxx, Live 0xc00b0000 (P)
sigmablock 70976 3 - Live 0xc002c000 (P)
tango3[bin]# cat /proc/self/maps
00400000-004b0000 r-xp 00000000 00:01 387        /bin/busybox
004bc000-004c0000 rw-p 000ac000 00:01 387        /bin/busybox
004c0000-004c4000 rwxp 004c0000 00:00 0          [heap]
2aaa8000-2aac8000 r-xp 00000000 00:01 624        /lib/ld-2.8.so
2aac8000-2aacc000 rw-p 2aac8000 00:00 0
2aad4000-2aad8000 rw-p 0001c000 00:01 624        /lib/ld-2.8.so
2aad8000-2ab54000 r-xp 00000000 00:01 514        /lib/libm-2.8.so
2ab54000-2ab60000 ---p 0007c000 00:01 514        /lib/libm-2.8.so
2ab60000-2ab64000 rw-p 00078000 00:01 514        /lib/libm-2.8.so
2ab64000-2acac000 r-xp 00000000 00:01 630        /lib/libc-2.8.so
2acac000-2acb8000 ---p 00148000 00:01 630        /lib/libc-2.8.so
2acb8000-2acc0000 r--p 00144000 00:01 630        /lib/libc-2.8.so
2acc0000-2acc4000 rw-p 0014c000 00:01 630        /lib/libc-2.8.so
2acc4000-2acc8000 rw-p 2acc4000 00:00 0
7f7c8000-7f81c000 rwxp 7f7c8000 00:00 0          [stack]

Most of them are consistent before and after the system reboot, except the stack, but
that is not a problem from the perspective of attacking embedded linux system. So, the
system being tested has ASLR disabled. How about NX ? Regarding to this issue, we first
assume the stack should always be NX protected. So, we will put some instructions in
the stack and then redirect the program counter into it. After that, we step over those
instructions and observe the outcomes. If the outcome is positive, it means the NX is
disabled. Otherwise, if exception incurred, then it means the NX is enabled and run
properly. We will run our test on a MIPS platform with GDB. Let's say we want to create
some instructions to change register $t0 to 0xffffffff now. Well, it is

lui $t0,0xffff
ori $t0,$t0,0xffff

Please refer my previous paper "How To Convert Assembly Instruction Into Machine Code
In Any Type Of Processors Platform" to obtain the respective machine code of that 2
instructions.

Host:# echo 'lui $t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
    3c08ffff     lui    t0,0xffff
Host:# echo 'ori $t0,$t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
    3508ffff     ori    t0,t0,0xffff

Well, let us put the machine codes into the stack. We need to run a dummy program, set
a breakpoint at _main, then continue the execution, and stop at the breakpoint.

tango3[gdb]# ./gdb ./hello
GNU gdb (GDB) 7.0
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "mips-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /root/cawan/mips-4.3/bin/gdb-7.0/gdb/hello...
(no debugging symbols found)...done.
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
Function "info_command" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
/root/cawan/mips-4.3/bin/gdb-7.0/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) break main
Breakpoint 1 at 0x400620
(gdb) run
Starting program: /root/cawan/mips-4.3/bin/gdb-7.0/gdb/hello

Breakpoint 1, 0x00400620 in main ()
(gdb)

Good, we are at the point. Let's check the register info.

(gdb) info reg
          zero       at       v0       v1       a0       a1       a2       a3
 R0   00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
            t0       t1       t2       t3       t4       t5       t6       t7
 R8   2ac372f4 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
            s0       s1       s2       s3       s4       s5       s6       s7
 R16  00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
            t8       t9       k0       k1       gp       sp       s8       ra
 R24  00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
        status       lo       hi badvaddr    cause       pc
      00001c13 00005e17 000001a5 2ab065d0 50808024 00400620
          fcsr      fir  restart
      00000000 01739300 00000000
(gdb)

Nice, $t0=2ac372f4, $sp=7ff5ba30, $pc=00400620

Let's check the content of stack.

(gdb) x/16x $sp
0x7ff5ba30:     0x7ff5bb24      0x00400658      0x004004f0      0x004cece8
0x7ff5ba40:     0x2ac3d950      0x00412580      0x00000000      0x2aaee948
0x7ff5ba50:     0x00000000      0x00000001      0x7ff5bb24      0x2aaee7fc
0x7ff5ba60:     0x2ac3d950      0x00000000      0x2aaee908      0x7ff5ba50
(gdb)

Let's change it with our instructions.

(00000000) nop
(00000000) nop
(3c08ffff) lui $t0,0xffff
(3508ffff) ori $t0,$t0,0xffff
(00000000) nop
(00000000) nop

(gdb) set *0x7ff5ba30 = 0x00000000
(gdb) set *(0x7ff5ba30+4) = 0x00000000
(gdb) set *(0x7ff5ba30+8) = 0x3c08ffff 
(gdb) set *(0x7ff5ba30+12) = 0x3508ffff
(gdb) set *(0x7ff5ba30+16) = 0x00000000
(gdb) set *(0x7ff5ba30+20) = 0x00000000
(gdb) x/16x $sp                       
0x7ff5ba30:     0x00000000      0x00000000      0x3c08ffff      0x3508ffff
0x7ff5ba40:     0x00000000      0x00000000      0x00000000      0x2aaee948
0x7ff5ba50:     0x00000000      0x00000001      0x7ff5bb24      0x2aaee7fc
0x7ff5ba60:     0x2ac3d950      0x00000000      0x2aaee908      0x7ff5ba50
(gdb) x/16i $pc
0x7ff5ba30:     nop
0x7ff5ba34:     nop
0x7ff5ba38:     lui     t0,0xffff
0x7ff5ba3c:     ori     t0,t0,0xffff
0x7ff5ba40:     nop
0x7ff5ba44:     nop
0x7ff5ba48:     nop
0x7ff5ba4c:     slti    t6,s5,-5816
0x7ff5ba50:     nop
0x7ff5ba54:     movf    zero,zero,$fcc0
0x7ff5ba58:     0x7ff5bb24
0x7ff5ba5c:     slti    t6,s5,-6148
0x7ff5ba60:     slti    v1,s6,-9904
0x7ff5ba64:     nop
0x7ff5ba68:     slti    t6,s5,-5880
0x7ff5ba6c:     subu.ph s7,ra,s5
(gdb) 


Fine, the content of stack has been changed to our instructions. Now, let us
redirect our program counter to the stack.

(gdb) set $pc = $sp
warning: GDB can't find the start of the function at 0x7ff5ba30.
(gdb) info reg
          zero       at       v0       v1       a0       a1       a2       a3
 R0   00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
            t0       t1       t2       t3       t4       t5       t6       t7
 R8   2ac372f4 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
            s0       s1       s2       s3       s4       s5       s6       s7
 R16  00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
            t8       t9       k0       k1       gp       sp       s8       ra
 R24  00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
        status       lo       hi badvaddr    cause       pc
      00001c13 00005e17 000001a5 2ab065d0 50808024 7ff5ba30
          fcsr      fir  restart
      00000000 01739300 00000000
(gdb)

Well, the program counter is already at the stack, and the $t0 register is 2ac372f4 now.
Let us step over those instructions, and we suppose once the program counter arrived at
the 5th instruction, register $t0 should be changed into 0xffffffff. Let's see.

(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba34.
0x7ff5ba34 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba38.
0x7ff5ba38 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba3c.
0x7ff5ba3c in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba40.
0x7ff5ba40 in ?? ()
(gdb) ni
warning: GDB can't find the start of the function at 0x7ff5ba44.
0x7ff5ba44 in ?? ()
(gdb) info reg
          zero       at       v0       v1       a0       a1       a2       a3
 R0   00000000 fffffff8 7ff5ba68 2aac8a70 00000001 7ff5bb24 7ff5bb2c 00000000
            t0       t1       t2       t3       t4       t5       t6       t7
 R8   ffffffff 0ffffffe 00000002 7ff5ba20 ffffffff 7ff5b978 2aab1b84 f0000000
            s0       s1       s2       s3       s4       s5       s6       s7
 R16  00400658 004004f0 004cece8 004ced40 00412580 004cece8 004ceda0 004cedb0
            t8       t9       k0       k1       gp       sp       s8       ra
 R24  00000000 00400610 00000000 00000000 2ac3d950 7ff5ba30 7ff5ba30 2aaee948
        status       lo       hi badvaddr    cause       pc
      00001c13 00005e17 000001a5 2ab065d0 50808024 7ff5ba44
          fcsr      fir  restart
      00000000 01739300 00000000
(gdb)

Awesome, the register $t0 has eventually changed to 0xffffffff. So, the MIPS platform
under test has NX disabled. In other words, it is easy to design shellcode to work with
appropriate exploit in attacking this platform.


pdf version:

http://www.scribd.com/doc/112540003/How-to-Check-for-ASLR-and-NX-Features-of-Embedded-Linux-System-1

Monday, November 5, 2012

How To Build A Kernel Shellcode Design and Testing Platform For Windows 8 By Using Windbg


How To Build A Kernel Shellcode Design and Testing Platform For Windows 8 By Using Windbg

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 5/11/2012

For windows kernel shellcoder, it is very important to has a testing platform in 
evaluating and verifying the shellcode at instruction level in runtime. So, windbg
should be the ideal tool to do the job. In order to build a testing platform, we 
need 2 pieces of memory areas, one with write and execute (WE) permission, and 
another one with write (W) permission. The one with WE permission is to let us put
our shellcode inside, and run it there. On the other hand, the one with W permission
is for temporary storage, so, we can store our variable or output there. A good 
example is sgdt command. The command will read the gdt register and store the content
into a memory area that we specified. Now, we need to search memory pages to find
one with WE permission and another one with W permission. Let's start now.

          
8 files are generated, which the file names from 80000000.txt to f0000000.txt.
The processes will take quite a while in scanning the kernel space page by page.
Based on the log files, quite a number of memory areas are found which can meet the 
requirement. However, most of them are protected by integrity check of the kernel.
In other words, when some bytes on those memory areas are modified, and let the 
kernel run again, the system will crash immediately. Fortunately, after several 
tries, a piece of memory area which has WE permission and out of the control of 
integrity check by the kernel has been found. 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    VA 811fc000
PDE at C0602040            PTE at C0408FE0
contains 0000000002A07063  contains 00000000025FC963
pfn 2a07      ---DA--KWEV   pfn 25fc      -G-DA--KWEV

(811fb480)   nt!HvlpLogicalProcessorRegions+0xb80   |  (81206480)   nt!HvlpNodes

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

The memory area is known as HvlpLogicalProcessorRegions and it is started from 
0x811fb480 and end at 0x81206480. Please note that the memory addresses will be 
different in your machine because the kernel base is always ASLRed. Now we need to 
make sure the HvlpLogicalProcessorRegions is included in the nt kernel export list
or not. 


There is nothing in the export list that match "HvlpLogicalProcessorRegions", and even
with prefix "Hvlp". If search for those with prefix "Hvl", then there are some, but 
nothing related to the "HvlpLogicalProcessorRegions". So, from the angle of kernel 
shellcode design, we can only get the base of "HvlpLogicalProcessorRegions" by using 
offset comparison technique as discussed in previous paper - "How to Defeat Windows 8 
ASLR in Getting the Address of KPCR". Anyway, since we are using windbg with symbol 
files now, we no need to consider this first. But now, how about the memory area with 
W permission ? Again, after several tries, a fixed address is very suitable to do the 
job, and it is located at 0xffdf0000.

///////////////////////////////////////////////////////////////////////////////////
                    VA ffdf0000
PDE at C0603FF0            PTE at C07FEF80
contains 0000000002A96063  contains 8000000002A58163
pfn 2a96      ---DA--KWEV   pfn 2a58      -G-DA--KW-V 

///////////////////////////////////////////////////////////////////////////////////

Nice, let's try with some instructions. First, check for any content in 
HvlpLogicalProcessorRegions.

kd> dd HvlpLogicalProcessorRegions
811fb480  00000000 00000000 00000000 00000000
811fb490  00000000 00000000 00000000 00000000
811fb4a0  00000000 00000000 00000000 00000000
811fb4b0  00000000 00000000 00000000 00000000
811fb4c0  00000000 00000000 00000000 00000000
811fb4d0  00000000 00000000 00000000 00000000
811fb4e0  00000000 00000000 00000000 00000000
811fb4f0  00000000 00000000 00000000 00000000

Full with zero...Fine, we start to put some instructions there.

kd> a HvlpLogicalProcessorRegions
811fb480 nop
nop
811fb481 nop
nop
811fb482 sgdt [0xffdf0000]
sgdt [0xffdf0000]
811fb489 nop
nop
811fb48a nop
nop
811fb48b 

The instruction "sgdt [0xffdf0000]" will write the content of gdt register into 
0xffdf0000. Let's check the memory of HvlpLogicalProcessorRegions again.

kd> dd HvlpLogicalProcessorRegions
811fb480  010f9090 df000005 009090ff 00000000
811fb490  00000000 00000000 00000000 00000000
811fb4a0  00000000 00000000 00000000 00000000
811fb4b0  00000000 00000000 00000000 00000000
811fb4c0  00000000 00000000 00000000 00000000
811fb4d0  00000000 00000000 00000000 00000000
811fb4e0  00000000 00000000 00000000 00000000
811fb4f0  00000000 00000000 00000000 00000000

It is easier to check it in bytes...

kd> db HvlpLogicalProcessorRegions
811fb480  90 90 0f 01 05 00 00 df-ff 90 90 00 00 00 00 00  ................
811fb490  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4b0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4e0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

Good, the instructions already there. Let the kernel run again to ensure the system
will not hang due to our modification to the kernel memory. Issue command 'g' and 
do something such as open windows explorer at windows 8, it should work properly.
Now, break the system again and check our instructions are still there or not.

kd> db HvlpLogicalProcessorRegions
811fb480  90 90 0f 01 05 00 00 df-ff 90 90 00 00 00 00 00  ................
811fb490  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4b0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4e0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
811fb4f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

Yes, still there. Now, we need to redirect the EIP to HvlpLogicalProcessorRegions.
Before that, we need to note down the current EIP first. 

kd> r eip
eip=811003a4

So, redirect the EIP to HvlpLogicalProcessorRegions now.

kd> r eip=HvlpLogicalProcessorRegions
kd> r eip
eip=811fb480

Well, let's disassemble it.

kd> u eip
nt!HvlpLogicalProcessorRegions:
811fb480 90              nop
811fb481 90              nop
811fb482 0f01050000dfff  sgdt    fword ptr ds:[0FFDF0000h]
811fb489 90              nop
811fb48a 90              nop
811fb48b 0000            add     byte ptr [eax],al
811fb48d 0000            add     byte ptr [eax],al
811fb48f 0000            add     byte ptr [eax],al

We are ready to run it now. Step over until reach at 0x811fb48a.

kd> p
nt!HvlpLogicalProcessorRegions+0x1:
811fb481 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0x2:
811fb482 0f01050000dfff  sgdt    fword ptr ds:[0FFDF0000h]
kd> p
nt!HvlpLogicalProcessorRegions+0x9:
811fb489 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0xa:
811fb48a 90              nop

Now, check the content of gdt register at ffdf0000.

kd> dd ffdf0000
ffdf0000  300003ff 0f998080 a2cd7d0e 00000000
ffdf0010  00000000 16c4f5d0 01cdbbb7 01cdbbb7
ffdf0020  0e234000 00000043 00000043 014c014c
ffdf0030  003a0043 0057005c 006e0069 006f0064
ffdf0040  00730077 00000000 00000000 00000000
ffdf0050  00000000 00000000 00000000 00000000
ffdf0060  00000000 00000000 00000000 00000000
ffdf0070  00000000 00000000 00000000 00000000
kd> db ffdf0000
ffdf0000  ff 03 00 30 80 80 99 0f-0e 7d cd a2 00 00 00 00  ...0.....}......
ffdf0010  00 00 00 00 d0 f5 c4 16-b7 bb cd 01 b7 bb cd 01  ................
ffdf0020  00 40 23 0e 43 00 00 00-43 00 00 00 4c 01 4c 01  .@#.C...C...L.L.
ffdf0030  43 00 3a 00 5c 00 57 00-69 00 6e 00 64 00 6f 00  C.:.\.W.i.n.d.o.
ffdf0040  77 00 73 00 00 00 00 00-00 00 00 00 00 00 00 00  w.s.............
ffdf0050  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
ffdf0060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
ffdf0070  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

gdt register is 48-bit, which is 6 bytes and the gdt base is located at byte 2-5 
(zero base). So, the gdt base should be 0x80803000. Let's verify.

kd> r gdtr
gdtr=80803000

Yes, it seems everything fine. How about to get the KPCR ?

kd> a HvlpLogicalProcessorRegions
811fb480 nop
nop
811fb481 nop
nop
811fb482 pushad
pushad
811fb483 nop
nop
811fb484 nop
nop
811fb485 sgdt [0xffdf0000]
sgdt [0xffdf0000]
811fb48c mov eax,[ffdf0002]
mov eax,[ffdf0002]
811fb491 mov dh,[eax+37]
mov dh,[eax+37]
811fb494 mov dl,[eax+34]
mov dl,[eax+34]
811fb497 mov bx,dx
mov bx,dx
811fb49a shl ebx,10
shl ebx,10
811fb49d mov bh,[eax+33]
mov bh,[eax+33]
811fb4a0 mov bl,[eax+32]
mov bl,[eax+32]
811fb4a3 nop
nop
811fb4a4 nop
nop
811fb4a5 popad
popad
811fb4a6 nop
nop
811fb4a7 nop
nop
811fb4a8

kd> r eip=HvlpLogicalProcessorRegions
kd> p
nt!HvlpLogicalProcessorRegions+0x1:
811fb481 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0x2:
811fb482 60              pushad
kd> p
nt!HvlpLogicalProcessorRegions+0x3:
811fb483 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0x4:
811fb484 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0x5:
811fb485 0f01050000dfff  sgdt    fword ptr ds:[0FFDF0000h]
kd> p
nt!HvlpLogicalProcessorRegions+0xc:
811fb48c a10200dfff      mov     eax,dword ptr ds:[FFDF0002h]
kd> p
nt!HvlpLogicalProcessorRegions+0x11:
811fb491 8a7037          mov     dh,byte ptr [eax+37h]
kd> r eax
eax=80803000
kd> p
nt!HvlpLogicalProcessorRegions+0x14:
811fb494 8a5034          mov     dl,byte ptr [eax+34h]
kd> db eax
80803000  00 00 00 00 00 00 00 00-ff ff 00 00 00 9b cf 00  ................
80803010  ff ff 00 00 00 93 cf 00-ff ff 00 00 00 fb cf 00  ................
80803020  ff ff 00 00 00 f3 cf 00-ab 20 00 80 7f 8b 00 80  ......... ......
80803030  80 42 00 90 20 93 40 81-ff 0f 00 00 00 f3 40 00  .B.. .@.......@.
80803040  ff ff 00 04 00 f2 00 00-00 00 00 00 00 00 00 00  ................
80803050  68 00 00 30 1d 89 00 81-68 00 68 30 1d 89 00 81  h..0....h.h0....
80803060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
80803070  ff 03 00 30 80 92 00 80-00 00 00 00 00 00 00 00  ...0............
kd> r dh
dh=81
kd> p
nt!HvlpLogicalProcessorRegions+0x17:
811fb497 668bda          mov     bx,dx
kd> r dl
dl=20
kd> p
nt!HvlpLogicalProcessorRegions+0x1a:
811fb49a c1e310          shl     ebx,10h
kd> r ebx
ebx=81208120
kd> p
nt!HvlpLogicalProcessorRegions+0x1d:
811fb49d 8a7833          mov     bh,byte ptr [eax+33h]
kd> r ebx
ebx=81200000
kd> p
nt!HvlpLogicalProcessorRegions+0x20:
811fb4a0 8a5832          mov     bl,byte ptr [eax+32h]
kd> r bh
bh=90
kd> p
nt!HvlpLogicalProcessorRegions+0x23:
811fb4a3 90              nop
kd> r bl
bl=0
kd> r ebx
ebx=81209000

Well, the value of ebx should be the KPCR, let's verify.

kd> dg 30
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 81209000 00004280 Data RW Ac 0 Bg By P  Nl 00000493

Good, we are at the right point. Now, let us extract the shellcode in getting KPCR.

811fb485 0f01050000dfff  sgdt    fword ptr ds:[0FFDF0000h]
811fb48c a10200dfff      mov     eax,dword ptr ds:[FFDF0002h]
811fb491 8a7037          mov     dh,byte ptr [eax+37h]
811fb494 8a5034          mov     dl,byte ptr [eax+34h]
811fb497 668bda          mov     bx,dx
811fb49a c1e310          shl     ebx,10h
811fb49d 8a7833          mov     bh,byte ptr [eax+33h]
811fb4a0 8a5832          mov     bl,byte ptr [eax+32h]

shellcode_get_kpcr=("\x0f\x01\x05\x00\x00\xdf\xff\xa1\x02\x00\xdf\xff\x8a\x70\x37"
                    "\x8a\x50\x34\x66\x8b\xda\xc1\xe3\x10\x8a\x78\x33\x8a\x58\x32")

So, after the shellcode_get_kpcr get executed, the address of KPCR should be at ebx, 
and we can do the rest of the things such as token stealing or whatever up to your 
imagination. Besides, this version of shellcode contains illegal null bytes which is 
normally not allowed by the system. Regarding how to avoid null bytes, I reserve this 
as your own exercise. After everything completed, we revert the machine to the 
original state. Let's run over the instruction "popad".

kd> p
nt!HvlpLogicalProcessorRegions+0x24:
811fb4a4 90              nop
kd> p
nt!HvlpLogicalProcessorRegions+0x25:
811fb4a5 61              popad
kd> p
nt!HvlpLogicalProcessorRegions+0x26:
811fb4a6 90              nop
kd> r eax
eax=00000001
kd> r ebx
ebx=8120b354

Now, reset the address of EIP to the original state.

ebx=8120b354
kd> r eip=811003a4

Issue command 'g' to run the kernel again, the system should revert to the working
state.

kd> g

Yes, the system now working well again. For your info, when using this technique in 
the real exploit, the shellcode can put directly to HvlpLogicalProcessorRegions by 
using multiple of write4 or write8. Regarding to the issue of how to get the address
of HvlpLogicalProcessorRegions in ASLRed kernel, please refer my previous paper of 

Sunday, November 4, 2012

How To Check Export Functions Of Windows 8 NT Kernel By Using Windbg


How To Check Export Functions Of Windows 8 NT Kernel By Using Windbg

by cawan (cawan[at]ieee.org)

on 4/11/2012

In most of the time, PE viewer approach is the most well-known technique in listing the
export functions from the export directory of PE file. For windows kernel, it is common
to use those PE viewers to parse the header of ntoskrnl.exe or ntkrnlpa.exe in getting
the contents under export directory. However, it is really cumbersome when we designing
the shellcode in windbg and keep switching to PE viewer to refer the export function list.
It is getting more annoying when the base address is ASLRed... So, we need to find a way
do everything in windbg, because we are lazy...

First of all, let us parse the PE header of the windows kernel from windbg.

kd> !dh /f nt

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
           14C machine (i386)
              14 number of sections
5010ADF0 time date stamp Thu Jul 26 10:39:44 2012

          0 file pointer to symbol table
          0 number of symbols
       E0 size of optional header
     122 characteristics
               Executable
               App can handle >2gb addresses
               32 bit word machine

OPTIONAL HEADER VALUES
           10B magic #
        10.10 linker version
    4B3E00 size of code
      CE200 size of initialized data
         2800 size of uninitialized data
     221310 address of entry point
         1000 base of code
         ----- new -----
 00400000 image base
         1000 section alignment
           200 file alignment
               1 subsystem (Native)
          6.02 operating system version
          6.02 image version
         6.02 subsystem version
    58E000 size of image
          800 size of headers
    550165 checksum
00040000 size of stack reserve
00002000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
       0  DLL characteristics
   4BA000 [   134CA] address [size] of Export Directory
    20B394 [         DC] address [size] of Import Directory
    538000 [    31A50] address [size] of Resource Directory
              0 [             0] address [size] of Exception Directory
   54C200 [       20F0] address [size] of Security Directory
   56A000 [    23A14] address [size] of Base Relocation Directory
  1C4AA4 [          38] address [size] of Debug Directory
              0 [            0] address [size] of Description Directory
              0 [            0] address [size] of Special Directory
              0 [            0] address [size] of Thread Storage Directory
      14490 [          40] address [size] of Load Configuration Directory
              0 [            0] address [size] of Bound Import Directory
   20B000 [        394] address [size] of Import Address Table Directory
              0 [            0] address [size] of Delay Import Directory
              0 [            0] address [size] of COR20 Header Directory
              0 [            0] address [size] of Reserved Directory

Well, the export directory is at 4ba000 and the size of this structure is 134ca.
Let us check it further

kd> dd nt+4ba000
81327000  00000000 5010adf0 00000000 004bff76
81327010  00000001 00000989 00000987 004ba028
81327020  004bc64c 004bec68 0035e96d 000f7470
81327030  000bc0d2 000ba677 000b2047 000d4a00
81327040  0007b7fb 0007ba2e 000d6718 000d679f
81327050  000ba781 000cee95 00170874 00163eb9
81327060  001708c0 00170100 00163ea4 00163e8f
81327070  00163e71 0017011c 00163e5c 00170174

We need to get the list of export functions name, from PE specification, we have this
structure.

public struct IMAGE_EXPORT_DIRECTORY
{
    public UInt32 Characteristics;
    public UInt32 TimeDateStamp;
    public UInt16 MajorVersion;
    public UInt16 MinorVersion;
    public UInt32 Name;
    public UInt32 Base;
    public UInt32 NumberOfFunctions;
    public UInt32 NumberOfNames;
    public UInt32 AddressOfFunctions;
    public UInt32 AddressOfNames;
    public UInt32 AddressOfNameOrdinals;
}

So, from IMAGE_EXPORT_DIRECTORY structure, AddressOfNames at offset 0x20 (32 in decimal)
has what we are looking for. Let us check address 0x004bc64c.

kd> dd nt+004bc64c
8132964c  004bff83 004bff95 004bffad 004bffcc
8132965c  004bffe0 004bfff3 004c0005 004c0012
8132966c  004c0031 004c003d 004c005b 004c0066
8132967c  004c0073 004c007f 004c008d 004c00a2
8132968c  004c00c6 004c00d3 004c00e2 004c00f2
8132969c  004c0104 004c0111 004c0123 004c0133
813296ac  004c014a 004c0169 004c018b 004c01a1
813296bc  004c01b7 004c01cc 004c01df 004c01f4

Those are pointers to the export functions name. Verify it.

kd> db nt+004bff83
8132cf83  41 6c 70 63 47 65 74 48-65 61 64 65 72 53 69 7a  AlpcGetHeaderSiz
8132cf93  65 00 41 6c 70 63 47 65-74 4d 65 73 73 61 67 65  e.AlpcGetMessage
8132cfa3  41 74 74 72 69 62 75 74-65 00 41 6c 70 63 49 6e  Attribute.AlpcIn
8132cfb3  69 74 69 61 6c 69 7a 65-4d 65 73 73 61 67 65 41  itializeMessageA
8132cfc3  74 74 72 69 62 75 74 65-00 42 67 6b 44 69 73 70  ttribute.BgkDisp
8132cfd3  6c 61 79 43 68 61 72 61-63 74 65 72 00 42 67 6b  layCharacter.Bgk
8132cfe3  47 65 74 43 6f 6e 73 6f-6c 65 53 74 61 74 65 00  GetConsoleState.
8132cff3  42 67 6b 47 65 74 43 75-72 73 6f 72 53 74 61 74  BgkGetCursorStat

There are a lot of strings starting from 004bff83. Check the first 2 items.

kd> da nt+004bff83
8132cf83  "AlpcGetHeaderSize"
kd> da nt+004bff95
8132cf95  "AlpcGetMessageAttribute"

By referring the IMAGE_EXPORT_DIRECTORY structure again, the NumberOfNames at offset 0x18
shows the number of export functions in the nt kernel. So, there are 987 export functions
in the nt kernel. We can write a script to dump all the exported functions now.





8132cf83  "AlpcGetHeaderSize"
8132cf95  "AlpcGetMessageAttribute"
8132cfad  "AlpcInitializeMessageAttribute"
8132cfcc  "BgkDisplayCharacter"
8132cfe0  "BgkGetConsoleState"
8132cff3  "BgkGetCursorState"
8132d005  "BgkSetCursor"
8132d012  "CcAddDirtyPagesToExternalCache"
8132d031  "CcCanIWrite"
8132d03d  "CcCoherencyFlushAndPurgeCache"
8132d05b  "CcCopyRead"
8132d066  "CcCopyReadEx"
8132d073  "CcCopyWrite"
8132d07f  "CcCopyWriteEx"
8132d08d  "CcCopyWriteWontFlush"
8132d0a2  "CcDeductDirtyPagesFromExternalCa"
8132d0c6  "CcDeferWrite"
8132d0d3  "CcFastCopyRead"
8132d0e2  "CcFastCopyWrite"
8132d0f2  "CcFastMdlReadWait"
8132d104  "CcFlushCache"
8132d111  "CcFlushCacheToLsn"
8132d123  "CcGetDirtyPages"
8132d133  "CcGetFileObjectFromBcb"
8132d14a  "CcGetFileObjectFromSectionPtrs"
8132d169  "CcGetFileObjectFromSectionPtrsRe"
8132d18b  "CcGetFlushedValidData"
8132d1a1  "CcGetLsnForFileObject"
8132d1b7  "CcInitializeCacheMap"
8132d1cc  "CcIsThereDirtyData"
8132d1df  "CcIsThereDirtyDataEx"
8132d1f4  "CcIsThereDirtyLoggedPages"
8132d20e  "CcMapData"
8132d218  "CcMdlRead"
8132d222  "CcMdlReadComplete"
8132d234  "CcMdlWriteAbort"
8132d244  "CcMdlWriteComplete"
8132d257  "CcPinMappedData"
8132d267  "CcPinRead"
8132d271  "CcPrepareMdlWrite"
8132d283  "CcPreparePinWrite"
8132d295  "CcPurgeCacheSection"
8132d2a9  "CcRegisterExternalCache"
8132d2c1  "CcRemapBcb"
8132d2cc  "CcRepinBcb"
8132d2d7  "CcScheduleReadAhead"
8132d2eb  "CcScheduleReadAheadEx"
...
...

How about if we need to know that an function name is included in the export functions list
or not ? Simple, let's say we need to know HalDispatchTable is in the export functions list
or not...



8132fed0  "HalDispatchTable"
.shell: Process exited

Yes, it is included. How about we want to dump the list of native api of windows 8 ? Simple.



81338eac  "ZwAccessCheckAndAuditAlarm"
81338ec7  "ZwAddBootEntry"
81338ed6  "ZwAddDriverEntry"
81338ee7  "ZwAdjustPrivilegesToken"
81338eff  "ZwAlertThread"
81338f0d  "ZwAllocateLocallyUniqueId"
81338f27  "ZwAllocateVirtualMemory"
81338f3f  "ZwAlpcAcceptConnectPort"
81338f57  "ZwAlpcCancelMessage"
81338f6b  "ZwAlpcConnectPort"
81338f7d  "ZwAlpcConnectPortEx"
81338f91  "ZwAlpcCreatePort"
81338fa2  "ZwAlpcCreatePortSection"
81338fba  "ZwAlpcCreateResourceReserve"
81338fd6  "ZwAlpcCreateSectionView"
81338fee  "ZwAlpcCreateSecurityContext"
8133900a  "ZwAlpcDeletePortSection"
81339022  "ZwAlpcDeleteResourceReserve"
8133903e  "ZwAlpcDeleteSectionView"
81339056  "ZwAlpcDeleteSecurityContext"
81339072  "ZwAlpcDisconnectPort"
81339087  "ZwAlpcQueryInformation"
8133909e  "ZwAlpcSendWaitReceivePort"
813390b8  "ZwAlpcSetInformation"
813390cd  "ZwAssignProcessToJobObject"
813390e8  "ZwCancelIoFile"
813390f7  "ZwCancelTimer"
81339105  "ZwClearEvent"
81339112  "ZwClose"
8133911a  "ZwCloseObjectAuditAlarm"
81339132  "ZwCommitComplete"
81339143  "ZwCommitEnlistment"
81339156  "ZwCommitTransaction"
8133916a  "ZwConnectPort"
81339178  "ZwCreateDirectoryObject"
81339190  "ZwCreateEnlistment"
813391a3  "ZwCreateEvent"
813391b1  "ZwCreateFile"
813391be  "ZwCreateIoCompletion"
813391d3  "ZwCreateJobObject"
813391e5  "ZwCreateKey"
813391f1  "ZwCreateKeyTransacted"
81339207  "ZwCreateResourceManager"
8133921f  "ZwCreateSection"
8133922f  "ZwCreateSymbolicLinkObject"
8133924a  "ZwCreateTimer"
81339258  "ZwCreateTransaction"
8133926c  "ZwCreateTransactionManager"
81339287  "ZwCreateWnfStateName"
8133929c  "ZwDeleteBootEntry"
813392ae  "ZwDeleteDriverEntry"
813392c2  "ZwDeleteFile"
813392cf  "ZwDeleteKey"
813392db  "ZwDeleteValueKey"
813392ec  "ZwDeleteWnfStateData"
81339301  "ZwDeleteWnfStateName"
81339316  "ZwDeviceIoControlFile"
8133932c  "ZwDisplayString"
8133933c  "ZwDuplicateObject"
8133934e  "ZwDuplicateToken"
8133935f  "ZwEnumerateBootEntries"
81339376  "ZwEnumerateDriverEntries"
8133938f  "ZwEnumerateKey"
8133939e  "ZwEnumerateTransactionObject"
813393bb  "ZwEnumerateValueKey"
813393cf  "ZwFlushBuffersFile"
813393e2  "ZwFlushBuffersFileEx"
813393f7  "ZwFlushInstructionCache"
8133940f  "ZwFlushKey"
8133941a  "ZwFlushVirtualMemory"
8133942f  "ZwFreeVirtualMemory"
81339443  "ZwFsControlFile"
81339453  "ZwGetNotificationResourceManager"
81339474  "ZwImpersonateAnonymousToken"
81339490  "ZwInitiatePowerAction"
813394a6  "ZwIsProcessInJob"
813394b7  "ZwLoadDriver"
813394c4  "ZwLoadKey"
813394ce  "ZwLoadKeyEx"
813394da  "ZwLockFile"
813394e5  "ZwLockProductActivationKeys"
81339501  "ZwMakeTemporaryObject"
81339517  "ZwMapViewOfSection"
8133952a  "ZwModifyBootEntry"
8133953c  "ZwModifyDriverEntry"
81339550  "ZwNotifyChangeKey"
81339562  "ZwNotifyChangeSession"
81339578  "ZwOpenDirectoryObject"
8133958e  "ZwOpenEnlistment"
8133959f  "ZwOpenEvent"
813395ab  "ZwOpenFile"
813395b6  "ZwOpenJobObject"
813395c6  "ZwOpenKey"
813395d0  "ZwOpenKeyEx"
813395dc  "ZwOpenKeyTransacted"
813395f0  "ZwOpenKeyTransactedEx"
81339606  "ZwOpenProcess"
81339614  "ZwOpenProcessToken"
81339627  "ZwOpenProcessTokenEx"
8133963c  "ZwOpenResourceManager"
81339652  "ZwOpenSection"
81339660  "ZwOpenSession"
8133966e  "ZwOpenSymbolicLinkObject"
81339687  "ZwOpenThread"
81339694  "ZwOpenThreadToken"
813396a6  "ZwOpenThreadTokenEx"
813396ba  "ZwOpenTimer"
813396c6  "ZwOpenTransaction"
813396d8  "ZwOpenTransactionManager"
813396f1  "ZwPowerInformation"
81339704  "ZwPrePrepareComplete"
81339719  "ZwPrePrepareEnlistment"
81339730  "ZwPrepareComplete"
81339742  "ZwPrepareEnlistment"
81339756  "ZwPropagationComplete"
8133976c  "ZwPropagationFailed"
81339780  "ZwPulseEvent"
8133978d  "ZwQueryBootEntryOrder"
813397a3  "ZwQueryBootOptions"
813397b6  "ZwQueryDefaultLocale"
813397cb  "ZwQueryDefaultUILanguage"
813397e4  "ZwQueryDirectoryFile"
813397f9  "ZwQueryDirectoryObject"
81339810  "ZwQueryDriverEntryOrder"
81339828  "ZwQueryEaFile"
81339836  "ZwQueryFullAttributesFile"
81339850  "ZwQueryInformationEnlistment"
8133986d  "ZwQueryInformationFile"
81339884  "ZwQueryInformationJobObject"
813398a0  "ZwQueryInformationProcess"
813398ba  "ZwQueryInformationResourceManage"
813398dc  "ZwQueryInformationThread"
813398f5  "ZwQueryInformationToken"
8133990d  "ZwQueryInformationTransaction"
8133992b  "ZwQueryInformationTransactionMan"
81339950  "ZwQueryInstallUILanguage"
81339969  "ZwQueryKey"
81339974  "ZwQueryLicenseValue"
81339988  "ZwQueryObject"
81339996  "ZwQueryQuotaInformationFile"
813399b2  "ZwQuerySection"
813399c1  "ZwQuerySecurityAttributesToken"
813399e0  "ZwQuerySecurityObject"
813399f6  "ZwQuerySymbolicLinkObject"
81339a10  "ZwQuerySystemEnvironmentValueEx"
81339a30  "ZwQuerySystemInformation"
81339a49  "ZwQueryValueKey"
81339a59  "ZwQueryVirtualMemory"
81339a6e  "ZwQueryVolumeInformationFile"
81339a8b  "ZwQueryWnfStateData"
81339a9f  "ZwQueryWnfStateNameInformation"
81339abe  "ZwReadFile"
81339ac9  "ZwReadOnlyEnlistment"
81339ade  "ZwRecoverEnlistment"
81339af2  "ZwRecoverResourceManager"
81339b0b  "ZwRecoverTransactionManager"
81339b27  "ZwRemoveIoCompletion"
81339b3c  "ZwRemoveIoCompletionEx"
81339b53  "ZwRenameKey"
81339b5f  "ZwReplaceKey"
81339b6c  "ZwRequestPort"
81339b7a  "ZwRequestWaitReplyPort"
81339b91  "ZwResetEvent"
81339b9e  "ZwRestoreKey"
81339bab  "ZwRollbackComplete"
81339bbe  "ZwRollbackEnlistment"
81339bd3  "ZwRollbackTransaction"
81339be9  "ZwSaveKey"
81339bf3  "ZwSaveKeyEx"
81339bff  "ZwSecureConnectPort"
81339c13  "ZwSetBootEntryOrder"
81339c27  "ZwSetBootOptions"
81339c38  "ZwSetCachedSigningLevel"
81339c50  "ZwSetDefaultLocale"
81339c63  "ZwSetDefaultUILanguage"
81339c7a  "ZwSetDriverEntryOrder"
81339c90  "ZwSetEaFile"
81339c9c  "ZwSetEvent"
81339ca7  "ZwSetInformationEnlistment"
81339cc2  "ZwSetInformationFile"
81339cd7  "ZwSetInformationJobObject"
81339cf1  "ZwSetInformationKey"
81339d05  "ZwSetInformationObject"
81339d1c  "ZwSetInformationProcess"
81339d34  "ZwSetInformationResourceManager"
81339d54  "ZwSetInformationThread"
81339d6b  "ZwSetInformationToken"
81339d81  "ZwSetInformationTransaction"
81339d9d  "ZwSetInformationVirtualMemory"
81339dbb  "ZwSetQuotaInformationFile"
81339dd5  "ZwSetSecurityObject"
81339de9  "ZwSetSystemEnvironmentValueEx"
81339e07  "ZwSetSystemInformation"
81339e1e  "ZwSetSystemTime"
81339e2e  "ZwSetTimer"
81339e39  "ZwSetTimerEx"
81339e46  "ZwSetValueKey"
81339e54  "ZwSetVolumeInformationFile"
81339e6f  "ZwTerminateJobObject"
81339e84  "ZwTerminateProcess"
81339e97  "ZwTraceEvent"
81339ea4  "ZwTranslateFilePath"
81339eb8  "ZwUnloadDriver"
81339ec7  "ZwUnloadKey"
81339ed3  "ZwUnloadKeyEx"
81339ee1  "ZwUnlockFile"
81339eee  "ZwUnlockVirtualMemory"
81339f04  "ZwUnmapViewOfSection"
81339f19  "ZwUpdateWnfStateData"
81339f2e  "ZwWaitForMultipleObjects"
81339f47  "ZwWaitForSingleObject"
81339f5d  "ZwWriteFile"
81339f69  "ZwYieldExecution"
.shell: Process exited

Yes, we get the complete list. This technique is really helpful when I did memory analysis
of kernel pool to build a kernel shellcode testing platform in windbg.

pdf version:
http://www.scribd.com/doc/112326715/How-to-Check-Export-Functions-of-Windows-8-NT-Kernel-by-Using-Windbg

Saturday, November 3, 2012

How To Convert Assembly Instruction Into Machine Code In Any Type Of Processors Platform


How To Convert Assembly Instruction Into Machine Code In Any Type Of Processors Platform

by cawan (cawan[at]ieee.org)

on 4/11/2012

In windows environment under x86 platform, it is easy to test any assembly instruction
with any debugger such as ollydbg, immunitydbg, or windbg. With ollydbg or immunitydbg,
simply open a dummy .exe file, it will automatically break at the beginning of the code
(_main or TLS, it is up to the debugger setting...). Then, from Code window, drag the
scrollbar to an area which is easy to be recognized, such as full with null instruction
or nop instruction. Click once onto any of that instruction, then press the space bar
once, an assemble window will pop out. So, we can put any assembly instruction there
and let the debugger to convert the assembly instruction into machine code, and replace
the original instruction at the place that we selected previously with our new instruction.
After that, right click on the new instruction, from the popup menu, select "new origin
here", and the EIP will be redirected here. Press F8 to step over the instruction to
observe what has been done by the instruction from register window. This technique is
useful in initial design and verification of shellcode design.

However, this technique is only valid in windows. How about if we want to test and
evaluate some instructions under linux environment when we need to design shellcode for
linux ? Can we use gdb to do the same thing ? A more serious question is, how to test and
evaluate each instruction in RISC processor such as MIPS, ARM, or PPC ? Well, it is simple.
First of all, I personally still have no idea in regarding how to make gdb to assemble
instruction into machine code. If anybody know how to do it, please let me know, thanks.
However, we can use something alternative, the gcc. In gcc, we can put the instruction
that we want to test in a .s file. It is not recommended to use .c file because the
discussion will get a little bit complicated when we need to deal withinline assembly
as well as assembly instruction with c expression operands. Besides, in order to avoid gcc
to find appropriate entry point in linking process, we need -c option to ask gcc to
compile only the .s file into .o object file. Let's do it.

Host:# echo 'movl $0xffff0000,%eax' > cawan.s
Host:# cat cawan.s
movl $0xffff0000,%eax
Host:# gcc -c cawan.s
Host:# ls cawan.o
cawan.o
Host:# objdump -d cawan.o

cawan.o:     file format elf32-i386


Disassembly of section .text:

00000000 <.text>:
   0: b8 00 00 ff ff       mov    $0xffff0000,%eax

Well, we know the machine code of instruction "mov $0xffff0000,%eax" is b80000ffff, and
it is 5 bytes long. Now, how about MIPS platform ? How about if we need to move 0xffffffff
into t0 register ? Before we start, it is important to understand majority of RISC processors
use fixed-length instruction. So, the maximum immediate value that can support is only 16-bit,
and if we need to move 0xffffffff into t0 register, we need 2 instructions to do the job.
Let's do it now. First we move 0xffff into upper 16-bit is t0 register with "lui $t0,0xffff".
Then we use "ori $t0,$t0,0xffff" to move 0xffff into the lower 16-bit of t0 register. We can
change that 2 instruction into machine code now.

Host:# echo 'lui $t0,0xffff' > cawan.s
Host:# ./mips-linux-gnu-gcc -EL -c cawan.s
Host:# ls cawan.o
cawan.o
Host:# file cawan.o
cawan.o: ELF 32-bit LSB relocatable, MIPS, MIPS32 rel2 version 1 (SYSV), not stripped
Host:# ./mips-linux-gnu-obj
mips-linux-gnu-objcopy  mips-linux-gnu-objdump
Host:# ./mips-linux-gnu-objdump -d cawan.o

cawan.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <.text>:
   0: 3c08ffff lui t0,0xffff

Good, the machine code of "lui $t0,0xffff" is 3c08ffff. Please note that we are using
MIPS cross compiler (mips-linux-gnu-gcc) to compile the .s file instead of the default
gcc in the host machine. The -EL option in MIPS gcc means to compliance little endian
architecture. When the compiled .o object being checked with file command, it shows the
ELF is really for little endian MIPS. Ok, let us try with "ori $t0,$t0,0xffff" now.

Host:# echo 'ori $t0,$t0,0xffff' > cawan.s
Host:# ./mips-linux-gnu-gcc -EL -c cawan.s
Host:# ./mips-linux-gnu-objdump -d cawan.o

cawan.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <.text>:
   0: 3508ffff ori t0,t0,0xffff

Nice, the machine code of "ori $t0,$t0,0xffff" is 3508ffff. So, we know we can use
3c08ffff following by 3508ffff to change the value of t0 register into 0xffffffff. But
how to run and evaluate it? Of course with gdb. We need to cross compile a gdb to run
in MIPS environment and use it to do our job. The techniques to use in cross compiling
gdb into MIPS platform will be discussed in next paper. Just assume the MIPS gdb is ready
right now, and we can use it to test our machine code now. Simply open a dummy executable
in gdb, set a breakpoint at _main, and run. The execution should stop at the breakpoint.
Then use set command to put those machine code into appropriate memory address, verify it
with x command. If everything ok, then set the program counter to the memory address that
has the machine codes to be tested. From here, use ni command to step over the instructions
one by one. Observe the state by using x command for memory, or info reg command for
registers. Sometimes, it is a little bit annoying to run several steps to convert an
assembly instruction into machine code. So, it is possible to cascade them as a single
command and display the output in a clearer format.

Host:# echo 'lui $t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3c08ffff lui t0,0xffff
Host:# echo 'ori $t0,$t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3508ffff ori t0,t0,0xffff

Besides, regarding to ARM platform, just change the MIPS gcc and objdump into
ARM version, cross compile the gdb, and do the same thing as mentioned. So, it is really
easy to design and test your shellcode in any type of embedded platform.

pdf version:
http://www.scribd.com/doc/112327593/How-to-Convert-Assembly-Instruction-Into-Machine-Code-in-Any-Type-of-Processors-Platform