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