Skip to content

Structure.py: 'u' format calcUnpackSize fix for higher unicode codepoint values. #1995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions impacket/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

from __future__ import division
from __future__ import print_function

import re
from struct import pack, unpack, calcsize

import six
Expand Down Expand Up @@ -66,7 +68,7 @@ class is the class to use when unpacking ':' fields.
some additional format specifiers:
: just copy the bytes from the field into the output string (input may be string, other structure, or anything responding to __str__()) (for unpacking, all what's left is returned)
z same as :, but adds a NUL byte at the end (asciiz) (for unpacking the first NUL byte is used as terminator) [asciiz string]
u same as z, but adds two NUL bytes at the end (after padding to an even size with NULs). (same for unpacking) [unicode string]
u same as z, but adds two NUL bytes at the end (after padding to an even size with NULs). (same for unpacking) [UTF16-le encoded bytes]
w DCE-RPC/NDR string (it's a macro for [ '<L=(len(field)+1)/2','"\\x00\\x00\\x00\\x00','<L=(len(field)+1)/2',':' ]
?-field length of field named 'field', formatted as specified with ? ('?' may be '!H' for example). The input value overrides the real length
?1*?2 array of elements. Each formatted as '?2', the number of elements in the array is stored as specified by '?1' (?1 is optional, or can also be a constant (number), for unpacking)
Expand Down Expand Up @@ -536,8 +538,16 @@ def calcUnpackSize(self, format, data, field = None):

# asciiz specifier
if format[:1] == 'u':
l = data.index(self.b('\x00\x00'))
return l + (l & 1 and 3 or 2)
# Positive lookahead to find overlapping NUL-NUL terminators (something like \x00\x00\x00 has 1 overlap)
matches = re.finditer(b'(?=(\x00\x00))', data)
for a_match in matches:
if a_match.start() % 2 == 0: # \x00\x00 at an even index
return a_match.start() + 2

# NUL-NUL terminator not found
hex_data = str(hexlify(data).decode('ascii'))
utf16_chunks = [hex_data[i:i + 4] for i in range(0, len(hex_data), 4)]
raise ValueError("Can't find NUL-NUL terminator in UTF-16le string '%s'" % ' '.join(utf16_chunks))

# DCE-RPC/NDR string specifier
if format[:1] == 'w':
Expand Down