Skip to content

Commit 6098f28

Browse files
committed
Merge branch 'stable' into beta
2 parents 2c3e783 + 1205b1a commit 6098f28

File tree

9 files changed

+77
-31
lines changed

9 files changed

+77
-31
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ The table below shows which release corresponds to each branch, and what date th
141141
[2476]: https://github.com/Gallopsled/pwntools/pull/2476
142142
[2364]: https://github.com/Gallopsled/pwntools/pull/2364
143143

144+
## 4.14.2
145+
146+
- [#2545][2545] SSH: fix download/upload with -1 exit status
147+
- [#2567][2567] Fix mistakenly parsing of ld-linux error messages.
148+
- [#2576][2576] regsort: respect register aliases
149+
150+
[2545]: https://github.com/Gallopsled/pwntools/pull/2545
151+
[2567]: https://github.com/Gallopsled/pwntools/pull/2567
152+
[2576]: https://github.com/Gallopsled/pwntools/pull/2576
153+
144154
## 4.14.1 (`stable`)
145155

146156
- [#2451][2451] Show symbols defined to value 0 (start of file)

pwnlib/elf/elf.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,13 @@ def _patch_elf_and_read_maps(self):
852852
log.warn_once("Injected /proc/self/maps code did not execute correctly")
853853
return {}
854854

855+
# Sometimes the original binary already fail to run, for example, in case glibc mismatches.
856+
try:
857+
int(data.split('-', 1)[0], 16)
858+
except ValueError:
859+
log.warn_once("Cannot execute `%s` to get /proc/self/maps", self.path)
860+
return {}
861+
855862
# Swap in the original ELF name
856863
data = data.replace(path, self.path)
857864

pwnlib/regsort.py

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
log = getLogger(__name__)
1717

18-
def check_cycle(reg, assignments):
18+
def check_cycle(reg, assignments, mapping=None):
1919
"""Walk down the assignment list of a register,
2020
return the path walked if it is encountered again.
2121
@@ -37,31 +37,38 @@ def check_cycle(reg, assignments):
3737
>>> check_cycle('a', {'a': 'b', 'b': 'c', 'c': 'd', 'd': 'a'})
3838
['a', 'b', 'c', 'd']
3939
"""
40-
return check_cycle_(reg, assignments, [])
41-
42-
def check_cycle_(reg, assignments, path):
43-
target = assignments[reg]
40+
if mapping is None:
41+
mapping = {}
42+
return check_cycle_(reg, assignments, [], mapping)
43+
44+
def check_cycle_(reg, assignments, path, mapping):
45+
target = assignments.get(reg)
46+
if target is None:
47+
real_reg = mapping.get(reg, reg)
48+
reg, target = next((k, v) for k,v in assignments.items() if mapping.get(k, k) == real_reg)
4449
path.append(reg)
4550

51+
real_target = mapping.get(target, target)
52+
4653
# No cycle, some other value (e.g. 1)
47-
if target not in assignments:
54+
if all(real_target != mapping.get(k, k) for k in assignments):
4855
return []
4956

5057
# Found a cycle
51-
if target in path:
58+
if any(real_target == mapping.get(k, k) for k in path):
5259
# Does the cycle *start* with target?
5360
# This determines whether the original register is
5461
# in the cycle, or just depends on registers in one.
55-
if target == path[0]:
62+
if real_target == mapping.get(path[0], path[0]):
5663
return path
5764

5865
# Just depends on one.
5966
return []
6067

6168
# Recurse
62-
return check_cycle_(target, assignments, path)
69+
return check_cycle_(target, assignments, path, mapping)
6370

64-
def extract_dependencies(reg, assignments):
71+
def extract_dependencies(reg, assignments, mapping=None):
6572
"""Return a list of all registers which directly
6673
depend on the specified register.
6774
@@ -77,7 +84,9 @@ def extract_dependencies(reg, assignments):
7784
['b', 'c']
7885
"""
7986
# sorted() is only for determinism
80-
return sorted([k for k,v in assignments.items() if v == reg])
87+
if mapping is None:
88+
mapping = {}
89+
return sorted([k for k,v in assignments.items() if mapping.get(v, v) == mapping.get(reg, reg)])
8190

8291

8392
def resolve_order(reg, deps):
@@ -110,7 +119,7 @@ def depends_on_cycle(reg, assignments, in_cycles):
110119
reg = assignments.get(reg, None)
111120
return False
112121

113-
def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
122+
def regsort(in_out, all_regs, mapping = None, tmp = None, xchg = True, randomize = None):
114123
"""
115124
Sorts register dependencies.
116125
@@ -233,6 +242,12 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
233242
if randomize is None:
234243
randomize = context.randomize
235244

245+
if mapping is None:
246+
if hasattr(all_regs, 'keys'):
247+
mapping = all_regs
248+
else:
249+
mapping = {}
250+
236251
sentinel = object()
237252

238253
# Drop all registers which will be set to themselves.
@@ -242,7 +257,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
242257

243258
# Collapse constant values
244259
#
245-
# For eaxmple, {'eax': 0, 'ebx': 0} => {'eax': 0, 'ebx': 'eax'}
260+
# For example, {'eax': 0, 'ebx': 0} => {'eax': 0, 'ebx': 'eax'}
246261
v_k = defaultdict(list)
247262
for k,v in sorted(in_out.items()):
248263
if v not in all_regs and v != 0:
@@ -263,7 +278,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
263278
# which are also 'outputs'.
264279
#
265280
# For example, {'eax': 1, 'ebx': 2, 'ecx': 'edx'}
266-
if not any(v in in_out for k,v in in_out.items()):
281+
inps = {mapping.get(k, k) for k in in_out}
282+
outs = {mapping.get(v, v) for v in in_out.values()}
283+
if not inps & outs:
267284
result = [('mov', k,in_out[k]) for k in sorted(in_out)]
268285

269286
if randomize:
@@ -280,7 +297,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
280297
# Output: {'A': [], 'B': ['A', 'C'], 'C': []}
281298
#
282299
# In this case, both A and C must be set before B.
283-
deps = {r: extract_dependencies(r, in_out) for r in in_out}
300+
deps = {r: extract_dependencies(r, in_out, mapping) for r in in_out}
284301

285302
# Final result which will be returned
286303
result = []
@@ -299,7 +316,7 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
299316

300317
while cycle_candidates:
301318
reg = cycle_candidates[0]
302-
cycle = check_cycle(reg, in_out)
319+
cycle = check_cycle(reg, in_out, mapping)
303320

304321
if cycle:
305322
if randomize:
@@ -395,6 +412,10 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
395412

396413
if tmp:
397414
for cycle in cycles:
415+
if len(cycle) == 1:
416+
[reg] = cycle
417+
result.append(('mov', reg, in_out[reg]))
418+
continue
398419

399420
first = cycle[0]
400421
last = cycle[-1]
@@ -411,6 +432,9 @@ def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):
411432
else:
412433
for cycle in cycles:
413434
size = len(cycle)
435+
if size == 1:
436+
[reg] = cycle
437+
result.append(('mov', reg, in_out[reg]))
414438
for i in range(size-1):
415439
result.append(('xchg', cycle[i], cycle[(i+1) % size]))
416440

pwnlib/shellcraft/registers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@
116116
['rbx', 'ebx', 'bx', 'bl'],
117117
['rcx', 'ecx', 'cx', 'cl'],
118118
['rdx', 'edx', 'dx', 'dl'],
119-
['rdi', 'edi', 'di'],
120-
['rsi', 'esi', 'si'],
121-
['rbp', 'ebp', 'bp'],
122-
['rsp', 'esp', 'sp'],
119+
['rdi', 'edi', 'di', 'dil'],
120+
['rsi', 'esi', 'si', 'sil'],
121+
['rbp', 'ebp', 'bp', 'bpl'],
122+
['rsp', 'esp', 'sp', 'spl'],
123123
['r8', 'r8d', 'r8w', 'r8b'],
124124
['r9', 'r9d', 'r9w', 'r9b'],
125125
['r10', 'r10d', 'r10w', 'r10b'],

pwnlib/shellcraft/templates/amd64/mov.asm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ Example:
5151
xor eax, eax
5252
mov ax, 0xc0c0
5353
>>> print(shellcraft.amd64.mov('rdi', 0xff).rstrip())
54-
mov edi, 0x1010101 /* 255 == 0xff */
55-
xor edi, 0x10101fe
54+
xor edi, edi
55+
mov dil, 0xff
5656
>>> print(shellcraft.amd64.mov('rax', 0xdead00ff).rstrip())
5757
mov eax, 0x1010101 /* 3735879935 == 0xdead00ff */
5858
xor eax, 0xdfac01fe

pwnlib/shellcraft/templates/amd64/setregs.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ if isinstance(eax, six.integer_types) and isinstance(edx, six.integer_types) and
5555
cdq = True
5656
reg_context.pop('rdx')
5757

58-
sorted_regs = regsort(reg_context, registers.amd64)
58+
sorted_regs = regsort(reg_context, registers.amd64, registers.native64)
5959
%>
6060
% if not sorted_regs:
6161
/* setregs noop */

pwnlib/shellcraft/templates/i386/mov.asm

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,9 @@ Example:
5858
>>> print(shellcraft.i386.mov('eax', 0xdead00ff).rstrip())
5959
mov eax, -0xdead00ff
6060
neg eax
61-
>>> print(shellcraft.i386.mov('eax', 0xc0).rstrip())
62-
xor eax, eax
63-
mov al, 0xc0
6461
>>> print(shellcraft.i386.mov('edi', 0xc0).rstrip())
65-
mov edi, -0xc0
66-
neg edi
62+
xor edi, edi
63+
mov dil, 0xc0
6764
>>> print(shellcraft.i386.mov('eax', 0xc000).rstrip())
6865
xor eax, eax
6966
mov ah, 0xc000 >> 8

pwnlib/shellcraft/templates/i386/setregs.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ sorted_regs = regsort(reg_context, registers.i386)
5454
% if not sorted_regs:
5555
/* setregs noop */
5656
% else:
57-
% for how, src, dst in regsort(reg_context, registers.i386):
57+
% for how, src, dst in regsort(reg_context, registers.i386, registers.native32):
5858
% if how == 'xchg':
5959
xchg ${src}, ${dst}
6060
% else:

pwnlib/tubes/ssh.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,11 @@ def update(has, total):
13591359
update(len(data), total)
13601360

13611361
result = c.wait()
1362-
if result != 0:
1362+
1363+
if result == -1:
1364+
self.warn_once("Could not verify success of file download %r, no error code" % (remote))
1365+
1366+
if result != 0 and result != -1:
13631367
h.failure('Could not download file %r (%r)' % (remote, result))
13641368
return
13651369

@@ -1539,7 +1543,11 @@ def upload_data(self, data, remote):
15391543
s.shutdown('send')
15401544
data = s.recvall()
15411545
result = s.wait()
1542-
if result != 0:
1546+
1547+
if result == -1:
1548+
self.warn_once("Could not verify success of file upload %r, no error code" % (remote))
1549+
1550+
if result != 0 and result != -1:
15431551
self.error("Could not upload file %r (%r)\n%s" % (remote, result, data))
15441552

15451553
def upload_file(self, filename, remote = None):

0 commit comments

Comments
 (0)