• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 8912ca5a8c3a9725c3ba6d30561607150a6faebe-PR-2205

pending completion
8912ca5a8c3a9725c3ba6d30561607150a6faebe-PR-2205

Pull #2205

github-actions

web-flow
Merge 81f463e2c into 8b4cacf8b
Pull Request #2205: Fix stable Python 2 installation from a built wheel

3878 of 6371 branches covered (60.87%)

12199 of 16604 relevant lines covered (73.47%)

0.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/pwnlib/qemu.py
1
"""Run foreign-architecture binaries
2

3
Overview
4
--------
5

6
So you want to exploit ARM binaries on your Intel PC?
7

8
Pwntools has a good level of integration with QEMU user-mode emulation,
9
in order to run, debug, and pwn foreign architecture binaries.
10

11
In general, everything magic happens "behind the scenes", and pwntools
12
attempts to make your life easier.
13

14
When using :class:`.process`, pwntools will attempt to blindly
15
execute the binary, in case your system is configured to use ``binfmt-misc``.
16

17
If this fails, pwntools will attempt to manually launch the binary under
18
qemu user-mode emulation.  Preference is given to statically-linked variants,
19
i.e. ``qemu-arm-static`` will be selected before ``qemu-arm``.
20

21
Debugging
22
~~~~~~~~~
23

24
When debugging binaries with :func:`.gdb.debug`, pwntools automatically adds
25
the appropriate command-line flags to QEMU to start its GDB stub, and
26
automatically informs GDB of the correct architecture and sysroot.
27

28
Sysroot
29
~~~~~~~
30
You can override the default sysroot by setting the ``QEMU_LD_PREFIX``
31
environment variable.  This affects where ``qemu`` will look for files when
32
``open()`` is called, e.g. when the linker is attempting to resolve ``libc.so``.
33

34
Required Setup
35
--------------
36

37
For Ubuntu 16.04 and newer, the setup is relatively straightforward for most
38
architectures.
39

40
First, install the QEMU emulator itself.  If your binary is statically-linked,
41
this is sufficient. ::
42

43
    $ sudo apt-get install qemu-user
44

45
If your binary is dynamically linked, you need to install libraries like libc.
46
Generally, this package is named ``libc6-$ARCH-cross``, e.g. ``libc-mips-cross``.
47
ARM comes in both soft-float and hard-float variants, e.g. ``armhf``. ::
48

49
    $ sudo apt-get install libc6-arm64-cross
50

51
If your binary relies on additional libraries, you can generally find them
52
easily with ``apt-cache search``.  For example, if it's a C++ binary it
53
may require ``libstdc++``. ::
54

55
    $ apt-cache search 'libstdc++' | grep arm64
56

57
Any other libraries that you require you'll have to find some other way.
58

59
Telling QEMU Where Libraries Are
60
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61

62
The libraries are now installed on your system at e.g. ``/usr/aarch64-linux-gnu``.
63

64
QEMU does not know where they are, and expects them to be at e.g. ``/etc/qemu-binfmt/aarch64``.
65
If you try to run your library now, you'll probably see an error about ``libc.so.6`` missing.
66

67
Create the ``/etc/qemu-binfmt`` directory if it does not exist, and create a symlink to
68
the appropriate path. ::
69

70
    $ sudo mkdir /etc/qemu-binfmt
71
    $ sudo ln -s /usr/aarch64-linux-gnu /etc/qemu-binfmt/aarch64
72

73
Now QEMU should be able to run the libraries.
74
"""
75
from __future__ import absolute_import
1✔
76
from __future__ import division
1✔
77

78
import os
1✔
79

80
from pwnlib.context import LocalContext
1✔
81
from pwnlib.context import context
1✔
82
from pwnlib.log import getLogger
1✔
83
from pwnlib.util import misc
1✔
84

85
log = getLogger(__name__)
1✔
86

87
@LocalContext
1✔
88
def archname():
89
    """
90
    Returns the name which QEMU uses for the currently selected
91
    architecture.
92

93
    >>> pwnlib.qemu.archname()
94
    'i386'
95
    >>> pwnlib.qemu.archname(arch='powerpc')
96
    'ppc'
97
    """
98
    return {
1✔
99
        ('amd64', 'little'):     'x86_64',
100
        ('arm', 'big'):          'armeb',
101
        ('mips', 'little'):      'mipsel',
102
        ('mips64', 'little'):    'mips64el',
103
        ('powerpc', 'big'):      'ppc',
104
        ('powerpc64', 'big'):    'ppc64',
105
        ('powerpc64', 'little'): 'ppc64le',
106
        ('thumb', 'little'):     'arm',
107
        ('thumb', 'big'):        'armeb',
108
    }.get((context.arch, context.endian), context.arch)
109

110
@LocalContext
1✔
111
def user_path():
112
    """
113
    Returns the path to the QEMU-user binary for the currently
114
    selected architecture.
115

116
    >>> pwnlib.qemu.user_path()
117
    'qemu-i386-static'
118
    >>> pwnlib.qemu.user_path(arch='thumb')
119
    'qemu-arm-static'
120
    """
121
    arch   = archname()
1✔
122
    system = 'qemu-system-' + arch
1✔
123
    normal = 'qemu-' + arch
1✔
124
    static = normal + '-static'
1✔
125

126
    if context.os == 'baremetal':
1!
127
        if misc.which(system):
×
128
            return system
×
129
    else:
130
        if misc.which(static):
1!
131
            return static
1✔
132

133
        if misc.which(normal):
×
134
            return normal
×
135

136
    log.warn_once("Neither %r nor %r are available" % (normal, static))
×
137

138
@LocalContext
1✔
139
def ld_prefix(path=None, env=None):
1✔
140
    """Returns the linker prefix for the selected qemu-user binary
141

142
    >>> pwnlib.qemu.ld_prefix(arch='arm')
143
    '/etc/qemu-binfmt/arm'
144
    """
145
    if context.os == 'baremetal':
1!
146
        return ""
×
147

148
    if path is None:
1!
149
        path = user_path()
1✔
150

151
    # Did we explicitly specify the path in an environment variable?
152
    if env and b'QEMU_LD_PREFIX' in env:
1!
153
        return env[b'QEMU_LD_PREFIX'].decode()
×
154

155
    if 'QEMU_LD_PREFIX' in os.environ:
1!
156
        return os.environ['QEMU_LD_PREFIX']
×
157

158
    # Cyclic imports!
159
    from pwnlib.tubes.process import process
1✔
160

161
    with context.quiet:
1✔
162
        with process([path, '--help'], env=env) as io:
1✔
163
            line = io.recvline_regex(b'QEMU_LD_PREFIX *=')
1✔
164

165
    _, libpath = line.split(b'=', 1)
1✔
166

167
    libpath = libpath.strip()
1✔
168

169
    if not isinstance(libpath, str):
1!
170
        libpath = libpath.decode('utf-8')
×
171

172
    return libpath
1✔
173

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc