Skip to content

Commit 07ff886

Browse files
authored
Allow creating an ELF from in-memory bytes (#2574)
1 parent e5cd224 commit 07ff886

File tree

4 files changed

+28
-10
lines changed

4 files changed

+28
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ The table below shows which release corresponds to each branch, and what date th
9090
- [#2504][2504] doc: add example case for `tuple` (host, port pair) in `gdb.attach`
9191
- [#2546][2546] ssh: Allow passing disabled_algorithms keyword argument from ssh to paramiko
9292
- [#2538][2538] Add `ssh -L` / `ssh.connect_remote()` workaround when `AllowTcpForwarding` is disabled
93-
- [#2574][2574] Detect when Terminator is being used as terminal
93+
- [#2574][2574] Allow creating an ELF from in-memory bytes
94+
- [#2575][2575] Detect when Terminator is being used as terminal
9495

9596
[2419]: https://github.com/Gallopsled/pwntools/pull/2419
9697
[2551]: https://github.com/Gallopsled/pwntools/pull/2551
@@ -108,6 +109,7 @@ The table below shows which release corresponds to each branch, and what date th
108109
[2546]: https://github.com/Gallopsled/pwntools/pull/2546
109110
[2538]: https://github.com/Gallopsled/pwntools/pull/2538
110111
[2574]: https://github.com/Gallopsled/pwntools/pull/2574
112+
[2575]: https://github.com/Gallopsled/pwntools/pull/2575
111113

112114
## 4.15.0 (`beta`)
113115

pwnlib/elf/corefile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,10 @@ def __init__(self, *a, **kw):
568568
self._address = 0
569569

570570
if self.elftype != 'CORE':
571-
log.error("%s is not a valid corefile" % self.file.name)
571+
log.error("%s is not a valid corefile" % self.path)
572572

573573
if self.arch not in prstatus_types:
574-
log.warn_once("%s does not use a supported corefile architecture, registers are unavailable" % self.file.name)
574+
log.warn_once("%s does not use a supported corefile architecture, registers are unavailable" % self.path)
575575

576576
prstatus_type = prstatus_types.get(self.arch)
577577
siginfo_type = siginfo_types.get(self.bits)

pwnlib/elf/elf.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@
3030
>>> disasm(open('/tmp/quiet-cat','rb').read(1))
3131
' 0: c3 ret'
3232
33+
An ELF can also be created from in-memory bytes.
34+
35+
>>> bytes = open('/bin/cat', 'rb').read()
36+
>>> e = ELF(bytes)
37+
>>> e.read(e.address+1, 3)
38+
b'ELF'
39+
>>> e.asm(e.address, 'ret')
40+
>>> e.save('/tmp/quiet-cat')
41+
>>> disasm(open('/tmp/quiet-cat','rb').read(1))
42+
' 0: c3 ret'
43+
3344
Module Members
3445
--------------
3546
"""
@@ -211,16 +222,21 @@ class ELF(ELFFile):
211222
_fill_gaps = True
212223

213224

214-
def __init__(self, path, checksec=True):
225+
def __init__(self, path_or_bytes, checksec=True):
215226
# elftools uses the backing file for all reads and writes
216227
# in order to permit writing without being able to write to disk,
217228
# mmap() the file.
218229

219-
#: :class:`file`: Open handle to the ELF file on disk
220-
self.file = open(path,'rb')
221-
222-
#: :class:`mmap.mmap`: Memory-mapped copy of the ELF file on disk
223-
self.mmap = mmap.mmap(self.file.fileno(), 0, access=mmap.ACCESS_COPY)
230+
if isinstance(path_or_bytes, (bytes, bytearray)) and path_or_bytes.startswith(b'\x7FELF'):
231+
self.file = self.mmap = mmap.mmap(-1, len(path_or_bytes))
232+
self.mmap.write(path_or_bytes)
233+
path = "<bytes>"
234+
else:
235+
#: :class:`file`: Open handle to the ELF file on disk
236+
self.file = open(path_or_bytes,'rb')
237+
#: :class:`mmap.mmap`: Memory-mapped copy of the ELF file on disk
238+
self.mmap = mmap.mmap(self.file.fileno(), 0, access=mmap.ACCESS_COPY)
239+
path = path_or_bytes
224240

225241
super(ELF,self).__init__(self.mmap)
226242

pwnlib/rop/rop.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,7 @@ def __cache_load(self, elf):
12711271
return None
12721272
gadgets = eval(open(filename).read())
12731273
gadgets = {k - elf.load_addr + elf.address:v for k, v in gadgets.items()}
1274-
log.info_once('Loaded %s cached gadgets for %r', len(gadgets), elf.file.name)
1274+
log.info_once('Loaded %s cached gadgets for %r', len(gadgets), elf.path)
12751275
return gadgets
12761276

12771277
def __cache_save(self, elf, data):

0 commit comments

Comments
 (0)