Module refinery.units.formats.pe.dotnet.dncode
Expand source code Browse git
from __future__ import annotations
from refinery.lib.dotnet.header import DotNetHeader, TypeDef, MethodBodyInfo, MethodCodeType
from refinery.units.formats import PathExtractorUnit, UnpackResult
class dncode(PathExtractorUnit):
"""
Extracts .NET IL (or Microsoft IL, MSIL) method bodies from a .NET PE file. Each method is
emitted as a separate chunk containing the raw CIL bytecode (without the method body header).
The output can be piped into `refinery.dnopc` for disassembly.
Methods that are abstract, imported, or use non-IL implementation (native, runtime, OPTIL)
are silently skipped.
"""
def unpack(self, data):
header = DotNetHeader(data, parse_resources=False)
tables = header.meta.Streams.Tables
if not tables.MethodDef:
return
memo = [tr.MethodList.Index - 1 for tr in tables.TypeDef]
memo.append(len(tables.MethodDef))
ranges = [range(*memo[k:k + 2]) for k in range(len(memo) - 1)]
method_owners: list[TypeDef | None] = [None] * len(tables.MethodDef)
for methods_range, typedef in zip(ranges, tables.TypeDef):
for index in methods_range:
if index < len(method_owners):
method_owners[index] = typedef
def printable(name: str) -> bool:
return name.replace('.', '').isidentifier()
view = memoryview(data)
for index, method in enumerate(tables.MethodDef):
if method.RVA == 0 or method.CodeType != MethodCodeType.IL:
continue
try:
offset = header.pe.rva_to_offset(method.RVA)
except Exception:
self.log_warn(F'failed to convert RVA 0x{method.RVA:08X} for method {method.Name}')
continue
try:
body = MethodBodyInfo.Parse(view[offset:])
except Exception:
self.log_warn(F'failed to parse method body at offset 0x{offset:08X} for method {method.Name}')
continue
if not printable(method_name := method.Name):
method_name = F'method_{method.RVA:08X}'
if (owner := method_owners[index]) is not None:
namespace = owner.TypeNamespace
type_name = owner.TypeName
if not printable(type_name):
type_name = F'type{index}'
if not printable(namespace):
namespace = F'ns{index}'
namespace = namespace.replace('.', '/')
path = F'{namespace}/{type_name}/{method_name}'
else:
path = method_name
yield UnpackResult(path, body.code, flags=method.Flags)
@classmethod
def handles(cls, data):
from refinery.lib.id import is_likely_pe_dotnet
return is_likely_pe_dotnet(data)
Classes
class dncode (*paths, list=False, join_path=False, drop_path=False, fuzzy=0, exact=False, regex=False, path=b'path')-
Extracts .NET IL (or Microsoft IL, MSIL) method bodies from a .NET PE file. Each method is emitted as a separate chunk containing the raw CIL bytecode (without the method body header). The output can be piped into
dnopcfor disassembly.Methods that are abstract, imported, or use non-IL implementation (native, runtime, OPTIL) are silently skipped.
Expand source code Browse git
class dncode(PathExtractorUnit): """ Extracts .NET IL (or Microsoft IL, MSIL) method bodies from a .NET PE file. Each method is emitted as a separate chunk containing the raw CIL bytecode (without the method body header). The output can be piped into `refinery.dnopc` for disassembly. Methods that are abstract, imported, or use non-IL implementation (native, runtime, OPTIL) are silently skipped. """ def unpack(self, data): header = DotNetHeader(data, parse_resources=False) tables = header.meta.Streams.Tables if not tables.MethodDef: return memo = [tr.MethodList.Index - 1 for tr in tables.TypeDef] memo.append(len(tables.MethodDef)) ranges = [range(*memo[k:k + 2]) for k in range(len(memo) - 1)] method_owners: list[TypeDef | None] = [None] * len(tables.MethodDef) for methods_range, typedef in zip(ranges, tables.TypeDef): for index in methods_range: if index < len(method_owners): method_owners[index] = typedef def printable(name: str) -> bool: return name.replace('.', '').isidentifier() view = memoryview(data) for index, method in enumerate(tables.MethodDef): if method.RVA == 0 or method.CodeType != MethodCodeType.IL: continue try: offset = header.pe.rva_to_offset(method.RVA) except Exception: self.log_warn(F'failed to convert RVA 0x{method.RVA:08X} for method {method.Name}') continue try: body = MethodBodyInfo.Parse(view[offset:]) except Exception: self.log_warn(F'failed to parse method body at offset 0x{offset:08X} for method {method.Name}') continue if not printable(method_name := method.Name): method_name = F'method_{method.RVA:08X}' if (owner := method_owners[index]) is not None: namespace = owner.TypeNamespace type_name = owner.TypeName if not printable(type_name): type_name = F'type{index}' if not printable(namespace): namespace = F'ns{index}' namespace = namespace.replace('.', '/') path = F'{namespace}/{type_name}/{method_name}' else: path = method_name yield UnpackResult(path, body.code, flags=method.Flags) @classmethod def handles(cls, data): from refinery.lib.id import is_likely_pe_dotnet return is_likely_pe_dotnet(data)Ancestors
Subclasses
Class variables
var reverse-
The type of the None singleton.
Methods
def unpack(self, data)-
Expand source code Browse git
def unpack(self, data): header = DotNetHeader(data, parse_resources=False) tables = header.meta.Streams.Tables if not tables.MethodDef: return memo = [tr.MethodList.Index - 1 for tr in tables.TypeDef] memo.append(len(tables.MethodDef)) ranges = [range(*memo[k:k + 2]) for k in range(len(memo) - 1)] method_owners: list[TypeDef | None] = [None] * len(tables.MethodDef) for methods_range, typedef in zip(ranges, tables.TypeDef): for index in methods_range: if index < len(method_owners): method_owners[index] = typedef def printable(name: str) -> bool: return name.replace('.', '').isidentifier() view = memoryview(data) for index, method in enumerate(tables.MethodDef): if method.RVA == 0 or method.CodeType != MethodCodeType.IL: continue try: offset = header.pe.rva_to_offset(method.RVA) except Exception: self.log_warn(F'failed to convert RVA 0x{method.RVA:08X} for method {method.Name}') continue try: body = MethodBodyInfo.Parse(view[offset:]) except Exception: self.log_warn(F'failed to parse method body at offset 0x{offset:08X} for method {method.Name}') continue if not printable(method_name := method.Name): method_name = F'method_{method.RVA:08X}' if (owner := method_owners[index]) is not None: namespace = owner.TypeNamespace type_name = owner.TypeName if not printable(type_name): type_name = F'type{index}' if not printable(namespace): namespace = F'ns{index}' namespace = namespace.replace('.', '/') path = F'{namespace}/{type_name}/{method_name}' else: path = method_name yield UnpackResult(path, body.code, flags=method.Flags)
Inherited members
PathExtractorUnit:CustomJoinBehaviourCustomPathSeparatorFilterEverythingRequiresactassemblecodecconsolefilterfinishhandlesis_quietis_reversibleisattylabelledleniencylog_alwayslog_debuglog_detachlog_faillog_infolog_levellog_warnloggernamenozzleoptional_dependenciesreadread1required_dependenciesresetrunsourcesuperinit
UnitBase: