Skip to content

Commit 509df40

Browse files
authored
Merge branch 'dev' into libcdb_local_libc
2 parents 4a19db2 + 993f590 commit 509df40

17 files changed

+398
-109
lines changed

.github/workflows/android.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/checkout@v4
1515

1616
- name: Cache for pip
17-
uses: actions/cache@v3
17+
uses: actions/cache@v4
1818
id: cache-pip
1919
with:
2020
path: ~/.cache/pip

.github/workflows/ci.yml

+10-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
git log --oneline --graph -10
2121
2222
- name: Cache for pip
23-
uses: actions/cache@v3
23+
uses: actions/cache@v4
2424
id: cache-pip
2525
with:
2626
path: ~/.cache/pip
@@ -178,18 +178,19 @@ jobs:
178178
pwn libcdb hash b229d1da1e161f95e839cf90cded5f719e5de308
179179
180180
- name: Build source and wheel distributions
181-
if: matrix.python_version > '2.7'
181+
if: matrix.python_version != '2.7'
182182
run: |
183183
python -m build
184184
185-
- uses: actions/upload-artifact@v3
185+
- uses: actions/upload-artifact@v4
186+
if: matrix.python_version != '2.7'
186187
with:
187188
name: packages
188189
path: dist/
189190

190-
- uses: actions/upload-artifact@v3
191+
- uses: actions/upload-artifact@v4
191192
with:
192-
name: coverage
193+
name: coverage-${{ matrix.python_version }}
193194
path: .coverage*
194195

195196

@@ -201,10 +202,10 @@ jobs:
201202
with:
202203
fetch-depth: 20
203204

204-
- uses: actions/download-artifact@v3
205+
- uses: actions/download-artifact@v4
205206
with:
206-
name: coverage
207-
path: .
207+
pattern: coverage-*
208+
merge-multiple: true
208209

209210
- name: Install coveralls
210211
run: |
@@ -243,7 +244,7 @@ jobs:
243244
needs: test
244245
steps:
245246
- name: Download artifacts
246-
uses: actions/download-artifact@v3
247+
uses: actions/download-artifact@v4
247248
with:
248249
name: packages
249250
path: dist

.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- name: Cache for pip
15-
uses: actions/cache@v3
15+
uses: actions/cache@v4
1616
id: cache-pip
1717
with:
1818
path: ~/.cache/pip

