epoch
This commit is contained in:
commit
7a46066a9a
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
|
@ -0,0 +1,17 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from dotnet.types import CLRSignature
|
||||||
|
from dotnet.tables import CLRTableType
|
||||||
|
from dotnet.file import CLRFile
|
||||||
|
|
||||||
|
file = CLRFile(sys.argv[1])
|
||||||
|
print(f'Entrypoint: {file.entrypoint.name}')
|
||||||
|
for cls in file.get_table(CLRTableType.TypeDef):
|
||||||
|
print('---')
|
||||||
|
print(f'Class: {cls.name}')
|
||||||
|
print('Fields:')
|
||||||
|
for f in cls.fields:
|
||||||
|
print(f'- {f.name}: {f.signature}')
|
||||||
|
print('Methods:')
|
||||||
|
for m in cls.methods:
|
||||||
|
print(f'- {m.name}: {m.signature}')
|
|
@ -0,0 +1,229 @@
|
||||||
|
import enum
|
||||||
|
import math
|
||||||
|
import collections
|
||||||
|
from destruct import Type, Struct
|
||||||
|
|
||||||
|
class CLRStreamType(enum.Enum):
|
||||||
|
Metadata = '#~'
|
||||||
|
String = '#Strings'
|
||||||
|
UserString = '#US'
|
||||||
|
Blob = '#Blob'
|
||||||
|
GUID = '#GUID'
|
||||||
|
|
||||||
|
class CLRTableType(enum.Enum):
|
||||||
|
Assembly = 0x20
|
||||||
|
AssemblyCPU = 0x21
|
||||||
|
AssemblyOS = 0x22
|
||||||
|
AssemblyRef = 0x23
|
||||||
|
AssemblyRefCPU = 0x24
|
||||||
|
AssemblyRefOS = 0x25
|
||||||
|
ClassLayout = 0x0F
|
||||||
|
Constant = 0x0B
|
||||||
|
CustomAttribute = 0x0C
|
||||||
|
DeclSecurity = 0x0E
|
||||||
|
EncLog = 0x1E
|
||||||
|
EncMap = 0x1F
|
||||||
|
EventMap = 0x12
|
||||||
|
Event = 0x14
|
||||||
|
EventPointer = 0x13
|
||||||
|
ExportedType = 0x27
|
||||||
|
Field = 0x04
|
||||||
|
FieldLayout = 0x10
|
||||||
|
FieldMarshal = 0x0D
|
||||||
|
FieldPointer = 0x03
|
||||||
|
FieldRVA = 0x1D
|
||||||
|
File = 0x26
|
||||||
|
GenericParam = 0x2A
|
||||||
|
GenericParamConstraint = 0x2C
|
||||||
|
ImplMap = 0x1C
|
||||||
|
InterfaceImpl = 0x09
|
||||||
|
ManifestResource = 0x28
|
||||||
|
MemberRef = 0x0A
|
||||||
|
MethodDef = 0x06
|
||||||
|
MethodImpl = 0x19
|
||||||
|
MethodPointer = 0x05
|
||||||
|
MethodSemantics = 0x18
|
||||||
|
MethodSpec = 0x2B
|
||||||
|
Module = 0x00
|
||||||
|
ModuleRef = 0x1A
|
||||||
|
NestedClass = 0x29
|
||||||
|
Param = 0x08
|
||||||
|
ParamPointer = 0x07
|
||||||
|
Property = 0x17
|
||||||
|
PropertyMap = 0x15
|
||||||
|
PropertyPointer = 0x16
|
||||||
|
StandAloneSig = 0x11
|
||||||
|
TypeDef = 0x02
|
||||||
|
TypeRef = 0x01
|
||||||
|
TypeSpec = 0x1B
|
||||||
|
Document = 0x30
|
||||||
|
MethodBody = 0x31
|
||||||
|
LocalScope = 0x32
|
||||||
|
LocalVariable = 0x33
|
||||||
|
LocalConstant = 0x34
|
||||||
|
ImportScope = 0x35
|
||||||
|
StateMachineMethod = 0x36
|
||||||
|
CustomDebugInformation = 0x37
|
||||||
|
|
||||||
|
class CLRElementType(enum.Enum):
|
||||||
|
End = 0x00
|
||||||
|
Void = 0x01
|
||||||
|
Boolean = 0x02
|
||||||
|
Char = 0x03
|
||||||
|
I1 = 0x04
|
||||||
|
U1 = 0x05
|
||||||
|
I2 = 0x06
|
||||||
|
U2 = 0x07
|
||||||
|
I4 = 0x08
|
||||||
|
U4 = 0x09
|
||||||
|
I8 = 0x0A
|
||||||
|
U8 = 0x0B
|
||||||
|
R4 = 0x0C
|
||||||
|
R8 = 0x0D
|
||||||
|
String = 0x0E
|
||||||
|
Pointer = 0x0F
|
||||||
|
ByRef = 0x10
|
||||||
|
ValueType = 0x11
|
||||||
|
Class = 0x12
|
||||||
|
Var = 0x13
|
||||||
|
Array = 0x14
|
||||||
|
GenericInst = 0x15
|
||||||
|
TypedByRef = 0x16
|
||||||
|
I = 0x18
|
||||||
|
U = 0x19
|
||||||
|
FnPtr = 0x1B
|
||||||
|
Object = 0x1C
|
||||||
|
SZArray = 0x1D
|
||||||
|
MVar = 0x1E
|
||||||
|
ReqModifier = 0x1F
|
||||||
|
OptModifier = 0x20
|
||||||
|
Internal = 0x21
|
||||||
|
Modifier = 0x40
|
||||||
|
Sentinel = 0x41
|
||||||
|
Pinned = 0x45
|
||||||
|
System = 0x50
|
||||||
|
Boxed = 0x51
|
||||||
|
Field = 0x53
|
||||||
|
Property = 0x54
|
||||||
|
Enum = 0x55
|
||||||
|
|
||||||
|
class CLRHeapFlags(enum.Flag):
|
||||||
|
BigStringStream = 1
|
||||||
|
BigGUIDStream = 2
|
||||||
|
BigBlobStream = 4
|
||||||
|
|
||||||
|
class CLRToken(Struct):
|
||||||
|
row = UInt(24)
|
||||||
|
table = Enum(CLRTableType, UInt(8))
|
||||||
|
|
||||||
|
class CLRCodedToken(Type):
|
||||||
|
def __init__(self, types):
|
||||||
|
self.types = types
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
metadata = context.user.metadata
|
||||||
|
row_counts = []
|
||||||
|
for t in self.types:
|
||||||
|
row_counts.append(metadata.row_counts.get(t, 0))
|
||||||
|
max_rows = max(row_counts)
|
||||||
|
table_bits = math.ceil(math.log(len(self.types), 2))
|
||||||
|
if max_rows < (1 << 16 - table_bits):
|
||||||
|
size = 2
|
||||||
|
else:
|
||||||
|
size = 4
|
||||||
|
val = int.from_bytes(input.read(size), 'little')
|
||||||
|
row = val >> table_bits
|
||||||
|
tag = val & (1 << (table_bits - 1))
|
||||||
|
return CLRToken(row=row, table=self.types[tag])
|
||||||
|
|
||||||
|
class CLRSectionReference(Struct):
|
||||||
|
rva = UInt(32)
|
||||||
|
size = UInt(32)
|
||||||
|
|
||||||
|
class CLRTableIndex(Type):
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
metadata = context.user.metadata
|
||||||
|
row_count = metadata.row_counts.get(self.type, 0)
|
||||||
|
if row_count < (1 << 16):
|
||||||
|
size = 2
|
||||||
|
else:
|
||||||
|
size = 4
|
||||||
|
return int.from_bytes(input.read(size), 'little')
|
||||||
|
|
||||||
|
class CLRTableRange(Type):
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
metadata = context.user.metadata
|
||||||
|
row_count = metadata.row_counts.get(self.type, 0)
|
||||||
|
if row_count < (1 << 16):
|
||||||
|
size = 2
|
||||||
|
else:
|
||||||
|
size = 4
|
||||||
|
return int.from_bytes(input.read(size), 'little')
|
||||||
|
|
||||||
|
class CLRStreamIndex(Type):
|
||||||
|
def __init__(self, type, child=None):
|
||||||
|
self.type = type
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
metadata = context.user.metadata
|
||||||
|
big_mapping = {
|
||||||
|
CLRStreamType.String: CLRHeapFlags.BigStringStream,
|
||||||
|
CLRStreamType.Blob: CLRHeapFlags.BigBlobStream,
|
||||||
|
CLRStreamType.GUID: CLRHeapFlags.BigGUIDStream,
|
||||||
|
}
|
||||||
|
flag = big_mapping.get(self.type, None)
|
||||||
|
if flag:
|
||||||
|
if metadata.heap_flags & flag:
|
||||||
|
size = 4
|
||||||
|
else:
|
||||||
|
size = 2
|
||||||
|
else:
|
||||||
|
size = 2
|
||||||
|
return int.from_bytes(input.read(size), 'little')
|
||||||
|
|
||||||
|
class MultiEnumMeta(type):
|
||||||
|
@classmethod
|
||||||
|
def __prepare__(mcls, name, bases, **kwargs):
|
||||||
|
return collections.OrderedDict()
|
||||||
|
|
||||||
|
def __new__(cls, name, bases, attrs, **kwargs):
|
||||||
|
parsers = {}
|
||||||
|
used = 0
|
||||||
|
for key, value in attrs.copy().items():
|
||||||
|
if isinstance(value, tuple):
|
||||||
|
if len(value) == 2:
|
||||||
|
child, mask = value
|
||||||
|
elif len(value) == 3:
|
||||||
|
child, offset, size = value
|
||||||
|
mask = ((1 << size) - 1) << offset
|
||||||
|
if issubclass(child, enum.Enum):
|
||||||
|
if mask is None:
|
||||||
|
mask = ~used
|
||||||
|
parsers[key] = (child, mask)
|
||||||
|
used |= mask
|
||||||
|
del attrs[key]
|
||||||
|
|
||||||
|
attrs['_parsers_'] = parsers
|
||||||
|
return super().__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
|
class MultiEnum(metaclass=MultiEnumMeta):
|
||||||
|
def __init__(self, value: int):
|
||||||
|
for field, (child, mask) in self._parsers_.items():
|
||||||
|
setattr(self, field, child(value & mask))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '{}({})'.format(self.__class__.__name__,
|
||||||
|
', '.join('{}: {}'.format(n, getattr(self, n)) for n in self._parsers_)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<{}({})>'.format(self.__class__.__name__,
|
||||||
|
', '.join('{}: {!r}'.format(n, getattr(self, n)) for n in self._parsers_)
|
||||||
|
)
|
|
@ -0,0 +1,175 @@
|
||||||
|
import pefile
|
||||||
|
import destruct
|
||||||
|
from destruct import Type, Struct, Arr
|
||||||
|
|
||||||
|
from .common import CLRSectionReference, CLRToken, CLRStreamType, CLRStreamIndex, CLRTableIndex, CLRTableRange
|
||||||
|
from .streams import STREAM_PARSERS
|
||||||
|
|
||||||
|
|
||||||
|
class CLRHeader(Struct):
|
||||||
|
size = UInt(32)
|
||||||
|
version_major = UInt(16)
|
||||||
|
version_minor = UInt(16)
|
||||||
|
metadata_info = CLRSectionReference
|
||||||
|
flags = UInt(32)
|
||||||
|
entrypoint = CLRToken
|
||||||
|
unk_info = CLRSectionReference
|
||||||
|
namesig_info = CLRSectionReference
|
||||||
|
_gap0x28 = Data(32)
|
||||||
|
|
||||||
|
class CLRStreamMetadata(Struct):
|
||||||
|
offset = UInt(32)
|
||||||
|
size = UInt(32)
|
||||||
|
name = AlignTo(Str(kind='c'), 4)
|
||||||
|
|
||||||
|
class CLRMetadataHeader(Struct):
|
||||||
|
magic = Sig(b'BSJB')
|
||||||
|
version_major = UInt(16)
|
||||||
|
version_minor = UInt(16)
|
||||||
|
_gap0x8 = Data(4)
|
||||||
|
version = Str(kind='pascal', length_type=UInt(32))
|
||||||
|
_gap0x12 = Data(2)
|
||||||
|
stream_count = UInt(16)
|
||||||
|
streams = Arr(CLRStreamMetadata)
|
||||||
|
|
||||||
|
def on_stream_count(self, spec, context):
|
||||||
|
spec.streams.count = self.stream_count
|
||||||
|
|
||||||
|
class CLRTableWrapper:
|
||||||
|
__slots__ = ('__file', '__table', '__index', '__child')
|
||||||
|
|
||||||
|
def __init__(self, file, table, index, child):
|
||||||
|
self.__file = file
|
||||||
|
self.__table = table
|
||||||
|
self.__index = index
|
||||||
|
self.__child = child
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
val = getattr(self.__child, name)
|
||||||
|
if isinstance(self.__child, destruct.Struct):
|
||||||
|
type = self.__child._spec[name]
|
||||||
|
if isinstance(type, CLRStreamIndex):
|
||||||
|
stream = type.type
|
||||||
|
if stream == CLRStreamType.String:
|
||||||
|
val = self.__file.get_string_at(val)
|
||||||
|
elif stream == CLRStreamType.Blob:
|
||||||
|
val = self.__file.get_blob_at(val)
|
||||||
|
elif stream == CLRStreamType.UserString:
|
||||||
|
val = self.__file.get_user_string_at(val)
|
||||||
|
elif stream == CLRStreamType.GUID:
|
||||||
|
val = self.__file.get_guid_at(val)
|
||||||
|
if type.child:
|
||||||
|
c = destruct.Context(type.child)
|
||||||
|
c.user.metadata = self.__file.streams[CLRStreamType.Metadata]
|
||||||
|
val = destruct.parse(type.child, val, c)
|
||||||
|
return val
|
||||||
|
elif isinstance(type, CLRTableIndex):
|
||||||
|
table = type.type
|
||||||
|
return self.__file.get_table_entry(table, val)
|
||||||
|
elif isinstance(type, CLRTableRange):
|
||||||
|
table = type.type
|
||||||
|
if self.__index + 1 < self.__file.get_table_size(self.__table):
|
||||||
|
next = self.__file.get_table_entry(self.__table, self.__index + 1)
|
||||||
|
end = min(self.__file.get_table_size(table), getattr(next.__child, name))
|
||||||
|
else:
|
||||||
|
end = self.__file.get_table_size(table)
|
||||||
|
return [self.__file.get_table_entry(table, i) for i in range(val, end)]
|
||||||
|
return val
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<{}: {!r} in {!r}>'.format(self.__class__.__name__, self.__child, self.__file)
|
||||||
|
|
||||||
|
class CLRFile:
|
||||||
|
def __init__(self, fn):
|
||||||
|
self.name = fn
|
||||||
|
self.pe = pefile.PE(fn)
|
||||||
|
self.header = None
|
||||||
|
self.metadata = None
|
||||||
|
self.streams = {}
|
||||||
|
self.parse()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<{}: "{}">'.format(self.__class__.__name__, self.name)
|
||||||
|
|
||||||
|
def parse_at(self, c, offset, size=None):
|
||||||
|
if size is None:
|
||||||
|
size = destruct.sizeof(c)
|
||||||
|
buf = self.pe.get_data(rva=offset, length=size)
|
||||||
|
return destruct.parse(c, buf)
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
net_data_entry = pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR']
|
||||||
|
if net_data_entry < len(self.pe.OPTIONAL_HEADER.DATA_DIRECTORY):
|
||||||
|
net_data_dir = self.pe.OPTIONAL_HEADER.DATA_DIRECTORY[net_data_entry]
|
||||||
|
net_offset = net_data_dir.VirtualAddress
|
||||||
|
net_size = net_data_dir.Size
|
||||||
|
else:
|
||||||
|
for section in self.pe.sections:
|
||||||
|
if section.Name.rstrip(b'\x00') != b'.text':
|
||||||
|
continue
|
||||||
|
net_offset = section.PointerToRawData + 8
|
||||||
|
net_size = 72
|
||||||
|
|
||||||
|
self.header = self.parse_at(CLRHeader, net_offset, net_size)
|
||||||
|
self.metadata = self.parse_at(CLRMetadataHeader, self.header.metadata_info.rva, self.header.metadata_info.size)
|
||||||
|
self.streams = {}
|
||||||
|
for s in self.metadata.streams:
|
||||||
|
type = CLRStreamType(s.name)
|
||||||
|
if type in STREAM_PARSERS:
|
||||||
|
stream = self.parse_at(STREAM_PARSERS[type], self.header.metadata_info.rva + s.offset, s.size)
|
||||||
|
else:
|
||||||
|
stream = None
|
||||||
|
self.streams[type] = stream
|
||||||
|
|
||||||
|
def get_table(self, t):
|
||||||
|
return (CLRTableWrapper(self, t, i, x) for i, x in enumerate(self.streams[CLRStreamType.Metadata].tables[t]))
|
||||||
|
|
||||||
|
def get_table_size(self, t):
|
||||||
|
return len(self.streams[CLRStreamType.Metadata].tables[t])
|
||||||
|
|
||||||
|
def get_table_entry(self, t, i):
|
||||||
|
return CLRTableWrapper(self, t, i, self.streams[CLRStreamType.Metadata].tables[t][i])
|
||||||
|
|
||||||
|
def get_string_at(self, i):
|
||||||
|
buf = bytearray()
|
||||||
|
while True:
|
||||||
|
c = self.streams[CLRStreamType.String].data[i]
|
||||||
|
if not c:
|
||||||
|
break
|
||||||
|
buf.append(c)
|
||||||
|
i += 1
|
||||||
|
return buf.decode('utf-8')
|
||||||
|
|
||||||
|
def _get_length_prefixed_value(self, stream, i):
|
||||||
|
length = self.streams[stream].data[i]
|
||||||
|
if (length >> 5) == 0b110:
|
||||||
|
length = length & 0b11111
|
||||||
|
nbytes = 4
|
||||||
|
elif (length >> 6) == 0b10:
|
||||||
|
length = length & 0b111111
|
||||||
|
nbytes = 2
|
||||||
|
else:
|
||||||
|
nbytes = 1
|
||||||
|
for off in range(nbytes - 1):
|
||||||
|
length = (length << 8) | self.streams[stream].data[i + 1 + off]
|
||||||
|
return self.streams[stream].data[i + nbytes:i + nbytes + length]
|
||||||
|
|
||||||
|
def get_blob_at(self, i):
|
||||||
|
return self._get_length_prefixed_value(CLRStreamType.Blob, i)
|
||||||
|
|
||||||
|
def get_user_string_at(self, i):
|
||||||
|
return self._get_length_prefixed_value(CLRStreamType.UserString, i)[:-1].decode('utf-16le')
|
||||||
|
|
||||||
|
def get_guid_at(self, i):
|
||||||
|
if i == 0:
|
||||||
|
return None
|
||||||
|
return self.streams[CLRStreamType.GUID].guids[i - 1]
|
||||||
|
|
||||||
|
def get_by_token(self, t):
|
||||||
|
if not t.row:
|
||||||
|
return None
|
||||||
|
return self.get_table_entry(t.table, t.row - 1)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entrypoint(self):
|
||||||
|
return self.get_by_token(self.header.entrypoint)
|
|
@ -0,0 +1,93 @@
|
||||||
|
import enum
|
||||||
|
import uuid
|
||||||
|
from destruct import Type, Struct, Arr
|
||||||
|
|
||||||
|
from .common import CLRStreamType, CLRTableType, CLRHeapFlags
|
||||||
|
from .tables import TABLE_PARSERS
|
||||||
|
|
||||||
|
|
||||||
|
STREAM_PARSERS = {}
|
||||||
|
|
||||||
|
def stream_parser(name):
|
||||||
|
def inner(c):
|
||||||
|
STREAM_PARSERS[name] = c
|
||||||
|
return c
|
||||||
|
return inner
|
||||||
|
|
||||||
|
class BitVector(Type):
|
||||||
|
ORDER_MAP = {
|
||||||
|
'be': 'big',
|
||||||
|
'le': 'little',
|
||||||
|
}
|
||||||
|
def __init__(self, size, child=None, order='be'):
|
||||||
|
self.size = size
|
||||||
|
self.order = order
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
data = int.from_bytes(input.read(self.size // 8), self.ORDER_MAP[self.order])
|
||||||
|
values = []
|
||||||
|
for i in range(self.size):
|
||||||
|
if data & (1 << i):
|
||||||
|
values.append(self.child(i) if self.child else i)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def emit(self, output, value, context):
|
||||||
|
data = 0
|
||||||
|
for i in values:
|
||||||
|
data |= (1 << i)
|
||||||
|
output.write(data.to_bytes(self.size // 8, self.ORDER_MAP[self.order]))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<BitVector[{}]>'.format(self.size)
|
||||||
|
|
||||||
|
@stream_parser(CLRStreamType.Metadata)
|
||||||
|
class CLRMetadataStream(Struct):
|
||||||
|
_gap0 = Data(4)
|
||||||
|
version_major = UInt(8)
|
||||||
|
version_minor = UInt(8)
|
||||||
|
heap_flags = Enum(CLRHeapFlags, UInt(8))
|
||||||
|
_gap7 = Data(1)
|
||||||
|
present = BitVector(64, CLRTableType, order='le')
|
||||||
|
sorted = BitVector(64, CLRTableType, order='le')
|
||||||
|
row_counts = Arr(UInt(32))
|
||||||
|
tables = Arr([])
|
||||||
|
|
||||||
|
def on_present(self, spec, context):
|
||||||
|
spec.row_counts.count = len(self.present)
|
||||||
|
spec.tables.count = len(self.present)
|
||||||
|
|
||||||
|
def on_row_counts(self, spec, context):
|
||||||
|
counts = {}
|
||||||
|
for p, count in zip(self.present, self.row_counts):
|
||||||
|
spec.tables.child.append(Arr(TABLE_PARSERS[p], count=count))
|
||||||
|
counts[p] = count
|
||||||
|
self.row_counts = counts
|
||||||
|
context.user.metadata = self
|
||||||
|
|
||||||
|
def on_tables(self, spec, context):
|
||||||
|
tables = {}
|
||||||
|
for p, table in zip(self.present, self.tables):
|
||||||
|
tables[p] = table
|
||||||
|
self.tables = tables
|
||||||
|
|
||||||
|
class GUID(Type):
|
||||||
|
def parse(self, input, context):
|
||||||
|
data = input.read(16)
|
||||||
|
return uuid.UUID(bytes=data)
|
||||||
|
|
||||||
|
def emit(self, value, output, context):
|
||||||
|
output.write(value.bytes)
|
||||||
|
|
||||||
|
def sizeof(self, value, context):
|
||||||
|
return 16
|
||||||
|
|
||||||
|
@stream_parser(CLRStreamType.GUID)
|
||||||
|
class CLRGUIDStream(Struct):
|
||||||
|
guids = Arr(GUID)
|
||||||
|
|
||||||
|
@stream_parser(CLRStreamType.String)
|
||||||
|
@stream_parser(CLRStreamType.UserString)
|
||||||
|
@stream_parser(CLRStreamType.Blob)
|
||||||
|
class CLRDataStream(Struct):
|
||||||
|
data = Data(None)
|
|
@ -0,0 +1,568 @@
|
||||||
|
import enum
|
||||||
|
from destruct import Struct
|
||||||
|
|
||||||
|
from .common import (
|
||||||
|
MultiEnum,
|
||||||
|
CLRElementType, CLRStreamType, CLRTableType,
|
||||||
|
CLRCodedToken, CLRStreamIndex, CLRTableIndex, CLRTableRange
|
||||||
|
)
|
||||||
|
from .types import CLRSignature
|
||||||
|
|
||||||
|
|
||||||
|
TABLE_PARSERS = {}
|
||||||
|
|
||||||
|
def table_parser(name):
|
||||||
|
def inner(c):
|
||||||
|
TABLE_PARSERS[name] = c
|
||||||
|
return c
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Module)
|
||||||
|
class CLRModuleTable(Struct):
|
||||||
|
generation = UInt(16)
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
mvid = CLRStreamIndex(CLRStreamType.GUID)
|
||||||
|
encid = CLRStreamIndex(CLRStreamType.GUID)
|
||||||
|
encbaseid = CLRStreamIndex(CLRStreamType.GUID)
|
||||||
|
|
||||||
|
|
||||||
|
ResolutionScope = CLRCodedToken([
|
||||||
|
CLRTableType.Module, CLRTableType.ModuleRef,
|
||||||
|
CLRTableType.AssemblyRef, CLRTableType.TypeRef
|
||||||
|
])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.TypeRef)
|
||||||
|
class CLRTypeRefTable(Struct):
|
||||||
|
scope = ResolutionScope
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
namespace = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
|
||||||
|
|
||||||
|
TypeDefOrRef = CLRCodedToken([
|
||||||
|
CLRTableType.TypeDef, CLRTableType.TypeRef, CLRTableType.TypeSpec
|
||||||
|
])
|
||||||
|
|
||||||
|
class CLRTypeVisiblity(enum.Enum):
|
||||||
|
NotPublic = 0x0
|
||||||
|
Public = 0x1
|
||||||
|
NestedPublic = 0x2
|
||||||
|
NestedPrivate = 0x3
|
||||||
|
NestedFamily = 0x4
|
||||||
|
NestedAssembly = 0x5
|
||||||
|
NestedFamANDAssem = 0x6
|
||||||
|
NestedFamORAssem = 0x7
|
||||||
|
|
||||||
|
class CLRTypeLayout(enum.Enum):
|
||||||
|
AutoLayout = 0x0
|
||||||
|
SequentialLayout = 0x8
|
||||||
|
ExplicitLayout = 0x10
|
||||||
|
|
||||||
|
class CLRTypeClassSemantics(enum.Enum):
|
||||||
|
Class = 0x0
|
||||||
|
Interface = 0x20
|
||||||
|
|
||||||
|
class CLRTypeStringFormatting(enum.IntFlag):
|
||||||
|
ANSI = 0
|
||||||
|
Unicode = 0x10000
|
||||||
|
Custom = 0x30000
|
||||||
|
|
||||||
|
class CLRTypeFlags(enum.Flag):
|
||||||
|
Abstract = 0x80
|
||||||
|
Sealed = 0x100
|
||||||
|
SpecialName = 0x400
|
||||||
|
RTSpecialName = 0x800
|
||||||
|
Import = 0x1000
|
||||||
|
Serializable = 0x2000
|
||||||
|
HasSecurity = 0x4000
|
||||||
|
BeforeFieldInit = 0x100000
|
||||||
|
IsTypeForwarder = 0x200000
|
||||||
|
|
||||||
|
class CLRTypeAttributes(MultiEnum):
|
||||||
|
visibility = (CLRTypeVisiblity, 0x7)
|
||||||
|
layout = (CLRTypeLayout, 0x18)
|
||||||
|
semantics = (CLRTypeClassSemantics, 0x20)
|
||||||
|
formatting = (CLRTypeStringFormatting, 0xC30000)
|
||||||
|
flags = (CLRTypeFlags, None)
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.TypeDef)
|
||||||
|
class CLRTypeDefTable(Struct):
|
||||||
|
flags = Enum(CLRTypeAttributes, UInt(32))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
namespace = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
extends = TypeDefOrRef
|
||||||
|
fields = CLRTableRange(CLRTableType.Field)
|
||||||
|
methods = CLRTableRange(CLRTableType.MethodDef)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.FieldPointer)
|
||||||
|
def CLRFieldPointerTable(Struct):
|
||||||
|
field = CLRTableIndex(CLRTableType.Field)
|
||||||
|
|
||||||
|
|
||||||
|
class CLRAccess(enum.Enum):
|
||||||
|
CompilerControlled = 0
|
||||||
|
Private = 1
|
||||||
|
FamANDAssem = 2
|
||||||
|
Assembly = 3
|
||||||
|
Family = 4
|
||||||
|
FamORAssem = 5
|
||||||
|
Public = 6
|
||||||
|
|
||||||
|
class CLRFieldFlags(enum.Flag):
|
||||||
|
Static = 0x10
|
||||||
|
InitOnly = 0x20
|
||||||
|
Literal = 0x40
|
||||||
|
NotSerialized = 0x80
|
||||||
|
HasFieldRVA = 0x100
|
||||||
|
SpecialName = 0x200
|
||||||
|
RTSpecialName = 0x400
|
||||||
|
HasFieldMarshal = 0x1000
|
||||||
|
PInvokeImpl = 0x2000
|
||||||
|
HasDefault = 0x8000
|
||||||
|
|
||||||
|
class CLRFieldAttributes(MultiEnum):
|
||||||
|
access = (CLRAccess, 0x7)
|
||||||
|
flags = (CLRFieldFlags, 0xFFF0)
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Field)
|
||||||
|
class CLRFieldTable(Struct):
|
||||||
|
flags = Enum(CLRFieldAttributes, UInt(16))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MethodPointer)
|
||||||
|
def CLRMethodPointerTable(Struct):
|
||||||
|
method = CLRTableIndex(CLRTableType.Method)
|
||||||
|
|
||||||
|
|
||||||
|
class CLRMemberVtableLayout(enum.Enum):
|
||||||
|
ReuseSlot = 0
|
||||||
|
NewSlot = 0x100
|
||||||
|
|
||||||
|
class CLRMethodFlags(enum.Flag):
|
||||||
|
Static = 0x10
|
||||||
|
Final = 0x20
|
||||||
|
Virtual = 0x40
|
||||||
|
HideBySig = 0x80
|
||||||
|
Strict = 0x200
|
||||||
|
Abstract = 0x400
|
||||||
|
SpecialName = 0x800
|
||||||
|
RTSpecialName = 0x1000
|
||||||
|
PInvokeImpl = 0x2000
|
||||||
|
HasSecurity = 0x4000
|
||||||
|
RequireSecObject = 0x8000
|
||||||
|
|
||||||
|
class CLRMethodAttributes(MultiEnum):
|
||||||
|
access = (CLRAccess, 0x7)
|
||||||
|
vtable = (CLRMemberVtableLayout, 0x100)
|
||||||
|
flags = (CLRMethodFlags, 0xFEF0)
|
||||||
|
|
||||||
|
class CLRMethodCodeType(enum.Enum):
|
||||||
|
IL = 0
|
||||||
|
Native = 1
|
||||||
|
OPTIL = 2
|
||||||
|
Runtime = 3
|
||||||
|
|
||||||
|
class CLRMethodManaged(enum.Enum):
|
||||||
|
Managed = 0
|
||||||
|
Unmanaged = 4
|
||||||
|
|
||||||
|
class CLRMethodImplFlags(enum.Flag):
|
||||||
|
NoInlining = 0x8
|
||||||
|
ForwardRef = 0x10
|
||||||
|
Synchronized = 0x20
|
||||||
|
NoOptimization = 0x40
|
||||||
|
PreserveSig = 0x80
|
||||||
|
AggressiveInlining = 0x100
|
||||||
|
InternalCall = 0x1000
|
||||||
|
|
||||||
|
class CLRMethodImplAttributes(MultiEnum):
|
||||||
|
code_type = (CLRMethodCodeType, 0x3)
|
||||||
|
managed = (CLRMethodManaged, 0x4)
|
||||||
|
flags = (CLRMethodImplFlags, 0xFFF8)
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MethodDef)
|
||||||
|
class CLRMethodDefTable(Struct):
|
||||||
|
rva = UInt(32)
|
||||||
|
impl_flags = Enum(CLRMethodImplAttributes, UInt(16))
|
||||||
|
flags = Enum(CLRMethodAttributes, UInt(16))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
params = CLRTableRange(CLRTableType.Param)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ParamPointer)
|
||||||
|
def CLRParamPointerTable(Struct):
|
||||||
|
param = CLRTableIndex(CLRTableType.Param)
|
||||||
|
|
||||||
|
|
||||||
|
class CLRParamAttributes(enum.Flag):
|
||||||
|
In = 0x1
|
||||||
|
Out = 0x2
|
||||||
|
Optional = 0x10
|
||||||
|
HasDefault = 0x1000
|
||||||
|
HasFieldMarshal = 0x2000
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Param)
|
||||||
|
class CLRParamTable(Struct):
|
||||||
|
flags = Enum(CLRParamAttributes, UInt(16))
|
||||||
|
sequence = UInt(16)
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
|
||||||
|
|
||||||
|
MemberRefParent = CLRCodedToken([
|
||||||
|
CLRTableType.MethodDef, CLRTableType.ModuleRef,
|
||||||
|
CLRTableType.TypeDef, CLRTableType.TypeRef, CLRTableType.TypeSpec
|
||||||
|
])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MemberRef)
|
||||||
|
class CLRMemberRefTable(Struct):
|
||||||
|
parent = MemberRefParent
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
|
||||||
|
|
||||||
|
HasCustomAttribute = CLRCodedToken([
|
||||||
|
CLRTableType.MethodDef, CLRTableType.Field,
|
||||||
|
CLRTableType.TypeDef, CLRTableType.TypeRef,
|
||||||
|
CLRTableType.Param, CLRTableType.InterfaceImpl,
|
||||||
|
CLRTableType.MemberRef, CLRTableType.Module, 'Permission',
|
||||||
|
CLRTableType.Property, CLRTableType.Event,
|
||||||
|
CLRTableType.StandAloneSig, CLRTableType.ModuleRef, CLRTableType.TypeSpec,
|
||||||
|
CLRTableType.Assembly, CLRTableType.AssemblyRef,
|
||||||
|
CLRTableType.File, CLRTableType.ExportedType, CLRTableType.ManifestResource,
|
||||||
|
CLRTableType.GenericParam, CLRTableType.GenericParamConstraint,
|
||||||
|
CLRTableType.MethodSpec
|
||||||
|
])
|
||||||
|
CustomAttributeType = CLRCodedToken([
|
||||||
|
None, None, CLRTableType.MethodDef, CLRTableType.MemberRef, None
|
||||||
|
])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.CustomAttribute)
|
||||||
|
class CLRCustomAttributeTable(Struct):
|
||||||
|
parent = HasCustomAttribute
|
||||||
|
type = CustomAttributeType
|
||||||
|
value = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.StandAloneSig)
|
||||||
|
class CLRStandAloneSigTable(Struct):
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.TypeSpec)
|
||||||
|
class CLRTypeSpecTable(Struct):
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
|
||||||
|
|
||||||
|
class AssemblyHashAlgorithm(enum.Enum):
|
||||||
|
Null = 0
|
||||||
|
MD5 = 0x8003
|
||||||
|
SHA1 = 0x8004
|
||||||
|
|
||||||
|
class AssemblyFlags(enum.Flag):
|
||||||
|
PublicKey = 0x1
|
||||||
|
Retargetable = 0x100
|
||||||
|
DisableJITOptimizing = 0x4000
|
||||||
|
EnableJITracking = 0x8000
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Assembly)
|
||||||
|
class CLRAssemblyTable(Struct):
|
||||||
|
hash_algo = Enum(AssemblyHashAlgorithm, UInt(32))
|
||||||
|
version_major = UInt(16)
|
||||||
|
version_minor = UInt(16)
|
||||||
|
build_number = UInt(16)
|
||||||
|
rev_number = UInt(16)
|
||||||
|
flags = Enum(AssemblyFlags, UInt(32))
|
||||||
|
public_key = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
culture = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.AssemblyCPU)
|
||||||
|
class CLRAssemblyCPUTable(Struct):
|
||||||
|
processor = UInt(32)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.AssemblyOS)
|
||||||
|
class CLRAssemblyOSTable(Struct):
|
||||||
|
platform_id = UInt(32)
|
||||||
|
version_major = UInt(32)
|
||||||
|
version_minor = UInt(32)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.AssemblyRef)
|
||||||
|
class CLRAssemblyRefTable(Struct):
|
||||||
|
version_major = UInt(16)
|
||||||
|
version_minor = UInt(16)
|
||||||
|
build_number = UInt(16)
|
||||||
|
rev_number = UInt(16)
|
||||||
|
flags = Enum(AssemblyFlags, UInt(32))
|
||||||
|
public_key = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
culture = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
hash_value = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.AssemblyRefCPU)
|
||||||
|
class CLRAssemblyRefCPUTable(Struct):
|
||||||
|
processor = UInt(32)
|
||||||
|
assembly = CLRTableIndex(CLRTableType.Assembly)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.AssemblyRefOS)
|
||||||
|
class CLRAssemblyRefOSTable(Struct):
|
||||||
|
platform_id = UInt(32)
|
||||||
|
version_major = UInt(32)
|
||||||
|
version_minor = UInt(32)
|
||||||
|
assembly = CLRTableIndex(CLRTableType.Assembly)
|
||||||
|
|
||||||
|
|
||||||
|
Implementation = CLRCodedToken([
|
||||||
|
CLRTableType.File, CLRTableType.AssemblyRef, CLRTableType.ExportedType
|
||||||
|
])
|
||||||
|
|
||||||
|
class ManifestResourceAttributes(enum.Enum):
|
||||||
|
Public = 1
|
||||||
|
Private = 2
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ManifestResource)
|
||||||
|
class CLRManifestResourceTable(Struct):
|
||||||
|
offset = UInt(32)
|
||||||
|
flags = Enum(ManifestResourceAttributes, UInt(32))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
implementation = Implementation
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.NestedClass)
|
||||||
|
class CLRNestedClassTable(Struct):
|
||||||
|
nested = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
enclosing = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.InterfaceImpl)
|
||||||
|
class CLRInterfaceImplTable(Struct):
|
||||||
|
type = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
interface = TypeDefOrRef
|
||||||
|
|
||||||
|
|
||||||
|
HasConstant = CLRCodedToken([
|
||||||
|
CLRTableType.Param, CLRTableType.Field, CLRTableType.Property
|
||||||
|
])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Constant)
|
||||||
|
class CLRConstantTable(Struct):
|
||||||
|
type = UInt(8)
|
||||||
|
_pad1 = UInt(8)
|
||||||
|
parent = HasConstant
|
||||||
|
value = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
HasDeclSecurity = CLRCodedToken([
|
||||||
|
CLRTableType.TypeDef, CLRTableType.MethodDef, CLRTableType.Assembly
|
||||||
|
])
|
||||||
|
|
||||||
|
class CLRSecurityAction(enum.Enum):
|
||||||
|
Demand = 2
|
||||||
|
Assert = 3
|
||||||
|
Deny = 4
|
||||||
|
PermitOnly = 5
|
||||||
|
LinkDemand = 6
|
||||||
|
InheritanceDemand = 7
|
||||||
|
RequestMinimum = 8
|
||||||
|
RequestOptional = 9
|
||||||
|
RequestRefuse = 10
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.DeclSecurity)
|
||||||
|
class CLRDeclSecurityTable(Struct):
|
||||||
|
action = Enum(CLRSecurityAction, UInt(16))
|
||||||
|
parent = HasDeclSecurity
|
||||||
|
permission_set = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ClassLayout)
|
||||||
|
class CLRClassLayoutTable(Struct):
|
||||||
|
packing_size = UInt(16)
|
||||||
|
class_size = UInt(32)
|
||||||
|
parent = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.FieldLayout)
|
||||||
|
class CLRFieldLayoutTable(Struct):
|
||||||
|
offset = UInt(32)
|
||||||
|
field = CLRTableIndex(CLRTableType.Field)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.EventMap)
|
||||||
|
class CLREventMapTable(Struct):
|
||||||
|
parent = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
events = CLRTableRange(CLRTableType.Event)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.EventPointer)
|
||||||
|
class CLREventPointerTable(Struct):
|
||||||
|
event = CLRTableIndex(CLRTableType.Event)
|
||||||
|
|
||||||
|
|
||||||
|
class CLREventAttributes(enum.Flag):
|
||||||
|
SpecialName = 0x200
|
||||||
|
RTSpecialName = 0x400
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Event)
|
||||||
|
class CLREventTable(Struct):
|
||||||
|
flags = Enum(CLREventAttributes, UInt(16))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
type = TypeDefOrRef
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.PropertyMap)
|
||||||
|
class CLRPropertyMapTable(Struct):
|
||||||
|
parent = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
properties = CLRTableRange(CLRTableType.Property)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.PropertyPointer)
|
||||||
|
class CLRPropertyPointerTable(Struct):
|
||||||
|
property = CLRTableIndex(CLRTableType.Property)
|
||||||
|
|
||||||
|
|
||||||
|
class CLRPropertyAttributes(enum.Flag):
|
||||||
|
SpecialName = 0x0200
|
||||||
|
RTSpecialName = 0x0400
|
||||||
|
HasDefault = 0x1000
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.Property)
|
||||||
|
class CLRPropertyTable(Struct):
|
||||||
|
flags = Enum(CLRPropertyAttributes, UInt(16))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
signature = CLRStreamIndex(CLRStreamType.Blob, CLRSignature)
|
||||||
|
|
||||||
|
|
||||||
|
HasSemantics = CLRCodedToken([CLRTableType.Event, CLRTableType.Property])
|
||||||
|
|
||||||
|
class CLRMethodSemanticsAttributes(enum.Enum):
|
||||||
|
Setter = 0x1
|
||||||
|
Getter = 0x2
|
||||||
|
Other = 0x4
|
||||||
|
AddOn = 0x8
|
||||||
|
RemoveOn = 0x10
|
||||||
|
Fire = 0x20
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MethodSemantics)
|
||||||
|
class CLRMethodSemanticsTable(Struct):
|
||||||
|
semantics = Enum(CLRMethodSemanticsAttributes, UInt(16))
|
||||||
|
method = CLRTableIndex(CLRTableType.MethodDef)
|
||||||
|
association = HasSemantics
|
||||||
|
|
||||||
|
|
||||||
|
MethodDefOrRef = CLRCodedToken([
|
||||||
|
CLRTableType.MethodDef, CLRTableType.MemberRef
|
||||||
|
])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MethodImpl)
|
||||||
|
class CLRMethodImplTable(Struct):
|
||||||
|
parent = CLRTableIndex(CLRTableType.TypeDef)
|
||||||
|
body = MethodDefOrRef
|
||||||
|
declaration = MethodDefOrRef
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ModuleRef)
|
||||||
|
class CLRModuleRefTable(Struct):
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
|
||||||
|
|
||||||
|
MemberForwarded = CLRCodedToken([CLRTableType.Field, CLRTableType.MethodDef])
|
||||||
|
|
||||||
|
class CLRVariance(enum.Enum):
|
||||||
|
No = 0
|
||||||
|
Covariant = 1
|
||||||
|
Contravariant = 2
|
||||||
|
|
||||||
|
class CLRConstraint(enum.Flag):
|
||||||
|
ReferenceTypeConstraint = 0x4
|
||||||
|
NotNullableValueTypeConstraint = 0x8
|
||||||
|
DefaultConstructorConstraint = 0x10
|
||||||
|
|
||||||
|
class CLRPInvokeAttributes(MultiEnum):
|
||||||
|
variance = (CLRVariance, 0b11)
|
||||||
|
constraint = (CLRConstraint, 0b11100)
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ImplMap)
|
||||||
|
class CLRImplMapTable(Struct):
|
||||||
|
flags = Enum(CLRPInvokeAttributes, UInt(16))
|
||||||
|
forwarded = MemberForwarded
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
scope = CLRTableIndex(CLRTableType.ModuleRef)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.FieldRVA)
|
||||||
|
class CLRFieldRVATable(Struct):
|
||||||
|
rva = UInt(32)
|
||||||
|
field = CLRTableIndex(CLRTableType.Field)
|
||||||
|
|
||||||
|
|
||||||
|
TypeOrMethodDef = CLRCodedToken([CLRTableType.TypeDef, CLRTableType.MethodDef])
|
||||||
|
|
||||||
|
class CLRGenericParamAttributes(MultiEnum):
|
||||||
|
variance = (CLRVariance, 0b11)
|
||||||
|
constraint = (CLRConstraint, 0b11100)
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.GenericParam)
|
||||||
|
class CLRGenericParamTable(Struct):
|
||||||
|
index = UInt(16)
|
||||||
|
flags = Enum(CLRGenericParamAttributes, UInt(16))
|
||||||
|
owner = TypeOrMethodDef
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.MethodSpec)
|
||||||
|
class CLRMethodSpecTable(Struct):
|
||||||
|
parent = MethodDefOrRef
|
||||||
|
instantiation = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.GenericParamConstraint)
|
||||||
|
class CLRGenericParamConstraintTable(Struct):
|
||||||
|
owner = CLRTableIndex(CLRTableType.GenericParam)
|
||||||
|
constraint = TypeDefOrRef
|
||||||
|
|
||||||
|
|
||||||
|
HasFieldMarshal = CLRCodedToken([CLRTableType.Field, CLRTableType.Param])
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.FieldMarshal)
|
||||||
|
class CLRFieldMarshalTable(Struct):
|
||||||
|
parent = HasFieldMarshal
|
||||||
|
native_type = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.EncLog)
|
||||||
|
class CLREncLogTable(Struct):
|
||||||
|
token = UInt(32)
|
||||||
|
func_code = UInt(32)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.EncMap)
|
||||||
|
class CLREncMapTable(Struct):
|
||||||
|
token = UInt(32)
|
||||||
|
|
||||||
|
|
||||||
|
class CLRFileAttributes(enum.Enum):
|
||||||
|
ContainsMetadata = 0
|
||||||
|
ContainsNoMetadata = 1
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.File)
|
||||||
|
class CLRFileTable(Struct):
|
||||||
|
flags = Enum(CLRFileAttributes, UInt(32))
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
hash = CLRStreamIndex(CLRStreamType.Blob)
|
||||||
|
|
||||||
|
|
||||||
|
@table_parser(CLRTableType.ExportedType)
|
||||||
|
class CLRExportedTypeTable(Struct):
|
||||||
|
flags = Enum(CLRTypeAttributes, UInt(32))
|
||||||
|
type_id = UInt(32)
|
||||||
|
name = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
namespace = CLRStreamIndex(CLRStreamType.String)
|
||||||
|
implementation = Implementation
|
|
@ -0,0 +1,253 @@
|
||||||
|
import enum
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
|
from destruct import parse, Type, Struct
|
||||||
|
from .common import CLRCodedToken, CLRTableType, CLRElementType, MultiEnum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CLRType:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CLRPrimitiveType(CLRType):
|
||||||
|
def __init__(self, type: CLRElementType):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.type.name.lower()
|
||||||
|
|
||||||
|
class CLRPointerType(CLRType):
|
||||||
|
def __init__(self, child: CLRType):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + '*'
|
||||||
|
|
||||||
|
class CLRRefType(CLRType):
|
||||||
|
def __init__(self, child: CLRType):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + '&'
|
||||||
|
|
||||||
|
class CLRPinnedType(CLRType):
|
||||||
|
def __init__(self, child: CLRType):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + ' fixed&'
|
||||||
|
|
||||||
|
class CLRUserTypeKind(enum.Enum):
|
||||||
|
Class = 'class'
|
||||||
|
ValueType = 'enum'
|
||||||
|
|
||||||
|
class CLRUserType(CLRType):
|
||||||
|
def __init__(self, token, kind):
|
||||||
|
self.token = token
|
||||||
|
self.kind = kind
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.token.table == CLRTableType.TypeRef:
|
||||||
|
prefix = 'ext-'
|
||||||
|
else:
|
||||||
|
prefix = ''
|
||||||
|
return '{}{}#{}'.format(prefix, self.kind.value, self.token.row)
|
||||||
|
|
||||||
|
class CLROptionalType(CLRType):
|
||||||
|
def __init__(self, child):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + '?'
|
||||||
|
|
||||||
|
class CLRRequiredType(CLRType):
|
||||||
|
def __init__(self, child):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + '!'
|
||||||
|
|
||||||
|
class CLRGenericParamScope(enum.Enum):
|
||||||
|
Type = 'type'
|
||||||
|
Method = 'method'
|
||||||
|
|
||||||
|
class CLRGenericParamType(CLRType):
|
||||||
|
def __init__(self, index, scope):
|
||||||
|
self.index = index
|
||||||
|
self.scope = scope
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '#' + str(self.index)
|
||||||
|
|
||||||
|
class CLRGenericInstantiationType(CLRType):
|
||||||
|
def __init__(self, child, args):
|
||||||
|
self.child = child
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + '[' + ', '.join(str(a) for a in self.args) + ']'
|
||||||
|
|
||||||
|
class CLRArrayType(CLRType):
|
||||||
|
def __init__(self, child, rank, sizes=None, lowers=None):
|
||||||
|
self.child = child
|
||||||
|
self.rank = rank
|
||||||
|
self.sizes = sizes or []
|
||||||
|
self.lowers = lowers or []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.child) + ''.join(
|
||||||
|
'[{}{}]'.format(str(lower) + '...' if lower else '', upper + (lower or 0) if upper else '')
|
||||||
|
for _, lower, upper in zip_longest(range(self.rank), self.lowers, self.sizes)
|
||||||
|
)
|
||||||
|
|
||||||
|
class CLRElement(Type):
|
||||||
|
def __init__(self, child):
|
||||||
|
self.child = child
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
nested_types = {
|
||||||
|
CLRElementType.Pointer: CLRPointerType,
|
||||||
|
CLRElementType.ByRef: CLRRefType,
|
||||||
|
CLRElementType.Pinned: CLRPinnedType,
|
||||||
|
}
|
||||||
|
token_types = {
|
||||||
|
CLRElementType.Class: lambda t: CLRUserType(t, CLRUserTypeKind.Class),
|
||||||
|
CLRElementType.ValueType: lambda t: CLRUserType(t, CLRUserTypeKind.ValueType),
|
||||||
|
CLRElementType.OptModifier: CLROptionalType,
|
||||||
|
CLRElementType.ReqModifier: CLRRequiredType,
|
||||||
|
}
|
||||||
|
int_types = {
|
||||||
|
CLRElementType.Var: lambda i: CLRGenericParamType(i, CLRGenericParamScope.Type),
|
||||||
|
CLRElementType.MVar: lambda i: CLRGenericParamType(i, CLRGenericParamScope.Method),
|
||||||
|
}
|
||||||
|
val = CLRElementType(parse(self.child, input, context))
|
||||||
|
if val in nested_types:
|
||||||
|
with context.enter(val.name, self):
|
||||||
|
val = nested_types[val](self.parse(input, context))
|
||||||
|
elif val in token_types:
|
||||||
|
with context.enter(val.name, self.child):
|
||||||
|
raw = parse(self.child, input, context)
|
||||||
|
token = parse(CLRCodedToken([CLRTableType.TypeDef, CLRTableType.TypeRef]), raw.to_bytes(4, 'little'), context)
|
||||||
|
val = token_types[val](token)
|
||||||
|
elif val in int_types:
|
||||||
|
with context.enter(val.name, self.child):
|
||||||
|
val = int_types[val](parse(self.child, input, context))
|
||||||
|
elif val == CLRElementType.Array:
|
||||||
|
with context.enter(val.name, self):
|
||||||
|
type = self.parse(input, context)
|
||||||
|
rank = parse(self.child, input, context)
|
||||||
|
nbounds = parse(self.child, input, context)
|
||||||
|
bounds = [parse(self.child, input, context) for _ in range(nbounds)]
|
||||||
|
nlo = parse(self.child, input, context)
|
||||||
|
lo = [parse(self.child, input, context) for _ in range(nlo)]
|
||||||
|
val = CLRArrayType(type, rank, bounds, lo)
|
||||||
|
elif val == CLRElementType.GenericInst:
|
||||||
|
with context.enter(val.name, self):
|
||||||
|
type = self.parse(input, context)
|
||||||
|
nargs = parse(self.child, input, context)
|
||||||
|
args = []
|
||||||
|
for i in range(nargs):
|
||||||
|
with context.enter(i, self):
|
||||||
|
args.append(self.parse(input, context))
|
||||||
|
val = CLRGenericInstantiationType(type, args)
|
||||||
|
else:
|
||||||
|
val = CLRPrimitiveType(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
class CLRCompressedInt(Type):
|
||||||
|
def __init__(self, signed=True):
|
||||||
|
self.signed = signed
|
||||||
|
|
||||||
|
def parse(self, input, context):
|
||||||
|
val = input.read(1)[0]
|
||||||
|
if (val >> 5) == 0b110:
|
||||||
|
nbytes = 4
|
||||||
|
b = bytearray([val & 0b11111])
|
||||||
|
elif (val >> 6) == 0b10:
|
||||||
|
nbytes = 2
|
||||||
|
b = bytearray([val & 0b111111])
|
||||||
|
else:
|
||||||
|
nbytes = 1
|
||||||
|
b = bytearray([val])
|
||||||
|
b.extend(input.read(nbytes - 1))
|
||||||
|
return int.from_bytes(b, byteorder='big', signed=self.signed)
|
||||||
|
|
||||||
|
class CLRCompressedUInt(Type):
|
||||||
|
def __new__(self):
|
||||||
|
return CLRCompressedInt(signed=False)
|
||||||
|
|
||||||
|
class CLRSignatureType(enum.Enum):
|
||||||
|
Default = 0x0
|
||||||
|
C = 0x1
|
||||||
|
StdCall = 0x2
|
||||||
|
ThisCall = 0x3
|
||||||
|
FastCall = 0x4
|
||||||
|
VarArg = 0x5
|
||||||
|
Field = 0x6
|
||||||
|
LocalVar = 0x7
|
||||||
|
Property = 0x8
|
||||||
|
|
||||||
|
class CLRSignatureFlags(enum.Flag):
|
||||||
|
Generic = 0x10
|
||||||
|
HasThis = 0x20
|
||||||
|
ExplicitThis = 0x40
|
||||||
|
|
||||||
|
class CLRSignatureAttributes(MultiEnum):
|
||||||
|
type = (CLRSignatureType, 0x0F)
|
||||||
|
flags = (CLRSignatureFlags, 0xF0)
|
||||||
|
|
||||||
|
class CLRMethodSignature(Struct):
|
||||||
|
param_count = CLRCompressedUInt()
|
||||||
|
ret_type = CLRElement(CLRCompressedUInt())
|
||||||
|
params = Arr(CLRElement(CLRCompressedUInt()))
|
||||||
|
|
||||||
|
def on_param_count(self, spec, context):
|
||||||
|
spec.params.count = self.param_count
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '(' + ', '.join(str(p) for p in self.params) + ') -> ' + str(self.ret_type)
|
||||||
|
|
||||||
|
class CLRFieldSignature(Struct):
|
||||||
|
type = CLRElement(CLRCompressedUInt())
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.type)
|
||||||
|
|
||||||
|
class CLRPropertySignature(Struct):
|
||||||
|
param_count = CLRCompressedUInt()
|
||||||
|
type = CLRElement(CLRCompressedUInt())
|
||||||
|
params = Arr(CLRElement(CLRCompressedUInt()))
|
||||||
|
|
||||||
|
def on_param_count(self, spec, context):
|
||||||
|
spec.params.count = self.param_count
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '(' + ', '.join(str(p) for p in self.params) + ') -> ' + str(self.ret_type)
|
||||||
|
|
||||||
|
class CLRLocalVarSignature(Struct):
|
||||||
|
count = CLRCompressedUInt()
|
||||||
|
vars = Arr(CLRElement(CLRCompressedUInt()))
|
||||||
|
|
||||||
|
def on_count(self, spec, context):
|
||||||
|
spec.vars.count = self.count
|
||||||
|
|
||||||
|
class CLRSignature(Struct):
|
||||||
|
attribs = Enum(CLRSignatureAttributes, UInt(8))
|
||||||
|
signature = Switch(options={
|
||||||
|
CLRSignatureType.Default: CLRMethodSignature,
|
||||||
|
CLRSignatureType.C: CLRMethodSignature,
|
||||||
|
CLRSignatureType.StdCall: CLRMethodSignature,
|
||||||
|
CLRSignatureType.ThisCall: CLRMethodSignature,
|
||||||
|
CLRSignatureType.FastCall: CLRMethodSignature,
|
||||||
|
CLRSignatureType.VarArg: CLRMethodSignature,
|
||||||
|
CLRSignatureType.Field: CLRFieldSignature,
|
||||||
|
CLRSignatureType.Property: CLRPropertySignature,
|
||||||
|
CLRSignatureType.LocalVar: CLRLocalVarSignature,
|
||||||
|
})
|
||||||
|
|
||||||
|
def on_attribs(self, spec, context):
|
||||||
|
spec.signature.selector = self.attribs.type
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.signature)
|
Loading…
Reference in New Issue