exorcise/exorcise/partition/ntfs/attributes.py

237 lines
5.8 KiB
Python

import os
import enum
from destruct import Struct, Switch
from .index import IndexNode
Attribute = Switch()
def attribute(id):
def inner(c):
Attribute.options[id] = c
return c
return inner
class FileFlag(enum.Flag):
ReadOnly = 1 << 0
Hidden = 1 << 1
System = 1 << 2
Archived = 1 << 5
Device = 1 << 6
Normal = 1 << 7
Temporary = 1 << 8
Sparse = 1 << 9
ReparsePoint = 1 << 10
Compressed = 1 << 11
Offline = 1 << 12
NotIndexed = 1 << 13
Encrypted = 1 << 14
Directory = 1 << 28
IndexView = 1 << 29
Unk31 = 1 << 31
@attribute(0x10)
class StandardInformationAttribute(Struct, partial=True):
creation_time = UInt(64)
modification_time = UInt(64)
meta_modification_time = UInt(64)
access_time = UInt(64)
flags = Enum(FileFlag, UInt(32))
version_max = UInt(32)
version = UInt(32)
class_id = UInt(32)
owner_id = UInt(32)
security_id = UInt(32)
quota_amount = UInt(64)
usn = UInt(64)
@attribute(0x20)
class AttributeListAttribute(Struct):
type = UInt(32)
length = UInt(16)
name_length = UInt(8)
name_offset = UInt(8)
vcn_start = UInt(64)
base_file_reference = UInt(64)
id = UInt(16)
name = Ref(Str(kind='raw', exact=True, elem_size=2, encoding='utf-16le'), reference=os.SEEK_CUR)
def on_name_length(self, spec, context):
spec.name.child.length = self.name_length
def on_name_offset(self, spec, context):
spec.name.point = self.name_offset - 0x1A
class FilenameNamespace(enum.Enum):
POSIX = 0
Win32 = 1
DOS = 2
WinDOS = 3
@attribute(0x30)
class FileNameAttribute(Struct):
parent_file = UInt(64)
creation_time = UInt(64)
modification_time = UInt(64)
meta_modification_time = UInt(64)
access_time = UInt(64)
allocated_size = UInt(64)
real_size = UInt(64)
flags = Enum(FileFlag, UInt(32))
unk3c = UInt(32)
length = UInt(8)
namespace = Enum(FilenameNamespace, UInt(8))
name = Str(kind='raw', exact=True, elem_size=2, encoding='utf-16le')
def on_length(self, spec, context):
spec.name.length = self.length
class GUID(Struct):
data = Data(16)
def __str__(self):
return '{{{}-{}-{}-{}-{}}}'.format(
self.data[0:4].hex(), self.data[4:6].hex(), self.data[6:8].hex(),
self.data[8:10].hex(), self.data[8:16].hex()
)
@attribute(0x40)
class ObjectIDAttribute(Struct, partial=True):
id = GUID
origin_volume_id = GUID
origin_id = GUID
origin_domain_id = GUID
class SecurityDescriptorFlag(enum.Flag):
DefaultOwner = 1 << 0
DefaultGroup = 1 << 1
HasDACL = 1 << 2
DefaultDACL = 1 << 3
HasSACL = 1 << 4
DefaultSACL = 1 << 5
NeedInheritDACL = 1 << 8
NeedInheritSACL = 1 << 9
InheritedDACL = 1 << 10
InheritedSACL = 1 << 11
ProtectedDACL = 1 << 12
ProtectedSACL = 1 << 13
ValidRMControl = 1 << 14
SelfRelative = 1 << 15
class AccessRight(enum.Flag):
StandardDelete = 1 << 16
StandardReadControl = 1 << 17
StandardWriteDAC = 1 << 18
StandardWriteOwner = 1 << 19
StandardSynchronize = 1 << 20
ACL = 1 << 23
GenericAll = 1 << 28
GenericExecute = 1 << 29
GenericWrite = 1 << 30
GenericRead = 1 << 31
class ACEType(enum.Enum):
# V1, V2
Allow = 0
Deny = 1
Audit = 2
Alarm = 3
# V3
AllowCompound = 4
# V4
AllowObject = 5
DenyObject = 6
AuditObject = 7
AlarmObject = 8
class ACEFlag(enum.Flag):
InheritObject = 1 << 0
InheritContainer = 1 << 1
InheritNoPropagate = 1 << 2
InheritOnly = 1 << 3
Inherited = 1 << 4
AuditSuccess = 1 << 6
AuditFail = 1 < 7
class ACE(Struct):
type = Enum(ACEType, UInt(8))
flags = Enum(ACEFlag, UInt(8))
size = UInt(16)
access = UInt(32)
data = Data()
def on_size(self, spec, context):
spec.data.length = self.size
class ACL(Struct):
revision = UInt(8)
_pad1 = Pad(1)
length = UInt(16)
entry_count = UInt(16)
_pad6 = Pad(2)
entries = Arr(ACE)
def on_entry_count(self, spec, context):
spec.count = self.on_entry_count
@attribute(0x50)
class SecurityDescriptorAttribute(Struct):
revision = UInt(8)
_pad1 = Pad(1)
flags = Enum(SecurityDescriptorFlag, UInt(16))
user_sid_offset = UInt(32)
group_sid_offset = UInt(32)
sacl_offset = UInt(32)
dacl_offset = UInt(32)
@attribute(0x60)
class VolumeNameAttribute(Struct):
name = Str(kind='raw', exact=True, elem_size=2, encoding='utf-16le')
class VolumeInformationFlag(enum.Flag):
Dirty = 1 << 0
ResizeLog = 1 << 1
DoUpgrade = 1 << 2
MountedByNT4 = 1 << 3
DeletingUSN = 1 << 4
RepairIDs = 1 << 5
ChkDskModified = 1 << 15
@attribute(0x70)
class VolumeInformationAttribute(Struct):
_pad0 = Pad(8)
version_major = UInt(8)
version_minor = UInt(8)
flags = Enum(VolumeInformationFlag, UInt(16))
@attribute(0x80)
class DataAttribute(Struct):
data = Data(0)
@attribute(0x90)
class IndexRootAttribute(Struct):
type = UInt(32)
collation = UInt(32)
record_size = UInt(32)
record_cluster_count = UInt(8)
_pad3 = Pad(3)
node = IndexNode[...]
def on_type(self, spec, context):
spec.node = IndexNode[Attribute.options[self.type]]
@attribute(0xA0)
class IndexAllocationAttribute(Struct, generics=['G']):
nodes = Arr(IndexNode[G])
@attribute(0xB0)
class BitmapAttribute(Struct):
data = Data(0)
@attribute(0x100)
class LoggedUtilityStreamAttribute(Struct):
data = Data(0)