Cross-Execute Your Linux Binaries, Don’t Cross-Compile Them (2024)

Back

Domen Puncer Kugler

June 5, 2024

6 mins read

Lolbins? Where we’re going, we don’t need lolbins.

At NCC Group, as a consultant in our hardware and embedded systems practice1, I often get to play with various devices, which is always fun, but getting your own software to run on them can be a bit of a pain.
This article documents a few realisations and tricks that make my life easier. There is nothing new about anything mentioned here, but there is also hardly anything written about these (ab)use cases.

The challenges we are looking to solve are:

  • Running standard Linux tools on your embedded device
  • Compiling your own tools to run on the embedded device
  • Running binaries from the embedded device on your PC

This can often be achieved by cross-compiling and/or statically compiling the target binary. It is very much a valid approach, but it can also be time-consuming, even when you’re seasoned at this sort of thing. So, the approach described here does not do that.

The realisation is that while dynamically linked binaries need some of the environment, it is actually not that hard to figure out what that environment is and to copy it over to the system where you want to run the binary.

Consider the example of running strace from an arm64 Raspberry Pi on an arm64 Android phone.

Just copying won’t work, since Android differs too much from common Linux distributions:

pi@rpi:~ $ adb push `which strace` /data/local/tmp/usr/bin/strace: 1 file pushed, 0 skipped. 16.0 MB/s (1640712 bytes in 0.098s)pi@rpi:~ $ adb exec-out /data/local/tmp/strace -ttewrite /bin/echo X/system/bin/sh: /data/local/tmp/strace: No such file or directorypi@rpi:~ $ adb exec-out ldd /data/local/tmp/strace  linux-vdso.so.1 => [vdso] (0x73edb38000)CANNOT LINK EXECUTABLE "linker64": library "libc.so.6" not found: needed by main executable

We can list the dependencies. strace depends on the dynamic linker, libraries and often on some special bits like VDSO.

pi@rpi:~ $ ldd `which strace` linux-vdso.so.1 (0x0000007faf464000) libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007faf0b0000) /lib/ld-linux-aarch64.so.1 (0x0000007faf427000)

We can copy the dependencies and use the appropriate dynamic linker to load them (the first highlighted bit enumerates the dependencies):

pi@rpi:~ $ bin=`which strace`; adb push $bin $(ldd $bin | sed -nre 's/^[^/]*(\/.*) \(0x.*\)$/\1/p') /data/local/tmp//usr/bin/strace: 1 file pushed, 0 skipped. 19.4 MB/s (1640712 bytes in 0.081s)/lib/aarch64-linux-gnu/libc.so.6: 1 file pushed, 0 skipped. 23.7 MB/s (1651472 bytes in 0.067s)/lib/ld-linux-aarch64.so.1: 1 file pushed, 0 skipped. 18.6 MB/s (202904 bytes in 0.010s)3 files pushed, 0 skipped. 19.0 MB/s (3495088 bytes in 0.176s)pi@rpi:~ $ adb exec-out /data/local/tmp/ld-linux-aarch64.so.1 --library-path /data/local/tmp/ /data/local/tmp/strace -ttewrite /bin/echo X10:36:27.842717 write(1, "X\n", 2X) = 210:36:27.845895 +++ exited with 0 +++

There, perfect, we have strace on our device now, and it only took two ugly one-liners.

My preferred way of setting up a cross architecture Linux chroot is using debootstrap and schroot. This assumes you are using a distribution from a Debian family (I do see there’s debootstrap for Fedora as well, haven’t tried it though).

Logan Chien posted this nice and short guide2, which basically boils down to following three sections:

kali@kali:~$ apt install debootstrap qemu-user-static schroot

Installing a base system

kali@kali:~$ sudo debootstrap --arch=arm64 bookworm ~/chroots/arm64-test...I: Base system installed successfully.

