Skip to content

Commit

Permalink
Add option to swap last sub authority endianness to SID reading (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper authored Oct 7, 2024
1 parent 7ac7a3a commit 5e3e6b4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 17 deletions.
16 changes: 12 additions & 4 deletions dissect/util/sid.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import BinaryIO, Union


def read_sid(fh: Union[BinaryIO, bytes], endian: str = "<") -> str:
def read_sid(fh: Union[BinaryIO, bytes], endian: str = "<", swap_last: bool = False) -> str:
"""Read a Windows SID from bytes.
Normally we'd do this with cstruct, but do it with just struct to keep dissect.util dependency-free.
Expand All @@ -21,18 +21,26 @@ def read_sid(fh: Union[BinaryIO, bytes], endian: str = "<") -> str:
Args:
fh: A file-like object or bytes object to read the SID from.
endian: Optional endianness for reading the sub authorities.
swap_list: Optional flag for swapping the endianess of the _last_ sub authority entry.
"""
if isinstance(fh, bytes):
fh = io.BytesIO(fh)

revision, sub_authority_count, authority = struct.unpack("BB6s", fh.read(8))
buf = fh.read(8)
revision = buf[0]
sub_authority_count = buf[1]
authority = int.from_bytes(buf[2:], "big")

sub_authorities = struct.unpack(f"{endian}{sub_authority_count}I", fh.read(sub_authority_count * 4))
sub_authority_buf = bytearray(fh.read(sub_authority_count * 4))
if sub_authority_count and swap_last:
sub_authority_buf[-4:] = sub_authority_buf[-4:][::-1]

sub_authorities = struct.unpack(f"{endian}{sub_authority_count}I", sub_authority_buf)

sid_elements = [
"S",
f"{revision}",
f"{authority[-1]}",
f"{authority}",
]
sid_elements.extend(map(str, sub_authorities))
readable_sid = "-".join(sid_elements)
Expand Down
65 changes: 52 additions & 13 deletions tests/test_sid.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
from __future__ import annotations

import io

import pytest

from dissect.util import sid

testdata = [
(b"\x01\x00\x00\x00\x00\x00\x00\x00", "S-1-0"),
(b"\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00", "S-1-1-0"),
(
b"\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\x15\xcd\x5b\x07\x00\x00\x00\x10\xf4\x01\x00\x00",
"S-1-5-21-123456789-268435456-500",
),
(io.BytesIO(b"\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"), "S-1-1-0"),
]


def id_fn(val):
if isinstance(val, (str,)):
Expand All @@ -22,6 +14,53 @@ def id_fn(val):
return ""


@pytest.mark.parametrize("binary_sid, readable_sid", testdata, ids=id_fn)
def test_read_sid(binary_sid, readable_sid):
assert readable_sid == sid.read_sid(binary_sid)
@pytest.mark.parametrize(
"binary_sid, readable_sid, endian, swap_last",
[
(
b"\x01\x00\x00\x00\x00\x00\x00\x00",
"S-1-0",
"<",
False,
),
(
b"\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00",
"S-1-1-0",
"<",
False,
),
(
b"\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\x15\xcd\x5b\x07\x00\x00\x00\x10\xf4\x01\x00\x00",
"S-1-5-21-123456789-268435456-500",
"<",
False,
),
(
io.BytesIO(b"\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"),
"S-1-1-0",
"<",
False,
),
(
b"\x01\x04\x00\x00\x00\x00\x00\x05\x00\x00\x00\x15\x07\x5b\xcd\x15\x10\x00\x00\x00\x00\x00\x01\xf4",
"S-1-5-21-123456789-268435456-500",
">",
False,
),
(
b"\x01\x04\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\x15\xcd\x5b\x07\x00\x00\x00\x10\x00\x00\x01\xf4",
"S-1-5-21-123456789-268435456-500",
"<",
True,
),
(
b"\x01\x04\x00\x00\x00\x00\x00\x05\x00\x00\x00\x15\x07\x5b\xcd\x15\x10\x00\x00\x00\xf4\x01\x00\x00",
"S-1-5-21-123456789-268435456-500",
">",
True,
),
],
ids=id_fn,
)
def test_read_sid(binary_sid: bytes | io.BinaryIO, endian: str, swap_last: bool, readable_sid: str) -> None:
assert readable_sid == sid.read_sid(binary_sid, endian, swap_last)

0 comments on commit 5e3e6b4

Please sign in to comment.