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

Gallopsled / pwntools / 11532588290

26 Oct 2024 02:29PM UTC coverage: 73.585% (+2.1%) from 71.491%
11532588290

push

github

peace-maker
Merge branch 'dev' into interactive

3767 of 6364 branches covered (59.19%)

1463 of 2234 new or added lines in 69 files covered. (65.49%)

85 existing lines in 22 files now uncovered.

13246 of 18001 relevant lines covered (73.58%)

0.74 hits per line

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

50.0
/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():
1✔
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():
1✔
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')  # doctest: +SKIP
143
    '/etc/qemu-binfmt/arm'
144
    """
UNCOV
145
    if context.os == 'baremetal':
×
146
        return ""
×
147

UNCOV
148
    if path is None:
×
UNCOV
149
        path = user_path()
×
150

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

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

158
    # Cyclic imports!
UNCOV
159
    from pwnlib.tubes.process import process
×
160

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

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

UNCOV
167
    libpath = libpath.strip()
×
168

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

UNCOV
172
    return libpath
×
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