Module refinery.lib.dotnet.disassembler.factory
Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Dict, Optional
from refinery.lib.dotnet.disassembler.model import (
Argument,
DisassemblerException,
Instruction,
Method, Op, String, )
class InstructionFactory:
@staticmethod
def create(data: bytes, i: int, op: Op) -> Instruction:
argument_data = (
data[len(op.code): len(op)] if op.fixed_length else data[len(op.code):]
)
if len(op) - len(op.code) != len(argument_data):
raise DisassemblerException(
'Mismatching argument length for "%s" %i - %i != %i: %s'
% (
op.mnemonic,
len(op),
len(op.code),
len(argument_data),
argument_data.hex(),
)
)
arguments = []
k = 0
for cil_arg in op.arguments:
arguments.append(Argument(argument_data[k: k + len(cil_arg)], cil_arg))
k += len(cil_arg)
return Instruction(data, i, op, arguments)
@staticmethod
def switch(data: bytes, i: int, op: Op) -> Instruction:
assert data[0] == 69
case_count_arg = op.arguments[0]
case_data = data[1:5]
cases = case_count_arg.unpack(case_data)
end_offset = (cases + 1) * 4
if len(data) < end_offset:
raise DisassemblerException(F'Check failed during switch disassembly: {len(data)} < ({cases} + 1) * 4')
if op.arguments[2] is not ...:
raise DisassemblerException('Last argument for switch op must be ellipsis.')
args = [Argument(case_data, case_count_arg)]
case_arg = op.arguments[1]
for k in range(4, end_offset, 4):
raw_data = data[1 + k:1 + k + 4]
args.append(Argument(raw_data, case_arg))
return Instruction(data[:1 + end_offset], i, op, args)
class OutputFactory:
def __init__(
self,
il_refs: bool = False,
address: bool = True,
hexdump: bool = True,
arguments: bool = True,
token_labels: Optional[Dict[int, str]] = None,
):
self._il_refs = il_refs
self._address = address
self._hexdump = hexdump
self._arguments = arguments
self._token_labels = {} if token_labels is None else token_labels
def extend_token_labels(self, token_labels: Dict[int, str]):
self._token_labels.update(token_labels)
def instruction(self, instruction: Instruction) -> str:
if not self._arguments or len(instruction.op.arguments) == 0:
args = ''
elif instruction.op.is_switch:
args = F" -> {', '.join(self._il(instruction, arg.value) for arg in instruction.arguments[1:])}"
else:
ins_argument = instruction.arguments[0]
op_argument = instruction.op.arguments[0]
args = f"(0x{ins_argument.value:X}"
if self._il_refs and op_argument.has_target:
args += f" -> {self._il(instruction, ins_argument.value)}"
elif isinstance(op_argument, Method) and ins_argument.value in self._token_labels.keys():
args += f" -> {self._token_labels[ins_argument.value]}"
elif isinstance(op_argument, String) and ins_argument.value in self._token_labels.keys():
args += f' -> "{self._token_labels[ins_argument.value]}"'
args += ')'
prefix_parts = []
if self._hexdump:
prefix_parts.append(f"/* {instruction.data.hex():<12} */")
if self._address:
prefix_parts.append(f"IL_{instruction.offset:04X}")
line = ' '.join(prefix_parts) + ': ' if prefix_parts else ''
line += F"{instruction.op.mnemonic}{args}"
return line
@staticmethod
def _il(instruction: Instruction, offset: int) -> str:
return F"IL_{instruction.offset + offset + len(instruction):04X}"
Classes
class InstructionFactory
-
Expand source code Browse git
class InstructionFactory: @staticmethod def create(data: bytes, i: int, op: Op) -> Instruction: argument_data = ( data[len(op.code): len(op)] if op.fixed_length else data[len(op.code):] ) if len(op) - len(op.code) != len(argument_data): raise DisassemblerException( 'Mismatching argument length for "%s" %i - %i != %i: %s' % ( op.mnemonic, len(op), len(op.code), len(argument_data), argument_data.hex(), ) ) arguments = [] k = 0 for cil_arg in op.arguments: arguments.append(Argument(argument_data[k: k + len(cil_arg)], cil_arg)) k += len(cil_arg) return Instruction(data, i, op, arguments) @staticmethod def switch(data: bytes, i: int, op: Op) -> Instruction: assert data[0] == 69 case_count_arg = op.arguments[0] case_data = data[1:5] cases = case_count_arg.unpack(case_data) end_offset = (cases + 1) * 4 if len(data) < end_offset: raise DisassemblerException(F'Check failed during switch disassembly: {len(data)} < ({cases} + 1) * 4') if op.arguments[2] is not ...: raise DisassemblerException('Last argument for switch op must be ellipsis.') args = [Argument(case_data, case_count_arg)] case_arg = op.arguments[1] for k in range(4, end_offset, 4): raw_data = data[1 + k:1 + k + 4] args.append(Argument(raw_data, case_arg)) return Instruction(data[:1 + end_offset], i, op, args)
Static methods
def create(data, i, op)
-
Expand source code Browse git
@staticmethod def create(data: bytes, i: int, op: Op) -> Instruction: argument_data = ( data[len(op.code): len(op)] if op.fixed_length else data[len(op.code):] ) if len(op) - len(op.code) != len(argument_data): raise DisassemblerException( 'Mismatching argument length for "%s" %i - %i != %i: %s' % ( op.mnemonic, len(op), len(op.code), len(argument_data), argument_data.hex(), ) ) arguments = [] k = 0 for cil_arg in op.arguments: arguments.append(Argument(argument_data[k: k + len(cil_arg)], cil_arg)) k += len(cil_arg) return Instruction(data, i, op, arguments)
def switch(data, i, op)
-
Expand source code Browse git
@staticmethod def switch(data: bytes, i: int, op: Op) -> Instruction: assert data[0] == 69 case_count_arg = op.arguments[0] case_data = data[1:5] cases = case_count_arg.unpack(case_data) end_offset = (cases + 1) * 4 if len(data) < end_offset: raise DisassemblerException(F'Check failed during switch disassembly: {len(data)} < ({cases} + 1) * 4') if op.arguments[2] is not ...: raise DisassemblerException('Last argument for switch op must be ellipsis.') args = [Argument(case_data, case_count_arg)] case_arg = op.arguments[1] for k in range(4, end_offset, 4): raw_data = data[1 + k:1 + k + 4] args.append(Argument(raw_data, case_arg)) return Instruction(data[:1 + end_offset], i, op, args)
class OutputFactory (il_refs=False, address=True, hexdump=True, arguments=True, token_labels=None)
-
Expand source code Browse git
class OutputFactory: def __init__( self, il_refs: bool = False, address: bool = True, hexdump: bool = True, arguments: bool = True, token_labels: Optional[Dict[int, str]] = None, ): self._il_refs = il_refs self._address = address self._hexdump = hexdump self._arguments = arguments self._token_labels = {} if token_labels is None else token_labels def extend_token_labels(self, token_labels: Dict[int, str]): self._token_labels.update(token_labels) def instruction(self, instruction: Instruction) -> str: if not self._arguments or len(instruction.op.arguments) == 0: args = '' elif instruction.op.is_switch: args = F" -> {', '.join(self._il(instruction, arg.value) for arg in instruction.arguments[1:])}" else: ins_argument = instruction.arguments[0] op_argument = instruction.op.arguments[0] args = f"(0x{ins_argument.value:X}" if self._il_refs and op_argument.has_target: args += f" -> {self._il(instruction, ins_argument.value)}" elif isinstance(op_argument, Method) and ins_argument.value in self._token_labels.keys(): args += f" -> {self._token_labels[ins_argument.value]}" elif isinstance(op_argument, String) and ins_argument.value in self._token_labels.keys(): args += f' -> "{self._token_labels[ins_argument.value]}"' args += ')' prefix_parts = [] if self._hexdump: prefix_parts.append(f"/* {instruction.data.hex():<12} */") if self._address: prefix_parts.append(f"IL_{instruction.offset:04X}") line = ' '.join(prefix_parts) + ': ' if prefix_parts else '' line += F"{instruction.op.mnemonic}{args}" return line @staticmethod def _il(instruction: Instruction, offset: int) -> str: return F"IL_{instruction.offset + offset + len(instruction):04X}"
Methods
def extend_token_labels(self, token_labels)
-
Expand source code Browse git
def extend_token_labels(self, token_labels: Dict[int, str]): self._token_labels.update(token_labels)
def instruction(self, instruction)
-
Expand source code Browse git
def instruction(self, instruction: Instruction) -> str: if not self._arguments or len(instruction.op.arguments) == 0: args = '' elif instruction.op.is_switch: args = F" -> {', '.join(self._il(instruction, arg.value) for arg in instruction.arguments[1:])}" else: ins_argument = instruction.arguments[0] op_argument = instruction.op.arguments[0] args = f"(0x{ins_argument.value:X}" if self._il_refs and op_argument.has_target: args += f" -> {self._il(instruction, ins_argument.value)}" elif isinstance(op_argument, Method) and ins_argument.value in self._token_labels.keys(): args += f" -> {self._token_labels[ins_argument.value]}" elif isinstance(op_argument, String) and ins_argument.value in self._token_labels.keys(): args += f' -> "{self._token_labels[ins_argument.value]}"' args += ')' prefix_parts = [] if self._hexdump: prefix_parts.append(f"/* {instruction.data.hex():<12} */") if self._address: prefix_parts.append(f"IL_{instruction.offset:04X}") line = ' '.join(prefix_parts) + ': ' if prefix_parts else '' line += F"{instruction.op.mnemonic}{args}" return line