This takes a minute or two and installs a base Debian Bookworm system for arm64. The distribution names come from Debian (http://ftp.debian.org/debian/dists/) or Ubuntu (http://archive.ubuntu.com/ubuntu/dists/). For the architecture names navigate into subfolders (for example http://ftp.debian.org/debian/dists/bookworm/main/). If you need a less common architecture try the testing channel, which supports riscv64 for example.

Setting up schroot

kali@kali:~$ echo "[arm64-test] directory=$HOME/chroots/arm64-testusers=$(whoami)root-users=$(whoami)type=directory" | sudo tee /etc/schroot/chroot.d/arm64-test

Now you can enter the chroot:

kali@kali:~$ schroot -c arm64-test(arm64-test)kali@kali:~$ uname -aLinux kali 6.5.0-kali3-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.5.6-1kali1 (2023-10-09) aarch64 GNU/Linux(arm64-test)kali@kali:~$ logoutkali@kali:~$ schroot -c arm64-test -u root(arm64-test)root@kali:/home/kali# iduid=0(root) gid=0(root) groups=0(root),4(adm),20(dialout),119(wireshark),142(kaboxer)

Finish

So, here you have it. Install the wanted binary, and copy it to your target device like we did before from Raspberry Pi.

(arm64-test)kali@kali:~$ # sudo apt install strace adb...(arm64-test)kali@kali:~$ bindeps() { echo "$1" $(ldd "$1" | sed -nre "s/^[^/]*(\/.*) \(0x.*\)$/\1/p"); }(arm64-test)kali@kali:~$ for i in $(bindeps `which strace`); do adb push $i /data/local/tmp/; done/usr/bin/strace: 1 file pushed, 0 skipped. 13.3 MB/s (1640712 bytes in 0.117s)/lib/aarch64-linux-gnu/libc.so.6: 1 file pushed, 0 skipped. 14.0 MB/s (1651472 bytes in 0.113s)/lib/ld-linux-aarch64.so.1: 1 file pushed, 0 skipped. 7.4 MB/s (202904 bytes in 0.026s)(arm64-test)kali@kali:~$ adb shellsargo:/ $ xrun() { k=/data/local/tmp; bin=$1; shift; $k/ld* --library-path $k $k/$bin "$@"; }
sargo:/ $ xrun strace -tte write /bin/echo X
16:31:59.159266 write(1, "X\n", 2X ) = 2 16:31:59.163322 +++ exited with 0 +++

Cross-compiling without cross-compiling

Well, now you have a full Linux distribution of your chosen architecture running, so you can just compile any special tools. Sure, it is emulated through QEMU under the hood, but for anything smallish one does not even notice the performance hit.

And you have avoided dealing with a toolchain to cross-compile for that one-off task.

In the above examples the binary we wished to run was copied onto the target device. Occasionally, one wants to do the reverse, run the binary from the device locally on your PC.

The exact same approach should work, and for anything non-trivial I would recommend a custom setup chroot, so you can easily place the required files in the correct locations (and it is also easy to later delete it all).

For a simple tool though, one can get away by using QEMU:

kali@kali:~/android_test$ adb exec-out 'bindeps() { echo "$1" $(ldd "$1" | sed -nre "s/^[^/]*(\/.*) \(0x.*\)$/\1/p"); }; bindeps `which dexdump`' | xargs -n1 adb pull/apex/com.android.art/bin/dexdump: 1 file pulled, 0 skipped. 11.6 MB/s (108744 bytes in 0.009s)/apex/com.android.art/lib64/libdexfile.so: 1 file pulled, 0 skipped. 4.7 MB/s (347040 bytes in 0.070s)/apex/com.android.art/lib64/libartpalette.so: 1 file pulled, 0 skipped. 2.0 MB/s (14896 bytes in 0.007s)/apex/com.android.art/lib64/libbase.so: 1 file pulled, 0 skipped. 13.3 MB/s (251152 bytes in 0.018s)/apex/com.android.art/lib64/libartbase.so: 1 file pulled, 0 skipped. 20.8 MB/s (497272 bytes in 0.023s)/apex/com.android.art/lib64/libc++.so: 1 file pulled, 0 skipped. 8.1 MB/s (671496 bytes in 0.079s)/apex/com.android.art/lib64/libziparchive.so: 1 file pulled, 0 skipped. 1.2 MB/s (79752 bytes in 0.066s)/apex/com.android.runtime/lib64/bionic/libc.so: 1 file pulled, 0 skipped. 26.1 MB/s (1013048 bytes in 0.037s)/apex/com.android.runtime/lib64/bionic/libdl.so: 1 file pulled, 0 skipped. 2.0 MB/s (13728 bytes in 0.006s)/apex/com.android.runtime/lib64/bionic/libm.so: 1 file pulled, 0 skipped. 12.7 MB/s (221072 bytes in 0.017s)/system/lib64/libz.so: 1 file pulled, 0 skipped. 6.5 MB/s (98016 bytes in 0.014s)/system/lib64/liblog.so: 1 file pulled, 0 skipped. 5.8 MB/s (62176 bytes in 0.010s)/system/lib64/libc++.so: 1 file pulled, 0 skipped. 25.7 MB/s (700400 bytes in 0.026s)kali@kali:~/android_test$ adb pull /system/bin/linker64/system/bin/linker64: 1 file pulled, 0 skipped. 13.1 MB/s (1802728 bytes in 0.131s)kali@kali:~/android_test$ qemu-arm64 -E LD_LIBRARY_PATH=$PWD ./linker64 $PWD/dexdumplinker: Warning: failed to find generated linker configuration from "/linkerconfig/ld.config.txt"WARNING: linker: Warning: failed to find generated linker configuration from "/linkerconfig/ld.config.txt"dexdump E 05-02 13:14:39 1728592 1728592 dexdump_main.cc:126] No file specifieddexdump E 05-02 13:14:39 1728592 1728592 dexdump_main.cc:41] Copyright (C) 2007 The Android Open Source Projectdexdump E 05-02 13:14:39 1728592 1728592 dexdump_main.cc:41] dexdump E 05-02 13:14:39 1728592 1728592 dexdump_main.cc:42] dexdump: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-j] [-l layout] [-n] [-o outfile] dexfile......