.github/workflows/pylint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- name: Cache for pip
15-
uses: actions/cache@v3
15+
uses: actions/cache@v4
1616
id: cache-pip
1717
with:
1818
path: ~/.cache/pip

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ The table below shows which release corresponds to each branch, and what date th
7979
- [#2309][2309] Detect challenge binary and libc in `pwn template`
8080
- [#2308][2308] Fix WinExec shellcraft to make sure it's 16 byte aligned
8181
- [#2279][2279] Make `pwn template` always set context.binary
82+
- [#2310][2310] Add support to start a process on Windows
83+
- [#2334][2334] Speed up disasm commandline tool with colored output
84+
- [#2328][2328] Lookup using $PATHEXT file extensions in `which` on Windows
85+
- [#2189][2189] Explicitly define p64/u64 functions for IDE support
86+
- [#2339][2339] Fix: Allow setting attributes on gdb Breakpoints
87+
- [#2323][2323] Retry failed lookups after one week in libcdb
8288
- [#2325][2325] Match against local system libc first in libcdb
8389

8490
[2242]: https://github.com/Gallopsled/pwntools/pull/2242
@@ -90,6 +96,12 @@ The table below shows which release corresponds to each branch, and what date th
9096
[2309]: https://github.com/Gallopsled/pwntools/pull/2309
9197
[2308]: https://github.com/Gallopsled/pwntools/pull/2308
9298
[2279]: https://github.com/Gallopsled/pwntools/pull/2279
99+
[2310]: https://github.com/Gallopsled/pwntools/pull/2310
100+
[2334]: https://github.com/Gallopsled/pwntools/pull/2334
101+
[2328]: https://github.com/Gallopsled/pwntools/pull/2328
102+
[2189]: https://github.com/Gallopsled/pwntools/pull/2189
103+
[2339]: https://github.com/Gallopsled/pwntools/pull/2339
104+
[2323]: https://github.com/Gallopsled/pwntools/pull/2323
93105
[2325]: https://github.com/Gallopsled/pwntools/pull/2325
94106

95107
## 4.12.0 (`beta`)

pwnlib/asm.py

+2
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,8 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
860860

861861

862862
lines = []
863+
864+
# Note: those patterns are also used in pwnlib/commandline/disasm.py
863865
pattern = '^( *[0-9a-f]+: *)', '((?:[0-9a-f]+ )+ *)', '(.*)'
864866
if not byte:
865867
pattern = pattern[::2]

pwnlib/commandline/disasm.py

+27-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import print_function
44

55
import argparse
6+
import re
67
import string
78
import sys
89

@@ -76,18 +77,34 @@ def main(args):
7677
from pygments.formatters import TerminalFormatter
7778
from pwnlib.lexer import PwntoolsLexer
7879

79-
offsets = disasm(dat, vma=safeeval.const(args.address), instructions=False, byte=False)
80-
bytes = disasm(dat, vma=safeeval.const(args.address), instructions=False, offset=False)
81-
instrs = disasm(dat, vma=safeeval.const(args.address), byte=False, offset=False)
82-
# instrs = highlight(instrs, PwntoolsLexer(), TerminalFormatter())
80+
dis = disasm(dat, vma=safeeval.const(args.address))
8381

84-
highlight_bytes = lambda t: ''.join(map(lambda x: x.replace('00', text.red('00')).replace('0a', text.red('0a')), group(2, t)))
85-
for o,b,i in zip(*map(str.splitlines, (offsets, bytes, instrs))):
86-
b = ' '.join(highlight_bytes(bb) for bb in b.split(' '))
87-
i = highlight(i.strip(), PwntoolsLexer(), TerminalFormatter()).strip()
88-
i = i.replace(',',', ')
82+
# Note: those patterns are copied from disasm function
83+
pattern = '^( *[0-9a-f]+: *)((?:[0-9a-f]+ )+ *)(.*)'
84+
lines = []
85+
for line in dis.splitlines():
86+
match = re.search(pattern, line)
87+
if not match:
88+
# Append as one element tuple
89+
lines.append((line,))
90+
continue
91+
92+
groups = match.groups()
93+
o, b, i = groups
94+
95+
lines.append((o, b, i))
8996

90-
print(o,b,i)
97+
98+
highlight_bytes = lambda t: ''.join(map(lambda x: x.replace('00', text.red('00')).replace('0a', text.red('0a')), group(2, t)))
99+
for line in lines:
100+
if len(line) == 3:
101+
o, b, i = line
102+
b = ' '.join(highlight_bytes(bb) for bb in b.split(' '))
103+
i = highlight(i.strip(), PwntoolsLexer(), TerminalFormatter()).strip()
104+
i = i.replace(',',', ')
105+
print(o,b,i)
106+
else:
107+
print(line[0])
91108
return
92109

93110
print(disasm(dat, vma=safeeval.const(args.address)))

pwnlib/gdb.py

+35-11
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,14 @@ def _gdbserver_port(gdbserver, ssh):
315315

316316
# Process /bin/bash created; pid = 14366
317317
# Listening on port 34816
318-
process_created = gdbserver.recvline()
318+
process_created = gdbserver.recvline(timeout=3)
319+
320+
if not process_created:
321+
log.error(
322+
'No output from gdbserver after 3 seconds. Try setting the SHELL=/bin/sh '
323+
'environment variable or using the env={} argument if you are affected by '
324+
'https://sourceware.org/bugzilla/show_bug.cgi?id=26116'
325+
)
319326

320327
if process_created.startswith(b'ERROR:'):
321328
raise ValueError(
@@ -645,7 +652,10 @@ def __init__(self, conn, *args, **kwargs):
645652
"""
646653
# Creates a real breakpoint and connects it with this mirror
647654
self.conn = conn
648-
self.server_breakpoint = conn.root.set_breakpoint(
655+
self.server_breakpoint = self._server_set_breakpoint(*args, **kwargs)
656+
657+
def _server_set_breakpoint(self, *args, **kwargs):
658+
return self.conn.root.set_breakpoint(
649659
self, hasattr(self, 'stop'), *args, **kwargs)
650660

651661
def __getattr__(self, item):
@@ -663,25 +673,43 @@ def __getattr__(self, item):
663673
raise AttributeError()
664674
return getattr(self.server_breakpoint, item)
665675

676+
def __setattr__(self, name, value):
677+
"""Set attributes of the real breakpoint."""
678+
if name in (
679+
'enabled',
680+
'silent',
681+
'thread',
682+
'task',
683+
'ignore_count',
684+
'hit_count'
685+
'condition',
686+
'commands',
687+
):
688+
return setattr(self.server_breakpoint, name, value)
689+
return super().__setattr__(name, value)
690+
666691
def exposed_stop(self):
667692
# Handle stop() call from the server.
668693
return self.stop()
669694

670-
class FinishBreakpoint:
695+
class FinishBreakpoint(Breakpoint):
671696
"""Mirror of ``gdb.FinishBreakpoint`` class.
672697
673698
See https://sourceware.org/gdb/onlinedocs/gdb/Finish-Breakpoints-in-Python.html
674699
for more information.
675700
"""
676701

677-
def __init__(self, conn, *args, **kwargs):
702+
def __init__(self, *args, **kwargs):
678703
"""Do not create instances of this class directly.
679704
680705
Use ``pwnlib.gdb.Gdb.FinishBreakpoint`` instead.
681706
"""
682-
# Creates a real finish breakpoint and connects it with this mirror
683-
self.conn = conn
684-
self.server_breakpoint = conn.root.set_finish_breakpoint(
707+
# See https://github.com/pylint-dev/pylint/issues/4228
708+
# pylint: disable=useless-super-delegation
709+
super().__init__(*args, **kwargs)
710+
711+
def _server_set_breakpoint(self, *args, **kwargs):
712+
return self.conn.root.set_finish_breakpoint(
685713
self, hasattr(self, 'stop'), hasattr(self, 'out_of_scope'),
686714
*args, **kwargs)
687715

@@ -701,10 +729,6 @@ def __getattr__(self, item):
701729
raise AttributeError()
702730
return getattr(self.server_breakpoint, item)
703731

704-
def exposed_stop(self):
705-
# Handle stop() call from the server.
706-
return self.stop()
707-
708732
def exposed_out_of_scope(self):
709733
# Handle out_of_scope() call from the server.
710734
return self.out_of_scope()

pwnlib/gdb_api_bridge.py

+1
Original file line numberDiff line numberDiff line change
@@ -110,5 +110,6 @@ def exposed_quit(self):
110110
socket_path=socket_path,
111111
protocol_config={
112112
'allow_all_attrs': True,
113+
'allow_setattr': True,
113114
},
114115
).start)

pwnlib/libcdb.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from __future__ import division
66

77
import os
8+
import time
89
import six
910
import tempfile
1011

@@ -35,6 +36,9 @@
3536
urls = os.environ['DEBUGINFOD_URLS'].split(' ')
3637
DEBUGINFOD_SERVERS = urls + DEBUGINFOD_SERVERS
3738

39+
# Retry failed lookups after some time
40+
NEGATIVE_CACHE_EXPIRY = 60 * 60 * 24 * 7 # 1 week
41+
3842
# https://gitlab.com/libcdb/libcdb wasn't updated after 2019,
3943
# but still is a massive database of older libc binaries.
4044
def provider_libcdb(hex_encoded_id, hash_type):
@@ -131,6 +135,10 @@ def search_by_hash(hex_encoded_id, hash_type='build_id', unstrip=True):
131135
cache, cache_valid = _check_elf_cache('libcdb', hex_encoded_id, hash_type)
132136
if cache_valid:
133137
return cache
138+
139+
# We searched for this buildid before, but didn't find anything.
140+
if cache is None:
141+
return None
134142

135143
# Run through all available libc database providers to see if we have a match.
136144
for provider in PROVIDERS:
@@ -163,6 +171,10 @@ def _search_debuginfo_by_hash(base_url, hex_encoded_id):
163171
cache, cache_valid = _check_elf_cache('libcdb_dbg', hex_encoded_id, 'build_id')
164172
if cache_valid:
165173
return cache
174+
175+
# We searched for this buildid before, but didn't find anything.
176+
if cache is None:
177+
return None
166178

167179
# Try to find separate debuginfo.
168180
url = '/buildid/{}/debuginfo'.format(hex_encoded_id)
@@ -213,8 +225,11 @@ def _check_elf_cache(cache_type, hex_encoded_id, hash_type):
213225

214226
data = read(cache)
215227
if not data.startswith(b'\x7FELF'):
216-
log.info_once("Skipping unavailable ELF %s", hex_encoded_id)
217-
return cache, False
228+
# Retry failed lookups after some time
229+
if time.time() > os.path.getmtime(cache) + NEGATIVE_CACHE_EXPIRY:
230+
return cache, False
231+
log.info_once("Skipping invalid cached ELF %s", hex_encoded_id)
232+
return None, False
218233

219234
log.info_once("Using cached data from %r", cache)
220235
return cache, True

0 commit comments

Comments
 (0)