🟀Cross-compiling Binaries

Compiling exploits for windows on Linux can be a bit of a hassle. It depends on OS (windows, linux,...) and the architecture (x86, x64). Compiling executable on one OS/arch to be used on different one is called cross-compiling. Thanks to diingus, i'll cover here all four most common cross-compile combination. I assume that you're using gcc with all dependencies preinstalled.

Windows

x86

x86 means 32 bit architecture

i686-w64-mingw32-gcc exploit.c -o exploit_32.exe

In case when code uses/includes winsock 2

i686-w64-mingw32-gcc exploit.c -oexploit_x86.exe -lws2_32

x64

x64 means 64 bit architecture. Sometimes also refered as amd64.

x86_64-w64-mingw32-gcc exploit.c -o exploit_64.exe

Linux

x86

gcc exploit.c -o exploit_x86 -m32

-m32 is optional if host architecture is x32

x64

gcc exploit.c -o exploit_x64 -m64

target specific

gcc exploit.c -o exploit_x64 -m64 -Wl,--hash-style=both

--hash-style=both

Depending on how your distro's GCC was configured, hash tables can be different. AFAIK most use either both or gnu styles by default. Both simply means that linked files will include, both gnu and sysv hashtables. This shouldn't matter unless you try to run your program on a system with dynamic linker which does not understand GNU hashtables. In that case, if program was built with -Wl,--hash-style=gnu, you'll get an error at startup about unsupported hashtable format.

compiling dynamic/static libraries

If you need to build a library and link it to the program, this is the way to go.

NOTE: all different build types from above are applicable here as well (win/lin, x86/x64)

These are the files used in all examples, so you can repeat everything by copy/paste commands.

library.h

#pragma once // this is to ensure that this h file (library.h) is only included once, even if it is mentioned in multiple places
#include <stdio.h>

void my_print(int a);

library.c

#include "library.h"

void my_print(int a)
{
    printf("my_print: %d\n", a);
}

program.c

#include "library.h"

void main()
{
    int n = 10;
    my_print(n);
}

Build a dynamically linkable library (so)

gcc -shared -fpic library.c -o library.so

Check the output file

file library.so
    library.so: ELF 32-bit LSB pie executable Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=eae3bc2e3a5be284d1dd8d13bd047edb98330d30, not stripped


nm library.so 
    00004014 b completed.6950
             w __cxa_finalize@@GLIBC_2.1.3
    00001070 t deregister_tm_clones
    00001100 t __do_global_dtors_aux
    00003f0c t __do_global_dtors_aux_fini_array_entry
    00004010 d __dso_handle
    00003f10 d _DYNAMIC
    0000118c T _fini
    00001150 t frame_dummy
    00003f08 t __frame_dummy_init_array_entry
    000020c4 r __FRAME_END__
    00004000 d _GLOBAL_OFFSET_TABLE_
             w __gmon_start__
    00002010 r __GNU_EH_FRAME_HDR
    00001000 T _init
             w _ITM_deregisterTMCloneTable
             w _ITM_registerTMCloneTable
    00001159 T my_print // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
             U printf@@GLIBC_2.0
    000010b0 t register_tm_clones
    00004014 d __TMC_END__
    00001187 t __x86.get_pc_thunk.ax
    00001060 t __x86.get_pc_thunk.bx
    00001155 t __x86.get_pc_thunk.dx


ldd library.so
    linux-gate.so.1 (0xb7fba000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7db5000)
    /lib/ld-linux.so.2 (0xb7fbc000)

Compile and link the program, using previously built library

gcc -L./ -lrary program.c -o program

NOTE: -lrary means library; 'lib' will be added by the compiler, so if you want to link something called 'library', you need to remove 'lib' part coz it will be added automatically.

Check the output file

file program
    program: ELF 32-bit LSB pie executable Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fb84b93b5662e24e8021111bca1a11bc8fcdc45a, not stripped


ldd program
    linux-gate.so.1 (0xb7fbf000)
    library.so => not found
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7dba000)
    /lib/ld-linux.so.2 (0xb7fc1000)

NOTE: in case of an error (like shown above), it means that loader doesn't know how to find library.so (the fact that it is in the same folder as program wasn't enough for loader to find it). The loader searches for libraries based on environment variable LD_LIBRARY_PATH; so, if you want to use the library.so (or any other missing library), you need to either add the folder which contains the missing to LD_LIBRARY_PATH, or to copy library.so to the place where other libraries (so files) reside.

WORKAROUND

In some cases you can link statically by compiling static library (.a) and then compile the program using and including that static library. That means that the library itself will be included in the final program. That may not work in some cases + it increases size of the final file. The example follows:

Compile to an object file

gcc -c library.c -o library.o

Make an archive out of it

ar rcs library.a library.o

Check the output files

file library.o
    library.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
file library.a
    library.a: current ar archive

compile with static libs

gcc -static program.c -L. -lrary -o program

IMPORTANT: the order of the arguments is VERY IMPORTANT; if you make a change in order, build will fail !!!

Check the output file

file program
    program: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=50ef66baa532078ccf1df75e3a82a1304b834110, not stripped

ldd program
    not a dynamic executable

'not a dynamic executable' - means that we did what we wanted - no dynamic executable was required, which means that everything app needs is already inside the executable.

_GNU_SOURCE macro

Sometimes, you will have to use additional functionalities in C which are not provided by standard C. In that case, you need to use additional functionalities, which can be turn on by macro _GNU_SOURCE.

From manual:

_GNU_SOURCE

Defining this macro (with any value) implicitly defines _ATFILE_SOURCE, _LARGEFILE64_SOURCE, _ISOC99_SOURCE, _XOPEN_SOURCE_EXTENDED, _POSIX_SOURCE, _POSIX_C_SOURCE with the value 200809L (200112L in glibc versions before 2.10; 199506L in glibc versions before 2.5; 199309L in glibc ver‐ sions before 2.1) and _XOPEN_SOURCE with the value 700 (600 in glibc versions before 2.10; 500 in glibc versions before 2.2). In addition, various GNU-specific extensions are also exposed.

Since glibc 2.19, defining _GNU_SOURCE also has the effect of implicitly defining _DEFAULT_SOURCE. In glibc versions before 2.20, defining _GNU_SOURCE also had the effect of implicitly defining _BSD_SOURCE and _SVID_SOURCE.

Note: _GNU_SOURCE needs to be defined before including header files so that the respective headers enable the features. For example:

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
...

_GNU_SOURCE can be also be enabled per compilation using -D flag:

$ gcc -D _GNU_SOURCE file.c

(-D is not specific to _GNU_SOURCE but any macro be defined this way).

Last updated