With the dynamic linker, dependency libraries and the target binary, we can use qemu-user to run our binary.

The observant reader will notice this differs slightly from the way ld was invoked before. It appears Android’s dynamic linker doesn’t support an argument to specify library path, so we have used LD_LIBRARY_PATH (in the first example above, we could have invoked strace this way as well: LD_LIBRRAY_PATH=/data/local/tmp /data/local/tmp/ld-linux-aarch64.so.1 /data/local/tmp/strace).

I hope you found this useful.

Helper functions

The list of dependencies that are to be copied along with the binary can be generated with:

$ bindeps() { echo "$1" $(ldd "$1" | sed -nre "s/^[^/]*(\/.*) \(0x.*\)$/\1/p"); }$ bindeps `which strace`

The binary can then be run on the target device with (Note the path will need adjusting and possibly linker arguments as well):

$ xrun() { k=/data/local/tmp; bin=$1; shift; $k/ld* --library-path $k $k/$bin "$@"; }
$ xrun strace -tte write /bin/echo X

Published by Domen Puncer Kugler

Published by Domen Puncer Kugler

View all posts by Domen Puncer Kugler ->

Here are some related articles you may find interesting

Public Report – Keyfork Implementation Review

In April 2024, Distrust engaged NCC Group’s Cryptography Services team to perform a cryptographic security assessment of keyfork, described as “an opinionated and modular toolchain for generating and managing a wide range of cryptographic keys offline and on smartcards from a shared mnemonic phrase”. The tool is intended to be…

June 6, 2024

1 min read

Why AI Will Not Fully Replace Humans for Web Penetration Testing

Written by: Steven van der Baan In the ever-evolving landscape of cybersecurity, the integration of artificial intelligence (AI) has revolutionized various aspects of threat detection, prevention, and mitigation. Web penetration testing, a crucial component of ensuring the security posture of digital assets, has seen significant advancements through AI-powered tools. While…

Machine Learning

May 31, 2024

2 mins read

Integrating DigitalOcean into ScoutSuite

We are excited to announce the addition of a new provider in our open-source, multi-cloud auditing tool ScoutSuite (on GitHub)! In April, we received a remarkable pull request from Asif Wani, Product Security Lead at DigitalOcean APAC, to integrate DigitalOcean services into ScoutSuite. After reviewing the request, NCC Group not…

Tool Release

May 27, 2024

1 min read

Previous post Next post

View articles by category

  • Academic Partnership (3)

  • Annual Research Report (3)

  • Asia Pacific Research (1)

  • Blockchain (5)

  • Books (17)

  • Business Insights (6)

  • Cloud Security (18)

  • Conferences (37)

  • Cryptography (117)

  • CTFs/Microcorruption (1)

  • Current events (1)

  • Cyber as a Science (6)

  • Cyber Security (403)

  • Detection and Threat Hunting (16)

  • Digital Forensics and Incident Response (DFIR) (23)

  • Disclosure Policy (1)

  • Emerging Technologies (12)

  • Engineering (5)

  • Fox-IT (18)

  • Fox-IT and European Research (8)

  • Intern Projects (2)

  • iSec Partners (52)

  • Machine Learning (30)

  • North American Research (28)

  • Patch notifications (35)

  • Presentations (55)

  • protocol_name (1)

  • Public interest technology (1)

  • Public interest technology (10)

  • Public Reports (53)

  • Public tools (105)

  • Reducing Vulnerabilities at Scale (22)

  • Research (367)

  • Research Paper (20)

  • Resources (2)

  • Reverse Engineering (49)

  • Standards (13)

  • Technical advisories (219)

  • Technology Policy (1)

  • Threat briefs (3)

  • Threat Intelligence (69)

  • Tool Release (110)

  • Transport (16)

  • Tutorial/Study Guide (48)

  • UK Research (10)

  • Uncategorized (28)

  • VSR (32)

  • Vulnerability (169)

  • Vulnerability Research (8)

  • Whitepapers (239)

