2020-06-01 17:34:15 +00:00
|
|
|
import enum
|
|
|
|
import math
|
|
|
|
from destruct import Type, Struct
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLIStreamType(enum.Enum):
|
2020-06-01 17:34:15 +00:00
|
|
|
Metadata = '#~'
|
|
|
|
String = '#Strings'
|
|
|
|
UserString = '#US'
|
|
|
|
Blob = '#Blob'
|
|
|
|
GUID = '#GUID'
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLITableType(enum.Enum):
|
2020-06-01 17:34:15 +00:00
|
|
|
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
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLIElementType(enum.Enum):
|
2020-06-01 17:34:15 +00:00
|
|
|
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
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLIHeapFlags(enum.Flag):
|
2020-06-01 17:34:15 +00:00
|
|
|
BigStringStream = 1
|
|
|
|
BigGUIDStream = 2
|
|
|
|
BigBlobStream = 4
|
|
|
|
|
2020-06-02 00:26:37 +00:00
|
|
|
class CLIToken(Struct, nocopy=True):
|
2020-06-01 17:34:15 +00:00
|
|
|
row = UInt(24)
|
2020-06-01 17:36:29 +00:00
|
|
|
table = Enum(CLITableType, UInt(8))
|
2020-06-01 17:34:15 +00:00
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLICodedToken(Type):
|
2020-06-01 17:34:15 +00:00
|
|
|
def __init__(self, types):
|
|
|
|
self.types = types
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def _get_size(self, metadata):
|
2020-06-01 17:34:15 +00:00
|
|
|
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):
|
2020-06-02 00:26:58 +00:00
|
|
|
return table_bits, 2
|
2020-06-01 17:34:15 +00:00
|
|
|
else:
|
2020-06-02 00:26:58 +00:00
|
|
|
return table_bits, 4
|
|
|
|
|
|
|
|
def parse(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
table_bits, size = self._get_size(metadata)
|
2020-06-01 17:34:15 +00:00
|
|
|
val = int.from_bytes(input.read(size), 'little')
|
|
|
|
row = val >> table_bits
|
2020-06-01 22:56:59 +00:00
|
|
|
tag = val & ((1 << table_bits) - 1)
|
2020-06-01 17:36:29 +00:00
|
|
|
return CLIToken(row=row, table=self.types[tag])
|
2020-06-01 17:34:15 +00:00
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def sizeof(self, value, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
_, size = self._get_size(metadata)
|
|
|
|
return size
|
|
|
|
|
|
|
|
|
2020-06-02 00:26:37 +00:00
|
|
|
class CLISectionReference(Struct, nocopy=True):
|
2020-06-01 17:34:15 +00:00
|
|
|
rva = UInt(32)
|
|
|
|
size = UInt(32)
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLITableIndex(Type):
|
2020-06-01 17:34:15 +00:00
|
|
|
def __init__(self, type):
|
|
|
|
self.type = type
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def _get_size(self, metadata):
|
2020-06-01 17:34:15 +00:00
|
|
|
row_count = metadata.row_counts.get(self.type, 0)
|
|
|
|
if row_count < (1 << 16):
|
2020-06-02 00:26:58 +00:00
|
|
|
return 2
|
2020-06-01 17:34:15 +00:00
|
|
|
else:
|
2020-06-02 00:26:58 +00:00
|
|
|
return 4
|
|
|
|
|
|
|
|
def parse(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
size = self._get_size(metadata)
|
2020-06-01 17:34:15 +00:00
|
|
|
return int.from_bytes(input.read(size), 'little')
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def sizeof(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
return self._get_size(metadata)
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLITableRange(Type):
|
2020-06-01 17:34:15 +00:00
|
|
|
def __init__(self, type):
|
|
|
|
self.type = type
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def _get_size(self, metadata):
|
2020-06-01 17:34:15 +00:00
|
|
|
row_count = metadata.row_counts.get(self.type, 0)
|
|
|
|
if row_count < (1 << 16):
|
2020-06-02 00:26:58 +00:00
|
|
|
return 2
|
2020-06-01 17:34:15 +00:00
|
|
|
else:
|
2020-06-02 00:26:58 +00:00
|
|
|
return 4
|
|
|
|
|
|
|
|
def parse(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
size = self._get_size(metadata)
|
2020-06-01 17:34:15 +00:00
|
|
|
return int.from_bytes(input.read(size), 'little')
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def sizeof(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
return self._get_size(metadata)
|
|
|
|
|
2020-06-01 17:36:29 +00:00
|
|
|
class CLIStreamIndex(Type):
|
2020-06-01 17:34:15 +00:00
|
|
|
def __init__(self, type, child=None):
|
|
|
|
self.type = type
|
|
|
|
self.child = child
|
|
|
|
|
2020-06-02 00:26:58 +00:00
|
|
|
def _get_size(self, metadata):
|
2020-06-01 17:34:15 +00:00
|
|
|
big_mapping = {
|
2020-06-01 17:36:29 +00:00
|
|
|
CLIStreamType.String: CLIHeapFlags.BigStringStream,
|
|
|
|
CLIStreamType.Blob: CLIHeapFlags.BigBlobStream,
|
|
|
|
CLIStreamType.GUID: CLIHeapFlags.BigGUIDStream,
|
2020-06-01 17:34:15 +00:00
|
|
|
}
|
|
|
|
flag = big_mapping.get(self.type, None)
|
2020-06-02 00:26:58 +00:00
|
|
|
if not flag:
|
|
|
|
return 2
|
|
|
|
elif metadata.heap_flags & flag:
|
|
|
|
return 4
|
2020-06-01 17:34:15 +00:00
|
|
|
else:
|
2020-06-02 00:26:58 +00:00
|
|
|
return 2
|
|
|
|
|
|
|
|
def parse(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
size = self._get_size(metadata)
|
2020-06-01 17:34:15 +00:00
|
|
|
return int.from_bytes(input.read(size), 'little')
|
2020-06-02 00:26:58 +00:00
|
|
|
|
|
|
|
def sizeof(self, input, context):
|
|
|
|
metadata = context.user.metadata
|
|
|
|
return self._get_size(metadata)
|