commit
7a46066a9a
8 changed files with 1337 additions and 0 deletions
@ -0,0 +1,17 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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