Most popular posts

Most recent posts

  • Public Report – Keyfork Implementation Review
  • Cross-Execute Your Linux Binaries, Don’t Cross-Compile Them
  • Why AI Will Not Fully Replace Humans for Web Penetration Testing
  • Integrating DigitalOcean into ScoutSuite
  • Cranim: A Toolkit for Cryptographic Visualization

Call us before you need us.

Our experts will help you.

Get in touch

Cross-Execute Your Linux Binaries, Don’t Cross-Compile Them (2024)

FAQs

How to do cross compilation in Linux? ›

Ways to cross compile
  1. Step one: Get a toolchain. ...
  2. Step two: Install any host tools that will be required (e.g. CMake)
  3. Step three: Cross build and install any libraries that will be required (e.g. OpenSSL, SQLite, etc..). ...
  4. Pro tips:
Oct 1, 2023

How to cross compile in Go? ›

Cross-compiling made easy with Golang
  1. Download and install prerequisite software.
  2. Verify whether new test packages for the software I'm testing are available on the build server.
  3. Get and set the required yum repos for the dependent software packages.
  4. Download and install the new test packages (based on step #2).
Jan 14, 2021

How do I compile and run Linux? ›

Compiling and Running C++ Programs in Linux
  1. Write your C++ program and save it with a . cpp extension.
  2. Open your terminal and navigate to the directory containing your C++ file.
  3. Compile the program with g++ filename. cpp -o outputname.
  4. Run the compiled program by typing ./outputname into the terminal.

What is an example of a cross compiler? ›

A cross compiler is a compiler capable of creating executable code for a platform other than the one on which the compiler is running. For example, a compiler that runs on a PC but generates code that runs on Android devices is a cross compiler.

How to compile Go Linux? ›

To compile a Go program, navigate to the directory containing your .go file and run go build <file>.go . This generates an executable in the same directory. The go build command compiles the programs, resolving dependencies and creating a binary.

Why is cross-compilation hard? ›

the make files, compilers, etc depend on the idea that they can go to a specific spot and find what they need. In the cross compiling case, though, the cross compiler, make files, etc cannot make these assumptions - if they do they will link the wrong libraries.

How does cross compilation work? ›

To cross-compile is to build on one platform a binary that will run on another platform. When speaking of cross-compilation, it is important to distinguish between the build platform on which the compilation is performed, and the host platform on which the resulting executable is expected to run.

How to cross-compile from x86 to arm? ›

Cross compilation will happen on a Linux x86 machine for 96Boards ARM device.
  1. Step 1: Update 96Boards (ARM) system and Host (x86 Machine) computer. ...
  2. Step 2: If you are using libsoc and or mraa make sure they are installed and up to date. ...
  3. Step 3: Install cross compilers on host machine. ...
  4. Step 4: Install package dependencies.

How to cross-compile Linux kernel for a arm board? ›

For that you need to download the ARM compilers first. I suggest you download the compiler from http://www.linaro.org/downloads/ then set the CROSS_COMPILE environment variable to arm-linux-gcc. Finally compile the code then run in ARM. use file <filename> whether it is ARM executable or not.

How to cross-compile kernel modules? ›

Inorder to setup the cross-compilation of kernel modules, follow the below steps.
  1. Build and install petalinux SDK [ Refer, PetaLinux Tools Documentation Reference Guide ]
  2. Source cross-compilation environment. ...
  3. Go to kernel source folder in petalinux build folder. ...
  4. Generate .config file for kernel and prepare modules.

Top Articles
Latest Posts
Article information

Author: Catherine Tremblay

Last Updated:

Views: 5907

Rating: 4.7 / 5 (47 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Catherine Tremblay

Birthday: 1999-09-23

Address: Suite 461 73643 Sherril Loaf, Dickinsonland, AZ 47941-2379

Phone: +2678139151039

Job: International Administration Supervisor

Hobby: Dowsing, Snowboarding, Rowing, Beekeeping, Calligraphy, Shooting, Air sports

Introduction: My name is Catherine Tremblay, I am a precious, perfect, tasty, enthusiastic, inexpensive, vast, kind person who loves writing and wants to share my knowledge and understanding with you.