Skip to content

Commit 76078a3

Browse files
committed
Merge branch 'beta' into dev
2 parents 07ff886 + 6098f28 commit 76078a3

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
@@ -151,6 +151,16 @@ The table below shows which release corresponds to each branch, and what date th
151151
[2364]: https://github.com/Gallopsled/pwntools/pull/2364
152152
[2496]: https://github.com/Gallopsled/pwntools/pull/2496
153153

154+
## 4.14.2
155+
156+
- [#2545][2545] SSH: fix download/upload with -1 exit status
157+
- [#2567][2567] Fix mistakenly parsing of ld-linux error messages.
158+
- [#2576][2576] regsort: respect register aliases
159+
160+
[2545]: https://github.com/Gallopsled/pwntools/pull/2545
161+
[2567]: https://github.com/Gallopsled/pwntools/pull/2567
162+
[2576]: https://github.com/Gallopsled/pwntools/pull/2576
163+
154164
## 4.14.1 (`stable`)
155165

156166
- [#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
@@ -868,6 +868,13 @@ def _patch_elf_and_read_maps(self):
868868
log.warn_once("Injected /proc/self/maps code did not execute correctly")
869869
return {}
870870

871+
# Sometimes the original binary already fail to run, for example, in case glibc mismatches.
872+
try:
873+
int(data.split('-', 1)[0], 16)
874+
except ValueError:
875+
log.warn_once("Cannot execute `%s` to get /proc/self/maps", self.path)
876+
return {}
877+
871878
# Swap in the original ELF name
872879
data = data.replace(path, self.path)
873880

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
@@ -153,10 +153,10 @@
153153
['rbx', 'ebx', 'bx', 'bl'],
154154
['rcx', 'ecx', 'cx', 'cl'],
155155
['rdx', 'edx', 'dx', 'dl'],
156-
['rdi', 'edi', 'di'],
157-
['rsi', 'esi', 'si'],
158-
['rbp', 'ebp', 'bp'],
159-
['rsp', 'esp', 'sp'],
156+
['rdi', 'edi', 'di', 'dil'],
157+
['rsi', 'esi', 'si', 'sil'],
158+
['rbp', 'ebp', 'bp', 'bpl'],
159+
['rsp', 'esp', 'sp', 'spl'],
160160
['r8', 'r8d', 'r8w', 'r8b'],
161161
['r9', 'r9d', 'r9w', 'r9b'],
162162
['r10', 'r10d', 'r10w', 'r10b'],

pwnlib/shellcraft/templates/amd64/mov.asm

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

pwnlib/shellcraft/templates/amd64/setregs.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ if isinstance(eax, int) and isinstance(edx, int) and eax >> 63 == edx:
5454
cdq = True
5555
reg_context.pop('rdx')
5656

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

pwnlib/shellcraft/templates/i386/mov.asm

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

pwnlib/shellcraft/templates/i386/setregs.asm

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

pwnlib/tubes/ssh.py

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

13931393
result = c.wait()
1394-
if result != 0:
1394+
1395+
if result == -1:
1396+
self.warn_once("Could not verify success of file download %r, no error code" % (remote))
1397+
1398+
if result != 0 and result != -1:
13951399
h.failure('Could not download file %r (%r)' % (remote, result))
13961400
return
13971401

@@ -1571,7 +1575,11 @@ def upload_data(self, data, remote):
15711575
s.shutdown('send')
15721576
data = s.recvall()
15731577
result = s.wait()
1574-
if result != 0:
1578+
1579+
if result == -1:
1580+
self.warn_once("Could not verify success of file upload %r, no error code" % (remote))
1581+
1582+
if result != 0 and result != -1:
15751583
self.error("Could not upload file %r (%r)\n%s" % (remote, result, data))
15761584

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

0 commit comments

Comments
 (0)